UINT_MAX-> float-> uint32_t VC ++上的结果为0

时间:2015-10-16 09:24:36

标签: c++ floating-point undefined-behavior

作为将一些代码移植到Windows的一些工作的一部分,我遇到了一个问题,其中uint32_t最大值的转换 - >浮动 - >使用visual c ++构建时,uint32_t导致0。 我将问题归结为一个简单的程序,该程序在运行不同的编译器时显示问题。

#include <iostream>
#include <limits>

using namespace std;

int main()
{
    uint32_t r1 = numeric_limits<uint32_t>::max();
    float r2 = static_cast<float>(numeric_limits<uint32_t>::max());
    uint32_t r3 = static_cast<uint32_t>(static_cast<float>(numeric_limits<uint32_t>::max()));


    cout << "r1 = " << r1 << endl
    << "r2 = " << r2 << endl
    << "r3 = " << r3 << endl;

    return 0;
}

当通过http://webcompiler.cloudapp.net/运行时,r3的输出为0,但是当通过https://ideone.com/ylf74N时,r3是最大值。

我猜测在转换回uint32_t时会发生+1,当它是UINT_MAX但是我想知道是否有人知道为什么或者究竟发生了什么?

2 个答案:

答案 0 :(得分:2)

当从整数类型转换为实数类型时,结果可能是不精确的并且朝向真实类型中最接近的可表示(高于或低于原始值)四舍五入。在你的情况下,浮点数在其尾数部分有24位,因此,0xFFFFFFFF不会在转换中保持不变,因为它需要32位尾数。因此,它可以转换为0x100000000(最接近上方)。如果发生这种情况,您将从浮点数转换为0x100000000到32位无符号类型。此转换导致未定义行为(包括不可预测/不可靠的结果),因为该值超出了32位无符号类型的范围。

你也可以使用其他编译器获得UB,你只是没有意识到它。通过引入 volaitle (在r1,r2和r3的声明中)进行环境优化,你会看到它(ideone.com/1CCat8)。

答案 1 :(得分:1)

在您的系统上,似乎float是32位类型,可能是IEEE754(但请注意标准并不坚持)。

numeric_limits<uint32_t>::max()是4294967295。

这对你的漂浮来说太大了。 (IEEE754 32位浮点中可容纳的最大奇数是8388607)。

所以你的号码被四舍五入到4294967296.(这是可以容纳的壁橱号码。)

当然,将它转换回uint32_t会导致它回绕到0。

对于其他系统,由于float输出,我们知道sizeof是32位。编译器正在进行错误优化。