先抛出几个问题
git
接下来就以这三个问题为目的来梳理一下前因后果。
github
首先在开始以前须要了解一下JavaScript的number类型在计算机中是如何存储的,这也是一切问题的基础。JavaScript的数字都是number类型的,不论是整数仍是浮点数都以IEEE754双精度的格式存储在计算机中,什么是双精度呢?就是以64个bit位来存储,具体的存储格式是:
浏览器
分别是1个符号位+11个指数位+52个尾数位
安全
举个例子,若是是5.5这个数字的话,则计算过程是这样的:
5.5 转二进制 =====> 101.1 科学计数法 =====> 1.011*2^2
存入计算机:
符号位:0
指数位:2 加1023 =====> 1025 转二进制 =====> 10000000001
尾数位:1.011 隐去小数点左边的1 =====> 011
存入计算机,以下图,截图来自IEEE754可视化,感兴趣能够把玩一下
测试
在浏览器控制台能够测试一下结果:
debug
0.1 转二进制 =====> 0.0001100110011001100...(1100循环)
转科学计数法 =====> 1.100110011...(1100循环) *2^-4
数据是无限循环的,可是可供使用的尾数位倒是有限的,只有52位可使用,因此在第53位会被舍去而且进位
最终在计算机中存储以下图:
3d
相似的0.2在计算机中的存储以下图:
orm
因此最终的计算就是:
cdn
0.00011001100110011001100110011001100110011001100110011010 + 0.0011001100110011001100110011001100110011001100110011010 = 0.0100110011001100110011001100110011001100110011001100111
能够看出来其实0.1是截断了一部分精度后获得的结果,那么这个问题就能够转化为:双精度浮点数是按什么规则来截断的呢?
blog
在双精度浮点数的英文wiki中能够找到中能够找到这么一段话:
大意是:若是一个 IEEE 754 的双精度浮点数被转成至少含17位有效数字的十进制数字字符串,当这个字符串转回双精度浮点数时,必需要跟原来的数相同;换句话说,若是一个双精度的浮点数转为十进制的数字时,只要它转回来的双精度浮点数不变,精度取最短的那个就行。
很明显1.005只是一个被截断后的数字,它的双精度浮点数表明的20位精度的数字是1.0049999999999998934,因此进行保留2位的四舍五入时,2位后的数字会被所有舍去。
为何最大安全整数是2^53-1?前面说到了JavaScript浮点数存储是52位尾数位,可是由于科学计数法小数点左侧的1会在存储时省去,因此52位尾数+省去的1位=53个可表示的位数。
2^53 转二进制 =====> 100000000000000000000000000000000000000000000000000000(53个0)
转为科学计数法 =====> 1.00000000000000000000000000000000000000000000000000000(53个0)*2^53
存入计算机 =====> 尾数位只有52位因此截掉末尾的0只能存52个0
2^53+1 转二进制 =====> 100000000000000000000000000000000000000000000000000001(52个0)
转为科学计数法 =====> 1.00000000000000000000000000000000000000000000000000001(52个0)
存入计算机 =====> 尾数位只有52位因此截掉末尾的1只能存52个0