bkietz commented on a change in pull request #10349:
URL: https://github.com/apache/arrow/pull/10349#discussion_r660102749
##########
File path: cpp/src/arrow/compute/kernels/scalar_arithmetic.cc
##########
@@ -454,6 +456,166 @@ struct PowerChecked {
}
};
+struct RoundUtils {
+ template <typename T, enable_if_t<std::is_floating_point<T>::value, bool> =
true>
+ static bool ApproxEqual(const T x, const T y, const int ulp = 7) {
+ // https://en.cppreference.com/w/cpp/types/numeric_limits/epsilon
+ // The machine epsilon has to be scaled to the magnitude of the values used
+ // and multiplied by the desired precision in ULPs (units in the last
place)
+ const auto eps_ulp = std::numeric_limits<T>::epsilon() * ulp;
+ const auto xy_diff = std::fabs(x - y);
+ const auto xy_sum = std::fabs(x + y);
+ return (xy_diff <= (xy_sum * eps_ulp))
+ // unless the result is subnormal
+ || (xy_diff < std::numeric_limits<T>::min());
+ }
+
+ template <typename T, enable_if_t<std::is_floating_point<T>::value, bool> =
true>
+ static bool IsHalf(T val) {
+ // |frac| == 0.5?
+ return ApproxEqual(std::fabs(std::fmod(val, T(1))), T(0.5));
+ }
+
+ template <typename T>
+ static constexpr enable_if_floating_point<T> Floor(T val) {
+ return std::floor(val);
+ }
+
+ template <typename T>
+ static constexpr enable_if_floating_point<T> Ceiling(T val) {
+ return std::ceil(val);
+ }
+
+ template <typename T>
+ static constexpr enable_if_floating_point<T> Truncate(T val) {
+ return std::trunc(val);
+ }
+
+ template <typename T>
+ static constexpr enable_if_floating_point<T> TowardsInfinity(T val) {
+ return std::signbit(val) ? std::floor(val) : std::ceil(val);
+ }
+
+ template <typename T>
+ static constexpr enable_if_floating_point<T> HalfDown(T val) {
+ return std::ceil(val - T(0.5));
+ }
+
+ template <typename T>
+ static constexpr enable_if_floating_point<T> HalfUp(T val) {
+ return std::floor(val + T(0.5));
+ }
+
+ template <typename T>
+ static enable_if_floating_point<T> HalfToEven(T val) {
+ if (IsHalf(val)) {
+ auto floor = std::floor(val);
+ // Odd + 1, Even + 0
+ return floor + (std::fmod(std::fabs(floor), T(2)) >= T(1));
+ }
+ return std::round(val);
+ }
+
+ template <typename T>
+ static enable_if_floating_point<T> HalfToOdd(T val) {
+ if (IsHalf(val)) {
+ auto floor = std::floor(val);
+ // Odd + 0, Even + 1
+ return floor + (std::fmod(std::fabs(floor), T(2)) < T(1));
+ }
+ return std::round(val);
+ }
+
+ template <typename T>
+ static constexpr enable_if_floating_point<T> Nearest(T val) {
+ return std::round(val);
+ }
+
+ template <typename T>
+ static constexpr enable_if_floating_point<T> HalfTowardsZero(T val) {
+ return std::copysign(std::ceil(std::fabs(val) - T(0.5)), val);
+ }
+
+ template <typename T>
+ static enable_if_floating_point<T> Round(T val, T mult, RoundMode round_mode,
+ Status* st) {
+ val /= mult;
+
+ T result;
+ switch (round_mode) {
Review comment:
Related: https://issues.apache.org/jira/browse/ARROW-13122
Kernel variants *should not* occur; instead we should have distinct kernels
for each RoundMode. We can't currently because we don't have access to function
options at dispatch time. If we did, instead of building a vector of execs we
could simply construct a kernel for each and let dispatch select the
appropriate kernel for the given RoundMode
--
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]