1616// under the License.
1717
1818#include < cmath>
19+ #include < memory>
20+ #include < type_traits>
21+ #include < vector>
1922
2023#include < gtest/gtest-spi.h>
2124#include < gtest/gtest.h>
3235#include " arrow/type.h"
3336#include " arrow/type_traits.h"
3437#include " arrow/util/checked_cast.h"
38+ #include " arrow/util/float16.h"
39+ #include " arrow/util/logger.h"
3540
36- namespace arrow {
41+ namespace arrow ::util {
3742
3843// Test basic cases for contains NaN.
3944class TestAssertContainsNaN : public ::testing::Test {};
@@ -198,8 +203,15 @@ void CheckWithinUlp(Float x, Float y, int n_ulp) {
198203 CheckWithinUlpSingle (-y, -x, n_ulp);
199204
200205 for (int exp : {1 , -1 , 10 , -10 }) {
201- Float x_scaled = std::ldexp (x, exp);
202- Float y_scaled = std::ldexp (y, exp);
206+ Float x_scaled (0 );
207+ Float y_scaled (0 );
208+ if constexpr (std::is_same_v<Float, Float16>) {
209+ x_scaled = Float16 (std::ldexp (x.ToFloat (), exp));
210+ y_scaled = Float16 (std::ldexp (y.ToFloat (), exp));
211+ } else {
212+ x_scaled = std::ldexp (x, exp);
213+ y_scaled = std::ldexp (y, exp);
214+ }
203215 CheckWithinUlpSingle (x_scaled, y_scaled, n_ulp);
204216 CheckWithinUlpSingle (y_scaled, x_scaled, n_ulp);
205217 }
@@ -219,8 +231,15 @@ void CheckNotWithinUlp(Float x, Float y, int n_ulp) {
219231 }
220232
221233 for (int exp : {1 , -1 , 10 , -10 }) {
222- Float x_scaled = std::ldexp (x, exp);
223- Float y_scaled = std::ldexp (y, exp);
234+ Float x_scaled (0 );
235+ Float y_scaled (0 );
236+ if constexpr (std::is_same_v<Float, Float16>) {
237+ x_scaled = Float16 (std::ldexp (x.ToFloat (), exp));
238+ y_scaled = Float16 (std::ldexp (y.ToFloat (), exp));
239+ } else {
240+ x_scaled = std::ldexp (x, exp);
241+ y_scaled = std::ldexp (y, exp);
242+ }
224243 CheckNotWithinUlpSingle (x_scaled, y_scaled, n_ulp);
225244 CheckNotWithinUlpSingle (y_scaled, x_scaled, n_ulp);
226245 }
@@ -242,6 +261,10 @@ TEST(TestWithinUlp, Double) {
242261 CheckWithinUlp (1.0 , 0.9999999999999999 , 1 );
243262 CheckWithinUlp (1.0 , 0.9999999999999988 , 11 );
244263 CheckNotWithinUlp (1.0 , 0.9999999999999988 , 10 );
264+ CheckWithinUlp (1.0000000000000002 , 0.9999999999999999 , 2 );
265+ CheckNotWithinUlp (1.0000000000000002 , 0.9999999999999999 , 1 );
266+ CheckWithinUlp (0.9999999999999988 , 1.0000000000000007 , 14 );
267+ CheckNotWithinUlp (0.9999999999999988 , 1.0000000000000007 , 13 );
245268
246269 CheckWithinUlp (123.4567 , 123.45670000000015 , 11 );
247270 CheckNotWithinUlp (123.4567 , 123.45670000000015 , 10 );
@@ -271,6 +294,10 @@ TEST(TestWithinUlp, Float) {
271294 CheckWithinUlp (1 .0f , 0 .99999994f , 1 );
272295 CheckWithinUlp (1 .0f , 0 .99999934f , 11 );
273296 CheckNotWithinUlp (1 .0f , 0 .99999934f , 10 );
297+ CheckWithinUlp (1 .0000001f , 0 .99999994f , 2 );
298+ CheckNotWithinUlp (1 .0000001f , 0 .99999994f , 1 );
299+ CheckWithinUlp (1 .0000013f , 0 .99999934f , 22 );
300+ CheckNotWithinUlp (1 .0000013f , 0 .99999934f , 21 );
274301
275302 CheckWithinUlp (123 .456f , 123 .456085f , 11 );
276303 CheckNotWithinUlp (123 .456f , 123 .456085f , 10 );
@@ -284,15 +311,65 @@ TEST(TestWithinUlp, Float) {
284311 CheckNotWithinUlp (12 .34f , -12 .34f , 10 );
285312}
286313
314+ std::vector<Float16> ConvertToFloat16Vector (const std::vector<float >& float_values) {
315+ std::vector<Float16> float16_vector;
316+ float16_vector.reserve (float_values.size ());
317+ for (auto & value : float_values) {
318+ float16_vector.emplace_back (value);
319+ }
320+ return float16_vector;
321+ }
322+
323+ TEST (TestWithinUlp, Float16) {
324+ for (Float16 f : ConvertToFloat16Vector ({0 .0f , 1e-8f , 1 .0f , 123 .456f })) {
325+ CheckWithinUlp (f, f, 0 );
326+ CheckWithinUlp (f, f, 1 );
327+ CheckWithinUlp (f, f, 42 );
328+ }
329+ CheckWithinUlp (Float16 (-0 .0f ), Float16 (0 .0f ), 1 );
330+ CheckWithinUlp (Float16 (1 .0f ), Float16 (1 .00097656f ), 1 );
331+ CheckWithinUlp (Float16 (1 .0f ), Float16 (1 .01074219f ), 11 );
332+ CheckNotWithinUlp (Float16 (1 .0f ), Float16 (1 .00097656f ), 0 );
333+ CheckNotWithinUlp (Float16 (1 .0f ), Float16 (1 .01074219f ), 10 );
334+ // left and right have a different exponent but are still very close
335+ CheckWithinUlp (Float16 (1 .0f ), Float16 (0 .999511719f ), 1 );
336+ CheckWithinUlp (Float16 (1 .0f ), Float16 (0 .994628906f ), 11 );
337+ CheckNotWithinUlp (Float16 (1 .0f ), Float16 (0 .994628906f ), 10 );
338+ CheckWithinUlp (Float16 (1.00097656 ), Float16 (0 .999511719f ), 2 );
339+ CheckNotWithinUlp (Float16 (1.00097656 ), Float16 (0 .999511719f ), 1 );
340+ CheckWithinUlp (Float16 (1 .01074219f ), Float16 (0 .994628906f ), 22 );
341+ CheckNotWithinUlp (Float16 (1 .01074219f ), Float16 (0 .994628906f ), 21 );
342+
343+ CheckWithinUlp (Float16 (123 .456f ), Float16 (124 .143501f ), 11 );
344+ // The assertion below does not work because ldexp(Float16(124.143501f), 10)
345+ // results in inf in Float16.
346+ // CheckNotWithinUlp(Float16(123.456f), Float16(124.143501f), 10);
347+
348+ CheckWithinUlp (std::numeric_limits<Float16>::infinity (),
349+ std::numeric_limits<Float16>::infinity (), 10 );
350+ CheckWithinUlp (-std::numeric_limits<Float16>::infinity (),
351+ -std::numeric_limits<Float16>::infinity (), 10 );
352+ CheckWithinUlp (std::numeric_limits<Float16>::quiet_NaN (),
353+ std::numeric_limits<Float16>::quiet_NaN (), 10 );
354+ CheckNotWithinUlp (std::numeric_limits<Float16>::infinity (),
355+ -std::numeric_limits<Float16>::infinity (), 10 );
356+ CheckNotWithinUlp (Float16 (12 .34f ), -std::numeric_limits<Float16>::infinity (), 10 );
357+ CheckNotWithinUlp (Float16 (12 .34f ), std::numeric_limits<Float16>::quiet_NaN (), 10 );
358+ CheckNotWithinUlp (Float16 (12 .34f ), Float16 (-12 .34f ), 10 );
359+ }
360+
287361TEST (AssertTestWithinUlp, Basics) {
288362 AssertWithinUlp (123.4567 , 123.45670000000015 , 11 );
289363 AssertWithinUlp (123 .456f , 123 .456085f , 11 );
364+ AssertWithinUlp (Float16 (123 .456f ), Float16 (124 .143501f ), 11 );
290365#ifndef _WIN32
291366 // GH-47442
292367 EXPECT_FATAL_FAILURE (AssertWithinUlp (123.4567 , 123.45670000000015 , 10 ),
293368 " not within 10 ulps" );
294369 EXPECT_FATAL_FAILURE (AssertWithinUlp (123 .456f , 123 .456085f , 10 ), " not within 10 ulps" );
370+ EXPECT_FATAL_FAILURE (AssertWithinUlp (Float16 (123 .456f ), Float16 (124 .143501f ), 10 ),
371+ " not within 10 ulps" );
295372#endif
296373}
297374
298- } // namespace arrow
375+ } // namespace arrow::util
0 commit comments