从 int 到 float 并返回时符号发生变化

考虑以下代码,这是我实际问题的 SSCCE:

Consider the following code, which is an SSCCE of my actual problem:

#include <iostream>

int roundtrip(int x)
{
    return int(float(x));
}

int main()
{
    int a = 2147483583;
    int b = 2147483584;
    std::cout << a << " -> " << roundtrip(a) << '
';
    std::cout << b << " -> " << roundtrip(b) << '
';
}

我的电脑(Xubuntu 12.04.3 LTS)上的输出是:

The output on my computer (Xubuntu 12.04.3 LTS) is:

2147483583 -> 2147483520
2147483584 -> -2147483648

注意正数 b 在往返后如何变成负数.这种行为是否明确?我本来希望 int-to-float 往返至少能正确保留符号...

Note how the positive number b ends up negative after the roundtrip. Is this behavior well-specified? I would have expected int-to-float round-tripping to at least preserve the sign correctly...

嗯,在ideone上,输出不一样:

2147483583 -> 2147483520
2147483584 -> 2147483647

g++ 团队是否同时修复了一个错误,或者两个输出都完全有效?

Did the g++ team fix a bug in the meantime, or are both outputs perfectly valid?

推荐答案

由于从浮点到整数的转换中溢出,您的程序正在调用未定义的行为.您看到的只是 x86 处理器上的常见症状.

Your program is invoking undefined behavior because of an overflow in the conversion from floating-point to integer. What you see is only the usual symptom on x86 processors.

最接近 2147483584float 值正好是 231(从整数到浮点的转换通常四舍五入到最接近的值,即可以up,在这种情况下是up.具体来说,整数到浮点的转换行为是实现定义的,大多数实现都将舍入定义为根据FPU舍入模式",而FPU的默认舍入模式是四舍五入到最近).

The float value nearest to 2147483584 is 231 exactly (the conversion from integer to floating-point usually rounds to the nearest, which can be up, and is up in this case. To be specific, the behavior when converting from integer to floating-point is implementation-defined, most implementations define rounding as being "according to the FPU rounding mode", and the FPU's default rounding mode is to round to the nearest).

然后,在将表示 231 的浮点数转换为 int 时,会发生溢出.此溢出是未定义的行为.一些处理器引发异常,其他处理器饱和.通常由编译器生成的 IA-32 指令 cvttsd2si 碰巧总是在溢出的情况下返回 INT_MIN,无论浮点数是正数还是负数.

Then, while converting from the float representing 231 to int, an overflow occurs. This overflow is undefined behavior. Some processors raise an exception, others saturate. The IA-32 instruction cvttsd2si typically generated by compilers happens to always return INT_MIN in case of overflow, regardless of whether the float is positive or negative.

即使您知道您的目标是英特尔处理器,也不应该依赖这种行为:当目标是 x86-64 时,编译器可以发出,用于从浮点到整数的转换,利用未定义行为返回结果的指令序列否则期望目标整数类型.

You should not rely on this behavior even if you know you are targeting an Intel processor: when targeting x86-64, compilers can emit, for the conversion from floating-point to integer, 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.

相关文章