[svn-r7882] Purpose:

Bug fix

Description:
    Handle denormalized floating-point values in a more general way that
uses a different 'epsilon' for determining if two values are "close enough"

Platforms tested:
    FreeBSD 4.9 (sleipnir)
    h5committest
    Pittsburgh Alpha Cluster (lemieux.psc.edu)
This commit is contained in:
Quincey Koziol 2003-11-25 14:26:01 -05:00
parent 5be9d3a22c
commit 3088616179

View File

@ -31,6 +31,9 @@
/* Define if you want to see a count of overflows */
#undef SHOW_OVERFLOWS
/* Epsilon for floating-point comparisons */
#define FP_EPSILON 0.000001
/*
* Offset from alinged memory returned by malloc(). This can be used to test
* that type conversions handle non-aligned buffers correctly.
@ -4897,6 +4900,8 @@ test_conv_flt_1 (const char *name, hid_t src, hid_t dst)
unsigned char *hw=NULL; /*ptr to hardware-conv'd*/
size_t i, j, k; /*counters */
int endian; /*machine endianess */
size_t dst_ebias; /* Destination type's exponent bias */
size_t dst_msize; /* Destination type's mantissa size */
#ifdef HANDLE_SIGFPE
pid_t child_pid; /*process ID of child */
@ -4990,6 +4995,10 @@ test_conv_flt_1 (const char *name, hid_t src, hid_t dst)
noverflows_g = 0;
#endif
/* Get "interesting" values */
dst_ebias=H5Tget_ebias(dst);
H5Tget_fields(dst,NULL,NULL,NULL,NULL,&dst_msize);
for (i=0; i<ntests; i++) {
/*
@ -5170,10 +5179,28 @@ test_conv_flt_1 (const char *name, hid_t src, hid_t dst)
check_mant[1] = frexp(((long double*)hw)[0], check_expo+1);
#endif
}
if (check_expo[0]==check_expo[1] &&
fabs(check_mant[0]-check_mant[1])<0.000001) {
continue;
}
/* Special check for denormalized values */
if(check_expo[0]<(-(int)dst_ebias) || check_expo[1]<(-(int)dst_ebias)) {
int expo_diff=check_expo[0]-check_expo[1];
int valid_bits=((dst_ebias+dst_msize)+MIN(check_expo[0],check_expo[1]))-1;
double epsilon=1.0;
/* Re-scale the mantissas based on any exponent difference */
if(expo_diff!=0)
check_mant[0] = ldexp(check_mant[0],(double)expo_diff);
/* Compute the proper epsilon */
epsilon=ldexp(epsilon,-valid_bits);
/* Check for "close enough" fit with scaled epsilon value */
if (fabs(check_mant[0]-check_mant[1])<=epsilon)
continue;
} /* end if */
else {
if (check_expo[0]==check_expo[1] &&
fabs(check_mant[0]-check_mant[1])<FP_EPSILON)
continue;
} /* end else */
}
#endif