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"
3539
36- namespace arrow {
40+ namespace arrow ::util {
3741
3842// Test basic cases for contains NaN.
3943class TestAssertContainsNaN : public ::testing::Test {};
@@ -198,8 +202,15 @@ void CheckWithinUlp(Float x, Float y, int n_ulp) {
198202 CheckWithinUlpSingle (-y, -x, n_ulp);
199203
200204 for (int exp : {1 , -1 , 10 , -10 }) {
201- Float x_scaled = std::ldexp (x, exp);
202- Float y_scaled = std::ldexp (y, exp);
205+ Float x_scaled (0 );
206+ Float y_scaled (0 );
207+ if constexpr (std::is_same_v<Float, Float16>) {
208+ x_scaled = Float16 (std::ldexp (x.ToFloat (), exp));
209+ y_scaled = Float16 (std::ldexp (y.ToFloat (), exp));
210+ } else {
211+ x_scaled = std::ldexp (x, exp);
212+ y_scaled = std::ldexp (y, exp);
213+ }
203214 CheckWithinUlpSingle (x_scaled, y_scaled, n_ulp);
204215 CheckWithinUlpSingle (y_scaled, x_scaled, n_ulp);
205216 }
@@ -219,8 +230,15 @@ void CheckNotWithinUlp(Float x, Float y, int n_ulp) {
219230 }
220231
221232 for (int exp : {1 , -1 , 10 , -10 }) {
222- Float x_scaled = std::ldexp (x, exp);
223- Float y_scaled = std::ldexp (y, exp);
233+ Float x_scaled (0 );
234+ Float y_scaled (0 );
235+ if constexpr (std::is_same_v<Float, Float16>) {
236+ x_scaled = Float16 (std::ldexp (x.ToFloat (), exp));
237+ y_scaled = Float16 (std::ldexp (y.ToFloat (), exp));
238+ } else {
239+ x_scaled = std::ldexp (x, exp);
240+ y_scaled = std::ldexp (y, exp);
241+ }
224242 CheckNotWithinUlpSingle (x_scaled, y_scaled, n_ulp);
225243 CheckNotWithinUlpSingle (y_scaled, x_scaled, n_ulp);
226244 }
@@ -242,6 +260,10 @@ TEST(TestWithinUlp, Double) {
242260 CheckWithinUlp (1.0 , 0.9999999999999999 , 1 );
243261 CheckWithinUlp (1.0 , 0.9999999999999988 , 11 );
244262 CheckNotWithinUlp (1.0 , 0.9999999999999988 , 10 );
263+ CheckWithinUlp (1.0000000000000002 , 0.9999999999999999 , 2 );
264+ CheckNotWithinUlp (1.0000000000000002 , 0.9999999999999999 , 1 );
265+ CheckWithinUlp (0.9999999999999988 , 1.0000000000000007 , 14 );
266+ CheckNotWithinUlp (0.9999999999999988 , 1.0000000000000007 , 13 );
245267
246268 CheckWithinUlp (123.4567 , 123.45670000000015 , 11 );
247269 CheckNotWithinUlp (123.4567 , 123.45670000000015 , 10 );
@@ -271,6 +293,10 @@ TEST(TestWithinUlp, Float) {
271293 CheckWithinUlp (1 .0f , 0 .99999994f , 1 );
272294 CheckWithinUlp (1 .0f , 0 .99999934f , 11 );
273295 CheckNotWithinUlp (1 .0f , 0 .99999934f , 10 );
296+ CheckWithinUlp (1 .0000001f , 0 .99999994f , 2 );
297+ CheckNotWithinUlp (1 .0000001f , 0 .99999994f , 1 );
298+ CheckWithinUlp (1 .0000013f , 0 .99999934f , 22 );
299+ CheckNotWithinUlp (1 .0000013f , 0 .99999934f , 21 );
274300
275301 CheckWithinUlp (123 .456f , 123 .456085f , 11 );
276302 CheckNotWithinUlp (123 .456f , 123 .456085f , 10 );
@@ -284,15 +310,65 @@ TEST(TestWithinUlp, Float) {
284310 CheckNotWithinUlp (12 .34f , -12 .34f , 10 );
285311}
286312
313+ std::vector<Float16> ConvertToFloat16Vector (const std::vector<float >& float_values) {
314+ std::vector<Float16> float16_vector;
315+ float16_vector.reserve (float_values.size ());
316+ for (auto & value : float_values) {
317+ float16_vector.emplace_back (value);
318+ }
319+ return float16_vector;
320+ }
321+
322+ TEST (TestWithinUlp, Float16) {
323+ for (Float16 f : ConvertToFloat16Vector ({0 .0f , 1e-8f , 1 .0f , 123 .456f })) {
324+ CheckWithinUlp (f, f, 0 );
325+ CheckWithinUlp (f, f, 1 );
326+ CheckWithinUlp (f, f, 42 );
327+ }
328+ CheckWithinUlp (Float16 (-0 .0f ), Float16 (0 .0f ), 1 );
329+ CheckWithinUlp (Float16 (1 .0f ), Float16 (1 .00097656f ), 1 );
330+ CheckWithinUlp (Float16 (1 .0f ), Float16 (1 .01074219f ), 11 );
331+ CheckNotWithinUlp (Float16 (1 .0f ), Float16 (1 .00097656f ), 0 );
332+ CheckNotWithinUlp (Float16 (1 .0f ), Float16 (1 .01074219f ), 10 );
333+ // left and right have a different exponent but are still very close
334+ CheckWithinUlp (Float16 (1 .0f ), Float16 (0 .999511719f ), 1 );
335+ CheckWithinUlp (Float16 (1 .0f ), Float16 (0 .994628906f ), 11 );
336+ CheckNotWithinUlp (Float16 (1 .0f ), Float16 (0 .994628906f ), 10 );
337+ CheckWithinUlp (Float16 (1.00097656 ), Float16 (0 .999511719f ), 2 );
338+ CheckNotWithinUlp (Float16 (1.00097656 ), Float16 (0 .999511719f ), 1 );
339+ CheckWithinUlp (Float16 (1 .01074219f ), Float16 (0 .994628906f ), 22 );
340+ CheckNotWithinUlp (Float16 (1 .01074219f ), Float16 (0 .994628906f ), 21 );
341+
342+ CheckWithinUlp (Float16 (123 .456f ), Float16 (124 .143501f ), 11 );
343+ // The assertion below does not work because ldexp(Float16(124.143501f), 10)
344+ // results in inf in Float16.
345+ // CheckNotWithinUlp(Float16(123.456f), Float16(124.143501f), 10);
346+
347+ CheckWithinUlp (std::numeric_limits<Float16>::infinity (),
348+ std::numeric_limits<Float16>::infinity (), 10 );
349+ CheckWithinUlp (-std::numeric_limits<Float16>::infinity (),
350+ -std::numeric_limits<Float16>::infinity (), 10 );
351+ CheckWithinUlp (std::numeric_limits<Float16>::quiet_NaN (),
352+ std::numeric_limits<Float16>::quiet_NaN (), 10 );
353+ CheckNotWithinUlp (std::numeric_limits<Float16>::infinity (),
354+ -std::numeric_limits<Float16>::infinity (), 10 );
355+ CheckNotWithinUlp (Float16 (12 .34f ), -std::numeric_limits<Float16>::infinity (), 10 );
356+ CheckNotWithinUlp (Float16 (12 .34f ), std::numeric_limits<Float16>::quiet_NaN (), 10 );
357+ CheckNotWithinUlp (Float16 (12 .34f ), Float16 (-12 .34f ), 10 );
358+ }
359+
287360TEST (AssertTestWithinUlp, Basics) {
288361 AssertWithinUlp (123.4567 , 123.45670000000015 , 11 );
289362 AssertWithinUlp (123 .456f , 123 .456085f , 11 );
363+ AssertWithinUlp (Float16 (123 .456f ), Float16 (124 .143501f ), 11 );
290364#ifndef _WIN32
291365 // GH-47442
292366 EXPECT_FATAL_FAILURE (AssertWithinUlp (123.4567 , 123.45670000000015 , 10 ),
293367 " not within 10 ulps" );
294368 EXPECT_FATAL_FAILURE (AssertWithinUlp (123 .456f , 123 .456085f , 10 ), " not within 10 ulps" );
369+ EXPECT_FATAL_FAILURE (AssertWithinUlp (Float16 (123 .456f ), Float16 (124 .143501f ), 10 ),
370+ " not within 10 ulps" );
295371#endif
296372}
297373
298- } // namespace arrow
374+ } // namespace arrow::util
0 commit comments