1 概述
浮点数指的是带有小数的数值,浮点运算即是小数的四则运算,常用来测量电脑运算速度。大部份计算机采用二進制(b=2)的表示方法。位(bit)是衡量浮点数所需存储空间的单位,通常为32位或64位,分别被叫作单精度和双精度。
2 误差现象
console.log(0.1+0.2); // 输出 0.30000000000000004
console.log(0.15+0.15); // 输出 0.3
console.log(0.7+0.1); // 输出 0.7999999999999999
console.log(0.6+0.2); // 输出 0.8
console.log(0.3*3); // 输出 0.8999999999999999
console.log(3*3/10); // 输出 0.9
从以上现象可以看出,并不是所有的浮点数运算都会出问题,只是部分。
0.7+0.1 输出有偏差
0.6+0.2 输出正确
具体是什么原因呢,继续向下看。
3 误差原因
不仅仅是JS,大多数语言在处理浮点数的时候都会遇到精度问题,准确的说,所有支持二进制浮点数运算(绝大部分都是 IEEE 754 的实现)的系统都存在这个现象。
其原因就是,在有限的存储空间下,绝大部分的十进制小数都不能用二进制浮点数来精确表示。例如,0.1 这个简单的十进制小数就不能用二进制浮点数来表示。所谓「计算机浮点数」,其实就是二进制的「科学计数法」。在十进制中,科学计数法的形式是:
相应的,二进制的科学计数法就是:
而在有限的存储空间下,十进制小数 0.1 无论如何也不能用这种形式来表示,因此,计算机在存储它时,产生了精度丢失,所以就出现了问题中所描述的现象。
更详细的可以点击链接查看 https://www.zhihu.com/question/20679634
4 解决方案
如何解决呢?看这个例子:
console.log(0.3*3); // 输出 0.8999999999999999
console.log(3*3/10); // 输出 0.9
浮点数计算有问题,整数计算是没问题的,那么将浮点转化成整数运算,之后再切回浮点就可以保证没有偏差了
注:不推荐js做太多的浮点运算。
以下方法可以帮助你修正浮点运算的偏差:
// 浮点数求和
function add(a, b) {
var c, d, e;
try {
c = a.toString().split(".")[1].length;
} catch (f) {
c = 0;
}
try {
d = b.toString().split(".")[1].length;
} catch (f) {
d = 0;
}
return e = Math.pow(10, Math.max(c, d)), (mul(a, e) + mul(b, e)) / e;
}
// 浮点数相减
function sub(a, b) {
var c, d, e;
try {
c = a.toString().split(".")[1].length;
} catch (f) {
c = 0;
}
try {
d = b.toString().split(".")[1].length;
} catch (f) {
d = 0;
}
return e = Math.pow(10, Math.max(c, d)), (mul(a, e) - mul(b, e)) / e;
}
// 浮点数相乘
function mul(a, b) {
var c = 0,
d = a.toString(),
e = b.toString();
try {
c += d.split(".")[1].length;
} catch (f) {}
try {
c += e.split(".")[1].length;
} catch (f) {}
return Number(d.replace(".", "")) * Number(e.replace(".", "")) / Math.pow(10, c);
}
// 浮点数相除
function div(a, b) {
var c, d, e = 0,
f = 0;
try {
e = a.toString().split(".")[1].length;
} catch (g) {}
try {
f = b.toString().split(".")[1].length;
} catch (g) {}
return c = Number(a.toString().replace(".", "")), d = Number(b.toString().replace(".", "")), mul(c / d, Math.pow(10, f - e));
}
验证
console.log(0.1+0.2); // 输出 0.30000000000000004
console.log(add(0.1, 0.2)); // 输出 0.3
console.log(0.7+0.1); // 输出 0.7999999999999999
console.log(add(0.7, 0.1)); // 输出 0.8
console.log(0.3*3); // 输出 0.8999999999999999
console.log(mul(0.3, 3)); // 输出 0.9
博文部分来自知乎和其它博客,感谢!