From: <no...@so...> - 2001-06-01 16:27:51
|
Patches item #429356, was updated on 2001-06-01 09:27 You can respond by visiting: http://sourceforge.net/tracker/?func=detail&atid=302435&aid=429356&group_id=2435 Category: runtime Group: None Status: Open Resolution: None Priority: 5 Submitted By: Greg Chicares (chicares) Assigned to: Nobody/Anonymous (nobody) Summary: RFC: fix LDBL_* macros in float.h Initial Comment: This file /gcc-2.95.2-1/i386-mingw32msvc/include/float.h * $Revision: 1.5 $ * $Author: cgf $ * $Date: 2000/02/05 04:04:54 $ contains this comment: * NOTE: long double is the same as double. I understand that the comment is made because the mingw startup code places the FPU in 53-bit-mantissa mode in an attempt to match msvc. However, it cannot match msvc because sizeof(long double) is 12 and mingw treats long doubles as XWORDs, and therefore the macros that follow the comment are not correct. The program below demonstrates some of the problems. Its output says LDBL_MAX is 1.79769e+308 LDBL_MAX_10_EXP is 308 but 1.234e999L / 1e999L is 1.234 showing that long doubles greater than the limits given are handled correctly, and DBL_EPSILON is 2.22045e-16 and 1.0 + 1e-16 == 1.0 however LDBL_EPSILON is 2.22045e-16 yet 1.0L + 1e-16L != 1.0L showing that adding half of the given machine epsilon to unity produces a number distinct from unity, violating the definition of epsilon. The program that produces these results is: #include <cfloat> #include <iostream> int main() { std::cout << "LDBL_MAX is " << LDBL_MAX << '\n' << "LDBL_MAX_10_EXP is " << LDBL_MAX_10_EXP << '\n' << "but 1.234e999L / 1e999L is " << 1.234e999L/1e999L << '\n' << '\n'; std::cout << "DBL_EPSILON is " << DBL_EPSILON << '\n' << "and 1.0 + 1e-16 " << ((1.0 == (1.0 + 1e-16 )) ? "==" : "!=") << " 1.0 " << '\n' << " however" << '\n' << "LDBL_EPSILON is " << LDBL_EPSILON << '\n' << "yet 1.0L + 1e-16L " << ((1.0L == (1.0L + 1e-16L)) ? "==" : "!=") << " 1.0L" << '\n' << '\n'; } This file /lib/gcc-lib/i386-mingw32msvc/2.95.2/include/float.h /* Produced by enquire version 4.3, CWI, Amsterdam */ has the same problems. It can be corrected by replacing it with this file: http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/config/fl oat-i386.h?rev=1.4&content-type=text/x-cvsweb-markup Should I propose that on the cygwin mailing list instead? (They'll probably just bounce it back to you; but it might be possible to get a broader discussion on their list.) There are at least two different ways to correct file /gcc-2.95.2-1/i386-mingw32msvc/include/float.h I seek guidance before offering patches: although I'm willing to assign all rights to FSF, my employer is not. Is it OK if I suggest a patch of no more than fifteen original lines, under the following philosophy? http://www.gnu.org/prep/maintain_5.html#SEC5 'You need not list someone who has contributed just a few lines (less than 15) of minor changes' I have prepared such patches but ask your advice before sending them. One removes everything not guarded by __STRICT_ANSI__ and explicitly includes the gcc-lib file, making appropriate changes to the _FLOAT_H_ header guards; this seems like the best way. The other is a nine-line patch that gives corrected values of the LDBL macros derived entirely from published sources; for instance, the Sun manual here http://docs.sun.com/htmlcoll/coll.648.2/iso-8859-1/NUMC OMPGD/ncg_math.html gives a correct value for LDBL_MIN, although it calls it "min positive normal". This is a data table rather than a system header, but it does bear a Sun copyright; is it OK to use that, the same way mingw has used stuff on msdn? I gather that the gcc-lib float header may be [L]GPL even though it bears no copyright, and hence cannot be used in mingw itself. As an alternative, I can derive all the constants from first principles using only my intel Programmers Reference Manual--e.g. LDBL_MIN is 00000000 00000001 10000000 00000000 ... 00000000 binary, or 0001 8000 0000 0000 0000 hex and I can devise a floating-point literal that causes that value to be loaded. (Not entirely trivial--an extra decimal digit or two is needed in some cases, but I know how to do that.) BTW, 'FLT_GUARD' and 'FLT_NORMALIZE' in file /gcc-2.95.2-1/i386-mingw32msvc/include/float.h are nonstandard; ms defines them http://msdn.microsoft.com/library/devprods/vs6/visualc/ vclang/_clang_limits_on_floating.2d.point_constants.htm but does not explain what they mean. If they're kept, they should be guarded with __STRICT_ANSI__. Greg Chicares chicares at mindspring dot com ---------------------------------------------------------------------- You can respond by visiting: http://sourceforge.net/tracker/?func=detail&atid=302435&aid=429356&group_id=2435 |
From: <no...@so...> - 2001-06-03 00:08:54
|
Patches item #429356, was updated on 2001-06-01 09:27 You can respond by visiting: http://sourceforge.net/tracker/?func=detail&atid=302435&aid=429356&group_id=2435 Category: runtime Group: None Status: Open Resolution: None Priority: 5 Submitted By: Greg Chicares (chicares) Assigned to: Nobody/Anonymous (nobody) Summary: RFC: fix LDBL_* macros in float.h Initial Comment: This file /gcc-2.95.2-1/i386-mingw32msvc/include/float.h * $Revision: 1.5 $ * $Author: cgf $ * $Date: 2000/02/05 04:04:54 $ contains this comment: * NOTE: long double is the same as double. I understand that the comment is made because the mingw startup code places the FPU in 53-bit-mantissa mode in an attempt to match msvc. However, it cannot match msvc because sizeof(long double) is 12 and mingw treats long doubles as XWORDs, and therefore the macros that follow the comment are not correct. The program below demonstrates some of the problems. Its output says LDBL_MAX is 1.79769e+308 LDBL_MAX_10_EXP is 308 but 1.234e999L / 1e999L is 1.234 showing that long doubles greater than the limits given are handled correctly, and DBL_EPSILON is 2.22045e-16 and 1.0 + 1e-16 == 1.0 however LDBL_EPSILON is 2.22045e-16 yet 1.0L + 1e-16L != 1.0L showing that adding half of the given machine epsilon to unity produces a number distinct from unity, violating the definition of epsilon. The program that produces these results is: #include <cfloat> #include <iostream> int main() { std::cout << "LDBL_MAX is " << LDBL_MAX << '\n' << "LDBL_MAX_10_EXP is " << LDBL_MAX_10_EXP << '\n' << "but 1.234e999L / 1e999L is " << 1.234e999L/1e999L << '\n' << '\n'; std::cout << "DBL_EPSILON is " << DBL_EPSILON << '\n' << "and 1.0 + 1e-16 " << ((1.0 == (1.0 + 1e-16 )) ? "==" : "!=") << " 1.0 " << '\n' << " however" << '\n' << "LDBL_EPSILON is " << LDBL_EPSILON << '\n' << "yet 1.0L + 1e-16L " << ((1.0L == (1.0L + 1e-16L)) ? "==" : "!=") << " 1.0L" << '\n' << '\n'; } This file /lib/gcc-lib/i386-mingw32msvc/2.95.2/include/float.h /* Produced by enquire version 4.3, CWI, Amsterdam */ has the same problems. It can be corrected by replacing it with this file: http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/config/fl oat-i386.h?rev=1.4&content-type=text/x-cvsweb-markup Should I propose that on the cygwin mailing list instead? (They'll probably just bounce it back to you; but it might be possible to get a broader discussion on their list.) There are at least two different ways to correct file /gcc-2.95.2-1/i386-mingw32msvc/include/float.h I seek guidance before offering patches: although I'm willing to assign all rights to FSF, my employer is not. Is it OK if I suggest a patch of no more than fifteen original lines, under the following philosophy? http://www.gnu.org/prep/maintain_5.html#SEC5 'You need not list someone who has contributed just a few lines (less than 15) of minor changes' I have prepared such patches but ask your advice before sending them. One removes everything not guarded by __STRICT_ANSI__ and explicitly includes the gcc-lib file, making appropriate changes to the _FLOAT_H_ header guards; this seems like the best way. The other is a nine-line patch that gives corrected values of the LDBL macros derived entirely from published sources; for instance, the Sun manual here http://docs.sun.com/htmlcoll/coll.648.2/iso-8859-1/NUMC OMPGD/ncg_math.html gives a correct value for LDBL_MIN, although it calls it "min positive normal". This is a data table rather than a system header, but it does bear a Sun copyright; is it OK to use that, the same way mingw has used stuff on msdn? I gather that the gcc-lib float header may be [L]GPL even though it bears no copyright, and hence cannot be used in mingw itself. As an alternative, I can derive all the constants from first principles using only my intel Programmers Reference Manual--e.g. LDBL_MIN is 00000000 00000001 10000000 00000000 ... 00000000 binary, or 0001 8000 0000 0000 0000 hex and I can devise a floating-point literal that causes that value to be loaded. (Not entirely trivial--an extra decimal digit or two is needed in some cases, but I know how to do that.) BTW, 'FLT_GUARD' and 'FLT_NORMALIZE' in file /gcc-2.95.2-1/i386-mingw32msvc/include/float.h are nonstandard; ms defines them http://msdn.microsoft.com/library/devprods/vs6/visualc/ vclang/_clang_limits_on_floating.2d.point_constants.htm but does not explain what they mean. If they're kept, they should be guarded with __STRICT_ANSI__. Greg Chicares chicares at mindspring dot com ---------------------------------------------------------------------- >Comment By: Danny Smith (dannysmith) Date: 2001-06-02 17:08 Message: Logged In: YES user_id=11494 Hello Greg, Yes there is certainly an inconsistency there. Thanks for your input. But I'm not sure that modifying float.h is the right thing to do. MSDN docs clearly emphasises that their CRT math functions do not support long double. Certainly printf doesn't. I think the problem is in gcc/config/i386/ where it defines #define LONG_DOUBLE_TYPE_SIZE 96 for i386. Have a look at this, which is the last part of the output from enquire (the same enquire that is referred to in your post), built with gcc: The first part is the same as the float.h in gcc-lib [...] /* Number of base-FLT_RADIX digits in the significand of a long double */ #undef LDBL_MANT_DIG #define LDBL_MANT_DIG 53 /* Number of decimal digits of precision in a long double */ #undef LDBL_DIG #define LDBL_DIG 15 /* Difference between 1.0 and the minimum long double greater than 1.0 */ #undef LDBL_EPSILON #ifndef __LDBL_UNION__ #define __LDBL_UNION__ union __convert_long_double { unsigned __convert_long_double_i[4]; long double __convert_long_double_d; }; #endif #define LDBL_EPSILON (__extension__ ((union __convert_long_double) {__convert_long_double_i: {0x0, 0x80000000, 0x3fcb, 0x0}}).__convert_long_double_d) /* Minimum int x such that FLT_RADIX**(x-1) is a normalised long double */ #undef LDBL_MIN_EXP #define LDBL_MIN_EXP (-16381) /* Minimum normalised long double */ #undef LDBL_MIN #define LDBL_MIN (__extension__ ((union __convert_long_double) {__convert_long_double_i: {0x0, 0x80000000, 0x1, 0x0}}).__convert_long_double_d) /* Minimum int x such that 10**x is a normalised long double */ #undef LDBL_MIN_10_EXP #define LDBL_MIN_10_EXP (-4931) /* Maximum int x such that FLT_RADIX**(x-1) is a representable long double */ #undef LDBL_MAX_EXP #define LDBL_MAX_EXP 16384 /* Maximum long double */ #undef LDBL_MAX #define LDBL_MAX (__extension__ ((union __convert_long_double) {__convert_long_double_i: {0xfffff800, 0xffffffff, 0x7ffe, 0x0}}).__convert_long_double_d) /* Maximum int x such that 10**x is a representable long double */ #undef LDBL_MAX_10_EXP #define LDBL_MAX_10_EXP 4932 /* *** Something fishy here! Exponent size + significand size doesn't match with the size of a long double! */ [end of enquire output] GCC defines long double as 96 bit, but enquire finds 69 (54 in significand-same as double, 15 in exp, as in Intel- style 80-bit or a 96-bit fp format ). IMHO when building gcc, something like this in the config/i386/mingw32.h target header would provide the safest solution: /* override i386.h setting: don't generate 96-bit XFmode insns */ #undef LONG_DOUBLE_TYPE_SIZE #define LONG_DOUBLE_TYPE_SIZE 64 This puts everything on the same level fp playing field. This is what was done in the old win-nt.h config file for NT3.x. One advantage of doing this would be greater portability to other win32 compilers But I could be very wrong....maybe we could define LONG_DOUBLE_TYPE_SIZE 80 when comiling gcc to provide Intel- style long doubles Danny ---------------------------------------------------------------------- You can respond by visiting: http://sourceforge.net/tracker/?func=detail&atid=302435&aid=429356&group_id=2435 |
From: <no...@so...> - 2001-06-03 10:07:10
|
Patches item #429356, was updated on 2001-06-01 09:27 You can respond by visiting: http://sourceforge.net/tracker/?func=detail&atid=302435&aid=429356&group_id=2435 Category: runtime Group: None Status: Open Resolution: None Priority: 5 Submitted By: Greg Chicares (chicares) Assigned to: Nobody/Anonymous (nobody) Summary: RFC: fix LDBL_* macros in float.h Initial Comment: This file /gcc-2.95.2-1/i386-mingw32msvc/include/float.h * $Revision: 1.5 $ * $Author: cgf $ * $Date: 2000/02/05 04:04:54 $ contains this comment: * NOTE: long double is the same as double. I understand that the comment is made because the mingw startup code places the FPU in 53-bit-mantissa mode in an attempt to match msvc. However, it cannot match msvc because sizeof(long double) is 12 and mingw treats long doubles as XWORDs, and therefore the macros that follow the comment are not correct. The program below demonstrates some of the problems. Its output says LDBL_MAX is 1.79769e+308 LDBL_MAX_10_EXP is 308 but 1.234e999L / 1e999L is 1.234 showing that long doubles greater than the limits given are handled correctly, and DBL_EPSILON is 2.22045e-16 and 1.0 + 1e-16 == 1.0 however LDBL_EPSILON is 2.22045e-16 yet 1.0L + 1e-16L != 1.0L showing that adding half of the given machine epsilon to unity produces a number distinct from unity, violating the definition of epsilon. The program that produces these results is: #include <cfloat> #include <iostream> int main() { std::cout << "LDBL_MAX is " << LDBL_MAX << '\n' << "LDBL_MAX_10_EXP is " << LDBL_MAX_10_EXP << '\n' << "but 1.234e999L / 1e999L is " << 1.234e999L/1e999L << '\n' << '\n'; std::cout << "DBL_EPSILON is " << DBL_EPSILON << '\n' << "and 1.0 + 1e-16 " << ((1.0 == (1.0 + 1e-16 )) ? "==" : "!=") << " 1.0 " << '\n' << " however" << '\n' << "LDBL_EPSILON is " << LDBL_EPSILON << '\n' << "yet 1.0L + 1e-16L " << ((1.0L == (1.0L + 1e-16L)) ? "==" : "!=") << " 1.0L" << '\n' << '\n'; } This file /lib/gcc-lib/i386-mingw32msvc/2.95.2/include/float.h /* Produced by enquire version 4.3, CWI, Amsterdam */ has the same problems. It can be corrected by replacing it with this file: http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/config/fl oat-i386.h?rev=1.4&content-type=text/x-cvsweb-markup Should I propose that on the cygwin mailing list instead? (They'll probably just bounce it back to you; but it might be possible to get a broader discussion on their list.) There are at least two different ways to correct file /gcc-2.95.2-1/i386-mingw32msvc/include/float.h I seek guidance before offering patches: although I'm willing to assign all rights to FSF, my employer is not. Is it OK if I suggest a patch of no more than fifteen original lines, under the following philosophy? http://www.gnu.org/prep/maintain_5.html#SEC5 'You need not list someone who has contributed just a few lines (less than 15) of minor changes' I have prepared such patches but ask your advice before sending them. One removes everything not guarded by __STRICT_ANSI__ and explicitly includes the gcc-lib file, making appropriate changes to the _FLOAT_H_ header guards; this seems like the best way. The other is a nine-line patch that gives corrected values of the LDBL macros derived entirely from published sources; for instance, the Sun manual here http://docs.sun.com/htmlcoll/coll.648.2/iso-8859-1/NUMC OMPGD/ncg_math.html gives a correct value for LDBL_MIN, although it calls it "min positive normal". This is a data table rather than a system header, but it does bear a Sun copyright; is it OK to use that, the same way mingw has used stuff on msdn? I gather that the gcc-lib float header may be [L]GPL even though it bears no copyright, and hence cannot be used in mingw itself. As an alternative, I can derive all the constants from first principles using only my intel Programmers Reference Manual--e.g. LDBL_MIN is 00000000 00000001 10000000 00000000 ... 00000000 binary, or 0001 8000 0000 0000 0000 hex and I can devise a floating-point literal that causes that value to be loaded. (Not entirely trivial--an extra decimal digit or two is needed in some cases, but I know how to do that.) BTW, 'FLT_GUARD' and 'FLT_NORMALIZE' in file /gcc-2.95.2-1/i386-mingw32msvc/include/float.h are nonstandard; ms defines them http://msdn.microsoft.com/library/devprods/vs6/visualc/ vclang/_clang_limits_on_floating.2d.point_constants.htm but does not explain what they mean. If they're kept, they should be guarded with __STRICT_ANSI__. Greg Chicares chicares at mindspring dot com ---------------------------------------------------------------------- >Comment By: Danny Smith (dannysmith) Date: 2001-06-03 03:07 Message: Logged In: YES user_id=11494 I was wrong. Greg, try this: Get a copy of enguire.c from GCC. Apply this patch to get the chip to use all 80 bits: [start of diff] --- enquire.c Fri Nov 05 14:09:42 1999 +++ enquirefp10.c Sun Jun 03 22:45:43 2001 @@ -297,6 +297,14 @@ Added NO_MEM */ +/* definitions from mingw's float.h */ +#ifdef __MINGW32__ +#define _PC_53 0x00010000 +#define _PC_64 0x00000000 +#define _MCW_PC 0x00030000 +unsigned int _controlfp(unsigned int,unsigned int); +#endif + /* Set FILENAME to the name of this file */ #ifndef FILENAME #ifdef NO_FILE @@ -666,6 +674,10 @@ int main(argc, argv) int argc; char *arg int dprec, fprec, lprec; int i; char *s; int bad; +#if defined __MINGW32__ && defined _USE_FP10_ +_controlfp(_PC_64, _MCW_PC); +#endif + #ifdef SIGFPE signal(SIGFPE, overflow); #endif @@ -673,6 +685,7 @@ int main(argc, argv) int argc; char *arg signal(SIGOVER, overflow); #endif /* Add more calls as necessary */ + Unexpected(1); [end of diff] Then compile enquire.c like so gcc -o enquirefp10.exe -DNO_LONG_DOUBLE_IO -D_USE_FP10_ enquirefp10.c and look at the header produced by enquirefp10 -f > float_fp10.h Do they match your definitions? Danny ---------------------------------------------------------------------- Comment By: Danny Smith (dannysmith) Date: 2001-06-02 17:08 Message: Logged In: YES user_id=11494 Hello Greg, Yes there is certainly an inconsistency there. Thanks for your input. But I'm not sure that modifying float.h is the right thing to do. MSDN docs clearly emphasises that their CRT math functions do not support long double. Certainly printf doesn't. I think the problem is in gcc/config/i386/ where it defines #define LONG_DOUBLE_TYPE_SIZE 96 for i386. Have a look at this, which is the last part of the output from enquire (the same enquire that is referred to in your post), built with gcc: The first part is the same as the float.h in gcc-lib [...] /* Number of base-FLT_RADIX digits in the significand of a long double */ #undef LDBL_MANT_DIG #define LDBL_MANT_DIG 53 /* Number of decimal digits of precision in a long double */ #undef LDBL_DIG #define LDBL_DIG 15 /* Difference between 1.0 and the minimum long double greater than 1.0 */ #undef LDBL_EPSILON #ifndef __LDBL_UNION__ #define __LDBL_UNION__ union __convert_long_double { unsigned __convert_long_double_i[4]; long double __convert_long_double_d; }; #endif #define LDBL_EPSILON (__extension__ ((union __convert_long_double) {__convert_long_double_i: {0x0, 0x80000000, 0x3fcb, 0x0}}).__convert_long_double_d) /* Minimum int x such that FLT_RADIX**(x-1) is a normalised long double */ #undef LDBL_MIN_EXP #define LDBL_MIN_EXP (-16381) /* Minimum normalised long double */ #undef LDBL_MIN #define LDBL_MIN (__extension__ ((union __convert_long_double) {__convert_long_double_i: {0x0, 0x80000000, 0x1, 0x0}}).__convert_long_double_d) /* Minimum int x such that 10**x is a normalised long double */ #undef LDBL_MIN_10_EXP #define LDBL_MIN_10_EXP (-4931) /* Maximum int x such that FLT_RADIX**(x-1) is a representable long double */ #undef LDBL_MAX_EXP #define LDBL_MAX_EXP 16384 /* Maximum long double */ #undef LDBL_MAX #define LDBL_MAX (__extension__ ((union __convert_long_double) {__convert_long_double_i: {0xfffff800, 0xffffffff, 0x7ffe, 0x0}}).__convert_long_double_d) /* Maximum int x such that 10**x is a representable long double */ #undef LDBL_MAX_10_EXP #define LDBL_MAX_10_EXP 4932 /* *** Something fishy here! Exponent size + significand size doesn't match with the size of a long double! */ [end of enquire output] GCC defines long double as 96 bit, but enquire finds 69 (54 in significand-same as double, 15 in exp, as in Intel- style 80-bit or a 96-bit fp format ). IMHO when building gcc, something like this in the config/i386/mingw32.h target header would provide the safest solution: /* override i386.h setting: don't generate 96-bit XFmode insns */ #undef LONG_DOUBLE_TYPE_SIZE #define LONG_DOUBLE_TYPE_SIZE 64 This puts everything on the same level fp playing field. This is what was done in the old win-nt.h config file for NT3.x. One advantage of doing this would be greater portability to other win32 compilers But I could be very wrong....maybe we could define LONG_DOUBLE_TYPE_SIZE 80 when comiling gcc to provide Intel- style long doubles Danny ---------------------------------------------------------------------- You can respond by visiting: http://sourceforge.net/tracker/?func=detail&atid=302435&aid=429356&group_id=2435 |
From: <no...@so...> - 2001-06-03 10:28:35
|
Patches item #429356, was updated on 2001-06-01 09:27 You can respond by visiting: http://sourceforge.net/tracker/?func=detail&atid=302435&aid=429356&group_id=2435 Category: runtime Group: None Status: Open Resolution: None Priority: 5 Submitted By: Greg Chicares (chicares) Assigned to: Nobody/Anonymous (nobody) Summary: RFC: fix LDBL_* macros in float.h Initial Comment: This file /gcc-2.95.2-1/i386-mingw32msvc/include/float.h * $Revision: 1.5 $ * $Author: cgf $ * $Date: 2000/02/05 04:04:54 $ contains this comment: * NOTE: long double is the same as double. I understand that the comment is made because the mingw startup code places the FPU in 53-bit-mantissa mode in an attempt to match msvc. However, it cannot match msvc because sizeof(long double) is 12 and mingw treats long doubles as XWORDs, and therefore the macros that follow the comment are not correct. The program below demonstrates some of the problems. Its output says LDBL_MAX is 1.79769e+308 LDBL_MAX_10_EXP is 308 but 1.234e999L / 1e999L is 1.234 showing that long doubles greater than the limits given are handled correctly, and DBL_EPSILON is 2.22045e-16 and 1.0 + 1e-16 == 1.0 however LDBL_EPSILON is 2.22045e-16 yet 1.0L + 1e-16L != 1.0L showing that adding half of the given machine epsilon to unity produces a number distinct from unity, violating the definition of epsilon. The program that produces these results is: #include <cfloat> #include <iostream> int main() { std::cout << "LDBL_MAX is " << LDBL_MAX << '\n' << "LDBL_MAX_10_EXP is " << LDBL_MAX_10_EXP << '\n' << "but 1.234e999L / 1e999L is " << 1.234e999L/1e999L << '\n' << '\n'; std::cout << "DBL_EPSILON is " << DBL_EPSILON << '\n' << "and 1.0 + 1e-16 " << ((1.0 == (1.0 + 1e-16 )) ? "==" : "!=") << " 1.0 " << '\n' << " however" << '\n' << "LDBL_EPSILON is " << LDBL_EPSILON << '\n' << "yet 1.0L + 1e-16L " << ((1.0L == (1.0L + 1e-16L)) ? "==" : "!=") << " 1.0L" << '\n' << '\n'; } This file /lib/gcc-lib/i386-mingw32msvc/2.95.2/include/float.h /* Produced by enquire version 4.3, CWI, Amsterdam */ has the same problems. It can be corrected by replacing it with this file: http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/config/fl oat-i386.h?rev=1.4&content-type=text/x-cvsweb-markup Should I propose that on the cygwin mailing list instead? (They'll probably just bounce it back to you; but it might be possible to get a broader discussion on their list.) There are at least two different ways to correct file /gcc-2.95.2-1/i386-mingw32msvc/include/float.h I seek guidance before offering patches: although I'm willing to assign all rights to FSF, my employer is not. Is it OK if I suggest a patch of no more than fifteen original lines, under the following philosophy? http://www.gnu.org/prep/maintain_5.html#SEC5 'You need not list someone who has contributed just a few lines (less than 15) of minor changes' I have prepared such patches but ask your advice before sending them. One removes everything not guarded by __STRICT_ANSI__ and explicitly includes the gcc-lib file, making appropriate changes to the _FLOAT_H_ header guards; this seems like the best way. The other is a nine-line patch that gives corrected values of the LDBL macros derived entirely from published sources; for instance, the Sun manual here http://docs.sun.com/htmlcoll/coll.648.2/iso-8859-1/NUMC OMPGD/ncg_math.html gives a correct value for LDBL_MIN, although it calls it "min positive normal". This is a data table rather than a system header, but it does bear a Sun copyright; is it OK to use that, the same way mingw has used stuff on msdn? I gather that the gcc-lib float header may be [L]GPL even though it bears no copyright, and hence cannot be used in mingw itself. As an alternative, I can derive all the constants from first principles using only my intel Programmers Reference Manual--e.g. LDBL_MIN is 00000000 00000001 10000000 00000000 ... 00000000 binary, or 0001 8000 0000 0000 0000 hex and I can devise a floating-point literal that causes that value to be loaded. (Not entirely trivial--an extra decimal digit or two is needed in some cases, but I know how to do that.) BTW, 'FLT_GUARD' and 'FLT_NORMALIZE' in file /gcc-2.95.2-1/i386-mingw32msvc/include/float.h are nonstandard; ms defines them http://msdn.microsoft.com/library/devprods/vs6/visualc/ vclang/_clang_limits_on_floating.2d.point_constants.htm but does not explain what they mean. If they're kept, they should be guarded with __STRICT_ANSI__. Greg Chicares chicares at mindspring dot com ---------------------------------------------------------------------- >Comment By: Danny Smith (dannysmith) Date: 2001-06-03 03:07 Message: Logged In: YES user_id=11494 I was wrong. Greg, try this: Get a copy of enguire.c from GCC. Apply this patch to get the chip to use all 80 bits: [start of diff] --- enquire.c Fri Nov 05 14:09:42 1999 +++ enquirefp10.c Sun Jun 03 22:45:43 2001 @@ -297,6 +297,14 @@ Added NO_MEM */ +/* definitions from mingw's float.h */ +#ifdef __MINGW32__ +#define _PC_53 0x00010000 +#define _PC_64 0x00000000 +#define _MCW_PC 0x00030000 +unsigned int _controlfp(unsigned int,unsigned int); +#endif + /* Set FILENAME to the name of this file */ #ifndef FILENAME #ifdef NO_FILE @@ -666,6 +674,10 @@ int main(argc, argv) int argc; char *arg int dprec, fprec, lprec; int i; char *s; int bad; +#if defined __MINGW32__ && defined _USE_FP10_ +_controlfp(_PC_64, _MCW_PC); +#endif + #ifdef SIGFPE signal(SIGFPE, overflow); #endif @@ -673,6 +685,7 @@ int main(argc, argv) int argc; char *arg signal(SIGOVER, overflow); #endif /* Add more calls as necessary */ + Unexpected(1); [end of diff] Then compile enquire.c like so gcc -o enquirefp10.exe -DNO_LONG_DOUBLE_IO -D_USE_FP10_ enquirefp10.c and look at the header produced by enquirefp10 -f > float_fp10.h Do they match your definitions? Danny ---------------------------------------------------------------------- Comment By: Danny Smith (dannysmith) Date: 2001-06-03 03:07 Message: Logged In: YES user_id=11494 I was wrong. Greg, try this: Get a copy of enguire.c from GCC. Apply this patch to get the chip to use all 80 bits: [start of diff] --- enquire.c Fri Nov 05 14:09:42 1999 +++ enquirefp10.c Sun Jun 03 22:45:43 2001 @@ -297,6 +297,14 @@ Added NO_MEM */ +/* definitions from mingw's float.h */ +#ifdef __MINGW32__ +#define _PC_53 0x00010000 +#define _PC_64 0x00000000 +#define _MCW_PC 0x00030000 +unsigned int _controlfp(unsigned int,unsigned int); +#endif + /* Set FILENAME to the name of this file */ #ifndef FILENAME #ifdef NO_FILE @@ -666,6 +674,10 @@ int main(argc, argv) int argc; char *arg int dprec, fprec, lprec; int i; char *s; int bad; +#if defined __MINGW32__ && defined _USE_FP10_ +_controlfp(_PC_64, _MCW_PC); +#endif + #ifdef SIGFPE signal(SIGFPE, overflow); #endif @@ -673,6 +685,7 @@ int main(argc, argv) int argc; char *arg signal(SIGOVER, overflow); #endif /* Add more calls as necessary */ + Unexpected(1); [end of diff] Then compile enquire.c like so gcc -o enquirefp10.exe -DNO_LONG_DOUBLE_IO -D_USE_FP10_ enquirefp10.c and look at the header produced by enquirefp10 -f > float_fp10.h Do they match your definitions? Danny ---------------------------------------------------------------------- Comment By: Danny Smith (dannysmith) Date: 2001-06-02 17:08 Message: Logged In: YES user_id=11494 Hello Greg, Yes there is certainly an inconsistency there. Thanks for your input. But I'm not sure that modifying float.h is the right thing to do. MSDN docs clearly emphasises that their CRT math functions do not support long double. Certainly printf doesn't. I think the problem is in gcc/config/i386/ where it defines #define LONG_DOUBLE_TYPE_SIZE 96 for i386. Have a look at this, which is the last part of the output from enquire (the same enquire that is referred to in your post), built with gcc: The first part is the same as the float.h in gcc-lib [...] /* Number of base-FLT_RADIX digits in the significand of a long double */ #undef LDBL_MANT_DIG #define LDBL_MANT_DIG 53 /* Number of decimal digits of precision in a long double */ #undef LDBL_DIG #define LDBL_DIG 15 /* Difference between 1.0 and the minimum long double greater than 1.0 */ #undef LDBL_EPSILON #ifndef __LDBL_UNION__ #define __LDBL_UNION__ union __convert_long_double { unsigned __convert_long_double_i[4]; long double __convert_long_double_d; }; #endif #define LDBL_EPSILON (__extension__ ((union __convert_long_double) {__convert_long_double_i: {0x0, 0x80000000, 0x3fcb, 0x0}}).__convert_long_double_d) /* Minimum int x such that FLT_RADIX**(x-1) is a normalised long double */ #undef LDBL_MIN_EXP #define LDBL_MIN_EXP (-16381) /* Minimum normalised long double */ #undef LDBL_MIN #define LDBL_MIN (__extension__ ((union __convert_long_double) {__convert_long_double_i: {0x0, 0x80000000, 0x1, 0x0}}).__convert_long_double_d) /* Minimum int x such that 10**x is a normalised long double */ #undef LDBL_MIN_10_EXP #define LDBL_MIN_10_EXP (-4931) /* Maximum int x such that FLT_RADIX**(x-1) is a representable long double */ #undef LDBL_MAX_EXP #define LDBL_MAX_EXP 16384 /* Maximum long double */ #undef LDBL_MAX #define LDBL_MAX (__extension__ ((union __convert_long_double) {__convert_long_double_i: {0xfffff800, 0xffffffff, 0x7ffe, 0x0}}).__convert_long_double_d) /* Maximum int x such that 10**x is a representable long double */ #undef LDBL_MAX_10_EXP #define LDBL_MAX_10_EXP 4932 /* *** Something fishy here! Exponent size + significand size doesn't match with the size of a long double! */ [end of enquire output] GCC defines long double as 96 bit, but enquire finds 69 (54 in significand-same as double, 15 in exp, as in Intel- style 80-bit or a 96-bit fp format ). IMHO when building gcc, something like this in the config/i386/mingw32.h target header would provide the safest solution: /* override i386.h setting: don't generate 96-bit XFmode insns */ #undef LONG_DOUBLE_TYPE_SIZE #define LONG_DOUBLE_TYPE_SIZE 64 This puts everything on the same level fp playing field. This is what was done in the old win-nt.h config file for NT3.x. One advantage of doing this would be greater portability to other win32 compilers But I could be very wrong....maybe we could define LONG_DOUBLE_TYPE_SIZE 80 when comiling gcc to provide Intel- style long doubles Danny ---------------------------------------------------------------------- You can respond by visiting: http://sourceforge.net/tracker/?func=detail&atid=302435&aid=429356&group_id=2435 |
From: <no...@so...> - 2001-06-04 06:21:53
|
Patches item #429356, was updated on 2001-06-01 09:27 You can respond by visiting: http://sourceforge.net/tracker/?func=detail&atid=302435&aid=429356&group_id=2435 Category: runtime Group: None Status: Open Resolution: None Priority: 5 Submitted By: Greg Chicares (chicares) Assigned to: Nobody/Anonymous (nobody) Summary: RFC: fix LDBL_* macros in float.h Initial Comment: This file /gcc-2.95.2-1/i386-mingw32msvc/include/float.h * $Revision: 1.5 $ * $Author: cgf $ * $Date: 2000/02/05 04:04:54 $ contains this comment: * NOTE: long double is the same as double. I understand that the comment is made because the mingw startup code places the FPU in 53-bit-mantissa mode in an attempt to match msvc. However, it cannot match msvc because sizeof(long double) is 12 and mingw treats long doubles as XWORDs, and therefore the macros that follow the comment are not correct. The program below demonstrates some of the problems. Its output says LDBL_MAX is 1.79769e+308 LDBL_MAX_10_EXP is 308 but 1.234e999L / 1e999L is 1.234 showing that long doubles greater than the limits given are handled correctly, and DBL_EPSILON is 2.22045e-16 and 1.0 + 1e-16 == 1.0 however LDBL_EPSILON is 2.22045e-16 yet 1.0L + 1e-16L != 1.0L showing that adding half of the given machine epsilon to unity produces a number distinct from unity, violating the definition of epsilon. The program that produces these results is: #include <cfloat> #include <iostream> int main() { std::cout << "LDBL_MAX is " << LDBL_MAX << '\n' << "LDBL_MAX_10_EXP is " << LDBL_MAX_10_EXP << '\n' << "but 1.234e999L / 1e999L is " << 1.234e999L/1e999L << '\n' << '\n'; std::cout << "DBL_EPSILON is " << DBL_EPSILON << '\n' << "and 1.0 + 1e-16 " << ((1.0 == (1.0 + 1e-16 )) ? "==" : "!=") << " 1.0 " << '\n' << " however" << '\n' << "LDBL_EPSILON is " << LDBL_EPSILON << '\n' << "yet 1.0L + 1e-16L " << ((1.0L == (1.0L + 1e-16L)) ? "==" : "!=") << " 1.0L" << '\n' << '\n'; } This file /lib/gcc-lib/i386-mingw32msvc/2.95.2/include/float.h /* Produced by enquire version 4.3, CWI, Amsterdam */ has the same problems. It can be corrected by replacing it with this file: http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/config/fl oat-i386.h?rev=1.4&content-type=text/x-cvsweb-markup Should I propose that on the cygwin mailing list instead? (They'll probably just bounce it back to you; but it might be possible to get a broader discussion on their list.) There are at least two different ways to correct file /gcc-2.95.2-1/i386-mingw32msvc/include/float.h I seek guidance before offering patches: although I'm willing to assign all rights to FSF, my employer is not. Is it OK if I suggest a patch of no more than fifteen original lines, under the following philosophy? http://www.gnu.org/prep/maintain_5.html#SEC5 'You need not list someone who has contributed just a few lines (less than 15) of minor changes' I have prepared such patches but ask your advice before sending them. One removes everything not guarded by __STRICT_ANSI__ and explicitly includes the gcc-lib file, making appropriate changes to the _FLOAT_H_ header guards; this seems like the best way. The other is a nine-line patch that gives corrected values of the LDBL macros derived entirely from published sources; for instance, the Sun manual here http://docs.sun.com/htmlcoll/coll.648.2/iso-8859-1/NUMC OMPGD/ncg_math.html gives a correct value for LDBL_MIN, although it calls it "min positive normal". This is a data table rather than a system header, but it does bear a Sun copyright; is it OK to use that, the same way mingw has used stuff on msdn? I gather that the gcc-lib float header may be [L]GPL even though it bears no copyright, and hence cannot be used in mingw itself. As an alternative, I can derive all the constants from first principles using only my intel Programmers Reference Manual--e.g. LDBL_MIN is 00000000 00000001 10000000 00000000 ... 00000000 binary, or 0001 8000 0000 0000 0000 hex and I can devise a floating-point literal that causes that value to be loaded. (Not entirely trivial--an extra decimal digit or two is needed in some cases, but I know how to do that.) BTW, 'FLT_GUARD' and 'FLT_NORMALIZE' in file /gcc-2.95.2-1/i386-mingw32msvc/include/float.h are nonstandard; ms defines them http://msdn.microsoft.com/library/devprods/vs6/visualc/ vclang/_clang_limits_on_floating.2d.point_constants.htm but does not explain what they mean. If they're kept, they should be guarded with __STRICT_ANSI__. Greg Chicares chicares at mindspring dot com ---------------------------------------------------------------------- >Comment By: Greg Chicares (chicares) Date: 2001-06-03 21:41 Message: Logged In: YES user_id=231935 Hi Danny-- What follows is kind of my "lab notes" and I'm afraid to edit them too much lest I lose some important facts. But let me give a summary first: - 80-bit long double is useful to some of us; ms advises not using long double at all, so those in the ms camp shouldn't care - Mumit and Mikey looked into changing long double to a 64-bit type and found they couldn't - with the modifications you suggested, enquire gives the correct results for 80-bit long double constants - enquire's technique causes problems with shadow headers, but gcc already has a patch for that; I think mingw should adopt this, adding only the nonstandard ms-style stuff to manipulate the FPU control word etc. > MSDN docs clearly emphasises that their CRT math > functions do not support long double. Certainly > printf doesn't. http://msdn.microsoft.com/library/devprods/vs6/visualc/vccore/_crt_long_double.htm In Win32 programming, however, the long double data type maps to the double, 64-bit precision data type. [...] The long double versions of these functions should not be used in new code. That means they've deprecated long double. So a programmer who follows their recommendation will not use long double. OTOH the ISO C standard (F.2/2) says Recommended practice The long double type should match an IEC 60559 extended format. > But I'm not sure that modifying float.h is the > right thing to do. [...] > IMHO when building gcc, something like this in the > config/i386/mingw32.h target header would provide > the safest solution: > /* override i386.h setting: don't generate > 96-bit XFmode insns */ > #undef LONG_DOUBLE_TYPE_SIZE > #define LONG_DOUBLE_TYPE_SIZE 64 I'm not sure there's any dilemma here. Programmers who want to conform to ms's dialect of the language will not use long double at all, and shouldn't care how it's implemented. Programmers who want to use intel extended precision have chosen to break with ms, and mingw should support them because it can. I maintain a GPL numerical-analysis program that needs all the precision it can get. It would be embarrassing to tell users to build it with a proprietary compiler instead of gcc. > This puts everything on the same level fp playing > field. [...] One advantage of doing this would be > greater portability to other win32 compilers Not necessarily. With the borland compiler, sizeof(long double) is 10; it uses 80-bit intel extended precision. (I believe gcc adds two extra dummy bytes to achieve double-word alignment.) As for RTL functions, the ISO C++ standard (26.5/5) says In addition to the double versions of the math functions in <cmath>, C++ adds float and long double overloaded versions of these functions mingw doesn't have either of these: float ceil(float); long double ceil(long double); so changing the meaning of long double won't make us compliant anyway. Curiously, borland has the same problem, even though they use 80-bit long doubles: http://www.dinkumware.com/borlib_test.html Math functions are now required in all three floating-point precisions. Borland has a true long double type, of greater precision than double (unlike Microsoft), and the library defines all the long double math functions. But it appears that these added functions simply turn around and call the existing double functions, a wholly inadequate expedient. Anyway, patching LONG_DOUBLE_TYPE_SIZE may not work: as Mumit says, http://groups.yahoo.com/group/mingw32/message/1968 The suggestion has been that we should simply force GCC to use 8-byte long doubles instead of the 12-byte, which is the usual size on most 32 bit platforms. However, there is a bug in gcc that causes problems if we try that, and I believe Mikey and I both ran into the same issue. Note that GCC currently will maintain all internal computations in 12-byte long doubles, but when you hand it over to say printf, MSVC runtime will get the wrong size. I use a different stdio library, and get around VC++ runtime brain-damage. I need larger than 64-bit long doubles. I think the relevant message is here: http://gcc.gnu.org/ml/gcc-bugs/1999-06n/msg00761.html As to using enquire.c to produce <float.h>, I ran enquire with the patches you suggested, and these values match what I would propose for 80-bit support: #define LDBL_MANT_DIG 64 #define LDBL_DIG 18 #define LDBL_MIN_EXP (-16381) #define LDBL_MIN_10_EXP (-4931) #define LDBL_MAX_EXP 16384 #define LDBL_MAX_10_EXP 4932 as do the values given for LDBL_EPSILON <--> 0x3fc08000000000000000 LDBL_MIN <--> 0x00018000000000000000 LDBL_MAX <--> 0x7ffeffffffffffffffff However, the 'union __convert_long_double' technique has been replaced in gcc due to some breakage I don't quite understand (URL below). Hex floating literals would be perfect, but they're broken, so standard (decimal) floating literals are needed instead. Here's a problem though: I get these values from the borland compiler, which uses 80-bit long double: volatile long double eps = 1.084202172485504434e-19L; volatile long double min = 3.362103143112093506e-4932L; volatile long double max = 1.189731495357231765e+4932L; I (perhaps superfluously) made them volatile and compiled them in gcc with this code: std::cout.precision(30); std::cout << eps << '\n'; std::cout << min << '\n'; std::cout << max << '\n'; Of course, they don't print correctly thanks to the msvc rtl, but gdb gives their hex representations: =>R7: Valid 0x3fc08000000000000000 +1.084202172485504434e-19 =>R7: Special 0x00007fffffffffffffff +0 Denormal =>R7: Valid 0x7ffeffffffffffffffff +Inf and 'min' is wrong: 0x00007fffffffffffffff wrong--denormal 0x00018000000000000000 correct However, this patch http://gcc.gnu.org/ml/libstdc++/2000-08/msg00047.html which explains the breakage mentioned above, and has been accepted in the latest CVS http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/config/float-i386.h?rev=1.4&content-type=text/x-cvsweb- markup suggests that instead we use the more precise value - volatile long double min = 3.362103143112093506e-4932L; + volatile long double min = 3.36210314311209350626e-4932L; which produces the desired =>R7: Valid 0x00018000000000000000 +0 For the record, the FPU state is: Status Word: 0xffff3838 OE UE PE TOP: 7 Control Word: 0xffff037f IM DM ZM OM UM PM PC: Extended Precision (64-bits) RC: Round to nearest Tag Word: 0xffffbfff (Don't worry about the '+0' or '+Inf' things on the right-hand end of the gdb output--they're invalid. We only want the hex values.) So rather than use enquire, I think gcc/gcc/config/float-i386.h rev 1.4 should be adopted for mingw, and we should point out that the msvc rtl will not work with it. Maybe we should provide a way to hook into mathinline.h instead for <math.h> functions, but that would be a different patch.... ---------------------------------------------------------------------- Comment By: Danny Smith (dannysmith) Date: 2001-06-03 03:07 Message: Logged In: YES user_id=11494 I was wrong. Greg, try this: Get a copy of enguire.c from GCC. Apply this patch to get the chip to use all 80 bits: [start of diff] --- enquire.c Fri Nov 05 14:09:42 1999 +++ enquirefp10.c Sun Jun 03 22:45:43 2001 @@ -297,6 +297,14 @@ Added NO_MEM */ +/* definitions from mingw's float.h */ +#ifdef __MINGW32__ +#define _PC_53 0x00010000 +#define _PC_64 0x00000000 +#define _MCW_PC 0x00030000 +unsigned int _controlfp(unsigned int,unsigned int); +#endif + /* Set FILENAME to the name of this file */ #ifndef FILENAME #ifdef NO_FILE @@ -666,6 +674,10 @@ int main(argc, argv) int argc; char *arg int dprec, fprec, lprec; int i; char *s; int bad; +#if defined __MINGW32__ && defined _USE_FP10_ +_controlfp(_PC_64, _MCW_PC); +#endif + #ifdef SIGFPE signal(SIGFPE, overflow); #endif @@ -673,6 +685,7 @@ int main(argc, argv) int argc; char *arg signal(SIGOVER, overflow); #endif /* Add more calls as necessary */ + Unexpected(1); [end of diff] Then compile enquire.c like so gcc -o enquirefp10.exe -DNO_LONG_DOUBLE_IO -D_USE_FP10_ enquirefp10.c and look at the header produced by enquirefp10 -f > float_fp10.h Do they match your definitions? Danny ---------------------------------------------------------------------- Comment By: Danny Smith (dannysmith) Date: 2001-06-03 03:07 Message: Logged In: YES user_id=11494 I was wrong. Greg, try this: Get a copy of enguire.c from GCC. Apply this patch to get the chip to use all 80 bits: [start of diff] --- enquire.c Fri Nov 05 14:09:42 1999 +++ enquirefp10.c Sun Jun 03 22:45:43 2001 @@ -297,6 +297,14 @@ Added NO_MEM */ +/* definitions from mingw's float.h */ +#ifdef __MINGW32__ +#define _PC_53 0x00010000 +#define _PC_64 0x00000000 +#define _MCW_PC 0x00030000 +unsigned int _controlfp(unsigned int,unsigned int); +#endif + /* Set FILENAME to the name of this file */ #ifndef FILENAME #ifdef NO_FILE @@ -666,6 +674,10 @@ int main(argc, argv) int argc; char *arg int dprec, fprec, lprec; int i; char *s; int bad; +#if defined __MINGW32__ && defined _USE_FP10_ +_controlfp(_PC_64, _MCW_PC); +#endif + #ifdef SIGFPE signal(SIGFPE, overflow); #endif @@ -673,6 +685,7 @@ int main(argc, argv) int argc; char *arg signal(SIGOVER, overflow); #endif /* Add more calls as necessary */ + Unexpected(1); [end of diff] Then compile enquire.c like so gcc -o enquirefp10.exe -DNO_LONG_DOUBLE_IO -D_USE_FP10_ enquirefp10.c and look at the header produced by enquirefp10 -f > float_fp10.h Do they match your definitions? Danny ---------------------------------------------------------------------- Comment By: Danny Smith (dannysmith) Date: 2001-06-02 17:08 Message: Logged In: YES user_id=11494 Hello Greg, Yes there is certainly an inconsistency there. Thanks for your input. But I'm not sure that modifying float.h is the right thing to do. MSDN docs clearly emphasises that their CRT math functions do not support long double. Certainly printf doesn't. I think the problem is in gcc/config/i386/ where it defines #define LONG_DOUBLE_TYPE_SIZE 96 for i386. Have a look at this, which is the last part of the output from enquire (the same enquire that is referred to in your post), built with gcc: The first part is the same as the float.h in gcc-lib [...] /* Number of base-FLT_RADIX digits in the significand of a long double */ #undef LDBL_MANT_DIG #define LDBL_MANT_DIG 53 /* Number of decimal digits of precision in a long double */ #undef LDBL_DIG #define LDBL_DIG 15 /* Difference between 1.0 and the minimum long double greater than 1.0 */ #undef LDBL_EPSILON #ifndef __LDBL_UNION__ #define __LDBL_UNION__ union __convert_long_double { unsigned __convert_long_double_i[4]; long double __convert_long_double_d; }; #endif #define LDBL_EPSILON (__extension__ ((union __convert_long_double) {__convert_long_double_i: {0x0, 0x80000000, 0x3fcb, 0x0}}).__convert_long_double_d) /* Minimum int x such that FLT_RADIX**(x-1) is a normalised long double */ #undef LDBL_MIN_EXP #define LDBL_MIN_EXP (-16381) /* Minimum normalised long double */ #undef LDBL_MIN #define LDBL_MIN (__extension__ ((union __convert_long_double) {__convert_long_double_i: {0x0, 0x80000000, 0x1, 0x0}}).__convert_long_double_d) /* Minimum int x such that 10**x is a normalised long double */ #undef LDBL_MIN_10_EXP #define LDBL_MIN_10_EXP (-4931) /* Maximum int x such that FLT_RADIX**(x-1) is a representable long double */ #undef LDBL_MAX_EXP #define LDBL_MAX_EXP 16384 /* Maximum long double */ #undef LDBL_MAX #define LDBL_MAX (__extension__ ((union __convert_long_double) {__convert_long_double_i: {0xfffff800, 0xffffffff, 0x7ffe, 0x0}}).__convert_long_double_d) /* Maximum int x such that 10**x is a representable long double */ #undef LDBL_MAX_10_EXP #define LDBL_MAX_10_EXP 4932 /* *** Something fishy here! Exponent size + significand size doesn't match with the size of a long double! */ [end of enquire output] GCC defines long double as 96 bit, but enquire finds 69 (54 in significand-same as double, 15 in exp, as in Intel- style 80-bit or a 96-bit fp format ). IMHO when building gcc, something like this in the config/i386/mingw32.h target header would provide the safest solution: /* override i386.h setting: don't generate 96-bit XFmode insns */ #undef LONG_DOUBLE_TYPE_SIZE #define LONG_DOUBLE_TYPE_SIZE 64 This puts everything on the same level fp playing field. This is what was done in the old win-nt.h config file for NT3.x. One advantage of doing this would be greater portability to other win32 compilers But I could be very wrong....maybe we could define LONG_DOUBLE_TYPE_SIZE 80 when comiling gcc to provide Intel- style long doubles Danny ---------------------------------------------------------------------- You can respond by visiting: http://sourceforge.net/tracker/?func=detail&atid=302435&aid=429356&group_id=2435 |
From: <no...@so...> - 2001-06-11 18:02:59
|
Patches item #429356, was updated on 2001-06-01 09:27 You can respond by visiting: http://sourceforge.net/tracker/?func=detail&atid=302435&aid=429356&group_id=2435 Category: runtime Group: None Status: Open Resolution: None >Priority: 4 Submitted By: Greg Chicares (chicares) Assigned to: Nobody/Anonymous (nobody) Summary: RFC: fix LDBL_* macros in float.h Initial Comment: This file /gcc-2.95.2-1/i386-mingw32msvc/include/float.h * $Revision: 1.5 $ * $Author: cgf $ * $Date: 2000/02/05 04:04:54 $ contains this comment: * NOTE: long double is the same as double. I understand that the comment is made because the mingw startup code places the FPU in 53-bit-mantissa mode in an attempt to match msvc. However, it cannot match msvc because sizeof(long double) is 12 and mingw treats long doubles as XWORDs, and therefore the macros that follow the comment are not correct. The program below demonstrates some of the problems. Its output says LDBL_MAX is 1.79769e+308 LDBL_MAX_10_EXP is 308 but 1.234e999L / 1e999L is 1.234 showing that long doubles greater than the limits given are handled correctly, and DBL_EPSILON is 2.22045e-16 and 1.0 + 1e-16 == 1.0 however LDBL_EPSILON is 2.22045e-16 yet 1.0L + 1e-16L != 1.0L showing that adding half of the given machine epsilon to unity produces a number distinct from unity, violating the definition of epsilon. The program that produces these results is: #include <cfloat> #include <iostream> int main() { std::cout << "LDBL_MAX is " << LDBL_MAX << '\n' << "LDBL_MAX_10_EXP is " << LDBL_MAX_10_EXP << '\n' << "but 1.234e999L / 1e999L is " << 1.234e999L/1e999L << '\n' << '\n'; std::cout << "DBL_EPSILON is " << DBL_EPSILON << '\n' << "and 1.0 + 1e-16 " << ((1.0 == (1.0 + 1e-16 )) ? "==" : "!=") << " 1.0 " << '\n' << " however" << '\n' << "LDBL_EPSILON is " << LDBL_EPSILON << '\n' << "yet 1.0L + 1e-16L " << ((1.0L == (1.0L + 1e-16L)) ? "==" : "!=") << " 1.0L" << '\n' << '\n'; } This file /lib/gcc-lib/i386-mingw32msvc/2.95.2/include/float.h /* Produced by enquire version 4.3, CWI, Amsterdam */ has the same problems. It can be corrected by replacing it with this file: http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/config/fl oat-i386.h?rev=1.4&content-type=text/x-cvsweb-markup Should I propose that on the cygwin mailing list instead? (They'll probably just bounce it back to you; but it might be possible to get a broader discussion on their list.) There are at least two different ways to correct file /gcc-2.95.2-1/i386-mingw32msvc/include/float.h I seek guidance before offering patches: although I'm willing to assign all rights to FSF, my employer is not. Is it OK if I suggest a patch of no more than fifteen original lines, under the following philosophy? http://www.gnu.org/prep/maintain_5.html#SEC5 'You need not list someone who has contributed just a few lines (less than 15) of minor changes' I have prepared such patches but ask your advice before sending them. One removes everything not guarded by __STRICT_ANSI__ and explicitly includes the gcc-lib file, making appropriate changes to the _FLOAT_H_ header guards; this seems like the best way. The other is a nine-line patch that gives corrected values of the LDBL macros derived entirely from published sources; for instance, the Sun manual here http://docs.sun.com/htmlcoll/coll.648.2/iso-8859-1/NUMC OMPGD/ncg_math.html gives a correct value for LDBL_MIN, although it calls it "min positive normal". This is a data table rather than a system header, but it does bear a Sun copyright; is it OK to use that, the same way mingw has used stuff on msdn? I gather that the gcc-lib float header may be [L]GPL even though it bears no copyright, and hence cannot be used in mingw itself. As an alternative, I can derive all the constants from first principles using only my intel Programmers Reference Manual--e.g. LDBL_MIN is 00000000 00000001 10000000 00000000 ... 00000000 binary, or 0001 8000 0000 0000 0000 hex and I can devise a floating-point literal that causes that value to be loaded. (Not entirely trivial--an extra decimal digit or two is needed in some cases, but I know how to do that.) BTW, 'FLT_GUARD' and 'FLT_NORMALIZE' in file /gcc-2.95.2-1/i386-mingw32msvc/include/float.h are nonstandard; ms defines them http://msdn.microsoft.com/library/devprods/vs6/visualc/ vclang/_clang_limits_on_floating.2d.point_constants.htm but does not explain what they mean. If they're kept, they should be guarded with __STRICT_ANSI__. Greg Chicares chicares at mindspring dot com ---------------------------------------------------------------------- >Comment By: Earnie Boyd (earnie) Date: 2001-06-09 21:46 Message: Logged In: YES user_id=15438 Just as the MSVC headers are off limits so are the GPLed headers from GLIBC. MinGW must remain free from copyright and license restrictions. The MinGW runtime headers must be placed in the Public Domain and not contaminated with other restrictions. The best resources are going to be the documentation you find on the net with the MSDN documentation taking precedence over any other. If you have other means to find this information as long as it cannot be construed as copying copyrighted headers or reverse engineering the values then you're welcome to use that. If the ANSI standards definitions work (they really should) then I would not have a problem with making changes to float.h based on these definitions as long as it can be proved to work w95, w98 wME, NT4 and NT5. Earnie. ---------------------------------------------------------------------- Comment By: Greg Chicares (chicares) Date: 2001-06-03 21:41 Message: Logged In: YES user_id=231935 Hi Danny-- What follows is kind of my "lab notes" and I'm afraid to edit them too much lest I lose some important facts. But let me give a summary first: - 80-bit long double is useful to some of us; ms advises not using long double at all, so those in the ms camp shouldn't care - Mumit and Mikey looked into changing long double to a 64-bit type and found they couldn't - with the modifications you suggested, enquire gives the correct results for 80-bit long double constants - enquire's technique causes problems with shadow headers, but gcc already has a patch for that; I think mingw should adopt this, adding only the nonstandard ms-style stuff to manipulate the FPU control word etc. > MSDN docs clearly emphasises that their CRT math > functions do not support long double. Certainly > printf doesn't. http://msdn.microsoft.com/library/devprods/vs6/visualc/vccore/_crt_long_double.htm In Win32 programming, however, the long double data type maps to the double, 64-bit precision data type. [...] The long double versions of these functions should not be used in new code. That means they've deprecated long double. So a programmer who follows their recommendation will not use long double. OTOH the ISO C standard (F.2/2) says Recommended practice The long double type should match an IEC 60559 extended format. > But I'm not sure that modifying float.h is the > right thing to do. [...] > IMHO when building gcc, something like this in the > config/i386/mingw32.h target header would provide > the safest solution: > /* override i386.h setting: don't generate > 96-bit XFmode insns */ > #undef LONG_DOUBLE_TYPE_SIZE > #define LONG_DOUBLE_TYPE_SIZE 64 I'm not sure there's any dilemma here. Programmers who want to conform to ms's dialect of the language will not use long double at all, and shouldn't care how it's implemented. Programmers who want to use intel extended precision have chosen to break with ms, and mingw should support them because it can. I maintain a GPL numerical-analysis program that needs all the precision it can get. It would be embarrassing to tell users to build it with a proprietary compiler instead of gcc. > This puts everything on the same level fp playing > field. [...] One advantage of doing this would be > greater portability to other win32 compilers Not necessarily. With the borland compiler, sizeof(long double) is 10; it uses 80-bit intel extended precision. (I believe gcc adds two extra dummy bytes to achieve double-word alignment.) As for RTL functions, the ISO C++ standard (26.5/5) says In addition to the double versions of the math functions in <cmath>, C++ adds float and long double overloaded versions of these functions mingw doesn't have either of these: float ceil(float); long double ceil(long double); so changing the meaning of long double won't make us compliant anyway. Curiously, borland has the same problem, even though they use 80-bit long doubles: http://www.dinkumware.com/borlib_test.html Math functions are now required in all three floating-point precisions. Borland has a true long double type, of greater precision than double (unlike Microsoft), and the library defines all the long double math functions. But it appears that these added functions simply turn around and call the existing double functions, a wholly inadequate expedient. Anyway, patching LONG_DOUBLE_TYPE_SIZE may not work: as Mumit says, http://groups.yahoo.com/group/mingw32/message/1968 The suggestion has been that we should simply force GCC to use 8-byte long doubles instead of the 12-byte, which is the usual size on most 32 bit platforms. However, there is a bug in gcc that causes problems if we try that, and I believe Mikey and I both ran into the same issue. Note that GCC currently will maintain all internal computations in 12-byte long doubles, but when you hand it over to say printf, MSVC runtime will get the wrong size. I use a different stdio library, and get around VC++ runtime brain-damage. I need larger than 64-bit long doubles. I think the relevant message is here: http://gcc.gnu.org/ml/gcc-bugs/1999-06n/msg00761.html As to using enquire.c to produce <float.h>, I ran enquire with the patches you suggested, and these values match what I would propose for 80-bit support: #define LDBL_MANT_DIG 64 #define LDBL_DIG 18 #define LDBL_MIN_EXP (-16381) #define LDBL_MIN_10_EXP (-4931) #define LDBL_MAX_EXP 16384 #define LDBL_MAX_10_EXP 4932 as do the values given for LDBL_EPSILON <--> 0x3fc08000000000000000 LDBL_MIN <--> 0x00018000000000000000 LDBL_MAX <--> 0x7ffeffffffffffffffff However, the 'union __convert_long_double' technique has been replaced in gcc due to some breakage I don't quite understand (URL below). Hex floating literals would be perfect, but they're broken, so standard (decimal) floating literals are needed instead. Here's a problem though: I get these values from the borland compiler, which uses 80-bit long double: volatile long double eps = 1.084202172485504434e-19L; volatile long double min = 3.362103143112093506e-4932L; volatile long double max = 1.189731495357231765e+4932L; I (perhaps superfluously) made them volatile and compiled them in gcc with this code: std::cout.precision(30); std::cout << eps << '\n'; std::cout << min << '\n'; std::cout << max << '\n'; Of course, they don't print correctly thanks to the msvc rtl, but gdb gives their hex representations: =>R7: Valid 0x3fc08000000000000000 +1.084202172485504434e-19 =>R7: Special 0x00007fffffffffffffff +0 Denormal =>R7: Valid 0x7ffeffffffffffffffff +Inf and 'min' is wrong: 0x00007fffffffffffffff wrong--denormal 0x00018000000000000000 correct However, this patch http://gcc.gnu.org/ml/libstdc++/2000-08/msg00047.html which explains the breakage mentioned above, and has been accepted in the latest CVS http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/config/float-i386.h?rev=1.4&content-type=text/x-cvsweb- markup suggests that instead we use the more precise value - volatile long double min = 3.362103143112093506e-4932L; + volatile long double min = 3.36210314311209350626e-4932L; which produces the desired =>R7: Valid 0x00018000000000000000 +0 For the record, the FPU state is: Status Word: 0xffff3838 OE UE PE TOP: 7 Control Word: 0xffff037f IM DM ZM OM UM PM PC: Extended Precision (64-bits) RC: Round to nearest Tag Word: 0xffffbfff (Don't worry about the '+0' or '+Inf' things on the right-hand end of the gdb output--they're invalid. We only want the hex values.) So rather than use enquire, I think gcc/gcc/config/float-i386.h rev 1.4 should be adopted for mingw, and we should point out that the msvc rtl will not work with it. Maybe we should provide a way to hook into mathinline.h instead for <math.h> functions, but that would be a different patch.... ---------------------------------------------------------------------- Comment By: Danny Smith (dannysmith) Date: 2001-06-03 03:07 Message: Logged In: YES user_id=11494 I was wrong. Greg, try this: Get a copy of enguire.c from GCC. Apply this patch to get the chip to use all 80 bits: [start of diff] --- enquire.c Fri Nov 05 14:09:42 1999 +++ enquirefp10.c Sun Jun 03 22:45:43 2001 @@ -297,6 +297,14 @@ Added NO_MEM */ +/* definitions from mingw's float.h */ +#ifdef __MINGW32__ +#define _PC_53 0x00010000 +#define _PC_64 0x00000000 +#define _MCW_PC 0x00030000 +unsigned int _controlfp(unsigned int,unsigned int); +#endif + /* Set FILENAME to the name of this file */ #ifndef FILENAME #ifdef NO_FILE @@ -666,6 +674,10 @@ int main(argc, argv) int argc; char *arg int dprec, fprec, lprec; int i; char *s; int bad; +#if defined __MINGW32__ && defined _USE_FP10_ +_controlfp(_PC_64, _MCW_PC); +#endif + #ifdef SIGFPE signal(SIGFPE, overflow); #endif @@ -673,6 +685,7 @@ int main(argc, argv) int argc; char *arg signal(SIGOVER, overflow); #endif /* Add more calls as necessary */ + Unexpected(1); [end of diff] Then compile enquire.c like so gcc -o enquirefp10.exe -DNO_LONG_DOUBLE_IO -D_USE_FP10_ enquirefp10.c and look at the header produced by enquirefp10 -f > float_fp10.h Do they match your definitions? Danny ---------------------------------------------------------------------- Comment By: Danny Smith (dannysmith) Date: 2001-06-03 03:07 Message: Logged In: YES user_id=11494 I was wrong. Greg, try this: Get a copy of enguire.c from GCC. Apply this patch to get the chip to use all 80 bits: [start of diff] --- enquire.c Fri Nov 05 14:09:42 1999 +++ enquirefp10.c Sun Jun 03 22:45:43 2001 @@ -297,6 +297,14 @@ Added NO_MEM */ +/* definitions from mingw's float.h */ +#ifdef __MINGW32__ +#define _PC_53 0x00010000 +#define _PC_64 0x00000000 +#define _MCW_PC 0x00030000 +unsigned int _controlfp(unsigned int,unsigned int); +#endif + /* Set FILENAME to the name of this file */ #ifndef FILENAME #ifdef NO_FILE @@ -666,6 +674,10 @@ int main(argc, argv) int argc; char *arg int dprec, fprec, lprec; int i; char *s; int bad; +#if defined __MINGW32__ && defined _USE_FP10_ +_controlfp(_PC_64, _MCW_PC); +#endif + #ifdef SIGFPE signal(SIGFPE, overflow); #endif @@ -673,6 +685,7 @@ int main(argc, argv) int argc; char *arg signal(SIGOVER, overflow); #endif /* Add more calls as necessary */ + Unexpected(1); [end of diff] Then compile enquire.c like so gcc -o enquirefp10.exe -DNO_LONG_DOUBLE_IO -D_USE_FP10_ enquirefp10.c and look at the header produced by enquirefp10 -f > float_fp10.h Do they match your definitions? Danny ---------------------------------------------------------------------- Comment By: Danny Smith (dannysmith) Date: 2001-06-02 17:08 Message: Logged In: YES user_id=11494 Hello Greg, Yes there is certainly an inconsistency there. Thanks for your input. But I'm not sure that modifying float.h is the right thing to do. MSDN docs clearly emphasises that their CRT math functions do not support long double. Certainly printf doesn't. I think the problem is in gcc/config/i386/ where it defines #define LONG_DOUBLE_TYPE_SIZE 96 for i386. Have a look at this, which is the last part of the output from enquire (the same enquire that is referred to in your post), built with gcc: The first part is the same as the float.h in gcc-lib [...] /* Number of base-FLT_RADIX digits in the significand of a long double */ #undef LDBL_MANT_DIG #define LDBL_MANT_DIG 53 /* Number of decimal digits of precision in a long double */ #undef LDBL_DIG #define LDBL_DIG 15 /* Difference between 1.0 and the minimum long double greater than 1.0 */ #undef LDBL_EPSILON #ifndef __LDBL_UNION__ #define __LDBL_UNION__ union __convert_long_double { unsigned __convert_long_double_i[4]; long double __convert_long_double_d; }; #endif #define LDBL_EPSILON (__extension__ ((union __convert_long_double) {__convert_long_double_i: {0x0, 0x80000000, 0x3fcb, 0x0}}).__convert_long_double_d) /* Minimum int x such that FLT_RADIX**(x-1) is a normalised long double */ #undef LDBL_MIN_EXP #define LDBL_MIN_EXP (-16381) /* Minimum normalised long double */ #undef LDBL_MIN #define LDBL_MIN (__extension__ ((union __convert_long_double) {__convert_long_double_i: {0x0, 0x80000000, 0x1, 0x0}}).__convert_long_double_d) /* Minimum int x such that 10**x is a normalised long double */ #undef LDBL_MIN_10_EXP #define LDBL_MIN_10_EXP (-4931) /* Maximum int x such that FLT_RADIX**(x-1) is a representable long double */ #undef LDBL_MAX_EXP #define LDBL_MAX_EXP 16384 /* Maximum long double */ #undef LDBL_MAX #define LDBL_MAX (__extension__ ((union __convert_long_double) {__convert_long_double_i: {0xfffff800, 0xffffffff, 0x7ffe, 0x0}}).__convert_long_double_d) /* Maximum int x such that 10**x is a representable long double */ #undef LDBL_MAX_10_EXP #define LDBL_MAX_10_EXP 4932 /* *** Something fishy here! Exponent size + significand size doesn't match with the size of a long double! */ [end of enquire output] GCC defines long double as 96 bit, but enquire finds 69 (54 in significand-same as double, 15 in exp, as in Intel- style 80-bit or a 96-bit fp format ). IMHO when building gcc, something like this in the config/i386/mingw32.h target header would provide the safest solution: /* override i386.h setting: don't generate 96-bit XFmode insns */ #undef LONG_DOUBLE_TYPE_SIZE #define LONG_DOUBLE_TYPE_SIZE 64 This puts everything on the same level fp playing field. This is what was done in the old win-nt.h config file for NT3.x. One advantage of doing this would be greater portability to other win32 compilers But I could be very wrong....maybe we could define LONG_DOUBLE_TYPE_SIZE 80 when comiling gcc to provide Intel- style long doubles Danny ---------------------------------------------------------------------- You can respond by visiting: http://sourceforge.net/tracker/?func=detail&atid=302435&aid=429356&group_id=2435 |
From: <no...@so...> - 2001-08-09 12:10:35
|
Patches item #429356, was opened at 2001-06-01 09:27 You can respond by visiting: http://sourceforge.net/tracker/?func=detail&atid=302435&aid=429356&group_id=2435 Category: runtime Group: None >Status: Deleted >Resolution: Rejected Priority: 4 Submitted By: Greg Chicares (chicares) Assigned to: Nobody/Anonymous (nobody) Summary: RFC: fix LDBL_* macros in float.h Initial Comment: This file /gcc-2.95.2-1/i386-mingw32msvc/include/float.h * $Revision: 1.5 $ * $Author: cgf $ * $Date: 2000/02/05 04:04:54 $ contains this comment: * NOTE: long double is the same as double. I understand that the comment is made because the mingw startup code places the FPU in 53-bit-mantissa mode in an attempt to match msvc. However, it cannot match msvc because sizeof(long double) is 12 and mingw treats long doubles as XWORDs, and therefore the macros that follow the comment are not correct. The program below demonstrates some of the problems. Its output says LDBL_MAX is 1.79769e+308 LDBL_MAX_10_EXP is 308 but 1.234e999L / 1e999L is 1.234 showing that long doubles greater than the limits given are handled correctly, and DBL_EPSILON is 2.22045e-16 and 1.0 + 1e-16 == 1.0 however LDBL_EPSILON is 2.22045e-16 yet 1.0L + 1e-16L != 1.0L showing that adding half of the given machine epsilon to unity produces a number distinct from unity, violating the definition of epsilon. The program that produces these results is: #include <cfloat> #include <iostream> int main() { std::cout << "LDBL_MAX is " << LDBL_MAX << '\n' << "LDBL_MAX_10_EXP is " << LDBL_MAX_10_EXP << '\n' << "but 1.234e999L / 1e999L is " << 1.234e999L/1e999L << '\n' << '\n'; std::cout << "DBL_EPSILON is " << DBL_EPSILON << '\n' << "and 1.0 + 1e-16 " << ((1.0 == (1.0 + 1e-16 )) ? "==" : "!=") << " 1.0 " << '\n' << " however" << '\n' << "LDBL_EPSILON is " << LDBL_EPSILON << '\n' << "yet 1.0L + 1e-16L " << ((1.0L == (1.0L + 1e-16L)) ? "==" : "!=") << " 1.0L" << '\n' << '\n'; } This file /lib/gcc-lib/i386-mingw32msvc/2.95.2/include/float.h /* Produced by enquire version 4.3, CWI, Amsterdam */ has the same problems. It can be corrected by replacing it with this file: http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/config/fl oat-i386.h?rev=1.4&content-type=text/x-cvsweb-markup Should I propose that on the cygwin mailing list instead? (They'll probably just bounce it back to you; but it might be possible to get a broader discussion on their list.) There are at least two different ways to correct file /gcc-2.95.2-1/i386-mingw32msvc/include/float.h I seek guidance before offering patches: although I'm willing to assign all rights to FSF, my employer is not. Is it OK if I suggest a patch of no more than fifteen original lines, under the following philosophy? http://www.gnu.org/prep/maintain_5.html#SEC5 'You need not list someone who has contributed just a few lines (less than 15) of minor changes' I have prepared such patches but ask your advice before sending them. One removes everything not guarded by __STRICT_ANSI__ and explicitly includes the gcc-lib file, making appropriate changes to the _FLOAT_H_ header guards; this seems like the best way. The other is a nine-line patch that gives corrected values of the LDBL macros derived entirely from published sources; for instance, the Sun manual here http://docs.sun.com/htmlcoll/coll.648.2/iso-8859-1/NUMC OMPGD/ncg_math.html gives a correct value for LDBL_MIN, although it calls it "min positive normal". This is a data table rather than a system header, but it does bear a Sun copyright; is it OK to use that, the same way mingw has used stuff on msdn? I gather that the gcc-lib float header may be [L]GPL even though it bears no copyright, and hence cannot be used in mingw itself. As an alternative, I can derive all the constants from first principles using only my intel Programmers Reference Manual--e.g. LDBL_MIN is 00000000 00000001 10000000 00000000 ... 00000000 binary, or 0001 8000 0000 0000 0000 hex and I can devise a floating-point literal that causes that value to be loaded. (Not entirely trivial--an extra decimal digit or two is needed in some cases, but I know how to do that.) BTW, 'FLT_GUARD' and 'FLT_NORMALIZE' in file /gcc-2.95.2-1/i386-mingw32msvc/include/float.h are nonstandard; ms defines them http://msdn.microsoft.com/library/devprods/vs6/visualc/ vclang/_clang_limits_on_floating.2d.point_constants.htm but does not explain what they mean. If they're kept, they should be guarded with __STRICT_ANSI__. Greg Chicares chicares at mindspring dot com ---------------------------------------------------------------------- Comment By: Earnie Boyd (earnie) Date: 2001-06-09 21:46 Message: Logged In: YES user_id=15438 Just as the MSVC headers are off limits so are the GPLed headers from GLIBC. MinGW must remain free from copyright and license restrictions. The MinGW runtime headers must be placed in the Public Domain and not contaminated with other restrictions. The best resources are going to be the documentation you find on the net with the MSDN documentation taking precedence over any other. If you have other means to find this information as long as it cannot be construed as copying copyrighted headers or reverse engineering the values then you're welcome to use that. If the ANSI standards definitions work (they really should) then I would not have a problem with making changes to float.h based on these definitions as long as it can be proved to work w95, w98 wME, NT4 and NT5. Earnie. ---------------------------------------------------------------------- Comment By: Greg Chicares (chicares) Date: 2001-06-03 21:41 Message: Logged In: YES user_id=231935 Hi Danny-- What follows is kind of my "lab notes" and I'm afraid to edit them too much lest I lose some important facts. But let me give a summary first: - 80-bit long double is useful to some of us; ms advises not using long double at all, so those in the ms camp shouldn't care - Mumit and Mikey looked into changing long double to a 64-bit type and found they couldn't - with the modifications you suggested, enquire gives the correct results for 80-bit long double constants - enquire's technique causes problems with shadow headers, but gcc already has a patch for that; I think mingw should adopt this, adding only the nonstandard ms-style stuff to manipulate the FPU control word etc. > MSDN docs clearly emphasises that their CRT math > functions do not support long double. Certainly > printf doesn't. http://msdn.microsoft.com/library/devprods/vs6/visualc/vccore/_crt_long_double.htm In Win32 programming, however, the long double data type maps to the double, 64-bit precision data type. [...] The long double versions of these functions should not be used in new code. That means they've deprecated long double. So a programmer who follows their recommendation will not use long double. OTOH the ISO C standard (F.2/2) says Recommended practice The long double type should match an IEC 60559 extended format. > But I'm not sure that modifying float.h is the > right thing to do. [...] > IMHO when building gcc, something like this in the > config/i386/mingw32.h target header would provide > the safest solution: > /* override i386.h setting: don't generate > 96-bit XFmode insns */ > #undef LONG_DOUBLE_TYPE_SIZE > #define LONG_DOUBLE_TYPE_SIZE 64 I'm not sure there's any dilemma here. Programmers who want to conform to ms's dialect of the language will not use long double at all, and shouldn't care how it's implemented. Programmers who want to use intel extended precision have chosen to break with ms, and mingw should support them because it can. I maintain a GPL numerical-analysis program that needs all the precision it can get. It would be embarrassing to tell users to build it with a proprietary compiler instead of gcc. > This puts everything on the same level fp playing > field. [...] One advantage of doing this would be > greater portability to other win32 compilers Not necessarily. With the borland compiler, sizeof(long double) is 10; it uses 80-bit intel extended precision. (I believe gcc adds two extra dummy bytes to achieve double-word alignment.) As for RTL functions, the ISO C++ standard (26.5/5) says In addition to the double versions of the math functions in <cmath>, C++ adds float and long double overloaded versions of these functions mingw doesn't have either of these: float ceil(float); long double ceil(long double); so changing the meaning of long double won't make us compliant anyway. Curiously, borland has the same problem, even though they use 80-bit long doubles: http://www.dinkumware.com/borlib_test.html Math functions are now required in all three floating-point precisions. Borland has a true long double type, of greater precision than double (unlike Microsoft), and the library defines all the long double math functions. But it appears that these added functions simply turn around and call the existing double functions, a wholly inadequate expedient. Anyway, patching LONG_DOUBLE_TYPE_SIZE may not work: as Mumit says, http://groups.yahoo.com/group/mingw32/message/1968 The suggestion has been that we should simply force GCC to use 8-byte long doubles instead of the 12-byte, which is the usual size on most 32 bit platforms. However, there is a bug in gcc that causes problems if we try that, and I believe Mikey and I both ran into the same issue. Note that GCC currently will maintain all internal computations in 12-byte long doubles, but when you hand it over to say printf, MSVC runtime will get the wrong size. I use a different stdio library, and get around VC++ runtime brain-damage. I need larger than 64-bit long doubles. I think the relevant message is here: http://gcc.gnu.org/ml/gcc-bugs/1999-06n/msg00761.html As to using enquire.c to produce <float.h>, I ran enquire with the patches you suggested, and these values match what I would propose for 80-bit support: #define LDBL_MANT_DIG 64 #define LDBL_DIG 18 #define LDBL_MIN_EXP (-16381) #define LDBL_MIN_10_EXP (-4931) #define LDBL_MAX_EXP 16384 #define LDBL_MAX_10_EXP 4932 as do the values given for LDBL_EPSILON <--> 0x3fc08000000000000000 LDBL_MIN <--> 0x00018000000000000000 LDBL_MAX <--> 0x7ffeffffffffffffffff However, the 'union __convert_long_double' technique has been replaced in gcc due to some breakage I don't quite understand (URL below). Hex floating literals would be perfect, but they're broken, so standard (decimal) floating literals are needed instead. Here's a problem though: I get these values from the borland compiler, which uses 80-bit long double: volatile long double eps = 1.084202172485504434e-19L; volatile long double min = 3.362103143112093506e-4932L; volatile long double max = 1.189731495357231765e+4932L; I (perhaps superfluously) made them volatile and compiled them in gcc with this code: std::cout.precision(30); std::cout << eps << '\n'; std::cout << min << '\n'; std::cout << max << '\n'; Of course, they don't print correctly thanks to the msvc rtl, but gdb gives their hex representations: =>R7: Valid 0x3fc08000000000000000 +1.084202172485504434e-19 =>R7: Special 0x00007fffffffffffffff +0 Denormal =>R7: Valid 0x7ffeffffffffffffffff +Inf and 'min' is wrong: 0x00007fffffffffffffff wrong--denormal 0x00018000000000000000 correct However, this patch http://gcc.gnu.org/ml/libstdc++/2000-08/msg00047.html which explains the breakage mentioned above, and has been accepted in the latest CVS http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/config/float-i386.h?rev=1.4&content-type=text/x-cvsweb- markup suggests that instead we use the more precise value - volatile long double min = 3.362103143112093506e-4932L; + volatile long double min = 3.36210314311209350626e-4932L; which produces the desired =>R7: Valid 0x00018000000000000000 +0 For the record, the FPU state is: Status Word: 0xffff3838 OE UE PE TOP: 7 Control Word: 0xffff037f IM DM ZM OM UM PM PC: Extended Precision (64-bits) RC: Round to nearest Tag Word: 0xffffbfff (Don't worry about the '+0' or '+Inf' things on the right-hand end of the gdb output--they're invalid. We only want the hex values.) So rather than use enquire, I think gcc/gcc/config/float-i386.h rev 1.4 should be adopted for mingw, and we should point out that the msvc rtl will not work with it. Maybe we should provide a way to hook into mathinline.h instead for <math.h> functions, but that would be a different patch.... ---------------------------------------------------------------------- Comment By: Danny Smith (dannysmith) Date: 2001-06-03 03:07 Message: Logged In: YES user_id=11494 I was wrong. Greg, try this: Get a copy of enguire.c from GCC. Apply this patch to get the chip to use all 80 bits: [start of diff] --- enquire.c Fri Nov 05 14:09:42 1999 +++ enquirefp10.c Sun Jun 03 22:45:43 2001 @@ -297,6 +297,14 @@ Added NO_MEM */ +/* definitions from mingw's float.h */ +#ifdef __MINGW32__ +#define _PC_53 0x00010000 +#define _PC_64 0x00000000 +#define _MCW_PC 0x00030000 +unsigned int _controlfp(unsigned int,unsigned int); +#endif + /* Set FILENAME to the name of this file */ #ifndef FILENAME #ifdef NO_FILE @@ -666,6 +674,10 @@ int main(argc, argv) int argc; char *arg int dprec, fprec, lprec; int i; char *s; int bad; +#if defined __MINGW32__ && defined _USE_FP10_ +_controlfp(_PC_64, _MCW_PC); +#endif + #ifdef SIGFPE signal(SIGFPE, overflow); #endif @@ -673,6 +685,7 @@ int main(argc, argv) int argc; char *arg signal(SIGOVER, overflow); #endif /* Add more calls as necessary */ + Unexpected(1); [end of diff] Then compile enquire.c like so gcc -o enquirefp10.exe -DNO_LONG_DOUBLE_IO -D_USE_FP10_ enquirefp10.c and look at the header produced by enquirefp10 -f > float_fp10.h Do they match your definitions? Danny ---------------------------------------------------------------------- Comment By: Danny Smith (dannysmith) Date: 2001-06-03 03:07 Message: Logged In: YES user_id=11494 I was wrong. Greg, try this: Get a copy of enguire.c from GCC. Apply this patch to get the chip to use all 80 bits: [start of diff] --- enquire.c Fri Nov 05 14:09:42 1999 +++ enquirefp10.c Sun Jun 03 22:45:43 2001 @@ -297,6 +297,14 @@ Added NO_MEM */ +/* definitions from mingw's float.h */ +#ifdef __MINGW32__ +#define _PC_53 0x00010000 +#define _PC_64 0x00000000 +#define _MCW_PC 0x00030000 +unsigned int _controlfp(unsigned int,unsigned int); +#endif + /* Set FILENAME to the name of this file */ #ifndef FILENAME #ifdef NO_FILE @@ -666,6 +674,10 @@ int main(argc, argv) int argc; char *arg int dprec, fprec, lprec; int i; char *s; int bad; +#if defined __MINGW32__ && defined _USE_FP10_ +_controlfp(_PC_64, _MCW_PC); +#endif + #ifdef SIGFPE signal(SIGFPE, overflow); #endif @@ -673,6 +685,7 @@ int main(argc, argv) int argc; char *arg signal(SIGOVER, overflow); #endif /* Add more calls as necessary */ + Unexpected(1); [end of diff] Then compile enquire.c like so gcc -o enquirefp10.exe -DNO_LONG_DOUBLE_IO -D_USE_FP10_ enquirefp10.c and look at the header produced by enquirefp10 -f > float_fp10.h Do they match your definitions? Danny ---------------------------------------------------------------------- Comment By: Danny Smith (dannysmith) Date: 2001-06-02 17:08 Message: Logged In: YES user_id=11494 Hello Greg, Yes there is certainly an inconsistency there. Thanks for your input. But I'm not sure that modifying float.h is the right thing to do. MSDN docs clearly emphasises that their CRT math functions do not support long double. Certainly printf doesn't. I think the problem is in gcc/config/i386/ where it defines #define LONG_DOUBLE_TYPE_SIZE 96 for i386. Have a look at this, which is the last part of the output from enquire (the same enquire that is referred to in your post), built with gcc: The first part is the same as the float.h in gcc-lib [...] /* Number of base-FLT_RADIX digits in the significand of a long double */ #undef LDBL_MANT_DIG #define LDBL_MANT_DIG 53 /* Number of decimal digits of precision in a long double */ #undef LDBL_DIG #define LDBL_DIG 15 /* Difference between 1.0 and the minimum long double greater than 1.0 */ #undef LDBL_EPSILON #ifndef __LDBL_UNION__ #define __LDBL_UNION__ union __convert_long_double { unsigned __convert_long_double_i[4]; long double __convert_long_double_d; }; #endif #define LDBL_EPSILON (__extension__ ((union __convert_long_double) {__convert_long_double_i: {0x0, 0x80000000, 0x3fcb, 0x0}}).__convert_long_double_d) /* Minimum int x such that FLT_RADIX**(x-1) is a normalised long double */ #undef LDBL_MIN_EXP #define LDBL_MIN_EXP (-16381) /* Minimum normalised long double */ #undef LDBL_MIN #define LDBL_MIN (__extension__ ((union __convert_long_double) {__convert_long_double_i: {0x0, 0x80000000, 0x1, 0x0}}).__convert_long_double_d) /* Minimum int x such that 10**x is a normalised long double */ #undef LDBL_MIN_10_EXP #define LDBL_MIN_10_EXP (-4931) /* Maximum int x such that FLT_RADIX**(x-1) is a representable long double */ #undef LDBL_MAX_EXP #define LDBL_MAX_EXP 16384 /* Maximum long double */ #undef LDBL_MAX #define LDBL_MAX (__extension__ ((union __convert_long_double) {__convert_long_double_i: {0xfffff800, 0xffffffff, 0x7ffe, 0x0}}).__convert_long_double_d) /* Maximum int x such that 10**x is a representable long double */ #undef LDBL_MAX_10_EXP #define LDBL_MAX_10_EXP 4932 /* *** Something fishy here! Exponent size + significand size doesn't match with the size of a long double! */ [end of enquire output] GCC defines long double as 96 bit, but enquire finds 69 (54 in significand-same as double, 15 in exp, as in Intel- style 80-bit or a 96-bit fp format ). IMHO when building gcc, something like this in the config/i386/mingw32.h target header would provide the safest solution: /* override i386.h setting: don't generate 96-bit XFmode insns */ #undef LONG_DOUBLE_TYPE_SIZE #define LONG_DOUBLE_TYPE_SIZE 64 This puts everything on the same level fp playing field. This is what was done in the old win-nt.h config file for NT3.x. One advantage of doing this would be greater portability to other win32 compilers But I could be very wrong....maybe we could define LONG_DOUBLE_TYPE_SIZE 80 when comiling gcc to provide Intel- style long doubles Danny ---------------------------------------------------------------------- You can respond by visiting: http://sourceforge.net/tracker/?func=detail&atid=302435&aid=429356&group_id=2435 |