[svn-r9807] Purpose: bug fix

Description: For FreeBSD (sleipnir), when GNU compilers do conversion from
unsigned long long to long double, the last 2 bytes of mantissa are lost.
The impact of precision loss isn't significant.

Solution:  Detect this case on FreeBSD in configure, ignore it in dtypes.c
test instead of return failure.

Platforms tested: sleipnir, fuss, modi4.  These systems are mainly concerned.
This commit is contained in:
Raymond Lu 2005-01-11 13:17:01 -05:00
parent 76ba1a99d3
commit a985c4c525
4 changed files with 164 additions and 2 deletions

90
configure vendored
View File

@ -33808,7 +33808,7 @@ else
unsigned long long l2 = (unsigned long long)d1;
unsigned long long l3 = (unsigned long long)d2;
unsigned long long l4;
unsigned long long l5 = 0x7fffffffffffffffLLU;
unsigned long long l5 = 0x7fffffffffffffffULL;
int ret = 0;
if(l1 <= l5 || l2 <= l5 || l3 <= l5)
@ -33883,6 +33883,94 @@ else
echo "${ECHO_T}no" >&6
fi
echo "$as_me:$LINENO: checking if converting unsigned long long to long double with precision work" >&5
echo $ECHO_N "checking if converting unsigned long long to long double with precision work... $ECHO_C" >&6
if test "${hdf5_cv_ullong_to_ldouble_precision_works+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
if test "$cross_compiling" = yes; then
{ { echo "$as_me:$LINENO: error: cannot run test program while cross compiling" >&5
echo "$as_me: error: cannot run test program while cross compiling" >&2;}
{ (exit 1); exit 1; }; }
else
cat >conftest.$ac_ext <<_ACEOF
#line $LINENO "configure"
#include "confdefs.h"
int main(void)
{
unsigned long long l = 0xa601e80bda85fcefULL;
long double ld;
unsigned char *c1, *c2;
int endian, size;
int tst_value = 1;
int i;
int ret = 0;
/* Determine this system's endianess */
c1 = (unsigned char*)calloc(1, sizeof(int));
memcpy(c1, &tst_value, sizeof(int));
if(c1[0]==1)
endian = 0; /* little endian */
else
endian = 1; /* big endian */
memset(&ld, 0, 12);
ld = (long double)l;
size = sizeof(long double);
c2 = (unsigned char*)malloc(size);
memcpy(c2, &ld, size);
/* Test if the last 2 bytes of mantissa are lost. Mainly for FreeBSD on Intel
* architecture(sleipnir) where it happens. */
if(endian==0 && c2[0]==0 && c2[1]==0) /*little endian*/
ret = 1;
free(c1);
free(c2);
done:
exit(ret);
}
_ACEOF
rm -f conftest$ac_exeext
if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
(eval $ac_link) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } && { ac_try='./conftest$ac_exeext'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; }; then
hdf5_cv_ullong_to_ldouble_precision_works=yes
else
echo "$as_me: program exited with status $ac_status" >&5
echo "$as_me: failed program was:" >&5
cat conftest.$ac_ext >&5
( exit $ac_status )
hdf5_cv_ullong_to_ldouble_precision_works=no
fi
rm -f core core.* *.core conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
fi
fi
if test ${hdf5_cv_ullong_to_ldouble_precision_works} = "yes"; then
cat >>confdefs.h <<\_ACEOF
#define ULLONG_TO_LDOUBLE_PRECISION_WORKS 1
_ACEOF
echo "$as_me:$LINENO: result: yes" >&5
echo "${ECHO_T}yes" >&6
else
echo "$as_me:$LINENO: result: no" >&5
echo "${ECHO_T}no" >&6
fi
H5_VERSION="`cut -d' ' -f3 $srcdir/README.txt | head -1`"

View File

@ -2685,7 +2685,7 @@ AC_CACHE_VAL([hdf5_cv_fp_to_ullong_right_maximum],
unsigned long long l2 = (unsigned long long)d1;
unsigned long long l3 = (unsigned long long)d2;
unsigned long long l4;
unsigned long long l5 = 0x7fffffffffffffffLLU;
unsigned long long l5 = 0x7fffffffffffffffULL;
int ret = 0;
if(l1 <= l5 || l2 <= l5 || l3 <= l5)
@ -2727,6 +2727,61 @@ else
AC_MSG_RESULT([no])
fi
dnl ----------------------------------------------------------------------
dnl Set the flag to indicate that the machine can convert from
dnl 'unsigned long long' to 'long double' without precision loss.
dnl (This flag should be set for all machines, except for FreeBSD(sleipnir)
dnl where the last 2 bytes of mantissa are lost when compiler tries to do
dnl the conversion.)
dnl
AC_MSG_CHECKING([if converting unsigned long long to long double with precision work])
AC_CACHE_VAL([hdf5_cv_ullong_to_ldouble_precision_works],
[AC_TRY_RUN([
int main(void)
{
unsigned long long l = 0xa601e80bda85fcefULL;
long double ld;
unsigned char *c1, *c2;
int endian, size;
int tst_value = 1;
int i;
int ret = 0;
/* Determine this system's endianess */
c1 = (unsigned char*)calloc(1, sizeof(int));
memcpy(c1, &tst_value, sizeof(int));
if(c1[0]==1)
endian = 0; /* little endian */
else
endian = 1; /* big endian */
memset(&ld, 0, 12);
ld = (long double)l;
size = sizeof(long double);
c2 = (unsigned char*)malloc(size);
memcpy(c2, &ld, size);
/* Test if the last 2 bytes of mantissa are lost. Mainly for FreeBSD on Intel
* architecture(sleipnir) where it happens. */
if(endian==0 && c2[0]==0 && c2[1]==0) /*little endian*/
ret = 1;
free(c1);
free(c2);
done:
exit(ret);
}
], [hdf5_cv_ullong_to_ldouble_precision_works=yes], [hdf5_cv_ullong_to_ldouble_precision_works=no],)])
if test ${hdf5_cv_ullong_to_ldouble_precision_works} = "yes"; then
AC_DEFINE([ULLONG_TO_LDOUBLE_PRECISION_WORKS], [1],
[Define if your system can convert unsigned long long to long double with correct precision.])
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
fi
dnl ----------------------------------------------------------------------
dnl Set some variables for general configuration information to be saved
dnl and installed with the libraries.

View File

@ -545,6 +545,10 @@
casts. */
#undef ULLONG_TO_FP_CAST_WORKS
/* Define if your system can convert unsigned long long to long double with
correct precision. */
#undef ULLONG_TO_LDOUBLE_PRECISION_WORKS
/* Define if the HDF5 v1.6 compatibility functions are to be compiled in */
#undef WANT_H5_V1_6_COMPAT

View File

@ -5849,6 +5849,21 @@ test_conv_int_float(const char *name, hid_t src, hid_t dst)
}
#endif /*end H5_FP_TO_ULLONG_BOTTOM_BIT_WORKS*/
/* For GNU compilers on FreeBSD(sleipnir), during conversion from 'unsigned long long'
* to 'long double', the last 2 bytes of mantissa are lost. But this loss seems
* acceptable. We allow it go through instead of fail it.
*/
#ifndef H5_ULLONG_TO_LDOUBLE_PRECISION_WORKS
if(src_type==INT_ULLONG && dst_type==FLT_LDOUBLE) {
long double tmp_s, tmp_h;
HDmemcpy(&tmp_s,&buf[j*dst_size],sizeof(long double));
HDmemcpy(&tmp_h,&hw[0],sizeof(long double));
/*Don't compare the last 2 bytes of mantissa*/
if(!HDmemcmp(&tmp_s+2, &tmp_h+2, sizeof(long double)-2))
continue; /*no error*/
}
#endif /*end H5_ULLONG_TO_LDOUBLE_PRECISION_WORKS*/
/* Print errors */
if (0==fails_this_test++)
H5_FAILED();