1
0
mirror of https://github.com/mariadb-corporation/mariadb-columnstore-engine.git synced 2025-08-01 06:46:55 +03:00

MCOL-4478 MCS now rounds the last digits of an avg() result for wide-DECIMAL argument

This commit is contained in:
Roman Nozdrin
2020-12-30 11:35:51 +00:00
parent cf11e03d4b
commit 5b9689ce55
4 changed files with 40 additions and 23 deletions

View File

@ -22,24 +22,6 @@
namespace datatypes namespace datatypes
{ {
struct lldiv_t_128
{
int128_t quot;
int128_t rem;
lldiv_t_128() : quot(0), rem(0) {}
lldiv_t_128(const int128_t& a_quot, const int128_t& a_rem)
: quot(a_quot), rem(a_rem) {}
};
inline lldiv_t_128 lldiv128(const int128_t& dividend, const int128_t& divisor)
{
if (UNLIKELY(divisor == 0) || UNLIKELY(dividend == 0))
return lldiv_t_128();
return lldiv_t_128(dividend / divisor, dividend % divisor);
}
template<typename BinaryOperation, template<typename BinaryOperation,
typename OpOverflowCheck, typename OpOverflowCheck,
typename MultiplicationOverflowCheck> typename MultiplicationOverflowCheck>
@ -115,7 +97,6 @@ namespace datatypes
? r.s128Value : r.value; ? r.s128Value : r.value;
opOverflowCheck(lValue, rValue); opOverflowCheck(lValue, rValue);
if (result.scale >= l.scale - r.scale) if (result.scale >= l.scale - r.scale)
{ {
int128_t scaleMultiplier; int128_t scaleMultiplier;
@ -213,7 +194,7 @@ namespace datatypes
// rem carries the value's sign, but needs to be normalized. // rem carries the value's sign, but needs to be normalized.
int64_t s = l.scale - r.scale; int64_t s = l.scale - r.scale;
int128_t divisor; int128_t divisor;
getScaleDivisor(divisor, abs(s)); getScaleDivisor(divisor, std::abs(s));
if (s < 0) if (s < 0)
{ {

View File

@ -161,6 +161,23 @@ inline void getScaleDivisor(T& divisor, const int8_t scale)
} }
} }
struct lldiv_t_128
{
int128_t quot;
int128_t rem;
lldiv_t_128() : quot(0), rem(0) {}
lldiv_t_128(const int128_t& a_quot, const int128_t& a_rem)
: quot(a_quot), rem(a_rem) {}
};
inline lldiv_t_128 lldiv128(const int128_t& dividend, const int128_t& divisor)
{
if (UNLIKELY(divisor == 0) || UNLIKELY(dividend == 0))
return lldiv_t_128();
return lldiv_t_128(dividend / divisor, dividend % divisor);
}
// @brief The class for Decimal related operations // @brief The class for Decimal related operations
// The class contains Decimal related operations are scale and // The class contains Decimal related operations are scale and
// precision aware. // precision aware.

View File

@ -111,6 +111,11 @@ template<>
struct is_uint128_t<uint128_t> { struct is_uint128_t<uint128_t> {
static const bool value = true; static const bool value = true;
}; };
inline int128_t abs(int128_t& x)
{
return (x >= 0) ? x : -x;
}
class TSInt128 class TSInt128
{ {

View File

@ -2788,7 +2788,7 @@ void RowAggregationUM::calculateAvgColumns()
uint32_t offset = fRow.getOffset(colOut); uint32_t offset = fRow.getOffset(colOut);
uint32_t scale = fRow.getScale(colOut); uint32_t scale = fRow.getScale(colOut);
// Get multiplied to deliver AVG with the scale closest // Get multiplied to deliver AVG with the scale closest
// to the expected original scale + 4. // to the expected original scale + 4.
// There is a counterpart in buildAggregateColumn. // There is a counterpart in buildAggregateColumn.
datatypes::Decimal::setScalePrecision4Avg(precision, scale); datatypes::Decimal::setScalePrecision4Avg(precision, scale);
int128_t* sumPnt = fRow.getBinaryField_offset<int128_t>(offset); int128_t* sumPnt = fRow.getBinaryField_offset<int128_t>(offset);
@ -2800,8 +2800,22 @@ void RowAggregationUM::calculateAvgColumns()
multOp(*sumPnt, datatypes::mcs_pow_10[scaleDiff], sum); multOp(*sumPnt, datatypes::mcs_pow_10[scaleDiff], sum);
else else
sum = *sumPnt; sum = *sumPnt;
int128_t avg = sum / cnt; datatypes::lldiv_t_128 avgAndRem = datatypes::lldiv128(sum, cnt);
fRow.setBinaryField_offset(&avg, sizeof(avg), offset); // Round the last digit
if (datatypes::abs(avgAndRem.rem) * 2 >= (int128_t)cnt)
{
if (utils::is_negative(avgAndRem.rem))
{
avgAndRem.quot--;
}
else
{
avgAndRem.quot++;
}
}
fRow.setBinaryField_offset(&avgAndRem.quot,
sizeof(avgAndRem.quot),
offset);
} }
} }
} }