diff options
author | Albert Cheng <acheng@hdfgroup.org> | 2004-04-16 21:26:37 (GMT) |
---|---|---|
committer | Albert Cheng <acheng@hdfgroup.org> | 2004-04-16 21:26:37 (GMT) |
commit | 7f2eb1127ab1a9c503f5cb65b7453c3c819b76a3 (patch) | |
tree | c00330e0ce715e887a54bd4e565d02a723e4af2f | |
parent | 84960eed3cf0f418da4a5e0cdca31eee76110b29 (diff) | |
download | hdf5-7f2eb1127ab1a9c503f5cb65b7453c3c819b76a3.zip hdf5-7f2eb1127ab1a9c503f5cb65b7453c3c819b76a3.tar.gz hdf5-7f2eb1127ab1a9c503f5cb65b7453c3c819b76a3.tar.bz2 |
[svn-r8360] Purpose:
bug fix.
Description:
On LANL QSC, test/dtypes "sw long double -> double" had failed when the
long double values were too small, smaller than the minimum double normalized
floating number. The hw in QSC converts them mostly to 0 but occasionally,
it converts to the some non-zero values which are still <= the minimum
double normalized number. But the conversion verification did not like
them and flagged them as errors.
Solution:
Added code to check if the src value is already smaller than the minimum
number the float class can hold. When that happens and if both hw and sw
conversion results are <= the minimum number, then accepts them as okay
because if the src is smaller than the dst minimum number, an underflow
has occured.
Platforms tested:
Tested in LANL QSC and Theta.
-rw-r--r-- | test/dtypes.c | 28 |
1 files changed, 28 insertions, 0 deletions
diff --git a/test/dtypes.c b/test/dtypes.c index 5193115..b9af7d6 100644 --- a/test/dtypes.c +++ b/test/dtypes.c @@ -4755,6 +4755,11 @@ my_isnan(dtype_t type, void *val) * Tuesday, June 23, 1998 * * Modifications: + * Albert Cheng, Apr 16, 2004 + * Check for underflow condition. If the src number is + * smaller than the dst MIN float number, consider it okay + * if the converted sw and hw dst are both less than or + * equal to the dst MIN float number. * *------------------------------------------------------------------------- */ @@ -4780,6 +4785,8 @@ test_conv_flt_1 (const char *name, hid_t src, hid_t dst) long double hw_ld; /*hardware-converted */ #endif unsigned char *hw=NULL; /*ptr to hardware-conv'd*/ + int underflow; /*underflow occurred */ + int uflow=0; /*underflow debug counters*/ size_t i, j, k; /*counters */ int endian; /*machine endianess */ size_t src_ebias; /* Source type's exponent bias */ @@ -4949,6 +4956,7 @@ test_conv_flt_1 (const char *name, hid_t src, hid_t dst) /* Check the software results against the hardware */ for (j=0; j<nelmts; j++) { + underflow = 0; hw_f = 911.0; hw_d = 911.0; #if H5_SIZEOF_LONG_DOUBLE!=H5_SIZEOF_DOUBLE @@ -4956,6 +4964,7 @@ test_conv_flt_1 (const char *name, hid_t src, hid_t dst) #endif /* The hardware conversion */ + /* Check for underflow when src is a "larger" float than dst.*/ if (FLT_FLOAT==src_type) { HDmemcpy(aligned, saved+j*sizeof(float), sizeof(float)); if (FLT_FLOAT==dst_type) { @@ -4975,6 +4984,7 @@ test_conv_flt_1 (const char *name, hid_t src, hid_t dst) if (FLT_FLOAT==dst_type) { hw_f = (float)(*((double*)aligned)); hw = (unsigned char*)&hw_f; + underflow = fabs(*((double*)aligned)) < FLT_MIN; } else if (FLT_DOUBLE==dst_type) { hw_d = *((double*)aligned); hw = (unsigned char*)&hw_d; @@ -4990,15 +5000,20 @@ test_conv_flt_1 (const char *name, hid_t src, hid_t dst) if (FLT_FLOAT==dst_type) { hw_f = *((long double*)aligned); hw = (unsigned char*)&hw_f; + underflow = fabsl(*((long double*)aligned)) < FLT_MIN; } else if (FLT_DOUBLE==dst_type) { hw_d = *((long double*)aligned); hw = (unsigned char*)&hw_d; + underflow = fabsl(*((long double*)aligned)) < DBL_MIN; } else { hw_ld = *((long double*)aligned); hw = (unsigned char*)&hw_ld; } #endif } + if (underflow){ + uflow++; + } /* Are the two results the same? */ for (k=0; k<dst_size; k++) @@ -5042,6 +5057,9 @@ test_conv_flt_1 (const char *name, hid_t src, hid_t dst) * exponents are the same and the mantissa is the same to a * certain precision. This is needed on machines that don't * round as expected. + * If the src number is smaller than the dst MIN float number, + * consider it okay if the converted sw and hw dst are both + * less than or equal to the dst MIN float number. */ { double check_mant[2]; @@ -5050,17 +5068,24 @@ test_conv_flt_1 (const char *name, hid_t src, hid_t dst) if (FLT_FLOAT==dst_type) { float x; HDmemcpy(&x, &buf[j*dst_size], sizeof(float)); + if (underflow && + fabsf(x) <= FLT_MIN && fabsf(hw_f) <= FLT_MIN) + continue; /* all underflowed, no error */ check_mant[0] = HDfrexpf(x, check_expo+0); check_mant[1] = HDfrexpf(hw_f, check_expo+1); } else if (FLT_DOUBLE==dst_type) { double x; HDmemcpy(&x, &buf[j*dst_size], sizeof(double)); + if (underflow && + fabs(x) <= DBL_MIN && fabs(hw_d) <= DBL_MIN) + continue; /* all underflowed, no error */ check_mant[0] = HDfrexp(x, check_expo+0); check_mant[1] = HDfrexp(hw_d, check_expo+1); #if H5_SIZEOF_LONG_DOUBLE!=H5_SIZEOF_DOUBLE } else { long double x; HDmemcpy(&x, &buf[j*dst_size], sizeof(long double)); + /* dst is largest float, no need to check underflow. */ check_mant[0] = HDfrexpl(x, check_expo+0); check_mant[1] = HDfrexpl(hw_ld, check_expo+1); #endif @@ -5193,6 +5218,9 @@ test_conv_flt_1 (const char *name, hid_t src, hid_t dst) #endif done: +#ifdef AKCDEBUG + printf("uflow=%d, fails_all_tests=%d\n", uflow, fails_all_tests); +#endif if (buf) aligned_free(buf); if (saved) aligned_free(saved); if (aligned) HDfree(aligned); |