如果我们继续将 float 1.0 除以 2 直到它达到零,会发生什么?

m_h*_*ere 1 c ieee-754

float f = 1.0;
while (f != 0.0) f = f / 2.0;
Run Code Online (Sandbox Code Playgroud)

该循环使用 32 位精度运行 150 次。为什么会这样?它是否四舍五入为零?

Eri*_*hil 5

在常见的 C 实现中,IEEE-754 二进制 32 格式用于float. 它也称为 \xe2\x80\x9c 单精度。\xe2\x80\x9d 它是一种基于二进制的格式,其中有限数表示为 \xc2\xb1 f \xe2\x80\xa22 e,其中f是 24 位[1, 2) 和e中的二进制数字是 [\xe2\x88\x92126, 127] 中的整数。

\n

在此格式中,1 表示为 +1.00000000000000000000000 2 \xe2\x80\xa22 0。将其除以 2 得到 \xc2\xbd,表示为 +1.00000000000000000000000 2 \xe2\x80\xa22 \xe2\x88\x921。除以 2 得到 +1.00000000000000000000000 2 \xe2\x80\xa22 \xe2\x88\x922,然后 +1.000000000000000000000000 2 \xe2\x80\xa22 \xe2\x88\x923,依此类推直到我们达到 +1.00000000000000000000000 2 \xe2\ x80\xa22 \xe2\x88\x92126

\n

当除以二时,数学结果为 +1.00000000000000000000000 2 \xe2\x80\xa22 \xe2\x88\x92127,但 \xe2\x88\x92127 低于正常指数范围, [\xe2\x88\x92126, 127 ]。相反,有效数变得非规范化;2 \xe2\x88\x92127由 +0.10000000000000000000000 2 \xe2\x80\xa22 \xe2\x88\x92126表示。除以 2 得到 +0.01000000000000000000000 2 \ xe2 \x80\xa22 \ xe2\x88\x92126,然后 +0.001000000000000000000000 2 \xe2\x80 \xa22 \xe2\x88\x92126 , +0.00010000000000000000000 2 \xe2\x80\xa22 \xe2\ x88\x92126,依此类推,直到 +0.00000000000000000000001 2 \xe2\x80\xa22 \xe2\x88\x92126

\n

至此,我们已经完成了149次除以2;+0.00000000000000000000001 2 \xe2\x80\xa22 \xe2\x88\x92126是 2 \xe2\x88\x92149

\n

执行下一次除法时,结果将是 2 \xe2\x88\x92150,但这无法以此格式表示。即使使用最低的非零有效数 0.00000000000000000000001 2和最低的指数 \xe2\x88\x92126 ,我们也无法得到 2 \xe2\x88\x92150。下一个较低的可表示数字是 +0.00000000000000000000000 2 \xe2\x80\xa22 \xe2\x88\x92126,等于 0。

\n

因此,除法的实数算术结果将是 2 \xe2\x88\x92150,但我们不能用这种格式表示。两个最接近的可表示数字是 +0.000000000000000000000001 2 \xe2\x80\xa22 \xe2\x88\x92126就在它上面, +0.0000000000000000000000000 2 \xe2\x80\xa22 \xe2\x88\x92126就在它上面在它下面。它们同样接近 2 \xe2\x88\x92150。默认舍入方法是取最接近的可表示数字,如果出现平局,则取偶数低位的数字。所以 +0.00000000000000000000000 2 \xe2\x80\xa22 \xe2\x88\x92126赢得平局,这是第 150的结果

\n