JS怎样存储数字

背景:

JS中小数运算和整数运算有时候都不精确,例如经典的例子:

为什么0.1+0.2 !== 0.3,

9007199254740991(最大安全数字,文章末尾有说明)+8===9007199254741000

或者将8改成10计算结果也是这个数,这就是因为计算机是以二进制存储数据所以JS的数字不是以十进制而是以二进制且是以双精度浮点法(IEEE 754)存放,

十进制的小数,转换为二进制后,可能是无限小数(十进制数 0.3 -> 0.010011001100110011001.....),

但是计算机对数字的存储能力有限,二进制小数位过多的数或过大的整数都无法精确表示,因此会丢失一些数据,在上述情况下就会造成精度缺失,具体如下:

数字存储规则:

(在计算机中,位bit是最小的存储单位,简称为bit ,1 byte = 8 bit ,1 KB = 1024 byte ,1 MB = 1024 KB ,1 GB = 1024 MB。)

JS在计算机中,给每个数字开辟一块内存空间,尺寸固定为64位;

64位分为这三段:[1] [2~12] [13~64]

[第1段] [第2段] [第3段]

第1段:1位,表示符号位,如果为1,是负数,如果为0,是正数
第2段:11位,表示指数位,这里的指数是2为底的指数,而不是10
第3段:52位,表示有效数字

举例:

0     1000 0000 011    1111 0000 0000 0000....    相当于: 1.1111∗2^(1027−1023)

中间段为指数位(1000 0000 011)等于1027,指数要减去1023的规则是为了能形成负指数来表示出小数;

特殊情况:

基于这种数字存放方式,有几个特殊情况的规则是:

0

指数为0,尾数为0,表示数字 0

正无穷

符号为0,指数为2047,尾数为0,表示正无穷

Infinity: 0 11111111111 00000000000...
负无穷

符号为1,指数为2047,尾数为0,表示负无穷

-Infinity: 1 11111111111 00000000000...
NaN

指数为2047,尾数不为0,表示NaN

NaN: 1 11111111111 01001010000...

最大数字

所以一个正常的数字,指数部分最多只能是2046,2047是特殊情况,因此这种方式能表示的最大数字为:

0 11111111110 1111111111.........(52个1)    相当于: 1.1111111111...∗2^1023

最大安全数字

但是这个最大数字不是安全数字,因为它前面的整数是不能通过这种方式连续表示出来的(安全数字定义:从1开始到该数字,均是连续的整数,并且该数字的下一个整数是存在的),那么这种方式能表示的最大安全数字是:

0 xxxxx 1111111111....         指数位先待定稍后再推算,有效数字位写满到最大也就是52个1  
相当于: 1.1111111111...∗2^?

十进制逢十进一,二进制逢二进一,十进制9.999...(小数点后n个9)去掉小数点的方式是*10^n,二进制1.111...(小数点后n个1)去掉小数点的方式是*2^n;

于是只要把1.1111111111...(小数点后52个1)的小数点去掉(*2^52)就是最大安全数字2^53−1=9007199254740991

于是文章开始的精度缺失例子:9007199254740991+8===9007199254741000

从数学上是计算错误,但因为正确计算结果9007199254740999无法用JS的存储数字方式表示出来,所以JS的计算结果会是9007199254741000。

  • 19
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值