如果上帝给我32个位 - 深度理解双精度浮点数

上帝给了我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

  1. 将10 转换成二进制 1010.0
  2. 看成 1.01 向右浮动3位


    十进制10在内存中的表示

a. 指数位为10000010,代表右浮动3位
b. 尾数为位01,补上起始1为1.01
可得二进制1010.0, 转十进制得10

0.125

  1. 0.125 转换成二进制 0.001
  2. 看成1.0 向左浮动3位
十进制0.125在内存中的表示

a. 指数位为01111100,代表左浮动3位
b. 尾数为位0,补上起始1为1.0
可得二进制0.001, 转十进制得0.125

更多示例

特殊情况
  1. 指数位全为1,此时如果:
  • 尾数位全为0
    表示无穷大,由符号位决定正负无穷大。
  • 尾数位不全为0
    表示NaN
  1. 指数位全为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

参考文献
THE FLOATING-POINT GUIDE
浮点数的二进制表示

其他
designare-table: 企业级react table组件, 兼容IE11
迅速搭建React源码测试环境
React Proptypes 转 React Typescript 工具

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,816评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,729评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,300评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,780评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,890评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,084评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,151评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,912评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,355评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,666评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,809评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,504评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,150评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,121评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,628评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,724评论 2 351