情景复现:
发现用 toFiexd() 四舍五入保留小数有时不是很精确,接下来用 a = 8.0345,b=8.045,举例如下:
var a = 8.035;
console.log(a.toFixed(2)) // 8.04
var b = 8.045;
console.log(b.toFixed(2)) // 8.04
不难看出 a 四舍五入保留两位小数为 8.04,正确;而 b 四舍五入保留两位小数应该为 8.05;
计算精度丢失的原因:
js采用64位浮点数表示法(几乎所有现代编程语言所采用),这是一种二进制表示法。二进制浮点数表示法并不能精确表示类似 0.1 这样简单的数字。
目前这个问题不只在js中才会出现,在任何使用二进制浮点数的编程语言中都会出现。
解决方案:
保留两位小数:
var a = 8.035;
var b = 8.045;
function number(data){
var value = Math.round(parseFloat(data) * 100) / 100;
var d = value.toString().split(".");
if (d.length == 1) {
value = value.toString() + ".00";
return value;
}
if (d.length > 1) {
if (d[1].length < 2) {
console.log(d[1])
value = value.toString() + "0";
}
return value;
}
}
console.log(number(a)); // 8.04
console.log(number(b)); // 8.05
自定义封装:
方案一: 使用 big.js(如果有大量连续的计算推荐使用)
- 既解决了浮点数计算精度丢失问题,又解决了 toFixed() 四舍五入精度丢失问题。
big.js
是big.js
,bignumber.js
,decimal.js
三姐妹中功能最少的,但也是体积最小的,压缩版只有3k
,对于处理js精度丢失已经足够用了。
import Big from 'big.js'
// 运算
const plus = Big(0.1).plus(0.2); // 加
const minus = Big(0.3).minus(0.1); // 减
const mul = Big(10.22).times(100); // 乘
const div = Big(2.4).div(0.8); // 除
// toFixed
const fixed = new Big(6.265).toFixed(2); // 6.27
console.log(
plus.toNumber(),
minus.toNumber(),
mul.toNumber(),
div.toNumber()
)
// 0.3 0.2 1022 3
方案二:有具体要求精确到第几位,用科学计数法
对运算结果进行四舍五入
function round(number, precision) {
return Math.round(+number + 'e' + precision) / Math.pow(10, precision);
}
round(8.1234567, 5); // 8.12346
或者:
function number(data,n){
var numbers = '';
// 保留几位小数后面添加几个0
for (var i = 0; i < n; i++) {
numbers += '0';
}
var s = 1 + numbers;
// 如果是整数需要添加后面的0
var spot = "." + numbers;
// Math.round四舍五入
// parseFloat() 函数可解析一个字符串,并返回一个浮点数。
var value = Math.round(parseFloat(data) * s) / s;
// 从小数点后面进行分割
var d = value.toString().split(".");
if (d.length == 1) {
value = value.toString() + spot;
return value;
}
if (d.length > 1) {
if (d[1].length < 2) {
value = value.toString() + "0";
}
return value;
}
}
// 例如:8.1235678 保留五位小数
number(8.12356,5);