解决浮点数运算误差

解决什么问题

前端计算产生的精度误差

1
2
console.log(0.14 * 100);
// log 14.000000000000002

解决方案

不推荐 toFixed()

1
2
console.log(100.toFixed(2)); // 100.00
console.log((0.105).toFixed(2)); // 0.10 与预期不符

这种方法大部分场合都适用,但是存在尾数是 5 的时候会不进位的问题。

不推荐 Math.round()

1
2
3
console.log(Math.round(100 * 100) / 100); //100
console.log(Math.round(100.0 * 100) / 100); //100
console.log(Math.round(100.01 * 100) / 100); //100.01

这种方法存在当数字是整数或者小数点后数字为 0,或者原数字长度比我们要保留的长度短时,保留有问题的情况。

推荐 自己封装

1
2
3
4
5
6
7
8
9
10
11
/**
* @description 四舍五入保留指定小数
* @param {Number} n 数字
* @param {Number} r 保留位数
*/
function preciseRound(n, r = 2) {
let int = Math.floor(n).toString();
if (typeof n !== 'number' || typeof r !== 'number') return 'Not a Number';
if (int[0] == '-' || int[0] == '+') int = int.slice(int[1], int.length);
return n.toPrecision(int.length + r);
}

其他

四舍五入格式化金额

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* 将数值四舍五入(保留2位小数)后格式化成金额形式
*
* @param num 数值(Number或者String)
* @return 金额格式的字符串,如'1,234,567.45'
* @type String
*/
function formatCurrency(num) {
num = num.toString().replace(/\$|\,/g, '');
if (isNaN(num)) num = '0';
const sign = num == (num = Math.abs(num));
num = Math.floor(num * 100 + 0.50000000001);
let cents = num % 100;
num = Math.floor(num / 100).toString();
if (cents < 10) cents = '0' + cents;
for (var i = 0; i < Math.floor((num.length - (1 + i)) / 3); i++)
num =
num.substring(0, num.length - (4 * i + 3)) +
',' +
num.substring(num.length - (4 * i + 3));
return (sign ? '' : '-') + num + '.' + cents;
}