简体   繁体   中英

Same FLT_EVAL_METHOD, different results in GCC/Clang

The following program (adapted from here ) is giving inconsistent results when compiled 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 t.c && ./a.out
FLT_EVAL_METHOD = 0
0.1 = 0x1.999999999999ap-4, 1.0/ten = 0x1.999999999999ap-4
r1=1

$ gcc -std=c99 -mpfmath=387 t.c && ./a.out
FLT_EVAL_METHOD = 2
0.1 = 0x0.0000000000001p-1022, 1.0/ten = 0x0p+0
r1=1

$ clang -std=c99 t.c && ./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 t.c && ./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 used to output 0 instead of 1 in the second test.

A possibly related question indicates that a bug has been corrected in GCC 4.6, which might explain why GCC's result is different.

I would like to confirm if any of these results would be incorrect, or if some subtle evaluation steps (eg a new preprocessor optimization) would justify the difference between these compilers.

This answer is about something that you should resolve before you go further, because it is going to make reasoning about what happens much harder otherwise:

Surely printing 0.1 = 0x0.07fff00000001p-1022 or 0.1 = 0x0.0000000000001p-1022 can only be a bug on your compilation platform caused by ABI mismatch when using -mfpmath=387 . None of these values can be excused by excess precision.

You could try to include your own conversion-to-readable-format in the test file, so that that conversion is also compiled with -mfpmath=387 . Or make a small stub in another file, not compiled with that option, with a minimalistic call convention:

In other 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();

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

evaluate all operations and constants to the range and precision of the long double type.

So, in this case, both 0.1 and 1.0 / ten are being evaluated to an extended precision approximation of 1/10.

I'm not sure what Clang is doing, though this question might provide some help.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM