使用-O选项的g ++浮点行为不是严格按照C ++ 11标准的标准吗?

时间:2018-07-17 13:01:05

标签: c++ c++11 gcc floating-point g++

考虑

int main() {
   double d = 1.0e+308;
   std::cout << (d*d)/1.0e+308;
}

在Linux CentOS系统(更确切地说是使用Intel的Linux 3.10.0-693.21.1.el7.x86_64)上与g ++版本4.8.5以及两个编译器选项-std = c ++ 11和-mfpmath = 387一起编译。至强X5690 CPU)。如预期的那样,这将输出值1e + 308,因为乘法d * d是按80位扩展精度计算的,因此不会发生溢出(使用这些编译器设置,FLT_EVAL_METHOD返回2)。现在考虑:

int main() {
   double d = 1.0e+308;
   double e;
   e = d*d;
   e = e/1.0e+308;
   std::cout << e;
}

由于d * d被分配给双精度参数e,并且根据我对ISO / IEC 14882:2011标准Sec的理解,这会再次输出inf-符合预期。在图5、11,脚注60中,e的值必须是(或至少必须表现为)真双精度值,即,随后使用时必须是inf。但是,这就是要点,当我在编译器选项中添加-O1时,程序的输出为1e + 308。在我看来,这违反了赋值(和强制转换)“执行其特定转换”的要求-请参阅上述c ++ 11-standard文档中的段落。当使用优化级别O1(或更高)时,我在这里误解了吗?还是在这方面gcc不符合标准?

1 个答案:

答案 0 :(得分:1)

这是提到的段落:

  

浮动操作数的值和浮动表达式的结果可以更大的形式表示   精度和范围超出类型要求;类型不会因此改变。

和脚注:

  

强制转换和赋值运算符仍必须按照5.4、5.2.9和5.17中所述执行其特定的转换。

我不认为GCC违反了此规定。 e的表示精度更高,这是标准所允许的(此处没有转换,因此脚注不适用)。

如果您不喜欢这种行为,请使用-ffloat-store选项,该选项将消除这种过高的精度,并且您的程序将打印inf(但此选项会使您的程序变慢)。


注意,这个规范有点奇怪。

考虑一下。这与您的示例相同,但是使用float:

#include <iostream>

int main() {
   float d = 2.0e+38f;
   float e;
   e = d*d;
   e = e/2e+38f;
   std::cout << e;
}

这将打印2e+38,而不是inf。现在,如果将d的类型更改为doublee = d*d处有一个转换,脚注适用,并且程序应打印inf。并且GCC的行为符合标准,并且确实打印了inf(已通过gcc 5.4.1和gcc 8.1.0测试)。