考虑
int main() {
double d = 1.0e+308;
std::cout << (d*d)/1.0e+308;
}
在 Linux CentOS 系统上使用 g++ 版本 4.8.5 和两个编译器选项 -std=c++11 和 -mfpmath=387 编译(更准确地说,Linux 3.10.0-693.21.1.el7.x86_64 with Intel至强 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;
}
这输出 inf - 再次如预期 - 因为 d*d 被分配给双参数 e 并且根据我对 ISO/IEC 14882:2011 标准 Sec 的理解。 5、11,脚注 60,e 的值必须是(或至少必须表现为)真正的 double 值,即在随后使用时必须是 inf。然而,这就是重点,当我将 -O1 添加到编译器选项时,程序的输出是 1e+308。这违反了 - 在我看来 - 分配(和强制转换)“执行其特定转换”的要求 - 请参阅上面提到的 c++11 标准文档中的段落。当使用优化级别 O1(或更高)时,我是否误解了这里的内容或者 gcc 不符合标准(在这方面)?
最佳答案
这是提到的段落:
The values of the floating operands and the results of floating expressions may be represented in greater precision and range than that required by the type; the types are not changed thereby.
还有脚注:
The cast and assignment operators must still perform their specific conversions as described in 5.4, 5.2.9 and 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
的类型更改为 double
:在 e = d*d
处有一个转换,脚注适用,并且您的程序应该打印 inf
。 GCC 的行为符合标准,它确实打印了 inf
(使用 gcc 5.4.1 和 gcc 8.1.0 测试)。
关于c++ - g++-带有-O选项的浮点行为不是严格的C++11标准保形?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51382062/