提问人:Kacper Iterman 提问时间:10/18/2023 最后编辑:user694733Kacper Iterman 更新时间:10/18/2023 访问量:100
为什么这个循环的行为会根据 int 值而有所不同?
Why does this loop behaves different depending on int value?
问:
我试图理解为什么这个 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 表示,但仍然找不到为什么会发生这种情况的答案。
答:
因为 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⁹111011100110101100101000
1+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 的同义词)
评论
上一个:== 在泛型类型中的行为
下一个:将标准布局对象数组转换为元素数组
评论
x
x+1
x
1234567890123456
1234567800000000
1
memcpy
unsigned int
static_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); }