Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions cpp/src/gandiva/precompiled/extended_math_ops.cc
Original file line number Diff line number Diff line change
Expand Up @@ -304,14 +304,21 @@ gdv_float64 bround_float64(gdv_float64 num) {
return num - diff_num;
}

// limit for abs(number * 10^scale_multiplier), computed in double - works for float32 and float64 versions.
// at or above 2^52 double (scaled) has no fractional part, so there is nothing to round
static const gdv_float64 kMaxRoundableScaledValue = static_cast<gdv_float64>(1LL << 52);
Comment thread
victor6567758 marked this conversation as resolved.
// rounds the number to the given scale
#define ROUND_DECIMAL_TO_SCALE(TYPE) \
FORCE_INLINE \
gdv_##TYPE round_##TYPE##_int32(gdv_##TYPE number, gdv_int32 out_scale) { \
gdv_float64 scale_multiplier = get_scale_multiplier(out_scale); \
return static_cast<gdv_##TYPE>( \
trunc(number * scale_multiplier + ((number >= 0) ? 0.5 : -0.5)) / \
scale_multiplier); \
// every ordered comparison with NaN is false: <, <=, >, >= and ==
#define ROUND_DECIMAL_TO_SCALE(TYPE) \
FORCE_INLINE \
gdv_##TYPE round_##TYPE##_int32(gdv_##TYPE number, gdv_int32 out_scale) { \
gdv_float64 scale_multiplier = get_scale_multiplier(out_scale); \
if (!(fabs(number) < kMaxRoundableScaledValue / scale_multiplier)) { \
return number; \
} \
gdv_float64 scaled = number * scale_multiplier; \
return static_cast<gdv_##TYPE>(trunc(scaled + ((number >= 0) ? 0.5 : -0.5)) / \
scale_multiplier); \
}

ROUND_DECIMAL_TO_SCALE(float32)
Expand Down
37 changes: 37 additions & 0 deletions cpp/src/gandiva/precompiled/extended_math_ops_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,20 @@ TEST(TestExtendedMathOps, TestRoundDecimal) {
EXPECT_FLOAT_EQ(round_float32_int32(static_cast<float>(9.134123), 2), 9.13f);
EXPECT_FLOAT_EQ(round_float32_int32(static_cast<float>(-1.923), 1), -1.9f);

const float max_float = std::numeric_limits<float>::max();
const float lowest_float = std::numeric_limits<float>::lowest();
EXPECT_EQ(round_float32_int32(max_float, 100), max_float);
EXPECT_EQ(round_float32_int32(lowest_float, 100), lowest_float);
EXPECT_EQ(round_float32_int32(1.0e30f, 2), 1.0e30f);
EXPECT_EQ(round_float32_int32(451.65f, 100), 451.65f);
EXPECT_EQ(round_float32_int32(-451.65f, 100), -451.65f);
EXPECT_EQ(round_float32_int32(16777216.0f, 2), 16777216.0f);

const float limit_float = static_cast<float>(std::ldexp(1.0, 52) / 100.0);
const float just_above_float = std::nextafter(limit_float, max_float);
EXPECT_EQ(round_float32_int32(limit_float, 2), limit_float);
EXPECT_EQ(round_float32_int32(just_above_float, 2), just_above_float);

VerifyFuzzyEquals(round_float64(1234.245), 1234);
VerifyFuzzyEquals(round_float64(-11.7892), -12);
VerifyFuzzyEquals(round_float64(1.4999999), 1);
Expand All @@ -165,6 +179,29 @@ TEST(TestExtendedMathOps, TestRoundDecimal) {
EXPECT_EQ(std::signbit(round_float64_int32(0, -2)), 0);
VerifyFuzzyEquals(round_float64_int32((double)INT_MAX + 1, 0), (double)INT_MAX + 1);
VerifyFuzzyEquals(round_float64_int32((double)INT_MIN - 1, 0), (double)INT_MIN - 1);

const double max_double = std::numeric_limits<double>::max();
const double lowest_double = std::numeric_limits<double>::lowest();
EXPECT_EQ(round_float64_int32(2.29e208, 100), 2.29e208);
Comment thread
victor6567758 marked this conversation as resolved.
EXPECT_EQ(round_float64_int32(-2.29e208, 100), -2.29e208);
EXPECT_EQ(round_float64_int32(max_double, 100), max_double);
EXPECT_EQ(round_float64_int32(lowest_double, 100), lowest_double);
EXPECT_EQ(round_float64_int32(451.65, 100), 451.65);
EXPECT_EQ(round_float64_int32(-451.65, 100), -451.65);

const double ticket_val = 2.2926114935177252E208;
EXPECT_EQ(round_float64_int32(ticket_val, 100), ticket_val);
EXPECT_EQ(round_float64_int32(-ticket_val, 100), -ticket_val);
for (gdv_int32 scale : {3, 4, 7, 8, 10, -100}) {
EXPECT_EQ(round_float64_int32(ticket_val, scale), ticket_val);
EXPECT_EQ(round_float64_int32(-ticket_val, scale), -ticket_val);
}
EXPECT_EQ(round_float64_int32(1.5, -100), 0);

const double limit_double = std::ldexp(1.0, 52) / 100.0;
const double just_above_double = std::nextafter(limit_double, max_double);
EXPECT_EQ(round_float64_int32(limit_double, 2), limit_double);
EXPECT_EQ(round_float64_int32(just_above_double, 2), just_above_double);
}

TEST(TestExtendedMathOps, TestBRoundDecimal) {
Expand Down
Loading