use*_*666 4 floating-point ieee-754
考虑一个 32 位浮点数(IEEE 754),尾数为 0-22(23 位),指数(8 位)为 23-30,符号(1 位)为 31
我想找出可以是的最小正数存储。
有人告诉我答案是 1.18*10 -38大约是 2 -126
我的分析如下,
如果我们将所有零放在尾数中并将所有 1 放在指数中,那么十进制等效值将是
1.0 x 2 -128 = 2.93 x 10 -39
我哪里出错了?
谢谢
我认为 IEEE-754 数字分为三个主要类别:特殊数字、普通数字和次正常数字。这些类别基于指数值,每个类别内还有一些子结构。\n特殊类别是具有最大指数值的类别,次正规类别具有最小指数,而普通类别是介于两者之间的所有指数。我们可以将事情总结在一个表格中(这里的具体值是单精度的值)float您所询问的,这里的具体值是单精度的值):
| 指数 | 有效数字 | 类别 | 调整后的有效数 | 形容词 实验值。 |
|---|---|---|---|---|
FF | 非零 | 南 | * | 不适用 |
FF | 0 | 无穷 | 不适用 | 不适用 |
01\xe2\x80\x93FE | 任何事物 | 法线 | (1)000000\xe2\x80\x93(1)7fffff | -126 \xe2\x80\x93 +127 |
00 | 非零 | 次正常 | 000000\xe2\x80\x937fffff | -126 |
00 | 0 | 零 | 0 | 不适用 |
关键是:
\n0x0110xfe到 254) ,减去 127 的偏差)。现在,您可能会认为对于次正规数,由于原始指数为 0,指数偏差为 127,因此实际指数应为 -127。(这也是我很长一段时间以来的想法。)但这会在次正常值中留下间隙。因此,次法线的指数为 -126,比您预期的高 1,并且最终与最小法线的指数匹配。
\n那么这些范围的作用是什么?
\n对于法线,最大原始有效数为0x7fffff, 或0xffffff添加隐式 1 位,其分数为0x1.fffffe, 或 1.99999988079071044921875。最小原始有效数为0x000000,或0x800000添加隐式 1 位,即0x1.000000, 或 1.0。
对于次正规数,最大原始有效数为0x7fffff,其分数为0x0.fffffe, 或 0.99999988079071044921875。最小原始有效数是0x000001,即0x0.000002, 或 0.00000011920928955078125。
将所有这些与最大和最小指数值放在一起,我们有:
\n| 临界点 | 推导 | 小数 | 十六进制 |
|---|---|---|---|
| 最大正常值 | 1.99999988\xc3\x97 2 127 | 3.4028234663852885981e+38 | 0xf.fffff0E+31 |
| 最小正常值 | 1.0 \xc3\x97 2 -126 | 1.175494350822287508e-38 | 0x4.000000E-32 |
| 最大次正常 | 0.99999988\xc3\x97 2 -126 | 1.175494210692441075e-38 | 0x3.fffff8E-32 |
| 最小低于正常值 | 0.000000119\xc3\x97 2 -126 | 1.401298464324817071e-45 | 0x8.000000E-38 |
所以当你听说最小的float是 1.18 \xc3\x97 10 -38时,显然有人在谈论最小的法线数,而忽略了次正常数的存在。正如您所看到的,最小的次法线要小得多。
在此表中,我们还可以看出为什么次正规数的指数必须是 -126,而不是 -127。次正常值应该覆盖最小正常值和零之间的范围。当指数为 -126 时,它们可以均匀且良好地做到这一点。另一方面,如果次正规数的指数为 -127,则最大次正规数将为 0.9999998 \xc3\x97 2 -127 = 5.877471053462205377e-39 或0x1.fffffcE-32,这已经是斜率到零的一半(可以这么说),其余的次正常值都挤在该值以下,在 1.175e-38 和 5.877e-39 之间留下了“大”差距。维基百科在“次正规数”页面上有一张漂亮的图片,说明了次正规数如何填补 0 附近的空白。
另请参阅此问题,了解有关如何构造 IEEE-754 浮点值的更多信息。
\n脚注:我在这个答案中使用了类似的符号0x1.fffffe,这是一个以 16 为基数的分数,这当然不是你的 C 编译器会接受的。然后0xf.fffffE+31是十六进制科学记数法,其中指数是 16 的幂,并且E不是作为有效数一部分的十六进制数字。这有点像printf/scanf格式%a,尽管%a它用于p标记其指数,即 2 的幂。