3 回答

TA贡献1883条经验 获得超3个赞
这意味着:decimalless scientific notation with exponent a power of two
8444249301319680*(2^-51) = 3.75 or 8444249301319680/(2^51) = 3.75
p-51
均值,也可以计算为2^-51
1/(2^51)
关于浮点算术的好文章。https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

TA贡献1820条经验 获得超10个赞
值得指出的是,由于浮点数的内部存储格式,运行时系统也特别容易生成输出。%b
如果我们忽略“非规范化”的浮点数(我们可以稍后将它们加回来),浮点数在内部存储为1.bbbbbb...对于某些位集(此处为“b”),bbb x 2exp,例如,值 4 存储为 。值 6 存储为 ,值 7 存储为 ,八 存储为 。值七分半是,七和四分之三是,依此类推。这里的每个位,在1.bbbb中,代表低于指数的2的下一个幂。1.000...000 <exp> 2
1.100...000 <exp> 2
1.110...000 <exp> 2
1.000...000 <exp> 3
1.111 <exp> 2
1.1111 <exp> 2
要使用格式打印出来,我们只需注意,我们需要连续四位,即值15十进制或0xf或二进制,这导致指数需要减少3,因此我们希望乘以2-1或1/2,而不是乘以22或4。因此,我们可以取实际的指数(2),减去3(因为我们移动“点”三次以打印二进制或15),从而打印出字符串 。1.111 <exp> 2
%b
1
1111
1111
15p-1
不过,这不是Go的印刷品:它打印 。这是相同的值(所以任何一个都是正确的输出)——但为什么呢?%b
8444249301319680p-50
好吧,是,在十六进制中,.扩展到完整的二进制,这是 。这是53个二进制数字。为什么53个二进制数字,而四个就足够了?8444249301319680
1E000000000000
1 1110 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
答案可以在Nick的答案中的链接中找到:IEEE 754浮点格式使用53位的“尾数”或“有效数”(后者是更好的术语,也是我通常尝试使用的术语,但你会看到前者经常弹出)。也就是说,有52 s,加上那个强行引入的领先者。因此,始终有 53 个二进制数字(对于 IEEE“双精度”)。1.bbb...bbb
b
1
如果我们只是把这个53进制数字视为十进制数,我们总是可以在没有小数点的情况下打印出来。这意味着我们只需调整两个指数的幂。
在IEEE754格式中,指数本身已经以“多余的形式”存储,并添加了1023(再次用于双精度)。这意味着它实际上以指数值为2 + 1023 = 1025存储。这意味着,为了获得2的实际幂,格式化数字的机器代码已经必须减去1023。我们可以让它同时再减去52。1.111000...000 <exp> 2
最后,由于隐含的始终存在,因此内部IEEE754编号实际上并不存储该位。因此,要读出值并对其进行转换,代码在内部执行以下操作:1
1
decimalPart := machineDependentReinterpretation1(&doubleprec_value) expPart := machineDependentReinterpretation2(&doubleprec_value)
其中,依赖于机器的重新解释只是提取正确的位,根据需要在小数部分放入隐含位,减去指数部分的偏移量(1023 + 52),然后执行以下操作:1
fmt.Sprint("%dp%d", decimalPart, expPart)
当以十进制打印浮点数时,基数转换(从基数 2 到基数 10)是有问题的,需要大量的代码才能正确舍入。像这样以二进制格式打印它要容易得多。
为读者提供的练习,以帮助理解这一点:
计算 1.102 x 22。注:1.12 为十进制 11/2。
计算 11.02 x 21。(11.02 是 3。
基于上述内容,当您左右“滑动二进制点”时会发生什么?
(更难)为什么我们可以假设一个领先的1?如有必要,请继续阅读。
为什么我们可以假设一个领先的1?
让我们首先注意,当我们使用十进制的科学记数法时,我们不能假设一个前导。数字可能是 1.7 x 103,或 5.1 x 105,或者其他什么。但是,当我们“正确”使用科学记数法时,第一个数字永远不会为零。也就是说,我们不写0.3 x 100,而是写3.0 x 10-1。在这种表示法中,位数告诉我们精度,第一个数字永远不必为零,通常也不应该是零。如果第一个数字为零,我们只需移动小数点并调整指数(请参阅上面的练习 1 和 2)。1
同样的规则也适用于浮点数。例如,我们不存储,而是将二进制点滑动到两个位置上并得到,并将指数减小2。如果我们可能想要存储,我们将二进制点向另一个位置滑动并增加指数。每当我们这样做时,第一个数字最终总是一个。0.01
1.00
11.1
这里有一个很大的例外,那就是:当我们这样做时,我们不能存储零!因此,我们不会对数字这样做。在 IEEE754 中,我们存储为全零位(符号除外,我们可以将其设置为存储 )。这有一个全零指数,计算机硬件将其作为特殊情况处理。0.0
0.0
-0.0
非规范化数字:当我们不能假设前导 1 时
这个系统有一个明显的缺陷(不能完全通过去规范来解决,但尽管如此,IEEE也有去规范)。也就是说:我们可以存储的最小数字“突然下溢”为零。Kahan有一个关于逐渐下溢的15页“简短教程”,我不打算试图总结,但是当我们达到最小允许指数(2-1023)并希望“变小”时,IEEE让我们停止使用这些带有前导位的“规范化”数字。1
这不会影响 Go 本身格式化浮点数的方式,因为 Go 只是“按原样”获取整个有效数。我们所要做的就是停止插入253“隐含1”,当输入值是非规范化的数字时,其他一切都只是工作。我们可以将这种魔力隐藏在依赖于机器的重新解释代码中,或者在Go中显式执行,以更方便的方式为准。float64

TA贡献1831条经验 获得超4个赞
科学记数法的五条规则如下:
基数始终为 10
指数必须是非零整数,这意味着它可以是正数或负数
系数的绝对值大于或等于 1,但应小于 10
系数带有符号 (+) 或 (-)
曼蒂萨携带其余的有效数字
p
%b
指数为2的幂的科学记数法(其p
)%e
科学记数法
- 3 回答
- 0 关注
- 117 浏览
添加回答
举报