The following code fails on (at least) Intel x86/x87 systems running Linux: /* * From C99: * 6.6 Constant expressions * * #5 An expression that evaluates to a constant is required in several * contexts. If a floating expression is evaluated in the translation * environment, the arithmetic precision and range shall be at least * as great as if the expression were being evaluated in the execution * environment. */ #include <float.h> /* *_EPSILON */ #include <stdio.h> /* printf() */ /* * Compute epsilon == Unit Last Place; may be + or - depends upon rounding. */ #define Q2 (((4.F /3.F - 1.F ) - 1.F /4.F )*3.F - 1.F /4.F ) /* * File scope is translation time */ static long double fs_ld2 = Q2; static double fs_d2 = Q2; static float fs_f2 = Q2; int main(void){ /* * Local scope is runtime */ long double ls_ld2 = Q2; double ls_d2 = Q2; float ls_f2 = Q2; if( fs_ld2 != ls_ld2 ){ (void)printf(" 1: BFP: translation time != runtime\n"); } if( fs_d2 != ls_d2 ){ (void)printf(" 2: BFP: translation time != runtime\n"); } if( fs_f2 != ls_f2 ){ (void)printf(" 3: BFP: translation time != runtime\n"); } if( fs_ld2 != fs_d2 ){ (void)printf(" 7: BFP: translation time: variable precision\n"); } if( fs_d2 != fs_f2 ){ (void)printf(" 8: BFP: translation time: variable precision\n"); } if( ls_ld2 != ls_d2 ){ (void)printf("11: BFP:runtime: variable precision\n"); } if( ls_d2 != ls_f2 ){ (void)printf("12: BFP:runtime: variable precision\n"); } (void)printf("ls_ld2=%Lg\n", ls_ld2); (void)printf("ls_d2 =%g\n", ls_d2); (void)printf("ls_f2 =%g\n", ls_f2); (void)printf("LD_EPS=%Lg\n", LDBL_EPSILON); (void)printf(" D_EPS=%g\n", DBL_EPSILON); (void)printf(" F_EPS=%g\n", FLT_EPSILON); (void)printf("fs_ld2=%Lg\n", fs_ld2); (void)printf("fs_d2 =%g\n", fs_d2); (void)printf("fs_f2 =%g\n", fs_f2); return 0; }
Subject: Re: New: Translation time Floating Point precision is too small On Thu, 29 Oct 2009, tydeman at tybor dot com wrote: > The following code fails on (at least) Intel x86/x87 systems running Linux: Please explain what you mean by "fails". With what options did you compile it? How was GCC configured? What did it output? What did you want it to output instead? Why do you think what it output was wrong?
Compile options: -std=gnu99 -pedantic -H -fno-builtin -frounding-math Since I take the gcc that comes with Fedora Core Linux 9 and 10, I have no idea how GCC was configured. The output shows that all the file scope (translation time) precisions used were small (ULP is same magnitude as FLT_EPSILON), while all the local scope (runtime) precisions used were large (ULP same magnitude as LDBL_EPSILON). All six should be the same magnitude as LDBL_EPSILON for this hardware. None of the messages with 1:, 2:, 3:, 7:, 8:, 11:, or 12: should be printed if things are done as per the C standard. A large precision implies a small magnitude ULP value (closer to zero).
If you want C99-conforming excess precision, then use 4.5 or later (not 4.4) with -fexcess-precision=standard or strict conformance options such as -std=c99 that imply it (not -std=gnu99). With that I get: ls_ld2=1.0842e-19 ls_d2 =1.0842e-19 ls_f2 =1.0842e-19 LD_EPS=1.0842e-19 D_EPS=2.22045e-16 F_EPS=1.19209e-07 fs_ld2=1.0842e-19 fs_d2 =1.0842e-19 fs_f2 =1.0842e-19 which I think is what you want. *** This bug has been marked as a duplicate of 323 ***
The requirement that translation time precision be at least as great as runtime precision existed in C89, C90, C95, and C99 (so has been around for 20 years). My code is a test of translation time precision versus runtime precision. The first code I saw in bug 323 involved 3 auto variables (so is just runtime). That is a different issue, so I believe that this bug is not a duplicate of 323. I used gnu99 instead of c99 for the std because I also am testing Decimal FP in addition to Binary FP. Where should I find documentation on compiler options to get as close to C99 conformance as possible? Also, C99 + Decimal FP conformance? The output you show is what I expected.
323 covers all excess precision issues. Predictable results that do not depend on when a computation is carried out require -fexcess-precision=standard which requires 4.5. It so happens that all C conformance options, including -std=c89, enable -fexcess-precision=standard; although C90 does not define any standard binding to excess precision such as C99 does with FLT_EVAL_METHOD, enabling it for C90 conformance seemed the best compromise. Options are documented in the GCC manual (specifically, invoke.texi in the GCC sources). The closest conformance options are -std={c89,iso9899:199409,c99} -pedantic (or -pedantic-errors if you want errors for constraint violations). There are no known target-independent conformance bugs in -std=c89 -pedantic or -std=iso9899:199409 -pedantic (excess precision issues are target-dependent) in 4.5 (there are various such bugs in 4.4). http://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html is the online version of the documentation for conformance options; http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html includes the floating-point options and http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html describes -pedantic. There are no options to enable C99 conformance except for allowing decimal floating point. If you want -fdecimal-fp or similar to enable decimal floating point in a strict conformance mode, that would be a separate issue. *** This bug has been marked as a duplicate of 323 ***