|
12 | 12 | #include "utils/MPFRWrapper/MPFRUtils.h" |
13 | 13 |
|
14 | 14 | using LlvmLibcPowF16Test = LIBC_NAMESPACE::testing::FPTest<float16>; |
15 | | -using LIBC_NAMESPACE::testing::tlog; |
16 | 15 |
|
17 | 16 | namespace mpfr = LIBC_NAMESPACE::testing::mpfr; |
18 | 17 |
|
19 | | -TEST_F(LlvmLibcPowF16Test, TrickyInputs) { |
20 | | - // These values are in half precision. |
21 | | - constexpr mpfr::BinaryInput<float16> INPUTS[] = { |
22 | | - {static_cast<float16>(0x1.08p-2f), static_cast<float16>(0x1.0cp-1f)}, |
23 | | - {static_cast<float16>(0x1.66p-1f), static_cast<float16>(0x1.f1p+1f)}, |
24 | | - {static_cast<float16>(0x1.c04p-1f), static_cast<float16>(0x1.2p+12f)}, |
25 | | - {static_cast<float16>(0x1.aep-1f), static_cast<float16>(0x1.f9p-1f)}, |
26 | | - {static_cast<float16>(0x1.ffcp-1f), static_cast<float16>(0x1.fffp-2f)}, |
27 | | - {static_cast<float16>(0x1.f55p-1f), static_cast<float16>(0x1.88p+12f)}, |
28 | | - {static_cast<float16>(0x1.e84p-1f), static_cast<float16>(0x1.2cp+13f)}, |
29 | | - }; |
30 | | - |
31 | | - for (auto input : INPUTS) { |
32 | | - float16 x = input.x; |
33 | | - float16 y = input.y; |
34 | | - EXPECT_MPFR_MATCH(mpfr::Operation::Pow, input, LIBC_NAMESPACE::powf16(x, y), |
35 | | - 1.0); // 1 ULP tolerance is enough for f16 |
| 18 | +static constexpr float16 SELECTED_VALS[] = { |
| 19 | + 0.5f16, 0.83984375f16, 1.0f16, 2.0f16, 3.0f16, 3.140625f16, 15.5f16, |
| 20 | +}; |
| 21 | + |
| 22 | +// Test selected x values against all possible y values. |
| 23 | +TEST_F(LlvmLibcPowF16Test, SelectedX_AllY) { |
| 24 | + for (size_t i = 0; i < sizeof(SELECTED_VALS) / sizeof(SELECTED_VALS[0]); |
| 25 | + ++i) { |
| 26 | + float16 x = SELECTED_VALS[i]; |
| 27 | + for (uint16_t y_u = 0; y_u <= 0x7c00U; ++y_u) { |
| 28 | + float16 y = FPBits(y_u).get_val(); |
| 29 | + |
| 30 | + mpfr::BinaryInput<float16> input{x, y}; |
| 31 | + float16 result = LIBC_NAMESPACE::powf16(x, y); |
| 32 | + EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Pow, input, result, 1.0); |
| 33 | + |
| 34 | + // If the result is infinity and we expect it to continue growing, we can |
| 35 | + // terminate the loop early. |
| 36 | + if (FPBits(result).is_inf() && FPBits(result).is_pos()) { |
| 37 | + // For x > 1, as y increases in the positive range, pow remains inf. |
| 38 | + if (x > static_cast<float16>(1.0f) && y > static_cast<float16>(0.0f)) { |
| 39 | + // The y_u loop covers the positive range up to 0x7BFF. |
| 40 | + break; |
| 41 | + } |
| 42 | + // For 0 < x < 1, as y becomes more negative, pow becomes inf. |
| 43 | + if (x > static_cast<float16>(0.0f) && x < static_cast<float16>(1.0f) && |
| 44 | + y < static_cast<float16>(0.0f)) { |
| 45 | + // The y_u loop covers the negative range from 0x8000. |
| 46 | + break; |
| 47 | + } |
| 48 | + } |
| 49 | + } |
36 | 50 | } |
37 | 51 | } |
38 | 52 |
|
39 | | -TEST_F(LlvmLibcPowF16Test, InFloat16Range) { |
40 | | - constexpr uint16_t X_COUNT = 63; |
41 | | - constexpr uint16_t X_START = FPBits(static_cast<float16>(0.25)).uintval(); |
42 | | - constexpr uint16_t X_STOP = FPBits(static_cast<float16>(4.0)).uintval(); |
43 | | - constexpr uint16_t X_STEP = (X_STOP - X_START) / X_COUNT; |
44 | | - |
45 | | - constexpr uint16_t Y_COUNT = 59; |
46 | | - constexpr uint16_t Y_START = FPBits(static_cast<float16>(0.25)).uintval(); |
47 | | - constexpr uint16_t Y_STOP = FPBits(static_cast<float16>(4.0)).uintval(); |
48 | | - constexpr uint16_t Y_STEP = (Y_STOP - Y_START) / Y_COUNT; |
49 | | - |
50 | | - auto test = [&](mpfr::RoundingMode rounding_mode) { |
51 | | - mpfr::ForceRoundingMode __r(rounding_mode); |
52 | | - if (!__r.success) |
53 | | - return; |
54 | | - |
55 | | - uint64_t fails = 0; |
56 | | - uint64_t count = 0; |
57 | | - uint64_t cc = 0; |
58 | | - float16 mx = 0.0, my = 0.0, mr = 0.0; |
59 | | - double tol = 1.0; // start with 1 ULP for half precision |
60 | | - |
61 | | - for (uint16_t i = 0, v = X_START; i <= X_COUNT; ++i, v += X_STEP) { |
62 | | - float16 x = FPBits(v).get_val(); |
63 | | - if (FPBits(x).is_inf_or_nan() || x < static_cast<float16>(0.0)) |
64 | | - continue; |
65 | | - |
66 | | - for (uint16_t j = 0, w = Y_START; j <= Y_COUNT; ++j, w += Y_STEP) { |
67 | | - float16 y = FPBits(w).get_val(); |
68 | | - if (FPBits(y).is_inf_or_nan()) |
69 | | - continue; |
70 | | - |
71 | | - float16 result = LIBC_NAMESPACE::powf16(x, y); |
72 | | - ++cc; |
73 | | - if (FPBits(result).is_inf_or_nan()) |
74 | | - continue; |
75 | | - |
76 | | - ++count; |
77 | | - mpfr::BinaryInput<float16> inputs{x, y}; |
78 | | - |
79 | | - if (!TEST_MPFR_MATCH_ROUNDING_SILENTLY(mpfr::Operation::Pow, inputs, |
80 | | - result, 1.0, rounding_mode)) { |
81 | | - ++fails; |
82 | | - while (!TEST_MPFR_MATCH_ROUNDING_SILENTLY( |
83 | | - mpfr::Operation::Pow, inputs, result, tol, rounding_mode)) { |
84 | | - mx = x; |
85 | | - my = y; |
86 | | - mr = result; |
87 | | - |
88 | | - if (tol > 128.0) // half precision is only ~11 bits |
89 | | - break; |
90 | | - |
91 | | - tol *= 2.0; |
92 | | - } |
| 53 | +// Test selected y values against all possible x values. |
| 54 | +TEST_F(LlvmLibcPowF16Test, SelectedY_AllX) { |
| 55 | + for (size_t i = 0; i < sizeof(SELECTED_VALS) / sizeof(SELECTED_VALS[0]); |
| 56 | + ++i) { |
| 57 | + float16 y = SELECTED_VALS[i]; |
| 58 | + for (uint16_t x_u = 0; x_u <= 0x7c00U; ++x_u) { |
| 59 | + float16 x = FPBits(x_u).get_val(); |
| 60 | + mpfr::BinaryInput<float16> input{x, y}; |
| 61 | + float16 result = LIBC_NAMESPACE::powf16(x, y); |
| 62 | + EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Pow, input, result, 1.0); |
| 63 | + |
| 64 | + // If the result is infinity and we expect it to continue growing, we can |
| 65 | + // terminate the loop early. |
| 66 | + if (FPBits(result).is_inf() && FPBits(result).is_pos()) { |
| 67 | + // For y > 0, as x increases in the positive range, pow remains inf. |
| 68 | + if (y > 0.0f16 && x > 0.0f16) { |
| 69 | + // The x_u loop covers the positive range up to 0x7BFF. |
| 70 | + break; |
93 | 71 | } |
94 | 72 | } |
95 | 73 | } |
96 | | - if (fails || (count < cc)) { |
97 | | - tlog << " powf16 failed: " << fails << "/" << count << "/" << cc |
98 | | - << " tests.\n" |
99 | | - << " Max ULPs is at most: " << static_cast<uint64_t>(tol) << ".\n"; |
100 | | - } |
101 | | - if (fails) { |
102 | | - mpfr::BinaryInput<float16> inputs{mx, my}; |
103 | | - EXPECT_MPFR_MATCH(mpfr::Operation::Pow, inputs, mr, 1.0, rounding_mode); |
104 | | - } |
105 | | - }; |
106 | | - |
107 | | - tlog << " Test Rounding To Nearest...\n"; |
108 | | - test(mpfr::RoundingMode::Nearest); |
109 | | - |
110 | | - tlog << " Test Rounding Downward...\n"; |
111 | | - test(mpfr::RoundingMode::Downward); |
112 | | - |
113 | | - tlog << " Test Rounding Upward...\n"; |
114 | | - test(mpfr::RoundingMode::Upward); |
115 | | - |
116 | | - tlog << " Test Rounding Toward Zero...\n"; |
117 | | - test(mpfr::RoundingMode::TowardZero); |
| 74 | + } |
118 | 75 | } |
0 commit comments