目录
一、发现问题
二、为什么会出现精度误差
三、精度误差的原因
四、如何解决精度出现误差的情况
1.使用toFixed()
2. 使用库,如decimal.js或bignumber.js
一、发现问题
在项目中总会出现数字需要相加的情况,但发现整数相加没问题,小数相加就出现问题了。
let add1 = 0.1+0.2;
let add2 = 0.11+0.22;
console.log(add1)
console.log(add2)
运行结果:
这结果肉眼可见的不对。
二、为什么会出现精度误差
0.1+0.2打眼一看就是0.3,但结果却是0.30000000000000004。
用if语句判断一下。
if(0.1+0.2==0.3){
console.log('等于')
}else{
console.log('不等于')
}
运行结果:
这是究竟为什么呢?
其实在JavaScript中,计算可能出现误差的原因通常是由于浮点数的精度问题。JavaScript 中的Number类型采用IEEE 754标准来表示浮点数,这个标准定义的是双精度浮点数,它能够表示的数值范围非常广泛,而这个标准在处理一些特别大或特别小的数时会出现舍入错误,所以计算机无法准确表示的小数有 0.1、0.2 或 0.3 这样的数字,因为它使用的是二进制浮点格式。
例如,当你尝试表示分数1/3时,由于3不是2的幂次方,JavaScript 无法精确地用双精度浮点数表示这个数值,结果会有舍入误差。
三、精度误差的原因
在JavaScript中的所有数字,无论是整数还是小数,都是以64位浮点数(double)形式存储。
浮点数的表示包括三部分:
- 符号位(Sign):0表示正数,1表示负数。
- 指数位(Exponent): r用科学计数法表示时的指数部分,即2的幂次方。
- 尾数位(Mantissa): r用科学计数法表示时的尾数部分。
浮点数的计算过程大致为:
- 先将两个浮点数转换成同一个表示形式(即同一个指数)。
- 将两个数的尾数相加。
- 处理可能出现的溢出和下溢情况。
背后的原理
其实在我们日常生活中通常使用10进制来进行计算,我们会发现当10除以2或者5的倍数时才可以被精确的表示,例如1/2、1/4、1/5、1/8 和 1/10等。因为2和5是10的质因数。但是 1/3、1/6 和 1/7 则是无限循环的小数。
同理,在计算机系统中使用的是二进制。只有一个分数使用基数2的质因数来表示时,它才可以被精确地表示,因为2是2的唯一质因数。
当我们尝试表示像 0.1 这样的十进制小数时,计算机会使用一个近似值。这个近似值是通过将无限循环的二进制小数转换为有限位数的浮点数表示来实现的。
因此,当我们在计算机中进行浮点数运算时,结果可能会有微小的误差。
例如,0.1 在二进制中的近似表示可能是 0.000110011001100…,但在计算机的浮点数表示中,它可能被截断或舍入为 0.00011001100110,这就导致了 0.1 + 0.2 在计算机中可能不等于 0.3,而是略微有所偏差。
四、如何解决精度出现误差的情况
1.使用toFixed()
保留小数点后几位
let add1 = 0.1+0.2;
let add2 = 0.11+0.22;
console.log(add1.toFixed(1))
console.log(add2.toFixed(2))
运行结果:
不足之处在于你能知道加的数字小数点后有多少位,不然就会四舍五入或者多出来点。
2. 使用库,如decimal.js或bignumber.js
// 使用npm安装
npm install decimal.js
// 在HTML中引入
<script src="https://cdnjs.cloudflare.com/ajax/libs/decimal.js/10.2.0/decimal.min.js"></script>
// 创建两个Decimal对象
let a = new Decimal('0.1');
let b = new Decimal('0.2');
// 进行加法运算
let sum = a.plus(b);
// 输出结果
console.log(sum.toString()); // 输出: 0.3
运行结果;
自我感觉这个好用。