toFixed()方法的坑

toFixed()方法的坑
javascript 中 toFixed 使用的是银行家舍入规则

银行家舍入:所谓银行家舍入法,其实质是一种四舍六入五取偶(又称四舍六入五留双)法

简单来说就是:四舍六入五考虑,五后非零就进一,五后为零看奇偶,五前为偶应舍去,五前为奇要进一。

但是不论引入 toFixed 解决浮点数计算精度缺失的问题也好,它有没有使用银行家舍入法也罢,都是为了解决精度的问题,但是又离不开二进制浮点数的环境,但至少他帮助我们找到了问题所在,从而让我们有解决方法。

四舍五入并不是真正的四舍五入

  1. chrome 上的测试结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(1.35).toFixed(1); // 1.4 正确

(1.335).toFixed(2); // 1.33 错误

(1.3335).toFixed(3); // 1.333 错误

(1.33335).toFixed(4); // 1.3334 正确

(1.333335).toFixed(5); // 1.33333 错误

(1.3333335).toFixed(6); // 1.333333 错误

(999.62225).toFixed(4); // 999.6223 正确

(999.62235).toFixed(4); // 999.6223 错误
  1. IE 上的测试结果:
1
2
3
4
5
6
7
8
9
10
11
(1.35).toFixed(1); // 1.4 正确

(1.335).toFixed(2); // 1.34 正确

(1.3335).toFixed(3); // 1.334 正确

(1.33335).toFixed(4); // 1.3334 正确

(1.333335).toFixed(5); // 1.33334 正确

(1.3333335).toFixed(6); // 1.333334 正确

下面是自己封装的格式化数字的方法,此外有一些自己封装的工具类 js工具库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
* 格式化数字
* @param {Number, String} val 需要格式化的数值
* @param {Number} num 小数点保留位数(noZero为true时该字段为最大位数)
* @param {Boolean} noZero 是否去除小数点末尾0
* @param {String} placeholder 不存在时显示的占位符
* @param {Boolean} comma 是否需要千分位
* @returns String
*/
function numF(val, num = 4, noZero = false, placeholder = "--", comma = true) {
if (isNaN(val) || (!val && val !== 0)) return placeholder;
val = Number(val) + "";
var pointInd = val.lastIndexOf(".");
val = val
? pointInd > -1
? Number(val.substring(0, val.lastIndexOf(".") + num + 1))
: Number(val)
: 0;

let commaFormat = comma ? "," : "";
// 整数部分
var intFormat = String(parseInt(val)).replace(
/(\d)(?=(?:\d{3})+$)/g,
"$1" + commaFormat
); // 千分位

// 小数部分
var floatVal = String(Number(val)).split(".")[1] || "";

var floatNum = floatVal || "";
if (!noZero) {
floatNum = floatVal.padEnd(num, 0);
}
return intFormat + (floatNum ? "." + floatNum : "");
}