最小的浮点数为什么是2^(-126),而不是2^(-128)?

4
考虑一个32位浮点数(IEEE 754),其中0-22用于尾数(23位),23-30用于指数(8位),31用于符号(1位)
我想找到可以存储的最小正数。
有人告诉我答案是1.18×10-38,约为2-126
我的分析如下:
如果我们在尾数中放置所有零,并在指数中放置所有一,则十进制等效值将为
1.0 x 2-128 = 2.93 x 10-39

我错在哪里了?
谢谢


3
根据Wikipedia的解释,“指数范围为-126到+127,因为指数-127(全为0)和+128(全为1)被保留用于特殊数字。” - Raymond Chen
1
我被告知答案是1.1810-38,但这是不正确的:该值是可表示的最小正常数。可表示的最小正数是2^149,约为1.410^-45。 - Mark Dickinson
3个回答

4
我认为IEEE-754数字可以分为三个主要类别:特殊数字、正常数字和次正常数字。这些类别基于指数的值,并且每个类别中还有一些子结构。特殊数字具有最大的指数值,次正常数字的指数是最小的,而正常数字则介于两者之间。我们可以用一个表格来总结这些内容(这里的具体值是针对单精度float的,正如你所问的)。
指数 尾数 类别 调整后的尾数 调整后的指数
FF 非零 NaN * n/a
FF 0 无穷大 n/a n/a
01FE 任意值 规格化数 (1)000000(1)7fffff -126 – +127
00 非零 非规格化数 0000007fffff -126
00 0 0 n/a
关键在于:
  • 普通数的有效数字为24位(通常称为“尾数”),其中前导位始终为1(因此是隐式的),指数范围为-126到+127(即0x010xfe或1到254,减去偏差127)。
  • 亚正常数的有效数字为23位,其中前导位不一定为1(因此是显式的),指数为-126。

现在,你可能会认为对于亚正常数来说,由于原始指数为0且指数偏差为127,实际指数应该为-127。(我也是这么想了很长时间。)但这将在亚正常数中留下一个空缺。因此,亚正常数的指数为-126,比您预期的高1,并最终与普通数中最小的指数相匹配。

那么这些范围是如何工作的呢?

对于普通数,最大的原始尾数是0x7fffff,加上隐含的1位后变成0xffffff,表示为分数是0x1.fffffe,或者等于1.99999988079071044921875。最小的原始尾数是0x000000,加上隐含的1位后变成0x800000,表示为分数是0x1.000000,或者等于1.0。
对于亚正常数,最大的原始尾数是0x7fffff,表示为分数是0x0.fffffe,或者等于0.99999988079071044921875。最小的原始尾数是0x000001,表示为分数是0x0.000002,或者等于0.00000011920928955078125。
将这些信息与最大和最小指数值结合起来,我们得到:
阈值 派生 十进制 十六进制
最大正常值 1.99999988 × 2127 3.4028234663852885981e+38 0xf.fffff0E+31
最小正常值 1.0 × 2-126 1.175494350822287508e-38 0x4.000000E-32
最大次正常值 0.99999988 × 2-126 1.175494210692441075e-38 0x3.fffff8E-32
最小次正常值 0.000000119 × 2-126 1.401298464324817071e-45 0x8.000000E-38
所以当你听到最小的float是1.18×10-38时,很明显有人在谈论最小的普通数字,并忽略了次标准数的存在。正如你所看到的,最小的次标准数要小得多。
在这个表中,我们还可以看到为什么亚规格数的指数必须是-126而不是-127。亚规格数应该覆盖最小正常数和零之间的范围。指数为-126时,它们可以均匀且良好地完成这项工作。另一方面,如果亚规格数的指数为-127,则最大的亚规格数将是0.9999998×2-127=5.877471053462205377e-39或0x1.fffffcE-32,已经接近零(就这样说),其余的亚规格数被挤在下面,留下一个“大”间隙,在1.175e-38和5.877e-39之间。维基百科有一张nice picture,来自“subnormal number”页面,说明了亚规格数填补了靠近0的间隙的方式。
另请参见this question,了解更多关于IEEE-754浮点值如何构造的信息。
注释:在本答案中,我使用类似于0x1.fffffe的符号表示十六进制小数,当然这不是您的C编译器可以接受的。而0xf.fffffE+31是十六进制科学计数法,其中指数是16的幂,并且E不是位于有效数字部分的十六进制数字。这有点像printf/scanf格式%a,尽管%a使用p来标记其指数,该指数是2的幂次方。

这是一个非常好的IEEE754解释。 - undefined

2
如果您在指数中全部使用1,则如果尾数为非零则会得到NaN,如果尾数为0,则会得到无穷大。有关详细信息,请参见维基百科IEEE 754。此外,当指数二进制等于0时,您的最小值位于非规格化数空间内。

我写了一篇关于denormal数的综合教程,网址为: https://dev59.com/nWsy5IYBdhLWcg3wvgr7#53203428 - Ciro Santilli OurBigBook.com

-2

虽然8位指数的范围是-127到+128,但有两种情况保留给特殊值(请参见此处),因此最小的负指数是-126。

顺便说一句,在IEEE 754指数中使用的基本系统Two's Complement中,无法将-128存储在8位中。


3
IEEE 754不使用二进制补码系统来存储指数。(我认为你的意思是“8位”而不是“8字节”。) - Mark Dickinson
1
在实际用于存储指数的系统中,他们可以选择任意连续的254个指数值范围(256减去两种特殊情况,即全0和全1)。 - Patricia Shanahan
我认为你的意思是,在IEEE754中有+零和-零,因此在一侧为-1至-126,在另一侧为+1至+128。 这也解释了最大的数字约为2^128 = 3.4 X 10^38。 - user1371666
3
@SuB: 在IEEE 754指数编码中,根本没有涉及到二进制补码。对于正常的数字,指数使用简单的偏差进行编码:对于binary32格式(“单精度”),偏差为127,对于binary64(“双精度”)则为1023。“二进制补码的有偏版本”几乎没有意义。 - Mark Dickinson
2
@SuB 不,二进制补码在IEEE 754的编码中根本没有涉及。 - Andrew
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接