8 个回答

浮点数运算问题,可以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中,变量在存储时并不区分numberfloat类型,而是统一按float存储。而javascript使用IEEE 754-2008 标准定义的64bit浮点格式存储number
按照IEEE 754的定义
decimal64对应的整形部分长度为10,小数部分长度为16,所以默认的计算结果为“1.7000000000000001”,如最后一个小数为0,则取1作为有效数字标志。
可以自己测试一下,把数字换成相对应的二进制:0.1(十进制) = 0.0001100110011001(二进制) 17(十进制) = 10001(二进制) 相乘运算。

解决方案地址:

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏