Permit half overflow within allowable ULP (#600)

* Permit half overflow within allowable ULP

Modify the algorithm for calculating half precision ULP error so
that it duplicates the behaviour of the single precision ULP algorithm,
in regards to allowing overflow within the defined ULP error.

In the case where the test value is infinity, but the reference is
finite, pretend the test value is 63336.0 and calculate the ULP error
against that.

Encountered this while testing half precision `hypot()` in PR !529,
for inputs `hypot(-48864.0, 43648.0)` which has reference
`65519.755799`. With RTE rounding this only just rounds to `65504` as half,
and returning INF is currently infinite ULP error. Using the leniency
introduced by this change however the error is `~0.5` within the `2` ULP
bounds defined by the spec.

* Run clang-format over changes

Code now conforms to style guidelines and allows `check-format.sh` to pass.
This commit is contained in:
Ewan Crawford
2020-10-28 10:13:40 +00:00
committed by GitHub
parent f162c8b5ef
commit 55976fad35
3 changed files with 17 additions and 58 deletions

View File

@@ -95,7 +95,6 @@ extern cl_device_fp_config gDoubleCapabilities;
float Abs_Error( float test, double reference );
float Ulp_Error( float test, double reference );
//float Ulp_Error_Half( float test, double reference );
float Bruteforce_Ulp_Error_Double( double test, long double reference );
uint64_t GetTime( void );

View File

@@ -1739,53 +1739,6 @@ float Abs_Error( float test, double reference )
return fabs((float)(reference-(double)test));
}
/*
#define HALF_MIN_EXP -13
#define HALF_MANT_DIG 11
float Ulp_Error_Half( float test, double reference )
{
union{ double d; uint64_t u; }u; u.d = reference;
// Note: This function presumes that someone has already tested whether the result is correctly,
// rounded before calling this function. That test:
//
// if( (float) reference == test )
// return 0.0f;
//
// would ensure that cases like fabs(reference) > FLT_MAX are weeded out before we get here.
// Otherwise, we'll return inf ulp error here, for what are otherwise correctly rounded
// results.
double testVal = test;
if( u.u & 0x000fffffffffffffULL )
{ // Non-power of two and NaN
if( isnan( reference ) && isnan( test ) )
return 0.0f; // if we are expecting a NaN, any NaN is fine
// The unbiased exponent of the ulp unit place
int ulp_exp = HALF_MANT_DIG - 1 - MAX( ilogb( reference), HALF_MIN_EXP-1 );
// Scale the exponent of the error
return (float) scalbn( testVal - reference, ulp_exp );
}
if( isinf( reference ) )
{
if( (double) test == reference )
return 0.0f;
return (float) (testVal - reference );
}
// reference is a normal power of two or a zero
int ulp_exp = HALF_MANT_DIG - 1 - MAX( ilogb( reference) - 1, HALF_MIN_EXP-1 );
// Scale the exponent of the error
return (float) scalbn( testVal - reference, ulp_exp );
}
*/
#if defined( __APPLE__ )
#include <mach/mach_time.h>
#endif