本文主要是介绍浮点数精度丢失问题,为什么 (0.1+0.2)!=0.3,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
所有的编程语言中都存在浮点数精度丢失问题.
例如在 js php c语言中(所有的语言中都一样)
(0.1+0.2)==0.3 返回 false
原因
参数的关键是是计算机为了方便电路运算采用iee754方案存储浮点数
例如 0.2 转换为科学计数为 2×10^-1
存储在计算机中(分为三部分),下面数据中的所有数据 均需要把 10进制的科学计数转为 2进制科学计数
sign | exponent | 有效数字 |
正负符号 | 指数 | 有效数字 |
产生精度丢失的关键原因就是:
计算机为了方便电路计算,采用如下转换方式
十进制小数到二进制小数一般是整数部分除 2 取余,逆序排列,小数部分使用乘 2 取整数位,顺序排列。二进制小数到十进制小数还是使用按权相加法。
例如:
// 二进制到十进制
10.01 = 1 * 2^-2 + 0 * 2^-1 + 0 * 2^0 + 1 * 2^1 = 2.25// 十进制到二进制
// 整数部分
2 / 2 = 1 .... 0
1 / 2 = 0 .... 1
// 小数部分
0.25 * 2 = 0.5 得到整数 0
0.5 * 2 = 1 得到整数 1
// 结果 10.01
我们来看
2.1 转为为 二进制的过程
2.1 分成两部分
// 整数部分
2 / 2 = 1 .... 0
1 / 2 = 0 .... 1// 小数部分
0.1 * 2 = 0.2 得到整数 0
0.2 * 2 = 0.4 得到整数 0
0.4 * 2 = 0.8 得到整数 0
0.8 * 2 = 1.6 得到整数 1
0.6 * 2 = 1.2 得到整数 1
0.2 * 2 = 0.4 得到整数 0
0.4 * 2 = 0.8 得到整数 0
0.8 * 2 = 1.6 得到整数 1
0.6 * 2 = 1.2 得到整数 1
0.2 * 2 = 0.4 得到整数 0
0.4 * 2 = 0.8 得到整数 0
0.8 * 2 = 1.6 得到整数 1
0.6 * 2 = 1.2 得到整数 1
...
最终二进制就是 落入无限循环结果为 10.00011 0011 0011........
0.1的二进制就是 0.00011 0011 0011........
0.2转为为二进制过程
0.2
//整数部分0
小数部分
0.2 * 2 = 0.4 得到整数 0
0.4 * 2 = 0.8 得到整数 0
0.8 * 2 = 1.6 得到整数 1
0.6 * 2 = 1.2 得到整数 1
0.2 * 2 = 0.4 得到整数 0
...
结果为 0.0011 0011.... 循环
0.3
//整数部分0
小数部分
0.3 * 2 = 0.6 得到整数 0
0.6 * 2 = 1.2 得到整数 1
0.2 * 2 = 0.4 得到整数 0
0.4 * 2 = 0.8 得到整数 0
0.8 * 2 = 1.6 得到整数 1
0.6 * 2 = 1.2 得到整数 1
...
结果为 0.01 0011 0011... 循环
十进制 | 二进制 |
0.1 | 0.00011 0011 0011........ |
0.2 | 0.0011 0011.... |
0.3 | 0.01 0011 0011... |
0.1 0.2 0.3转为二进制的时候都是 无限循环小数,而实际计算机存储的时候只能保存一定的小数位数(舍弃后面的,从而产生了精度丢失的问题)
这样就产生了 (0.1+0.2) != 0.3
解决方案
1.转为整数运算(根据需要的精度)
parseInt(0.1*10+0.2*10) === parseInt(0.3*10)
2.转为字符串,很多三方 大数运算库用的就是这个方案(性能差)
3.使用 BCD 码存储和运算二进制小数,bcd使用4位二进制表示一个十进制,运算方式同字符串一样 需要一位一位的取出来运算
这篇关于浮点数精度丢失问题,为什么 (0.1+0.2)!=0.3的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!