我们不防用js计算一下下列的代码,看看浏览器弹出的结果
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
</body>
<script>
var x = 0.1;
var y = 0.2;
var z= x+y;
alert(z); //弹出结果z
</script>
</html>
下面是运算结果
可以看到结果并不是我们想要的0.3,而是一个稍微带一些误差的小数,为什么会出现这种情况呢
我们知道计算机因为内部的构造原因(集成电路的引脚大多只有两种电平状态),数据都最终会转换为二进制进行计算,十进制小数是转换为二进制时,将小数部分除以2取整数部分再将小数部分除以2,循环下去,下面是我列的一些十进制小数和二进制之间的转换
二进制在前 十进制灾后
二进制 | 十进制 |
---|---|
0.001 | 0.125 |
0.0001 | 0.0625 |
0.00000000000000001 | 0.00000762939453125 |
0.000 | 0 |
大家可以看到js小数点后最多显示了17位小数,那么0到0.00000762939453125之间的十进制数就无法表示,这里就会产生误差
那么十进制转二进制呢
十进制 | 二进制 |
---|---|
0.1 | 0.0001100110011001100110011001100110011001100110011001101… |
0.2 | 0.001100110011001100110011001100110011001100110011001101… |
0.3 | 0.0100110011001100110011001100110011001100110011001101… |
0.4 | 0.01100110011001100110011001100110011001100110011001101… |
0.5 | 0.1 |
我们可以看到十进制转换为二进制时例如0.1不会精确的转换为一个准确的二进制值,这也是误差所在
所以你在js中让0.1和0.2相加时,对应的数据转化为二进制出现了误差,二进制转十进制又可能造成一次误差,结果就并不完美。
如何解决这个问题呢
1.使用toFixed(n) (n是四舍五入保留几位小数)
我想最简单的方式就是给结果一个精度,js的toFixed(n)方法可以简单的设置精度,例如将上面的代码其中一段进行更改
var x = 0.1;
var y = 0.2;
var z= x+y;
alert(z.toFixed(2));
结果如下
得到了你想要的精度。
2.小数点移位后计算
如果说先要不设置精度直接得到0.3这个结果,还有一种方法
就是将做运算的两个数的小数点同时向右移动最大小数的位数,例如1.111和0.1相加时,两个数小数点同时向右移动三位,转换为1111+100=1211,再移动回来得到1.211,当然这只是个例子,你可以用这种方法计算0.1+0.2,具体的实现代码如果有必要,我会之后再发一次。