You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
6.1.6
The Number Type*
The Number type has exactly 18437736874454810627 (that is, ) values, representing the double-precision 64-bit format IEEE 754-2008 values as specified in the IEEE Standard for Binary Floating-Point Arithmetic, except that the 9007199254740990 (that is, ) distinct “Not-a-Number” values of the IEEE Standard are represented in ECMAScript as a single special value.
如果你看不懂这句话,仔细阅读本篇博客就对了!
首先看下10进制转换为2进制的方法。
数字逻辑电路上的算法是 (0.1)10 = (0.0)2。
吐槽一句,大二的专业课数字逻辑电路终于用在工作上了。
0.1*2 = 0.2 ,整数位为0,且精度只到十分位,因此是0.0。
如果是不限精度的话,转换后的二进制数应该是:0.000110011001100110011(0011)无限循环。
如果表示成一个奇怪的形式,则是
(-1)^0*1.100110011(0011)* 2^-4
上述式子可类比十进制科学计数法公式。
0.0001234567 = 1.234567 * 10^-4
为什么要这样表示?
-1的0次幂又是什么意思?
这是国际标准组织IEEE754对于浮点数表示方式的一种定义。
格式为;
因此才有了下面的形式:
对应的0.2为:
那么这和javascript有什么关系呢?
因为IEEE754标准里,还有两种特殊的定义。
IEEE 754规定,对于32位的浮点数,最高的1位是符号位S,接着的8位是指数E,剩下的23位为有效数字M。
对于64位的浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。
问题还是一样,这和我们的javascript有什么关系呢?
因为javascript中Number类型,就是严格按照IEEE754标准来定义的。下面给出了最新版的ecma-262版本中关于Number类型的定义。
再看一下wiki百科给出的IEEE754标准:
因此,javascript的Number类型, 最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。
拿0.1举例来说:
(-1)^0*1.100110011(无限循环0011) * 2^-4
S = 0,M = 1.100110011(无限循环0011),E =-4
这里的无限循环就有限了,循环位数最多只能有52位.
JS中的0.1,在引擎中运算时,实质上会编译成:
1.1001100110011001100110011001100110011001100110011001*2^-4
0.2同理,会编译成:
1.1001100110011001100110011001100110011001100110011001*2^- 3
拿出关键的指数部分和有效位部分:
①式转化为纯小数,小数最低位的1001被高位的0000挤出有效范围,得到③式
②式转化为纯小数,小数最低位的001被高位的000挤出有效范围,得到④式
原因是什么?
原因就是JS中的Number类型,二进制小数的有效位数只有52位,从0到51位(包括边界)。
在chrome控制台输入
(0.1).toString('2')
并打印结果为:"0.0001100110011001100110011001100110011001100110011001101"
不多不少,小数部分刚好52位,与规范以及我们的猜想完全契合。
回到0.1+0.2===0.30000000000000004这个经典问题。
在EcmaScript中,无关Browser环境,还是Nodejs环境,0.1+0.2的实际计算过程如下:
最后得到的⑤式其实0.300000000000000004(17位十进制数)的二进制形式。
这就是0.1+0.2 ===0.300000000000000004的原因。
虽然我们期望的理想结果是返回0.3,恰恰印证了现实往往很骨感的说法。
有没有让0.1+02返回为0.3的办法呢?
因为不只是这一个精度丢失特例,还有很多情况都会造成精度丢失,比如:
0.3 / 0.1===2.9999999999999996以及0.7 * 180==125.99999999998等等。
那么有没有办法解决这个问题呢?
移步下一篇博客:如何解决0.1 +0.2===0.30000000000000004类问题
鸣谢单位:
https://segmentfault.com/a/1190000005022170
http://demon.tw/copy-paste/javascript-precision.html
http://www.ruanyifeng.com/blog/2010/06/ieee_floating-point_representation.html
http://www.css88.com/archives/7340#more-7340
http://www.ecma-international.org/ecma-262/8.0/index.html
https://en.wikipedia.org/wiki/Floating-point_arithmetic#Internal_representation
The text was updated successfully, but these errors were encountered: