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`.
This commit is contained in:
Antonio Sanchez
2020-11-23 14:13:59 -08:00
parent 4cf01d2cf5
commit 38abf2be42
3 changed files with 35 additions and 11 deletions

View File

@@ -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) );