我们前端在做计算过程中,特别时小数的计算,都会遇到意想不到的结果,通常我们在价格的计算中遇到很多问题,这是由于 JS 中的 Number 类型是一个浮点类型。
Nubmer 类型
我们先看看 JS 中的 Number 类型。它并不像其它的语言有不同的数字类型,例如:整型、长整型、浮点类型等等,定义不同的数字类型存储的空间也不一样。然而 JS 中的 Number 类型都是浮点类型并且存储空间为 8 数节(byte)(8*8 bit位)。其中Number 类型值的整数最多15位,小数最多17位。
注:1byte=8bit,1kb=1024byte,1mb=1024kb
精度问题
JS 中的 Number 是一个双精度浮点类型,双精度浮点类型在 64 位存储空间中的内容如下:
todo:
1位 | 11位 | 52位 |
---|---|---|
符号位 | 指数位 | 小数位 |
0表示正,1表示负 | -1022~+1023 | 任意 |
由于计算机在计算的过程中,会把十进制数字先转换成二进制,然后做运算,因为浮点类型的小数位的限制而截断了运算完的二进制,这时候再把它转换成了十进制就产生了精度的问题。
举个例子:
0.1 + 0.2 = ?
- 0.1 转换成二进制:0.000110011001100110....
- 0.2 转换成二进制:0.001100110011001100....
- 0.000110011001100110.... + 0.001100110011001100.... = 0.0100110011001100110011001100110011001100110011001100...还很多,如果超过了 52 位就截断了。
- 然后转换成十进制:0.30000000000000004
如何解决精度问题
简单的四舍五入
通过简单的四舍五入可以解决一些问题。
(0.1 + 0.2).toFixed(1);//0.3
换算成整型计算
当然这种四舍五入的方式明显是经不起考验的。彻底消除运算过程中的精度,需要将所有数字升位转化为整型了再做计算,计算完毕后再将最终结果进行相应的降位处理。
function add(num1, num2) {
var p1 = 0;
var p2 = 0;
if (num1.toString().split('.').length > 1) {
p1 = num1.toString().split('.')[1].length;
}
if (num2.toString().split('.').length > 1) {
p2 = num2.toString().split(".")[1].length;
}
var p = p1 > p2 ? p1 : p2;
var n1 = num1 * Math.pow(10, p);
var n2 = num2 * Math.pow(10, p);
var result = (n1 + n2) / Math.pow(10, p);
return result;
}
add(0.1, 0.2);//0.3
网友评论