diff options
author | Antonio Sanchez <cantonios@google.com> | 2020-11-23 14:13:59 -0800 |
---|---|---|
committer | Antonio Sanchez <cantonios@google.com> | 2020-11-23 14:13:59 -0800 |
commit | 38abf2be4289a8da5db2d5b1db759f26800ae1d3 (patch) | |
tree | d12493bc35c41785aceef33fa7374ff3a386d662 /test/half_float.cpp | |
parent | 4cf01d2cf5e10c38fdec01acd335b11b924de399 (diff) |
Fix Half NaN definition and test.
The `half_float` test was failing with `-mcpu=cortex-a55` (native `__fp16`) due
to a bad NaN bit-pattern comparison (in the case of casting a float to `__fp16`,
the signaling `NaN` is quieted). There was also an inconsistency between
`numeric_limits<half>::quiet_NaN()` and `NumTraits::quiet_NaN()`. Here we
correct the inconsistency and compare NaNs according to the IEEE 754
definition.
Also modified the `bfloat16_float` test to match.
Tested with `cortex-a53` and `cortex-a55`.
Diffstat (limited to 'test/half_float.cpp')
-rw-r--r-- | test/half_float.cpp | 22 |
1 files changed, 16 insertions, 6 deletions
diff --git a/test/half_float.cpp b/test/half_float.cpp index cf6df547a..b2c22197f 100644 --- a/test/half_float.cpp +++ b/test/half_float.cpp @@ -136,12 +136,22 @@ void test_numtraits() VERIFY_IS_EQUAL( numext::bit_cast<numext::uint16_t>(std::numeric_limits<half>::infinity()), numext::bit_cast<numext::uint16_t>(half(std::numeric_limits<float>::infinity())) ); - VERIFY_IS_EQUAL( - numext::bit_cast<numext::uint16_t>(std::numeric_limits<half>::quiet_NaN()), - numext::bit_cast<numext::uint16_t>(half(std::numeric_limits<float>::quiet_NaN())) ); - VERIFY_IS_EQUAL( - numext::bit_cast<numext::uint16_t>(std::numeric_limits<half>::signaling_NaN()), - numext::bit_cast<numext::uint16_t>(half(std::numeric_limits<float>::signaling_NaN())) ); + // There is no guarantee that casting a 32-bit NaN to 16-bit has a precise + // bit pattern. We test that it is in fact a NaN, then test the signaling + // bit (msb of significand is 1 for quiet, 0 for signaling). + const numext::uint16_t HALF_QUIET_BIT = 0x0200; + VERIFY( + (numext::isnan)(std::numeric_limits<half>::quiet_NaN()) + && (numext::isnan)(half(std::numeric_limits<float>::quiet_NaN())) + && ((numext::bit_cast<numext::uint16_t>(std::numeric_limits<half>::quiet_NaN()) & HALF_QUIET_BIT) > 0) + && ((numext::bit_cast<numext::uint16_t>(half(std::numeric_limits<float>::quiet_NaN())) & HALF_QUIET_BIT) > 0) ); + // After a cast to half, a signaling NaN may become non-signaling + // (e.g. in the case of casting float to native __fp16). Thus, we check that + // both are NaN, and that only the `numeric_limits` version is signaling. + VERIFY( + (numext::isnan)(std::numeric_limits<half>::signaling_NaN()) + && (numext::isnan)(half(std::numeric_limits<float>::signaling_NaN())) + && ((numext::bit_cast<numext::uint16_t>(std::numeric_limits<half>::signaling_NaN()) & HALF_QUIET_BIT) == 0) ); VERIFY( (std::numeric_limits<half>::min)() > half(0.f) ); VERIFY( (std::numeric_limits<half>::denorm_min)() > half(0.f) ); |