github-actions[bot] commented on code in PR #68738:
URL: https://github.com/apache/doris/pull/68738#discussion_r4215868316
##########
be/test/exprs/function/function_round_test.cpp:
##########
@@ -974,6 +975,28 @@ FloatTestDataSet round_bankers_float64_cases = {{2.5, 0,
2.0},
{123.123456, 4, 123.123500},
{123456789.123456, 4,
123456789.123500}};
+const FloatTestDataSet large_scale_round_cases = {
+ {1.234e-20, 20, 1e-20}, {1.23456789e20, 20, 1.23456789e20},
+ {1e20, -19, 1e20}, {1e20, -20, 1e20},
+ {1e20, -25, 0}, {1e20, std::numeric_limits<Int16>::min(), 0}};
+const FloatTestDataSet large_scale_round_bankers_cases = {
+ {1.234e-20, 20, 1e-20},
+ {5e19, -20, 0},
Review Comment:
[P1] Correct the FLOAT banker test expectation. This row is also run as
TYPE_FLOAT. Casting 5e19 to Float32 stores 50000001002043867136, just above the
5e19 tie; `nearbyint(input / 1e20)` therefore returns 1 and the result is
FLOAT(1e20), while this fixture expects 0. The new test will fail for each
FLOAT constness combination. Use separate FLOAT and DOUBLE expectations or a
representable FLOAT tie.
##########
be/src/exprs/function/round.h:
##########
@@ -459,6 +461,56 @@ struct Dispatcher {
FloatRoundingImpl<T, rounding_mode, scale_mode,
tie_breaking_mode>,
IntegerRoundingImpl<T, rounding_mode, scale_mode,
tie_breaking_mode>>>;
+ static typename PrimitiveTypeTraits<T>::CppType
apply_float_rounding_with_large_scale(
+ typename PrimitiveTypeTraits<T>::CppType value, Int32 scale_arg) {
+ using ValueType = typename PrimitiveTypeTraits<T>::CppType;
+ const double input = static_cast<double>(value);
+ if (!std::isfinite(input)) {
+ return value;
+ }
+
+ if (scale_arg > 19) {
+ const double unit = std::pow(10.0,
-static_cast<double>(scale_arg));
Review Comment:
[P2] Keep enough precision for a subnormal decimal quantum. At scale 323,
`pow(10,-323)` rounds to `2 * DBL_TRUE_MIN`, although the requested unit is
slightly larger. `round(DBL_TRUE_MIN, 323)` then sees an artificial 0.5 tie and
returns `2 * DBL_TRUE_MIN`; the actual input is below half of `1e-323`, so the
correct result is zero. Add a subnormal boundary case and avoid deciding the
decimal bucket from this rounded unit.
##########
be/src/exprs/function/round.h:
##########
@@ -459,6 +461,56 @@ struct Dispatcher {
FloatRoundingImpl<T, rounding_mode, scale_mode,
tie_breaking_mode>,
IntegerRoundingImpl<T, rounding_mode, scale_mode,
tie_breaking_mode>>>;
+ static typename PrimitiveTypeTraits<T>::CppType
apply_float_rounding_with_large_scale(
+ typename PrimitiveTypeTraits<T>::CppType value, Int32 scale_arg) {
+ using ValueType = typename PrimitiveTypeTraits<T>::CppType;
+ const double input = static_cast<double>(value);
+ if (!std::isfinite(input)) {
+ return value;
+ }
+
+ if (scale_arg > 19) {
+ const double unit = std::pow(10.0,
-static_cast<double>(scale_arg));
+ if (unit == 0) {
+ return value;
+ }
+ const double upper_spacing =
+ std::abs(static_cast<double>(std::nextafter(
+ value,
std::numeric_limits<ValueType>::infinity())) -
+ input);
+ const double lower_spacing =
+ std::abs(input - static_cast<double>(std::nextafter(
+ value,
-std::numeric_limits<ValueType>::infinity())));
+ if (unit < std::min(upper_spacing, lower_spacing) / 2) {
+ return value;
+ }
+ const double scaled = input / unit;
+ if (!std::isfinite(scaled)) {
+ // At this magnitude the requested decimal precision is finer
+ // than the input type can represent.
+ return value;
+ }
+ return
static_cast<ValueType>(roundWithMode<tie_breaking_mode>(scaled, rounding_mode) *
Review Comment:
[P2] Reconstruct the selected decimal multiple accurately. For
`ceil(2.5e-20, 20)`, the integer choice is correctly 3, but `3 * pow(10,-20)`
yields `2.9999999999999997e-20`, one DOUBLE ULP below the intended decimal
ceiling `3e-20`. The negative-scale branch similarly returns
`1.0000000000000001e23` for `ceil(1.0,-23)` on this libm. The rounded binary
power must not become the final decimal grid value.
##########
be/src/exprs/function/round.h:
##########
@@ -459,6 +461,56 @@ struct Dispatcher {
FloatRoundingImpl<T, rounding_mode, scale_mode,
tie_breaking_mode>,
IntegerRoundingImpl<T, rounding_mode, scale_mode,
tie_breaking_mode>>>;
+ static typename PrimitiveTypeTraits<T>::CppType
apply_float_rounding_with_large_scale(
+ typename PrimitiveTypeTraits<T>::CppType value, Int32 scale_arg) {
+ using ValueType = typename PrimitiveTypeTraits<T>::CppType;
+ const double input = static_cast<double>(value);
+ if (!std::isfinite(input)) {
+ return value;
+ }
+
+ if (scale_arg > 19) {
+ const double unit = std::pow(10.0,
-static_cast<double>(scale_arg));
+ if (unit == 0) {
+ return value;
+ }
+ const double upper_spacing =
+ std::abs(static_cast<double>(std::nextafter(
+ value,
std::numeric_limits<ValueType>::infinity())) -
+ input);
+ const double lower_spacing =
+ std::abs(input - static_cast<double>(std::nextafter(
+ value,
-std::numeric_limits<ValueType>::infinity())));
+ if (unit < std::min(upper_spacing, lower_spacing) / 2) {
+ return value;
+ }
+ const double scaled = input / unit;
Review Comment:
[P2] Avoid crossing decimal grid boundaries in the `double` quotient. DOUBLE
`round(1.4999999999999998e-20,20)` becomes an artificial `1.5` tie here and
returns `2e-20` instead of `1e-20`. Directed modes also fail:
`ceil(1.3e-20,21)` computes `13.000000000000002` and returns about `1.4e-20`
instead of `1.3e-20`; the negative-scale `floor(1.3e26,-25)` likewise chooses
12 instead of 13 units. Preserve enough precision for both half and integer
boundaries before applying the rounding mode.
##########
be/src/exprs/function/round.h:
##########
@@ -476,13 +528,39 @@ struct Dispatcher {
size_t scale = 1;
FunctionRoundingImpl<ScaleMode::Zero>::apply(col->get_data(), scale, vec_res);
} else if (scale_arg > 0) {
- size_t scale = int_exp10(scale_arg);
-
FunctionRoundingImpl<ScaleMode::Positive>::apply(col->get_data(), scale,
- vec_res);
+ if constexpr (is_float_or_double(T)) {
+ if (scale_arg > 19) {
+ for (size_t i = 0; i < vec_res.size(); ++i) {
Review Comment:
[P3] Compute the constant-scale power once per block. This loop calls
`apply_float_rounding_with_large_scale` for every row, and the helper calls
`pow(10,-scale_arg)` each time even though `scale_arg` is constant here. The
previous vector path computed the scale once. Pass a precomputed quantum into
the row helper for both positive and negative large scales.
##########
be/src/exprs/function/round.h:
##########
@@ -459,6 +461,56 @@ struct Dispatcher {
FloatRoundingImpl<T, rounding_mode, scale_mode,
tie_breaking_mode>,
IntegerRoundingImpl<T, rounding_mode, scale_mode,
tie_breaking_mode>>>;
+ static typename PrimitiveTypeTraits<T>::CppType
apply_float_rounding_with_large_scale(
+ typename PrimitiveTypeTraits<T>::CppType value, Int32 scale_arg) {
+ using ValueType = typename PrimitiveTypeTraits<T>::CppType;
+ const double input = static_cast<double>(value);
+ if (!std::isfinite(input)) {
+ return value;
+ }
+
+ if (scale_arg > 19) {
+ const double unit = std::pow(10.0,
-static_cast<double>(scale_arg));
+ if (unit == 0) {
+ return value;
+ }
+ const double upper_spacing =
+ std::abs(static_cast<double>(std::nextafter(
+ value,
std::numeric_limits<ValueType>::infinity())) -
+ input);
+ const double lower_spacing =
+ std::abs(input - static_cast<double>(std::nextafter(
+ value,
-std::numeric_limits<ValueType>::infinity())));
+ if (unit < std::min(upper_spacing, lower_spacing) / 2) {
+ return value;
+ }
+ const double scaled = input / unit;
+ if (!std::isfinite(scaled)) {
+ // At this magnitude the requested decimal precision is finer
+ // than the input type can represent.
+ return value;
+ }
+ return
static_cast<ValueType>(roundWithMode<tie_breaking_mode>(scaled, rounding_mode) *
+ unit);
+ }
+
+ const double scale = std::pow(10.0, -static_cast<double>(scale_arg));
+ if (!std::isfinite(scale)) {
+ if constexpr (rounding_mode == RoundingMode::Floor) {
+ return input < 0 ? -std::numeric_limits<ValueType>::infinity()
+ : std::copysign(ValueType {0}, value);
+ } else if constexpr (rounding_mode == RoundingMode::Ceil) {
+ return input > 0 ? std::numeric_limits<ValueType>::infinity()
+ : std::copysign(ValueType {0}, value);
+ } else {
+ return std::copysign(ValueType {0}, value);
+ }
+ }
+
+ const double rounded = roundWithMode<tie_breaking_mode>(input / scale,
rounding_mode);
Review Comment:
[P2] Preserve directed rounding when the quotient underflows. For DOUBLE
`ceil(1e-30, -300)`, `pow(10,300)` is finite, but `1e-30 / 1e300` becomes zero
before `ceil`, so this returns zero instead of `1e300`; `floor(-1e-310,-20)`
similarly returns signed zero instead of `-1e20`. Handle a nonzero input whose
finite quotient underflows before calling the rounding mode.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]