andishgar commented on code in PR #48224:
URL: https://github.com/apache/arrow/pull/48224#discussion_r2569562687


##########
cpp/src/arrow/testing/math.cc:
##########
@@ -17,53 +17,107 @@
 
 #include "arrow/testing/math.h"
 
+#include <algorithm>
 #include <cmath>
 #include <limits>
+#include <type_traits>
 
 #include <gtest/gtest.h>
 
+#include "arrow/util/float16.h"
 #include "arrow/util/logging_internal.h"
 
 namespace arrow {
 namespace {
 
 template <typename Float>
-bool WithinUlpOneWay(Float left, Float right, int n_ulps) {
-  // The delta between 1.0 and the FP value immediately before it.
-  // We're using this value because `frexp` returns a mantissa between 0.5 and 
1.0.
-  static const Float kOneUlp = Float(1.0) - std::nextafter(Float(1.0), 
Float(0.0));
+struct FloatToUInt;
 
-  DCHECK_GE(n_ulps, 1);
+template <>
+struct FloatToUInt<double> {
+  using Type = uint64_t;
+};
 
-  if (left == 0) {
-    return left == right;
+template <>
+struct FloatToUInt<float> {
+  using Type = uint32_t;
+};
+
+template <>
+struct FloatToUInt<util::Float16> {
+  using Type = uint16_t;
+};
+
+template <typename Float>
+struct UlpDistanceUtil {
+ public:
+  using UIntType = typename FloatToUInt<Float>::Type;
+  static const UIntType kNumberOfBits = sizeof(Float) * 8;
+  static const UIntType kSignMask = static_cast<UIntType>(1) << (kNumberOfBits 
- 1);
+
+  // This implementation is inspired by:
+  // 
https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
+  static UIntType UlpDistnace(Float left, Float right) {
+    auto unsigned_left = BitCast<UIntType>(left);
+    auto unsigned_right = BitCast<UIntType>(right);
+    auto biased_left = ConvertSignAndMagnitudeToBiased(unsigned_left);
+    auto biased_right = ConvertSignAndMagnitudeToBiased(unsigned_right);
+    if (biased_left > biased_right) {
+      std::swap(biased_left, biased_right);
+    }
+    return biased_right - biased_left;
   }
-  if (left < 0) {
-    left = -left;
-    right = -right;
+
+ private:
+  template <typename To, typename From>
+  union BitCastUnion {
+    explicit BitCastUnion(From from) : from(from) {}
+    From from;
+    To to;
+  };
+
+  template <typename To, typename From>
+  static UIntType BitCast(From value) {
+    assert(sizeof(To) == sizeof(From));
+    BitCastUnion<To, From> bit_cast(value);
+    return bit_cast.to;
   }

Review Comment:
   @pitrou Regarding this:
   I'm aware that the goal of the load functions in `arrow/util/ubsan` is to 
address the issue of unaligned loads on the x86-64 architecture. As far as I 
have checked, I should use the function below.
   
   
https://github.com/apache/arrow/blob/fa41b2674bfab627ec1c69b4b4fb52d9caff8c15/cpp/src/arrow/util/ubsan.h#L70-L79
   
   However, two questions come to my mind:
   
   1-Is there any point in using this function? I mean, when the function is 
called, the value has already been loaded. This function is supposed to load 
the value byte by byte via memcpy, right?
   
   2-This only works for types that have a default constructor. However, it is 
possible for a type to be trivially copyable without having a default 
constructor. Shouldn’t this be considered a bug?
   
   Given this, is it okay to use this function? Keep in mind that this method 
is intended to be used in the next PR for the array. Additionally, this way of 
bit-casting is certainly much slower since it operates byte by byte.



-- 
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]

Reply via email to