AndreGeng / AndreGeng.github.io

blog repository
1 stars 0 forks source link

js是怎么存储number的 #19

Open AndreGeng opened 5 years ago

AndreGeng commented 5 years ago

大家肯定都听过javascript中0.1 + 0.2 !== 0.3的“事实”,这里尝试再去解释下这个问题。 首先javascript中number的存储格式是参照IEEE_754, 具体是按照其中的binary64, 或者说是double的精度来存储的。 number一共占用了64位,第一位代表数字的符号,第1~11位是数字的指数,剩下的52位用来存储尾数。如下图所示。 image

尾数的存储

图中可看到尾数的位数有52位,其实它可以存储53位, 因为尾数的第一位默认为1。 e.g. 尾数:0b1 指数: 1, 其实相当于 11Math.pow(2, 1) 那0是如何存储的呢,js中当尾数为0且指数为-1023时代表零,其实它相当于1 Math.pow(2, -1023) ps: 在chrome 71.0.3578.98版本下试了下,发现Math.pow(2, -1075) === 0返回为true, 这。。可能浏览器实现上有差异??

指数的存储

指数共11位,有符号数的取值范围-1023~1024, 其中1024用来代表infinity(尾数等于0)和NaN(尾数大于零),-1023用来代表0

那对于像1/10这样的十进制数,由于分母10可分解因子只有2与5,而5是总是不能分解成2的指数倍的,所以计算机内是不能准确的存储0.1这个小数的,只能存储它的近似值。这和1/3在十进制中只能用小数近似表示是一个道理。 0.1内存中表示为‘11001100110011001100110011001100110011001100110011010’ Math.pow(2, -56) 0.2内存中表示为‘11001100110011001100110011001100110011001100110011010’ Math.pow(2, -55) 0.1 + 0.2的过程中需要进行移位操作。(0b11001100110011001100110011001100110011001100110011010 + 0b110011001100110011001100110011001100110011001100110100) * Math.pow(2, -56), 移位的过程会使误差扩大化,最终导致了0.1 + 0.2 !== 0.3

reference: how numbers are encoded in javascript