考虑以下代码,这是我实际问题的SSCCE:
#include <iostream>
int roundtrip(int x)
{
return int(float(x));
}
int main()
{
int a = 2147483583;
int b = 2147483584;
std::cout << a << " -> " << roundtrip(a) << '\n';
std::cout << b << " -> " << roundtrip(b) << '\n';
}
我的电脑(Xubuntu 12.04.3 LTS)上的输出是:
2147483583 -> 2147483520
2147483584 -> -2147483648
请注意在往返后正数b
如何结束为负数。这种行为是否明确规定?我原本期望int-to-float round-tripping至少能正确保存符号......
嗯,on ideone,输出不同:
2147483583 -> 2147483520
2147483584 -> 2147483647
g ++团队是否在此期间修复了错误,或两个输出都完全有效?
答案 0 :(得分:69)
由于从浮点到整数的转换溢出,您的程序正在调用未定义的行为。你看到的只是x86处理器上常见的症状。
最接近float
的{{1}}值恰好是2 31 (从整数到浮点的转换通常是舍入到最近的,可以是up,并且是在这种情况下。具体来说,从整数转换为浮点时的行为是实现定义的,大多数实现将舍入定义为“根据FPU舍入模式”,FPU的默认舍入模式是舍入到最近的)。
然后,在从表示2 31 的float转换为2147483584
时,发生溢出。这种溢出是未定义的行为。一些处理器引发异常,其他处理器饱和。通常由编译器生成的IA-32指令int
在溢出的情况下总是返回cvttsd2si
,无论浮动是正还是负。
即使您知道自己的目标是英特尔处理器,也不应该依赖此行为:当定位x86-64时,编译器可以发出,从浮点数转换为整数sequences of instructions that take advantage of the undefined behavior to return results other than what you might otherwise expect for the destination integer type。