pitrou commented on a change in pull request #10349:
URL: https://github.com/apache/arrow/pull/10349#discussion_r707400565
##########
File path: cpp/src/arrow/compute/kernels/scalar_arithmetic.cc
##########
@@ -852,24 +853,238 @@ struct LogbChecked {
}
};
+struct RoundUtil {
+ // Calculate powers of ten with arbitrary integer exponent
+ template <typename T = double>
+ static enable_if_floating_point<T> Pow10(int64_t power) {
+ static constexpr T lut[] = {1e0F, 1e1F, 1e2F, 1e3F, 1e4F, 1e5F, 1e6F,
1e7F,
+ 1e8F, 1e9F, 1e10F, 1e11F, 1e12F, 1e13F, 1e14F,
1e15F};
+ int64_t lut_size = (sizeof(lut) / sizeof(*lut));
+ int64_t abs_power = std::abs(power);
+ auto pow10 = lut[std::min(abs_power, lut_size - 1)];
+ while (abs_power-- >= lut_size) {
+ pow10 *= 1e1F;
+ }
+ return (power >= 0) ? pow10 : (1 / pow10);
+ }
+};
+
+// Specializations of rounding implementations for round kernels
+template <typename, RoundMode>
+struct RoundImpl;
+
+template <typename T>
+struct RoundImpl<T, RoundMode::DOWN> {
+ static constexpr enable_if_floating_point<T> Round(const T val) {
+ return std::floor(val);
+ }
+};
+
+template <typename T>
+struct RoundImpl<T, RoundMode::UP> {
+ static constexpr enable_if_floating_point<T> Round(const T val) {
+ return std::ceil(val);
+ }
+};
+
+template <typename T>
+struct RoundImpl<T, RoundMode::TOWARDS_ZERO> {
+ static constexpr enable_if_floating_point<T> Round(const T val) {
+ return std::trunc(val);
+ }
+};
+
+template <typename T>
+struct RoundImpl<T, RoundMode::TOWARDS_INFINITY> {
+ static constexpr enable_if_floating_point<T> Round(const T val) {
+ return std::signbit(val) ? std::floor(val) : std::ceil(val);
+ }
+};
+
+template <typename T>
+struct RoundImpl<T, RoundMode::HALF_DOWN> {
Review comment:
Can you add a comment that the implementations below are only invoked if
the input has a fractional part equal to 0.5? Otherwise reading this is a bit
confusing.
##########
File path: cpp/src/arrow/compute/kernels/scalar_arithmetic_test.cc
##########
@@ -1352,6 +1403,213 @@ TYPED_TEST(TestUnaryArithmeticFloating, AbsoluteValue) {
}
}
+TYPED_TEST_SUITE(TestUnaryRoundIntegral, IntegralTypes);
+TYPED_TEST_SUITE(TestUnaryRoundSigned, SignedIntegerTypes);
+TYPED_TEST_SUITE(TestUnaryRoundUnsigned, UnsignedIntegerTypes);
+TYPED_TEST_SUITE(TestUnaryRoundFloating, FloatingTypes);
+
+const std::vector<RoundMode> kRoundModes{
+ RoundMode::DOWN,
+ RoundMode::UP,
+ RoundMode::TOWARDS_ZERO,
+ RoundMode::TOWARDS_INFINITY,
+ RoundMode::HALF_DOWN,
+ RoundMode::HALF_UP,
+ RoundMode::HALF_TOWARDS_ZERO,
+ RoundMode::HALF_TOWARDS_INFINITY,
+ RoundMode::HALF_TO_EVEN,
+ RoundMode::HALF_TO_ODD,
+};
+
+TYPED_TEST(TestUnaryRoundSigned, Round) {
+ // Test different rounding modes for integer rounding
+ std::string values("[0, 1, -13, -50, 115]");
+ this->SetRoundNdigits(0);
+ for (const auto& round_mode : kRoundModes) {
+ this->SetRoundMode(round_mode);
+ this->AssertUnaryOp(Round, values, ArrayFromJSON(float64(), values));
+ }
+
+ // Test different round N-digits for nearest rounding mode
+ std::vector<std::pair<int64_t, std::string>> ndigits_and_expected{{
+ {-2, "[0, 0, -0, -100, 100]"},
+ {-1, "[0, 0, -10, -50, 120]"},
+ {0, values},
+ {1, values},
+ {2, values},
+ }};
+ this->SetRoundMode(RoundMode::HALF_TOWARDS_INFINITY);
+ for (const auto& pair : ndigits_and_expected) {
+ this->SetRoundNdigits(pair.first);
+ this->AssertUnaryOp(Round, values, ArrayFromJSON(float64(), pair.second));
+ }
+}
+
+TYPED_TEST(TestUnaryRoundUnsigned, Round) {
+ // Test different rounding modes for integer rounding
+ std::string values("[0, 1, 13, 50, 115]");
+ this->SetRoundNdigits(0);
+ for (const auto& round_mode : kRoundModes) {
+ this->SetRoundMode(round_mode);
+ this->AssertUnaryOp(Round, values, ArrayFromJSON(float64(), values));
+ }
+
+ // Test different round N-digits for nearest rounding mode
+ std::vector<std::pair<int64_t, std::string>> ndigits_and_expected{{
+ {-2, "[0, 0, 0, 100, 100]"},
+ {-1, "[0, 0, 10, 50, 120]"},
+ {0, values},
+ {1, values},
+ {2, values},
+ }};
+ this->SetRoundMode(RoundMode::HALF_TOWARDS_INFINITY);
+ for (const auto& pair : ndigits_and_expected) {
+ this->SetRoundNdigits(pair.first);
+ this->AssertUnaryOp(Round, values, ArrayFromJSON(float64(), pair.second));
+ }
+}
+
+TYPED_TEST(TestUnaryRoundFloating, Round) {
+ this->SetNansEqual(true);
+
+ // Test different rounding modes for integer rounding
Review comment:
"integer"?
--
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]