mirror of
https://github.com/HDFGroup/hdf5.git
synced 2024-11-27 02:10:55 +08:00
[svn-r12425] Purpose: Bug fix
Description: Data conversion from long double to (unsigned) long long returns some incorrect values on Mac OS 10.4 and SGI IRIX64 6.5. The conversions start to go wrong when the long double is 20041683600089727.779961 (0x4351ccf385ebc8a0bfcc2a...). If adjusting the values higher by assigning 0x...c8a0cf... or 0x...c8a0df..., the converted values go wild. Solution: Detect this error in configure.in and disable compiler conversions from long double to (unsigned) long long for Mac OS 10.4 and IRIX64 6.5. Platforms tested: h5committest, Mac OS 10.4, and IRIX64 6.5.
This commit is contained in:
parent
9db9e82cd1
commit
823fbd0e88
100
configure
vendored
100
configure
vendored
@ -51683,6 +51683,106 @@ else
|
||||
echo "${ECHO_T}no" >&6
|
||||
fi
|
||||
|
||||
echo "$as_me:$LINENO: checking if correctly converting long double to (unsigned) long long values" >&5
|
||||
echo $ECHO_N "checking if correctly converting long double to (unsigned) long long values... $ECHO_C" >&6
|
||||
|
||||
if test ${ac_cv_sizeof_long_double} = 0; then
|
||||
hdf5_ldouble_to_llong_accurate=${hdf5_ldouble_to_llong_accurate=no}
|
||||
else
|
||||
if test "${hdf5_ldouble_to_llong_accurate+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
|
||||
See \`config.log' for more details." >&5
|
||||
echo "$as_me: error: cannot run test program while cross compiling
|
||||
See \`config.log' for more details." >&2;}
|
||||
{ (exit 1); exit 1; }; }
|
||||
else
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
/* confdefs.h. */
|
||||
_ACEOF
|
||||
cat confdefs.h >>conftest.$ac_ext
|
||||
cat >>conftest.$ac_ext <<_ACEOF
|
||||
/* end confdefs.h. */
|
||||
|
||||
int main(void)
|
||||
{
|
||||
long double ld = 20041683600089727.779961L;
|
||||
long long ll;
|
||||
unsigned long long ull;
|
||||
unsigned char s[16];
|
||||
int ret = 0;
|
||||
|
||||
if(sizeof(long double) == 16) {
|
||||
/*make sure the long double type is the same as the failing type
|
||||
*which has 16 bytes in size and 11 bits of exponent. If it is,
|
||||
*the bit sequence should be like below. It's not
|
||||
*a decent way to check but this info isn't available. */
|
||||
memcpy(s, &ld, 16);
|
||||
if(s[0]==0x43 && s[1]==0x51 && s[2]==0xcc && s[3]==0xf3 &&
|
||||
s[4]==0x85 && s[5]==0xeb && s[6]==0xc8 && s[7]==0xa0 &&
|
||||
s[8]==0xbf && s[9]==0xcc && s[10]==0x2a && s[11]==0x3c) {
|
||||
|
||||
/*slightly adjust the bit sequence (s[8]=0xdf). The converted
|
||||
*values will go wild on Mac OS 10.4 and IRIX64 6.5.*/
|
||||
s[0]=0x43; s[1]=0x51; s[2]=0xcc; s[3]=0xf3;
|
||||
s[4]=0x85; s[5]=0xeb; s[6]=0xc8; s[7]=0xa0;
|
||||
s[8]=0xdf; s[9]=0xcc; s[10]=0x2a; s[11]=0x3c;
|
||||
s[12]=0x3d; s[13]=0x85; s[14]=0x56; s[15]=0x20;
|
||||
|
||||
memcpy(&ld, s, 16);
|
||||
ll = (long long)ld;
|
||||
ull = (unsigned long long)ld;
|
||||
|
||||
if(ll != 20041683600089728 || ull != 20041683600089728)
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
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_ldouble_to_llong_accurate=yes
|
||||
else
|
||||
echo "$as_me: program exited with status $ac_status" >&5
|
||||
echo "$as_me: failed program was:" >&5
|
||||
sed 's/^/| /' conftest.$ac_ext >&5
|
||||
|
||||
( exit $ac_status )
|
||||
hdf5_ldouble_to_llong_accurate=no
|
||||
fi
|
||||
rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
|
||||
fi
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
if test ${hdf5_ldouble_to_llong_accurate} = "yes"; then
|
||||
|
||||
cat >>confdefs.h <<\_ACEOF
|
||||
#define LDOUBLE_TO_LLONG_ACCURATE 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`"
|
||||
|
||||
|
63
configure.in
63
configure.in
@ -3093,6 +3093,69 @@ else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
|
||||
dnl ----------------------------------------------------------------------
|
||||
dnl Set the flag to indicate that the machine can accurately convert
|
||||
dnl 'long double' to '(unsigned) long long' values. (This flag should be set for
|
||||
dnl all machines, except for Mac OS 10.4 and SGI IRIX64 6.5. When the bit sequence
|
||||
dnl of long double is 0x4351ccf385ebc8a0bfcc2a3c..., the values of (unsigned)long long
|
||||
dnl start to go wrong on these two machines. Adjusting it higher to
|
||||
dnl 0x4351ccf385ebc8a0dfcc... or 0x4351ccf385ebc8a0ffcc... will make the converted
|
||||
dnl values wildly wrong. This test detects this wrong behavior and disable the test.
|
||||
dnl
|
||||
AC_MSG_CHECKING([if correctly converting long double to (unsigned) long long values])
|
||||
|
||||
if test ${ac_cv_sizeof_long_double} = 0; then
|
||||
hdf5_ldouble_to_llong_accurate=${hdf5_ldouble_to_llong_accurate=no}
|
||||
else
|
||||
AC_CACHE_VAL([hdf5_ldouble_to_llong_accurate],
|
||||
[AC_TRY_RUN([
|
||||
int main(void)
|
||||
{
|
||||
long double ld = 20041683600089727.779961L;
|
||||
long long ll;
|
||||
unsigned long long ull;
|
||||
unsigned char s[16];
|
||||
int ret = 0;
|
||||
|
||||
if(sizeof(long double) == 16) {
|
||||
/*make sure the long double type is the same as the failing type
|
||||
*which has 16 bytes in size and 11 bits of exponent. If it is,
|
||||
*the bit sequence should be like below. It's not
|
||||
*a decent way to check but this info isn't available. */
|
||||
memcpy(s, &ld, 16);
|
||||
if(s[0]==0x43 && s[1]==0x51 && s[2]==0xcc && s[3]==0xf3 &&
|
||||
s[4]==0x85 && s[5]==0xeb && s[6]==0xc8 && s[7]==0xa0 &&
|
||||
s[8]==0xbf && s[9]==0xcc && s[10]==0x2a && s[11]==0x3c) {
|
||||
|
||||
/*slightly adjust the bit sequence (s[8]=0xdf). The converted
|
||||
*values will go wild on Mac OS 10.4 and IRIX64 6.5.*/
|
||||
s[0]=0x43; s[1]=0x51; s[2]=0xcc; s[3]=0xf3;
|
||||
s[4]=0x85; s[5]=0xeb; s[6]=0xc8; s[7]=0xa0;
|
||||
s[8]=0xdf; s[9]=0xcc; s[10]=0x2a; s[11]=0x3c;
|
||||
s[12]=0x3d; s[13]=0x85; s[14]=0x56; s[15]=0x20;
|
||||
|
||||
memcpy(&ld, s, 16);
|
||||
ll = (long long)ld;
|
||||
ull = (unsigned long long)ld;
|
||||
|
||||
if(ll != 20041683600089728 || ull != 20041683600089728)
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
done:
|
||||
exit(ret);
|
||||
}
|
||||
], [hdf5_ldouble_to_llong_accurate=yes], [hdf5_ldouble_to_llong_accurate=no],)])
|
||||
fi
|
||||
|
||||
if test ${hdf5_ldouble_to_llong_accurate} = "yes"; then
|
||||
AC_DEFINE([LDOUBLE_TO_LLONG_ACCURATE], [1],
|
||||
[Define if your system can convert long double to (unsigned) long long values correctly.])
|
||||
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.
|
||||
|
13
src/H5Tpkg.h
13
src/H5Tpkg.h
@ -138,10 +138,10 @@
|
||||
#endif
|
||||
|
||||
/* Define an internal macro for converting long double to long long. SGI compilers give some incorrect
|
||||
* conversions. HP-UX 11.00 compiler generates floating exception. The hard conversion on Windows
|
||||
* .NET 2003 has a bug and gives wrong exception value. */
|
||||
* conversions. Mac OS 10.4 gives incorrect conversions. HP-UX 11.00 compiler generates floating exception.
|
||||
* The hard conversion on Windows .NET 2003 has a bug and gives wrong exception value. */
|
||||
#if (H5_WANT_DATA_ACCURACY && !H5_HW_FP_TO_LLONG_NOT_WORKS && H5_LDOUBLE_TO_INTEGER_ACCURATE && \
|
||||
H5_LDOUBLE_TO_INTEGER_WORKS) || \
|
||||
H5_LDOUBLE_TO_INTEGER_WORKS && H5_LDOUBLE_TO_LLONG_ACCURATE) || \
|
||||
(!H5_WANT_DATA_ACCURACY && !H5_HW_FP_TO_LLONG_NOT_WORKS && H5_LDOUBLE_TO_INTEGER_WORKS)
|
||||
#define H5T_CONV_INTERNAL_LDOUBLE_LLONG 1
|
||||
#endif
|
||||
@ -156,10 +156,11 @@
|
||||
#define H5T_CONV_INTERNAL_FP_ULLONG 0
|
||||
#endif
|
||||
|
||||
/* Define an internal macro for converting long double to all integers. SGI compilers give some incorrect
|
||||
* conversions. HP-UX 11.00 compiler generates floating exception. */
|
||||
/* Define an internal macro for converting long double to unsigned long long. SGI compilers give some
|
||||
* incorrect conversions. Mac OS 10.4 gives incorrect conversions. HP-UX 11.00 compiler generates
|
||||
* floating exception. */
|
||||
#if (H5_WANT_DATA_ACCURACY && H5_LDOUBLE_TO_INTEGER_ACCURATE && H5_LDOUBLE_TO_INTEGER_WORKS && \
|
||||
H5_FP_TO_ULLONG_ACCURATE && H5_FP_TO_ULLONG_RIGHT_MAXIMUM) || \
|
||||
H5_FP_TO_ULLONG_ACCURATE && H5_FP_TO_ULLONG_RIGHT_MAXIMUM && H5_LDOUBLE_TO_LLONG_ACCURATE) || \
|
||||
(!H5_WANT_DATA_ACCURACY && H5_LDOUBLE_TO_INTEGER_WORKS)
|
||||
#define H5T_CONV_INTERNAL_LDOUBLE_ULLONG 1
|
||||
#else
|
||||
|
@ -383,6 +383,10 @@
|
||||
/* Define if your system can convert from long double to integer values. */
|
||||
#undef LDOUBLE_TO_INTEGER_WORKS
|
||||
|
||||
/* Define if your system can convert long double to (unsigned) long long
|
||||
values correctly. */
|
||||
#undef LDOUBLE_TO_LLONG_ACCURATE
|
||||
|
||||
/* Define if your system can convert long double to unsigned int values
|
||||
correctly. */
|
||||
#undef LDOUBLE_TO_UINT_ACCURATE
|
||||
|
@ -5120,10 +5120,26 @@ run_fp_int_conv(const char *name)
|
||||
#endif
|
||||
|
||||
#if H5_SIZEOF_LONG_LONG!=H5_SIZEOF_LONG && H5_SIZEOF_LONG_DOUBLE!=0
|
||||
#ifdef H5_LDOUBLE_TO_LLONG_ACCURATE
|
||||
nerrors += test_conv_int_fp(name, test_values, H5T_NATIVE_LDOUBLE, H5T_NATIVE_LLONG);
|
||||
#ifdef H5_FP_TO_ULLONG_RIGHT_MAXIMUM
|
||||
#else /*H5_LDOUBLE_TO_LLONG_ACCURATE*/
|
||||
{
|
||||
char str[256]; /*string */
|
||||
|
||||
sprintf(str, "Testing %s %s -> %s conversions",
|
||||
name, "long double", "long long");
|
||||
printf("%-70s", str);
|
||||
SKIPPED();
|
||||
#if H5_SIZEOF_LONG_DOUBLE!=0
|
||||
HDputs(" Test skipped due to hardware conversion error.");
|
||||
#else
|
||||
HDputs(" Test skipped due to disabled long double.");
|
||||
#endif
|
||||
}
|
||||
#endif /*H5_LDOUBLE_TO_LLONG_ACCURATE*/
|
||||
#if H5_FP_TO_ULLONG_RIGHT_MAXIMUM && H5_LDOUBLE_TO_LLONG_ACCURATE
|
||||
nerrors += test_conv_int_fp(name, test_values, H5T_NATIVE_LDOUBLE, H5T_NATIVE_ULLONG);
|
||||
#else /*H5_FP_TO_ULLONG_RIGHT_MAXIMUM*/
|
||||
#else /*H5_FP_TO_ULLONG_RIGHT_MAXIMUM && H5_LDOUBLE_TO_LLONG_ACCURATE*/
|
||||
{
|
||||
char str[256]; /*string */
|
||||
|
||||
@ -5137,7 +5153,7 @@ run_fp_int_conv(const char *name)
|
||||
HDputs(" Test skipped due to disabled long double.");
|
||||
#endif
|
||||
}
|
||||
#endif /*H5_FP_TO_ULLONG_RIGHT_MAXIMUM*/
|
||||
#endif /*H5_FP_TO_ULLONG_RIGHT_MAXIMUM && H5_LDOUBLE_TO_LLONG_ACCURATE*/
|
||||
#endif
|
||||
#endif
|
||||
#else /*H5_LDOUBLE_TO_INTEGER_WORKS && H5_LDOUBLE_TO_INTEGER_ACCURATE*/
|
||||
|
Loading…
Reference in New Issue
Block a user