为什么浮点变量在C#中停止递增为16777216?

2024-04-29 12:23:16 发布

您现在位置:Python中文网/ 问答频道 /正文

float a = 0;
while (true)
{
    a++;
    if (a > 16777216)
        break; // Will never break... a stops at 16777216
}

有谁能解释一下为什么在这段代码中,浮点值不再递增为16777216?

编辑:

或者更简单:

float a = 16777217; // a becomes 16777216

Tags: 代码true编辑iffloatwillat浮点
4条回答

IEEE-754浮点数(32位)的简短汇总:

  • 1位符号(0表示正数,1表示负数)
  • 8位指数(带-127偏差,此处不重要)
  • 23位“尾数”
  • 除了指数值0和255之外,可以将该值计算为:(sign ? -1 : +1) * 2^exponent * (1.0 + mantissa)
    • 尾数位表示小数分隔符后面的二进制数字,例如1001 0000 0000 0000 0000 000 = 2^-1 + 2^-4 = .5 + .0625 = .5625,小数分隔符前面的值不存储,而是隐式假设为1(如果指数为255,则假设为0,但这在这里并不重要),因此对于指数为30,例如,此尾数示例表示值1.5625

现在以你为例:

16777216正好是224,将表示为32位浮点,如下所示:

  • 符号=0(正数)
  • 指数=24(存储为24+127=151=10010111
  • 尾数=.0
  • 作为32位浮点表示:0 10010111 00000000000000000000000
  • 因此:Value=(+1) * 2^24 * (1.0 + .0) = 2^24 = 16777216

现在让我们看看数字16777217,或者正好是224+1:

  • 符号和指数相同
  • 尾数必须正好是2-24,这样(+1) * 2^24 * (1.0 + 2^-24) = 2^24 + 1 = 16777217
  • 这就是问题所在。尾数不能有值2-24,因为它只有23位,所以数字16777217不能用32位浮点数的精度表示!

当您在二进制表示中查看该值时,您将看到它是一个1和多个零,即1 0000 0000 0000 0000 0000 0000,或者正好是2^24。这意味着,在16777216,这个数字刚刚增长了一位数。

由于它是一个浮点数,这可能意味着它末端的最后一个仍被存储的数字(即在其精度范围内)也会向左移动。

可能,你看到的是,最后一个数字的精度已经移到了一个以上,所以增加一个就不再有什么区别了。

IEEE-754浮点数(32位)的简短汇总:

  • 1位符号(0表示正数,1表示负数)
  • 8位指数(带-127偏差,此处不重要)
  • 23位“尾数”
  • 除了指数值0和255之外,可以将该值计算为:(sign ? -1 : +1) * 2^exponent * (1.0 + mantissa)
    • 尾数位表示小数分隔符后面的二进制数字,例如1001 0000 0000 0000 0000 000 = 2^-1 + 2^-4 = .5 + .0625 = .5625,小数分隔符前面的值不存储,而是隐式假设为1(如果指数为255,则假设为0,但这在这里并不重要),因此对于指数为30,例如,这个尾数示例表示值1.5625

现在以你为例:

16777216正好是224,将表示为32位浮点,如下所示:

  • 符号=0(正数)
  • 指数=24(存储为24+127=151=10010111
  • 尾数=.0
  • 作为32位浮点表示:0 10010111 00000000000000000000000
  • 因此:Value=(+1) * 2^24 * (1.0 + .0) = 2^24 = 16777216

现在让我们看看数字16777217,或者正好是224+1:

  • 符号和指数相同
  • 尾数必须正好是2-24,这样(+1) * 2^24 * (1.0 + 2^-24) = 2^24 + 1 = 16777217
  • 这就是问题所在。尾数不能有值2-24,因为它只有23位,所以数字16777217不能用32位浮点数的精度来表示!

16777217不能用浮点数精确表示。float可以精确表示的下一个最高数字是16777218。

因此,尝试将浮点值16777216增加到16777217,这不能用浮点表示。

相关问题 更多 >