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 |