简体   繁体   English

相同的FLT_EVAL_METHOD,GCC / Clang中的结果不同

[英]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). 当使用GCC(4.8.2)和Clang(3.5.1)编译时,以下程序(从此处改编)给出不一致的结果。 In particular, the GCC result does not change even when FLT_EVAL_METHOD does. 特别是,即使FLT_EVAL_METHOD ,GCC结果也不会改变。

#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. 请注意,根据这篇博文 ,GCC 4.4.3用于在第二次测试中输出0而不是1。

A possibly related question indicates that a bug has been corrected in GCC 4.6, which might explain why GCC's result is different. 一个可能相关的问题表明在GCC 4.6中已经纠正了一个错误,这可能解释了为什么GCC的结果不同。

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 . 当使用-mfpmath=387时,肯定打印0.1 = 0x0.07fff00000001p-10220.1 = 0x0.0000000000001p-1022只能是编译平台上由ABI不匹配引起的错误。 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 . 您可以尝试在测试文件中包含您自己的转换为可读格式,以便使用-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 : 在使用-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 忽略Pascal Cuoq解决的printf问题,我认为GCC在这里是正确的:根据C99标准, FLT_EVAL_METHOD == 2应该

evaluate all operations and constants to the range and precision of the long double type. 评估long double类型的范围和精度的所有操作和常量。

So, in this case, both 0.1 and 1.0 / ten are being evaluated to an extended precision approximation of 1/10. 因此,在这种情况下, 0.11.0 / ten都被评估为1/10的扩展精度近似值。

I'm not sure what Clang is doing, though this question might provide some help. 我不确定Clang在做什么,虽然这个问题可能会提供一些帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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