上帝给了我32个位,让我重新设计数字的存储方式。为了大家学起来不头疼,我就这么设计:
第一位留给正负号,剩下的,16位用于表示整数部分,15位用于表示小数部分,设计完毕。
固定小数点突然有几个人找到我,告诉我他们遇到了问题。
彩票中心:整数位只有16位,最大能表示65535, 一百万不到!我们这里一秒钟都几个亿的资金流,怎么处理?
芯片制造商:我们这的工艺都是纳米级的(0.000001毫米),你的小数位只有15位,精度就到0.00003(1 / 2^15),差太多了!
物理学家:光速(约300000000)和引力常量(约0.0000000000667)我们都需要,你自己看着办吧。
上帝只给了32个位,多要点不合适,那么只能重新设计了。既然固定小数点的设计不能满足大多数的需求,我们就让它浮动起来,遇到大数的时候多给整数留位置,遇到小数的时候多给小数留位置。
怎么实现浮动呢?
对于十进制数 567.0
- 小数点向右浮动1位可以看成 567.0 * 10^1 = 5670.0
- 小数点向左浮动1位可以看成 567.0 * 10^-1 = 56.7
我们发现利用10^n 次方可以控制小数点的浮动,其中指数n决定了小数点的浮动方向和移动次数。
这个性质对于二进制同样适用。
可以用2^n 次方来控制小数点的浮动,其中指数n决定了小数点的浮动方向和移动次数。那么我们就从32位中留下一些位置,用来保存指数n的信息,剩下的用来保存数的信息。
于是这样一个设计轮廓出现了:
符号位 - 1 位
指数位 - 8 位
尾数位 - 23 位
轮廓已经出现了,现在我们来完善一些细节。
A. 任何一个十进制数都可以转换成对应的二进制
10.0 --> 1010.0
4.0 --> 100.0
1.25 --> 1.01
0.125 --> 0.001
B. 除了0,任何一个二进制数都可以看成如下形式
1010.0 - 将1.01的小数点向右浮动3位
100.0 - 将1.0的小数点右浮动2位
1.01 - 将1.01的小数点右浮动0位
0.001 - 将1.0的小数点左浮动3位
C. 从A和B我们总结出:对于一个十进制非零数n,都可以由对应的二进制数1.xxxxxxx... 浮动小数点得到。
于是我们可以把小数点的浮动信息保存在指数位,而1.xxxxxxx... 则保存到尾数位。
指数位
怎么用8个位来保存浮动信息呢?
8个位能表示255个数
- 我们用一半的数来代表右移动一位,两位,三位…
- 用一个数来代表右移零位
- 用剩下的数来代表左移一位,两位,三位..
于是这样规定
...
10000010 (130)- 代表向右浮动3位
10000001 (129) - 代表向右浮动2位
10000000(128) - 代表向右浮动1位
01111111(127) - 代表向右浮动0位
0111110(126) - 代表向左浮动1位
01111101 (125)- 代表向左浮动2位
01111100 (124)- 代表向左浮动3位
…
尾数位
由C得出,除了0,尾数位保存的二进制数都是形如1.xxxxxxx... 的二进制数字,于是我们将起始的1 省略,只将xxxxxxxxxxxx放入尾数位中,读取时再补上起始位的1。即1.01只将01保存到尾数位中。这样无形中将23位变成了24位,增大了一倍的存储范围。
对于0,还有其他一些特殊情况,我们稍后处理。
主要规则都设计完毕了,我们来看看十进制的10和0.125在内存中怎么表示。
10
- 将10 转换成二进制 1010.0
-
看成 1.01 向右浮动3位
十进制10在内存中的表示
a. 指数位为10000010,代表右浮动3位
b. 尾数为位01,补上起始1为1.01
可得二进制1010.0, 转十进制得10
0.125
- 0.125 转换成二进制 0.001
- 看成1.0 向左浮动3位
a. 指数位为01111100,代表左浮动3位
b. 尾数为位0,补上起始1为1.0
可得二进制0.001, 转十进制得0.125
特殊情况
- 指数位全为1,此时如果:
- 尾数位全为0
表示无穷大,由符号位决定正负无穷大。 - 尾数位不全为0
表示NaN
- 指数位全为0。此情况下尾数位读取时不再补1,而成为形如0.000000的数。此时如果:
- 尾数位全为0
表示0 - 尾数位不全为0
表示接近0的很小的数字
这种存储方式就是单精度浮点数的存储方式,能表示的最大安全整数是2^24 - 1 = 16777215,
小数精度1 / 2^24 约等于 0.0000005。似乎只勉强满足了芯片制造的需求。
但是,
当我们把指数位从8位扩大到11位,尾数位从23位扩大到52位,加上符号位全长64位。这就是双精度浮点数的存储方式了
最大安全数为 2^53 -1 = 9007199254740991
小数精度1 / 2 ^ 53 约等于 0.0000000000000001
网友评论