mirror of
https://github.com/KhronosGroup/OpenCL-CTS.git
synced 2026-03-24 07:59:01 +00:00
Fix testing of half-precision fma. (#1882)
Half-precision functions are generally tested against the single-precision reference. This causes double rounding: first to single precision, then from there to half precision. For the most part, it is good enough, but specifically in the case of fma, a correctly rounded result is required and is not obtained, for instance for arguments 0x1.eacp+7, 0x1.3f4p+4, 0x1.c04p+14, which produce an exact result of 0x1.065fffp+15 which should be rounded to half-prefcision 0x1.064p+15, but was previously first rounded to single-precision 0x1.066p+15, and from there to half-precision 0x1.068p+15. Testing against reference_fmal gives us sufficient precision that double rounding does not cause issues. The f_fma(..., FLUSHED) calls for FTZ testing cannot be updated the same way but do not need to be: these calls all have at least one constant operand of zero. If one operand is zero, double rounding cannot be an issue.
This commit is contained in:
@@ -369,7 +369,7 @@ static float Ulp_Error_Half_Float(float test, double reference)
|
|||||||
return (float)scalbn(testVal - reference, ulp_exp);
|
return (float)scalbn(testVal - reference, ulp_exp);
|
||||||
}
|
}
|
||||||
|
|
||||||
float Ulp_Error_Half(cl_half test, float reference)
|
float Ulp_Error_Half(cl_half test, double reference)
|
||||||
{
|
{
|
||||||
return Ulp_Error_Half_Float(cl_half_to_float(test), reference);
|
return Ulp_Error_Half_Float(cl_half_to_float(test), reference);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ static int vlog_win32(const char *format, ...);
|
|||||||
|
|
||||||
extern const char *IGetErrorString(int clErrorCode);
|
extern const char *IGetErrorString(int clErrorCode);
|
||||||
|
|
||||||
extern float Ulp_Error_Half(cl_half test, float reference);
|
extern float Ulp_Error_Half(cl_half test, double reference);
|
||||||
extern float Ulp_Error(float test, double reference);
|
extern float Ulp_Error(float test, double reference);
|
||||||
extern float Ulp_Error_Double(double test, long double reference);
|
extern float Ulp_Error_Double(double test, long double reference);
|
||||||
|
|
||||||
|
|||||||
@@ -237,8 +237,8 @@ int TestFunc_Half_Half_Half_Half(const Func *f, MTdata d, bool relaxedMode)
|
|||||||
for (size_t j = 0; j < bufferElements; j++)
|
for (size_t j = 0; j < bufferElements; j++)
|
||||||
{
|
{
|
||||||
feclearexcept(FE_OVERFLOW);
|
feclearexcept(FE_OVERFLOW);
|
||||||
res[j] = HFF((float)f->func.f_fma(
|
res[j] = HFD((double)f->dfunc.f_fff(HTF(hp0[j]), HTF(hp1[j]),
|
||||||
HTF(hp0[j]), HTF(hp1[j]), HTF(hp2[j]), CORRECTLY_ROUNDED));
|
HTF(hp2[j])));
|
||||||
overflow[j] =
|
overflow[j] =
|
||||||
FE_OVERFLOW == (FE_OVERFLOW & fetestexcept(FE_OVERFLOW));
|
FE_OVERFLOW == (FE_OVERFLOW & fetestexcept(FE_OVERFLOW));
|
||||||
}
|
}
|
||||||
@@ -246,8 +246,8 @@ int TestFunc_Half_Half_Half_Half(const Func *f, MTdata d, bool relaxedMode)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (size_t j = 0; j < bufferElements; j++)
|
for (size_t j = 0; j < bufferElements; j++)
|
||||||
res[j] = HFF((float)f->func.f_fma(
|
res[j] = HFD((double)f->dfunc.f_fff(HTF(hp0[j]), HTF(hp1[j]),
|
||||||
HTF(hp0[j]), HTF(hp1[j]), HTF(hp2[j]), CORRECTLY_ROUNDED));
|
HTF(hp2[j])));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the data back
|
// Read the data back
|
||||||
@@ -277,9 +277,9 @@ int TestFunc_Half_Half_Half_Half(const Func *f, MTdata d, bool relaxedMode)
|
|||||||
{
|
{
|
||||||
int fail;
|
int fail;
|
||||||
cl_half test = ((cl_half *)q)[j];
|
cl_half test = ((cl_half *)q)[j];
|
||||||
float ref1 = f->func.f_fma(HTF(hp0[j]), HTF(hp1[j]),
|
double ref1 = (double)f->dfunc.f_fff(
|
||||||
HTF(hp2[j]), CORRECTLY_ROUNDED);
|
HTF(hp0[j]), HTF(hp1[j]), HTF(hp2[j]));
|
||||||
cl_half correct = HFF(ref1);
|
cl_half correct = HFD(ref1);
|
||||||
|
|
||||||
// Per section 10 paragraph 6, accept any result if an input
|
// Per section 10 paragraph 6, accept any result if an input
|
||||||
// or output is a infinity or NaN or overflow
|
// or output is a infinity or NaN or overflow
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ extern RoundingMode gFloatToHalfRoundingMode;
|
|||||||
extern cl_half_rounding_mode gHalfRoundingMode;
|
extern cl_half_rounding_mode gHalfRoundingMode;
|
||||||
|
|
||||||
#define HFF(num) cl_half_from_float(num, gHalfRoundingMode)
|
#define HFF(num) cl_half_from_float(num, gHalfRoundingMode)
|
||||||
|
#define HFD(num) cl_half_from_double(num, gHalfRoundingMode)
|
||||||
#define HTF(num) cl_half_to_float(num)
|
#define HTF(num) cl_half_to_float(num)
|
||||||
|
|
||||||
#define LOWER_IS_BETTER 0
|
#define LOWER_IS_BETTER 0
|
||||||
|
|||||||
Reference in New Issue
Block a user