评论

javascript浮点数存储计算

javascript浮点数存储计算

双精度数的存储方法

js中不区分整数和浮点数,统一按双精度浮点数存储(就是c++里的double)。使用64位固定长度

  • 符号位S : 第一位 表示正负,0正
  • 指数位E: 中间的11位
  • 尾数位M:后面的52位

公式遵循科学计数法规范,十进制中M∈(0,10) 二进制就(0,2),所以M的整数部分只能是1,可以舍去省下一位。 那么4.5 二进制100.1 科学计数法位 1.001*2^2 则s=0,m=001,e= 2(e的二进制表示下面解释一下)。

指数有正负,E表示的二进制在(0-2^11)之间 因此就就取中间值 1023 为 0 。 1024 则为1,1022为-1。

大数溢出的问题

可以看出来M只有52位,所以一直到2^52 -1 都不会有溢出,即 1.111(.后52个1)*2^52。

然后+1成2^53, 其实M位已经开始溢出了一位0,1.00(.后52个0)*2^53 。 但是因为进位后舍弃的是0,并未影响2^53的准确度。 这时候就比较明朗了,2^53+1 最后的一位1依然被舍弃, 所以 2^53+1= 2^53。 2^53+2 则又正常。

可以得出个规律:

  • (2^53, 2^54)之间的数 每两个精确一个,而且是只有偶数可以精确
  • (2^54, 2^55)之间的数 每4个精确一个,而且是只有4的倍数可以精确
  • …… 以2的更高次幂的继续跳

浮点误差

0.1===0.10000000000000001
//true

0.1===0.1000000000000001
//false

0.1 转换为二进制后,0.00011001100……本身就是无限循环的。这个例子其实还是受限于M的位数, 2^53 约等于10^16. 所以0.1000000000000001十六位的时候仍然正确判断,十七位就溢出 认为他们相等了。

0.1+0.2
//0.30000000000000004
// 0.1 和 0.2 都转化成二进制后再进行运算
0.00011001100110011001100110011001100110011001100110011010 +
0.0011001100110011001100110011001100110011001100110011010 =
0.0100110011001100110011001100110011001100110011001100111

// 转成十进制正好是 0.30000000000000004

上面讲到0.1转为二进制后,0.00011001100……是1100无限循环,而js只能有53位的尾数存储,所以其实存储的0.1 是接近0.1000000000000000055511的数

那么 为什么会出现下面的情况

0.1
//0.1

其实就是第一个例子下讲到的2^53 约等于10^16,所以以十进制表示的时候,最多就16位,多余的部分就舍去。

0.1.toPrecision(22)
//0.1000000000000000055511
点赞 2
收藏
评论

1 个评论

  • 陈嘉涵
    陈嘉涵
    2019-04-02

    赞~

    2019-04-02
    赞同
    回复
登录 后发表内容