This is an automated email from the ASF dual-hosted git repository.

yiguolei pushed a commit to branch branch-4.2
in repository https://gitbox.apache.org/repos/asf/doris.git

commit 091b5b503e0856a40213505a1642455b66e6a669
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Thu Sep 24 09:20:53 2026 +0800

    branch-4.1: [fix](function) Fix decimal rounding overflow at scale 
boundaries #68251 (#68415)
    
    Cherry-picked from #68251
    
    Co-authored-by: Mryange <[email protected]>
---
 be/src/exprs/function/round.h                  | 248 +++++++------------------
 be/test/exprs/function/function_round_test.cpp |  88 +++++++++
 2 files changed, 150 insertions(+), 186 deletions(-)

diff --git a/be/src/exprs/function/round.h b/be/src/exprs/function/round.h
index 1b44ef1dfb2..2aefa906fcc 100644
--- a/be/src/exprs/function/round.h
+++ b/be/src/exprs/function/round.h
@@ -108,41 +108,42 @@ struct IntegerRoundingComputation {
 
     static size_t prepare(size_t scale) { return scale; }
 
-    /// Integer overflow is Ok.
     static ALWAYS_INLINE T compute_impl(T x, T scale, T target_scale) {
+        T quotient = x / scale;
+        const T remainder = x - quotient * scale;
+
         if constexpr (rounding_mode == RoundingMode::Trunc) {
-            return target_scale > 1 ? x / scale * target_scale : x / scale;
+            return target_scale > 1 ? quotient * target_scale : quotient;
         }
         if constexpr (rounding_mode == RoundingMode::Floor) {
-            if (x < 0) {
-                x -= scale - 1;
+            if (remainder < 0) {
+                --quotient;
             }
-            return target_scale > 1 ? x / scale * target_scale : x / scale;
+            return target_scale > 1 ? quotient * target_scale : quotient;
         }
         if constexpr (rounding_mode == RoundingMode::Ceil) {
-            if (x >= 0) {
-                x += scale - 1;
+            if (remainder > 0) {
+                ++quotient;
             }
-            return target_scale > 1 ? x / scale * target_scale : x / scale;
+            return target_scale > 1 ? quotient * target_scale : quotient;
         }
         if constexpr (rounding_mode == RoundingMode::Round) {
-            if (x < 0) {
-                x -= scale;
-            }
+            const T abs_remainder = remainder < 0 ? -remainder : remainder;
+            const T remainder_complement = scale - abs_remainder;
+            const T carry = remainder < 0 ? -1 : 1;
             if constexpr (tie_breaking_mode == TieBreakingMode::Auto) {
-                x = (x + scale / 2) / scale;
+                if (remainder != 0 && abs_remainder >= remainder_complement) {
+                    quotient += carry;
+                }
             }
             if constexpr (tie_breaking_mode == TieBreakingMode::Bankers) {
-                T quotient = (x + scale / 2) / scale;
-                if (quotient * scale == x + scale / 2) {
-                    // round half to even
-                    x = (quotient + (x < 0)) & ~1;
-                } else {
-                    // round the others as usual
-                    x = quotient;
+                if (remainder != 0 &&
+                    (abs_remainder > remainder_complement ||
+                     (abs_remainder == remainder_complement && (quotient & 1) 
!= 0))) {
+                    quotient += carry;
                 }
             }
-            return target_scale > 1 ? x * target_scale : x;
+            return target_scale > 1 ? quotient * target_scale : quotient;
         }
     }
 
@@ -157,7 +158,21 @@ struct IntegerRoundingComputation {
                                       U target_scale) {
         if constexpr (sizeof(T) <= sizeof(scale) && scale_mode == 
ScaleMode::Negative) {
             if (scale >= std::numeric_limits<T>::max()) {
-                *out = 0;
+                if constexpr (!is_decimal(Type)) {
+                    *out = 0;
+                } else {
+                    // A saturated divisor is larger than every valid value of 
this Decimal type.
+                    // Only directed rounding can produce one representable 
target unit.
+                    if (target_scale >= std::numeric_limits<T>::max()) {
+                        *out = T(0);
+                    } else if constexpr (rounding_mode == RoundingMode::Floor) 
{
+                        *out = *in < 0 ? -target_scale : T(0);
+                    } else if constexpr (rounding_mode == RoundingMode::Ceil) {
+                        *out = *in > 0 ? target_scale : T(0);
+                    } else {
+                        *out = T(0);
+                    }
+                }
                 return;
             }
         }
@@ -176,28 +191,21 @@ private:
 
 public:
     static NO_INLINE void apply(const Container& in, UInt32 in_scale, 
Container& out,
-                                Int16 out_scale) {
-        Int16 scale_arg = in_scale - out_scale;
+                                Int16 out_scale, Int16 result_scale) {
+        Int32 scale_arg = static_cast<Int32>(in_scale) - out_scale;
         if (scale_arg > 0) {
             auto scale = DecimalScaleParams::get_scale_factor<Type>(scale_arg);
+            auto target_scale =
+                    DecimalScaleParams::get_scale_factor<Type>(result_scale - 
out_scale);
 
-            const NativeType* __restrict p_in = reinterpret_cast<const 
NativeType*>(in.data());
+            const auto* __restrict p_in = reinterpret_cast<const 
NativeType*>(in.data());
             const NativeType* end_in = reinterpret_cast<const 
NativeType*>(in.data()) + in.size();
-            NativeType* __restrict p_out = 
reinterpret_cast<NativeType*>(out.data());
-
-            if (out_scale < 0) {
-                auto negative_scale = 
DecimalScaleParams::get_scale_factor<Type>(-out_scale);
-                while (p_in < end_in) {
-                    Op::compute(p_in, scale, p_out, negative_scale);
-                    ++p_in;
-                    ++p_out;
-                }
-            } else {
-                while (p_in < end_in) {
-                    Op::compute(p_in, scale, p_out, 1);
-                    ++p_in;
-                    ++p_out;
-                }
+            auto* __restrict p_out = reinterpret_cast<NativeType*>(out.data());
+
+            while (p_in < end_in) {
+                Op::compute(p_in, scale, p_out, target_scale);
+                ++p_in;
+                ++p_out;
             }
         } else {
             memcpy(out.data(), in.data(), in.size() * sizeof(T));
@@ -205,16 +213,13 @@ public:
     }
 
     static NO_INLINE void apply(const NativeType& in, UInt32 in_scale, 
NativeType& out,
-                                Int16 out_scale) {
-        Int16 scale_arg = in_scale - out_scale;
+                                Int16 out_scale, Int16 result_scale) {
+        Int32 scale_arg = static_cast<Int32>(in_scale) - out_scale;
         if (scale_arg > 0) {
             auto scale = DecimalScaleParams::get_scale_factor<Type>(scale_arg);
-            if (out_scale < 0) {
-                auto negative_scale = 
DecimalScaleParams::get_scale_factor<Type>(-out_scale);
-                Op::compute(&in, scale, &out, negative_scale);
-            } else {
-                Op::compute(&in, scale, &out, 1);
-            }
+            auto target_scale =
+                    DecimalScaleParams::get_scale_factor<Type>(result_scale - 
out_scale);
+            Op::compute(&in, scale, &out, target_scale);
         } else {
             memcpy(&out, &in, sizeof(NativeType));
         }
@@ -486,72 +491,27 @@ struct Dispatcher {
             const auto* const decimal_col =
                     check_and_get_column<typename 
PrimitiveTypeTraits<T>::ColumnType>(col_general);
             const auto& vec_src = decimal_col->get_data();
-            const size_t input_rows_count = vec_src.size();
             auto col_res = 
PrimitiveTypeTraits<T>::ColumnType::create(vec_src.size(), result_scale);
             auto& vec_res = col_res->get_data();
 
             if (!vec_res.empty()) {
-                FunctionRoundingImpl<ScaleMode::Negative>::apply(
-                        decimal_col->get_data(), decimal_col->get_scale(), 
vec_res, scale_arg);
-            }
-            // We need to always make sure result decimal's scale is as 
expected as its in plan
-            // So we need to append enough zero to result.
-
-            // Case 0: scale_arg <= -(integer part digits count)
-            //      do nothing, because result is 0
-            // Case 1: scale_arg <= 0 && scale_arg > -(integer part digits 
count)
-            //      decimal parts has been erased, so add them back by 
multiply 10^(result_scale)
-            // Case 2: scale_arg > 0 && scale_arg < result_scale
-            //      decimal part now has scale_arg digits, so multiply 
10^(result_scale - scal_arg)
-            // Case 3: scale_arg >= input_scale
-            //      do nothing
-
-            if (scale_arg <= 0) {
-                for (size_t i = 0; i < input_rows_count; ++i) {
-                    vec_res[i] = DecimalV2Value(vec_res[i].value() * 
int_exp10(result_scale));
-                }
-            } else if (scale_arg > 0 && scale_arg < result_scale) {
-                for (size_t i = 0; i < input_rows_count; ++i) {
-                    vec_res[i] = DecimalV2Value(vec_res[i].value() *
-                                                int_exp10(result_scale - 
scale_arg));
-                }
+                
FunctionRoundingImpl<ScaleMode::Negative>::apply(decimal_col->get_data(),
+                                                                 
decimal_col->get_scale(), vec_res,
+                                                                 scale_arg, 
result_scale);
             }
-
             return col_res;
         } else if constexpr (is_decimal(T)) {
             const auto* const decimal_col =
                     check_and_get_column<typename 
PrimitiveTypeTraits<T>::ColumnType>(col_general);
             const auto& vec_src = decimal_col->get_data();
-            const size_t input_rows_count = vec_src.size();
             auto col_res = 
PrimitiveTypeTraits<T>::ColumnType::create(vec_src.size(), result_scale);
             auto& vec_res = col_res->get_data();
 
             if (!vec_res.empty()) {
-                FunctionRoundingImpl<ScaleMode::Negative>::apply(
-                        decimal_col->get_data(), decimal_col->get_scale(), 
vec_res, scale_arg);
+                
FunctionRoundingImpl<ScaleMode::Negative>::apply(decimal_col->get_data(),
+                                                                 
decimal_col->get_scale(), vec_res,
+                                                                 scale_arg, 
result_scale);
             }
-            // We need to always make sure result decimal's scale is as 
expected as its in plan
-            // So we need to append enough zero to result.
-
-            // Case 0: scale_arg <= -(integer part digits count)
-            //      do nothing, because result is 0
-            // Case 1: scale_arg <= 0 && scale_arg > -(integer part digits 
count)
-            //      decimal parts has been erased, so add them back by 
multiply 10^(result_scale)
-            // Case 2: scale_arg > 0 && scale_arg < result_scale
-            //      decimal part now has scale_arg digits, so multiply 
10^(result_scale - scal_arg)
-            // Case 3: scale_arg >= input_scale
-            //      do nothing
-
-            if (scale_arg <= 0) {
-                for (size_t i = 0; i < input_rows_count; ++i) {
-                    vec_res[i].value *= int_exp10(result_scale);
-                }
-            } else if (scale_arg > 0 && scale_arg < result_scale) {
-                for (size_t i = 0; i < input_rows_count; ++i) {
-                    vec_res[i].value *= int_exp10(result_scale - scale_arg);
-                }
-            }
-
             return col_res;
         } else {
             static_assert(false);
@@ -607,29 +567,7 @@ struct Dispatcher {
             for (size_t i = 0; i < input_row_count; ++i) {
                 DecimalRoundingImpl<T, rounding_mode, 
tie_breaking_mode>::apply(
                         decimal_col->get_element(i).value(), input_scale,
-                        col_res->get_element(i).value(), 
col_scale_i32.get_data()[i]);
-            }
-
-            for (size_t i = 0; i < input_row_count; ++i) {
-                // For func(ColumnDecimal, ColumnInt32), we should always have 
same scale with source Decimal column
-                // So we need this check to make sure the result have correct 
digits count
-                //
-                // Case 0: scale_arg <= -(integer part digits count)
-                //      do nothing, because result is 0
-                // Case 1: scale_arg <= 0 && scale_arg > -(integer part digits 
count)
-                //      decimal parts has been erased, so add them back by 
multiply 10^(scale_arg)
-                // Case 2: scale_arg > 0 && scale_arg < result_scale
-                //      decimal part now has scale_arg digits, so multiply 
10^(result_scale - scal_arg)
-                // Case 3: scale_arg >= input_scale
-                //      do nothing
-                const Int32 scale_arg = col_scale_i32.get_data()[i];
-                if (scale_arg <= 0) {
-                    col_res->get_element(i) = 
DecimalV2Value(col_res->get_element(i).value() *
-                                                             
int_exp10(result_scale));
-                } else if (scale_arg > 0 && scale_arg < result_scale) {
-                    col_res->get_element(i) = 
DecimalV2Value(col_res->get_element(i).value() *
-                                                             
int_exp10(result_scale - scale_arg));
-                }
+                        col_res->get_element(i).value(), 
col_scale_i32.get_data()[i], result_scale);
             }
 
             return col_res;
@@ -643,27 +581,7 @@ struct Dispatcher {
             for (size_t i = 0; i < input_row_count; ++i) {
                 DecimalRoundingImpl<T, rounding_mode, 
tie_breaking_mode>::apply(
                         decimal_col->get_element(i).value, input_scale,
-                        col_res->get_element(i).value, 
col_scale_i32.get_data()[i]);
-            }
-
-            for (size_t i = 0; i < input_row_count; ++i) {
-                // For func(ColumnDecimal, ColumnInt32), we should always have 
same scale with source Decimal column
-                // So we need this check to make sure the result have correct 
digits count
-                //
-                // Case 0: scale_arg <= -(integer part digits count)
-                //      do nothing, because result is 0
-                // Case 1: scale_arg <= 0 && scale_arg > -(integer part digits 
count)
-                //      decimal parts has been erased, so add them back by 
multiply 10^(scale_arg)
-                // Case 2: scale_arg > 0 && scale_arg < result_scale
-                //      decimal part now has scale_arg digits, so multiply 
10^(result_scale - scal_arg)
-                // Case 3: scale_arg >= input_scale
-                //      do nothing
-                const Int32 scale_arg = col_scale_i32.get_data()[i];
-                if (scale_arg <= 0) {
-                    col_res->get_element(i).value *= int_exp10(result_scale);
-                } else if (scale_arg > 0 && scale_arg < result_scale) {
-                    col_res->get_element(i).value *= int_exp10(result_scale - 
scale_arg);
-                }
+                        col_res->get_element(i).value, 
col_scale_i32.get_data()[i], result_scale);
             }
 
             return col_res;
@@ -701,29 +619,7 @@ struct Dispatcher {
             for (size_t i = 0; i < input_rows_count; ++i) {
                 DecimalRoundingImpl<T, rounding_mode, 
tie_breaking_mode>::apply(
                         general_val, input_scale, 
col_res->get_element(i).value(),
-                        col_scale_i32.get_data()[i]);
-            }
-
-            for (size_t i = 0; i < input_rows_count; ++i) {
-                // For func(ColumnDecimal, ColumnInt32), we should always have 
same scale with source Decimal column
-                // So we need this check to make sure the result have correct 
digits count
-                //
-                // Case 0: scale_arg <= -(integer part digits count)
-                //      do nothing, because result is 0
-                // Case 1: scale_arg <= 0 && scale_arg > -(integer part digits 
count)
-                //      decimal parts has been erased, so add them back by 
multiply 10^(scale_arg)
-                // Case 2: scale_arg > 0 && scale_arg < result_scale
-                //      decimal part now has scale_arg digits, so multiply 
10^(result_scale - scal_arg)
-                // Case 3: scale_arg >= input_scale
-                //      do nothing
-                const Int32 scale_arg = col_scale_i32.get_data()[i];
-                if (scale_arg <= 0) {
-                    col_res->get_element(i) = 
DecimalV2Value(col_res->get_element(i).value() *
-                                                             
int_exp10(result_scale));
-                } else if (scale_arg > 0 && scale_arg < result_scale) {
-                    col_res->get_element(i) = 
DecimalV2Value(col_res->get_element(i).value() *
-                                                             
int_exp10(result_scale - scale_arg));
-                }
+                        col_scale_i32.get_data()[i], result_scale);
             }
 
             return col_res;
@@ -739,27 +635,7 @@ struct Dispatcher {
             for (size_t i = 0; i < input_rows_count; ++i) {
                 DecimalRoundingImpl<T, rounding_mode, 
tie_breaking_mode>::apply(
                         general_val, input_scale, 
col_res->get_element(i).value,
-                        col_scale_i32.get_data()[i]);
-            }
-
-            for (size_t i = 0; i < input_rows_count; ++i) {
-                // For func(ColumnDecimal, ColumnInt32), we should always have 
same scale with source Decimal column
-                // So we need this check to make sure the result have correct 
digits count
-                //
-                // Case 0: scale_arg <= -(integer part digits count)
-                //      do nothing, because result is 0
-                // Case 1: scale_arg <= 0 && scale_arg > -(integer part digits 
count)
-                //      decimal parts has been erased, so add them back by 
multiply 10^(scale_arg)
-                // Case 2: scale_arg > 0 && scale_arg < result_scale
-                //      decimal part now has scale_arg digits, so multiply 
10^(result_scale - scal_arg)
-                // Case 3: scale_arg >= input_scale
-                //      do nothing
-                const Int32 scale_arg = col_scale_i32.get_data()[i];
-                if (scale_arg <= 0) {
-                    col_res->get_element(i).value *= int_exp10(result_scale);
-                } else if (scale_arg > 0 && scale_arg < result_scale) {
-                    col_res->get_element(i).value *= int_exp10(result_scale - 
scale_arg);
-                }
+                        col_scale_i32.get_data()[i], result_scale);
             }
 
             return col_res;
diff --git a/be/test/exprs/function/function_round_test.cpp 
b/be/test/exprs/function/function_round_test.cpp
index 1c6b8ab8385..deb2482fb9e 100644
--- a/be/test/exprs/function/function_round_test.cpp
+++ b/be/test/exprs/function/function_round_test.cpp
@@ -59,20 +59,33 @@ using Decimal32FloorFunction = 
FunctionRounding<DecimalRoundTwoImpl<FloorName, T
                                                 RoundingMode::Floor, 
TieBreakingMode::Auto>;
 using Decimal64FloorFunction = FunctionRounding<DecimalRoundTwoImpl<FloorName, 
TYPE_DECIMAL64>,
                                                 RoundingMode::Floor, 
TieBreakingMode::Auto>;
+using Decimal128FloorFunction = 
FunctionRounding<DecimalRoundTwoImpl<FloorName, TYPE_DECIMAL128I>,
+                                                 RoundingMode::Floor, 
TieBreakingMode::Auto>;
+using Decimal256FloorFunction = 
FunctionRounding<DecimalRoundTwoImpl<FloorName, TYPE_DECIMAL256>,
+                                                 RoundingMode::Floor, 
TieBreakingMode::Auto>;
 using Decimal32CeilFunction = FunctionRounding<DecimalRoundTwoImpl<CeilName, 
TYPE_DECIMAL32>,
                                                RoundingMode::Ceil, 
TieBreakingMode::Auto>;
 using Decimal64CeilFunction = FunctionRounding<DecimalRoundTwoImpl<CeilName, 
TYPE_DECIMAL64>,
                                                RoundingMode::Ceil, 
TieBreakingMode::Auto>;
+using Decimal128CeilFunction = FunctionRounding<DecimalRoundTwoImpl<CeilName, 
TYPE_DECIMAL128I>,
+                                                RoundingMode::Ceil, 
TieBreakingMode::Auto>;
+using Decimal256CeilFunction = FunctionRounding<DecimalRoundTwoImpl<CeilName, 
TYPE_DECIMAL256>,
+                                                RoundingMode::Ceil, 
TieBreakingMode::Auto>;
 using Decimal32RoundFunction = FunctionRounding<DecimalRoundTwoImpl<RoundName, 
TYPE_DECIMAL32>,
                                                 RoundingMode::Round, 
TieBreakingMode::Auto>;
 using Decimal64RoundFunction = FunctionRounding<DecimalRoundTwoImpl<RoundName, 
TYPE_DECIMAL64>,
                                                 RoundingMode::Round, 
TieBreakingMode::Auto>;
+using Decimal128RoundFunction = 
FunctionRounding<DecimalRoundTwoImpl<RoundName, TYPE_DECIMAL128I>,
+                                                 RoundingMode::Round, 
TieBreakingMode::Auto>;
 using Decimal32RoundBankersFunction =
         FunctionRounding<DecimalRoundTwoImpl<RoundBankersName, 
TYPE_DECIMAL32>, RoundingMode::Round,
                          TieBreakingMode::Bankers>;
 using Decimal64RoundBankersFunction =
         FunctionRounding<DecimalRoundTwoImpl<RoundBankersName, 
TYPE_DECIMAL64>, RoundingMode::Round,
                          TieBreakingMode::Bankers>;
+using Decimal128RoundBankersFunction =
+        FunctionRounding<DecimalRoundTwoImpl<RoundBankersName, 
TYPE_DECIMAL128I>,
+                         RoundingMode::Round, TieBreakingMode::Bankers>;
 
 using FloatTruncateFunction = 
FunctionRounding<DoubleRoundTwoImpl<TruncateName>,
                                                RoundingMode::Trunc, 
TieBreakingMode::Auto>;
@@ -1022,6 +1035,44 @@ static void decimal_checker(const DecimalTestDataSet& 
round_test_cases, bool dec
     }
 }
 
+template <typename FuncType, typename DecimalType>
+static void check_decimal_rounding(typename DecimalType::NativeType input, int 
input_precision,
+                                   int input_scale, int scale_arg, int 
result_precision,
+                                   int result_scale, typename 
DecimalType::NativeType expected,
+                                   bool decimal_col_is_const, bool 
scale_col_is_const) {
+    auto func = std::dynamic_pointer_cast<FuncType>(FuncType::create());
+    auto col_general = ColumnDecimal<DecimalType::PType>::create(1, 
input_scale);
+    col_general->get_element(0) = DecimalType(input);
+    auto col_scale = ColumnInt32::create();
+    col_scale->insert(Field::create_field<TYPE_INT>(scale_arg));
+
+    Block block;
+    auto input_type =
+            
std::make_shared<DataTypeDecimal<DecimalType::PType>>(input_precision, 
input_scale);
+    if (decimal_col_is_const) {
+        block.insert({ColumnConst::create(std::move(col_general), 1), 
std::move(input_type),
+                      "col_general"});
+    } else {
+        block.insert({std::move(col_general), std::move(input_type), 
"col_general"});
+    }
+    if (scale_col_is_const) {
+        block.insert({ColumnConst::create(std::move(col_scale), 1),
+                      std::make_shared<DataTypeInt32>(), "col_scale"});
+    } else {
+        block.insert({std::move(col_scale), std::make_shared<DataTypeInt32>(), 
"col_scale"});
+    }
+    block.insert(
+            {nullptr,
+             
std::make_shared<DataTypeDecimal<DecimalType::PType>>(result_precision, 
result_scale),
+             "col_res"});
+
+    const ColumnNumbers arguments = {0, 1};
+    ASSERT_TRUE(func->execute_impl(nullptr, block, arguments, 2, 1).ok());
+    const auto& result =
+            assert_cast<const 
ColumnDecimal<DecimalType::PType>&>(*block.get_by_position(2).column);
+    EXPECT_EQ(result.get_element(0).value, expected);
+}
+
 template <typename FuncType, PrimitiveType FloatPType>
 static void float_checker(const FloatTestDataSet& round_test_cases, bool 
float_col_is_const) {
     using FloatType = typename PrimitiveTypeTraits<FloatPType>::CppType;
@@ -1109,6 +1160,43 @@ TEST(RoundFunctionTest, normal_decimal_const) {
     decimal_checker<Decimal64RoundBankersFunction, 
Decimal64>(round_decimal64_cases, true);
 }
 
+TEST(RoundFunctionTest, decimal_scale_boundaries) {
+    check_decimal_rounding<Decimal32CeilFunction, Decimal32>(1, 9, 9, -1, 9, 
0, 10, false, true);
+    check_decimal_rounding<Decimal32FloorFunction, Decimal32>(-1, 9, 9, -1, 9, 
0, -10, false, true);
+
+    const Int128 scale20 = common::exp10_i128(20);
+    check_decimal_rounding<Decimal128CeilFunction, Decimal128V3>(scale20 + 
scale20 / 2, 38, 20, 0,
+                                                                 38, 20, 
scale20 * 2, false, false);
+    check_decimal_rounding<Decimal128FloorFunction, Decimal128V3>(scale20 + 
scale20 / 2, 38, 20, 0,
+                                                                  38, 20, 
scale20, false, false);
+    check_decimal_rounding<Decimal128CeilFunction, Decimal128V3>(scale20 + 
scale20 / 2, 38, 20, 0,
+                                                                 38, 20, 
scale20 * 2, true, false);
+    check_decimal_rounding<Decimal128FloorFunction, Decimal128V3>(scale20 + 
scale20 / 2, 38, 20, 0,
+                                                                  38, 20, 
scale20, true, false);
+
+    const Int128 decimal128_fraction = common::exp10_i128(37) * 9;
+    check_decimal_rounding<Decimal128CeilFunction, 
Decimal128V3>(decimal128_fraction, 38, 38, 0, 38,
+                                                                 0, 1, false, 
true);
+    check_decimal_rounding<Decimal128FloorFunction, 
Decimal128V3>(-decimal128_fraction, 38, 38, 0,
+                                                                  38, 0, -1, 
false, true);
+
+    const Int128 decimal128_half = common::exp10_i128(37) * 5;
+    check_decimal_rounding<Decimal128RoundFunction, 
Decimal128V3>(decimal128_half, 38, 38, 0, 38, 0,
+                                                                  1, false, 
true);
+    check_decimal_rounding<Decimal128RoundFunction, 
Decimal128V3>(-decimal128_half, 38, 38, 0, 38,
+                                                                  0, -1, 
false, true);
+    check_decimal_rounding<Decimal128RoundBankersFunction, 
Decimal128V3>(decimal128_half, 38, 38, 0,
+                                                                         38, 
0, 0, false, true);
+    check_decimal_rounding<Decimal128RoundBankersFunction, 
Decimal128V3>(-decimal128_half, 38, 38,
+                                                                         0, 
38, 0, 0, false, true);
+
+    const wide::Int256 decimal256_fraction = common::exp10_i256(75) * 9;
+    check_decimal_rounding<Decimal256CeilFunction, 
Decimal256>(decimal256_fraction, 76, 76, 0, 76,
+                                                               0, 1, false, 
true);
+    check_decimal_rounding<Decimal256FloorFunction, 
Decimal256>(-decimal256_fraction, 76, 76, 0, 76,
+                                                                0, -1, false, 
true);
+}
+
 /// tests for func(Column, Column) with float input
 TEST(RoundFunctionTest, normal_float) {
     float_checker<FloatTruncateFunction, TYPE_FLOAT>(trunc_float32_cases, 
false);


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to