Same FLT_EVAL_METHOD, different results in GCC / Clang

The following program (adapted from here ) gives inconsistent results when compiling with GCC (4.8.2) and Clang (3.5.1). In particular, the GCC result does not change even when FLT_EVAL_METHOD does.

 #include <stdio.h> #include <float.h> int r1; double ten = 10.0; int main(int c, char **v) { printf("FLT_EVAL_METHOD = %d\n", FLT_EVAL_METHOD); r1 = 0.1 == (1.0 / ten); printf("0.1 = %a, 1.0/ten = %a\n", 0.1, 1.0 / ten); printf("r1=%d\n", r1); } 

Tests:

 $ gcc -std=c99 tc && ./a.out FLT_EVAL_METHOD = 0 0.1 = 0x1.999999999999ap-4, 1.0/ten = 0x1.999999999999ap-4 r1=1 $ gcc -std=c99 -mpfmath=387 tc && ./a.out FLT_EVAL_METHOD = 2 0.1 = 0x0.0000000000001p-1022, 1.0/ten = 0x0p+0 r1=1 $ clang -std=c99 tc && ./a.out FLT_EVAL_METHOD = 0 0.1 = 0x1.999999999999ap-4, 1.0/ten = 0x1.999999999999ap-4 r1=1 $ clang -std=c99 -mfpmath=387 -mno-sse tc && ./a.out FLT_EVAL_METHOD = 2 0.1 = 0x0.07fff00000001p-1022, 1.0/ten = 0x0p+0 r1=0 

Note that according to this blog post, GCC 4.4.3 is used to output 0 instead of 1 in the second test.

A possibly related question indicates that the bug was fixed in GCC 4.6, which may explain why the GCC result is different.

I would like to confirm whether any of these results will be incorrect or if some subtle stages of the evaluation (for example, new preprocessor optimization) justify the difference between these compilers.

+7
c gcc floating-point clang
source share
2 answers

This answer is about something that you have to decide before you go any further, because it will make reasoning about what happens a lot more complicated:

Undoubtedly, printing 0.1 = 0x0.07fff00000001p-1022 or 0.1 = 0x0.0000000000001p-1022 can only be an error on your compilation platform caused by ABI mismatch when using -mfpmath=387 . None of these values ​​can be caused by excessive accuracy.

You can try to include your own conversion format in the reading in the test file, so that the conversion can also be compiled with -mfpmath=387 . Or make a small stub in another file that is not compiled with this option, with a minimal calling convention:

In another file:

 double d; void print_double(void) { printf("%a", d); } 

In the file compiled with -mfpmath=387 :

 extern double d; d = 0.1; print_double(); 
+6
source share

Ignoring the printf problem that Pascal Quoc addressed, I think GCC is correct here: according to the C99 standard, FLT_EVAL_METHOD == 2 should

evaluate all operations and constants in the range and accuracy of the long double type.

So, in this case, both 0.1 and 1.0 / ten are estimated in the approximation with an expanded accuracy of 1/10.

I'm not sure what Clang is doing, although this question may help.

0
source share

All Articles