为什么这个循环的行为会根据 int 值而有所不同?

Why does this loop behaves different depending on int value?

提问人:Kacper Iterman 提问时间:10/18/2023 最后编辑:user694733Kacper Iterman 更新时间:10/18/2023 访问量:100

问:

我试图理解为什么这个 while 循环有时会迭代 16 次,有时它是无限循环(例如,当 i == 10^8 时),有时根本不迭代(例如,当 i == 10^9 时)。

#include <iostream>

using namespace std;

int main() {
    int i;
    cin >> i;
    float x = i;
    while (x < (float)(i + 16)) {
        cout << x << endl;
        x++;
    }

    return 0;
}

我试图将浮点数转换为二进制 IEE 754 表示,但仍然找不到为什么会发生这种情况的答案。

C++ while-loop 类型转换

评论

3赞 chi 10/18/2023
对于大浮点,我们有等于 。浮点数的有效数字数量有限:例如,可以用近似形式表示,如粗略地说,加起来没有效果。(更糟糕的是,这种情况发生在二进制数字上,而不是十进制数字。xx+1x123456789012345612345678000000001
2赞 Aconcagua 10/18/2023
你的意思是你试图打印浮点数的二进制表示?以不同的方式做!将有问题的值分配给浮点数(但要注意潜在的精度损失,您可能没有存储确切的值!),然后返回到相同大小的无符号积分(很可能 - 您可能会应用)。现在,您可以非常轻松地读出各个位:memcpyunsigned intstatic_assert(sizeof(SelectedIntegerType) == sizeof(float)unsigned int rep; memcpy(&rep, &value, sizeof(rep)); for(unsigned int mask = 1 << numberOfBits - 1; mask; mask >>= 1) { std::cout << ((rep & mask) == mask); }

答:

4赞 chrslg 10/18/2023 #1

因为 100000000 和 100000001 在 float32 中的表示形式相同。 但是 100000000 和 100000016 没有。

所以,你进入了循环,但随后是无效的。++

另一方面 1000000000 和 1000000016 在 float32 中具有相同的表示形式。所以你甚至不进入循环。

在python中(用python代码回答C++问题可能很奇怪;仅仅因为它是一个解释器,所以显示快速示例会更快;但毕竟,你指定了两种不同的语言,C和C++,所以我必须至少失败其中一种语言,为什么不是两种。它表明问题与 32 位浮点表示有关,而不是与语言本身有关)

x=1e8
np.float32(x+16)-x
# 16 (note that np.float32(x) is 100000020. But same numerical error make 100000020-100000000=16
np.float32(x+1)-x
# 0 
x=1e9
np.float32(x+16)-x
# 0
np.float32(x+1)-x
# 0

具体来说,1e9 由 32 位浮点
数中的位表示。
01001110 01101110 01101011 00101000

第一个 0 是符号(正)。 然后,我们有 8 位指数 10011100 = 156。由于这是相对于 127,因此是 29。 然后我们有一个隐式 1,然后是 23 位尾数。所以。即 1.862645149230957。所以总共,+1.862645149230957×2²⁹ = 10⁹1110111001101011001010001+1/2+1/4+0/8+1/16+...+0/2²³

我们已经知道它是 1e9。只是为了确定我们理解这些位的含义。

并对下一个数字执行相同的操作。该表示中的下一个数字是
01001110 01101110 01101011 00101001

同样,符号 +、指数 29 和尾数,相同的 +1 = 1+1/2+1/4+0/8+...+0/2²²+1/2²³ = 1.8626452684402466。 所以总的来说,下一个数字是 1000000064.0111011100110101100101001

换句话说,1000000000 和 1000000064 之间没有任何关系(或者更准确地说,没有什么“不同”。从 32 位浮点数的角度来看,介于两者之间的所有数字都是 1000000000 或 1000000064 的同义词)

评论

0赞 Kacper Iterman 10/18/2023
非常感谢,现在我完全明白了。这很有趣,我从来没有想过那么深。