请看sf上的这篇回答https://segmentfault.com/q/10...
http://madscript.com/javascri...
浮点数运算问题,可以google js 0.1+0.2 !=0.3 有很多文章
IEEE754规范导致的,不仅javasxcript这样,其他语言也有这种情况。对于2的倍数可以无损的表示,对于其他的就无力了。。。
因为浮点数是以二进制来存储的,而用二进制表示十进制是不能精确表示的,即使浮点数的十进制有效数字比较少,那也不一定能用二进制精确表示。为什么呢?首先浮点数小数位的二进制是这样对应的:小数后1位:0.5 (2^-1)小数后2位:0.25 (2^-2)...小数位n位:2^-n也就是说,任何一个浮点数的小数部分都是由2^-1 ... 2^-n组合而成的,这样就能理解为什么有效位数少的浮点数也不能精确表示了,比如0.1,就无法用上面的位数组合而精确表示出来,不信把浮点数所有位数输出来试试:
(0.1).toFixed(20)
输出:'0.10000000000000000555'而如果把0.1换成0.5,那就可以精确表示了,因为0.5可以用2^-1精确表示啊!同理,0.625也可以。那我们平时为什么可以直接输出0.3呢?那是因为JavaScript输出的时候默认做了舍入处理。
回到问题,把0.1*17的全部精度输出来:
(0.1*17).toFixed(20)
输出:'1.70000000000000017764'很明显是做了舍入了。那为什么0.1*13不会产生这样的现象呢?
(0.1*13).toFixed(20)
输出:'1.30000000000000004441'对比一下就可以发现后面的有效数字比0.1*17少一位,舍入成0了。
数字在计算机中是十进制是以二进制存储的。十进制中的有限不循环小数,在二进制中可能为无限循环小数0.1(十进制) = 0.0001100110011001...(二进制)17(十进制) = 10001(二进制)计算机的计算结果也就是0.0001100110011001 * 10001(二进制)=1.1011001100110011(二进制) = 1.6999969482421875(十进制)
其实这是js作浮点运算的一个bug。在JavsScript中,变量在存储时并不区分number和float类型,而是统一按float存储。而javascript使用IEEE 754-2008 标准定义的64bit浮点格式存储number。按照IEEE 754的定义:decimal64对应的整形部分长度为10,小数部分长度为16,所以默认的计算结果为“1.7000000000000001”,如最后一个小数为0,则取1作为有效数字标志。可以自己测试一下,把数字换成相对应的二进制:0.1(十进制) = 0.0001100110011001(二进制) 17(十进制) = 10001(二进制) 相乘运算。
js
bug
JavsScript
number
float
javascript
IEEE 754-2008
64bit
decimal64
解决方案地址:
解决办法:解决办法
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
暂无简介
文章 0 评论 0
接受
发布评论
评论(8)
请看sf上的这篇回答https://segmentfault.com/q/10...
http://madscript.com/javascri...
浮点数运算问题,可以google js 0.1+0.2 !=0.3 有很多文章
IEEE754规范导致的,不仅javasxcript这样,其他语言也有这种情况。对于2的倍数可以无损的表示,对于其他的就无力了。。。
因为浮点数是以二进制来存储的,而用二进制表示十进制是不能精确表示的,即使浮点数的十进制有效数字比较少,那也不一定能用二进制精确表示。为什么呢?
首先浮点数小数位的二进制是这样对应的:
小数后1位:0.5 (2^-1)
小数后2位:0.25 (2^-2)
...
小数位n位:2^-n
也就是说,任何一个浮点数的小数部分都是由2^-1 ... 2^-n组合而成的,这样就能理解为什么有效位数少的浮点数也不能精确表示了,比如0.1,就无法用上面的位数组合而精确表示出来,不信把浮点数所有位数输出来试试:
输出:'0.10000000000000000555'
而如果把0.1换成0.5,那就可以精确表示了,因为0.5可以用2^-1精确表示啊!同理,0.625也可以。
那我们平时为什么可以直接输出0.3呢?那是因为JavaScript输出的时候默认做了舍入处理。
回到问题,把0.1*17的全部精度输出来:
输出:'1.70000000000000017764'
很明显是做了舍入了。
那为什么0.1*13不会产生这样的现象呢?
输出:'1.30000000000000004441'
对比一下就可以发现后面的有效数字比0.1*17少一位,舍入成0了。
数字在计算机中是十进制是以二进制存储的。
十进制中的有限不循环小数,在二进制中可能为无限循环小数
0.1(十进制) = 0.0001100110011001...(二进制)
17(十进制) = 10001(二进制)
计算机的计算结果也就是0.0001100110011001 * 10001(二进制)=1.1011001100110011(二进制) = 1.6999969482421875(十进制)
其实这是
js
作浮点运算的一个bug
。在
JavsScript
中,变量在存储时并不区分number
和float
类型,而是统一按float
存储。而javascript
使用IEEE 754-2008
标准定义的64bit
浮点格式存储number
。按照IEEE 754的定义:
decimal64
对应的整形部分长度为10,小数部分长度为16,所以默认的计算结果为“1.7000000000000001”,如最后一个小数为0,则取1作为有效数字标志。可以自己测试一下,把数字换成相对应的二进制:0.1(十进制) = 0.0001100110011001(二进制) 17(十进制) = 10001(二进制) 相乘运算。
解决方案地址:
解决办法:解决办法