toFixed方法详解

最近做的项目涉及到金额的计算,有一种方式就是进行四舍五入的规则进行小数点后面的尾数处理,以前一直以为 toFixed 方法就是四舍五入的,直到测试测出金额计算的 bug 我才如梦初醒,才深究了下 toFixed 这个方法。
toFixed 方法在 IE10 及以上里面是正常的四舍五入,但是别的浏览器里面就不一样了,它不是正常的四舍五入,比如:

1
2
3
4
var a = 1.335;
console.log(a.toFixed(2));
// IE 1.34
//chorme 1.33

其他的浏览器我没去一一测试,所以如果大家用了其他浏览器的还是需要去实际测试一下,我这里就说说 javascript 的 toFixed()方法的四舍五入原理:

toFixed 它是一个四舍六入五成双的诡异的方法,”四舍六入五成双”含义:对于位数很多的近似数,当有效位数确定后,其后面多余的数字应该舍去,只保留有效数字最末一位,这种舍入规则是“四舍六入五成双”,也即“4 舍 6 入 5 凑偶”这里“四”是指 ≤4 时舍去,”六”是指 ≥6 时进上,”五”指的是根据 5 后面的数字来定,当 5 后有数时,舍 5 入 1;当 5 后无有效数字时,需要分两种情况来讲:①5 前为奇数,舍 5 入 1;②5 前为偶数,舍 5 不进。(0 是偶数)

经过我的测试发现,在 chorme 下面(最新版),并没有遵守这个规则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var b = 1.335;
b.toFixed(2);
("1.33");
var b = 1.345;
b.toFixed(2);
("1.34");
var b = 1.355;
b.toFixed(2);
("1.35");
var b = 1.365;
b.toFixed(2);
("1.36");
var b = 1.375;
b.toFixed(2);
("1.38");
var b = 1.385;
b.toFixed(2);
("1.39");

可以发现在 chorme 下没有完全去遵循这个规律,或许它有自己的算法,但是毕竟它没有遵循通用的算法,所以 tofixed 这个方法在涉及到金钱计算的业务中还是少用。

下面再再说说我自己的做法,就是根据精确位数来取小数点后的数,然后判断精确位是大于 4 还是小于等于 4。
我们的业务是最多精确到两位小数,最少就是取整,不留小数。

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
function money(money, len) {
//len是需要精确的位数,如百分位就是2
var result = 0;
//先进行一个千分位的四舍五入,保证0.0999这种情况在保留一位小数的时候能是对的,这一位可以这么做没什么问题
var money = parseFloat(money).toFixed(3);
try {
var Integer = money.split(".")[0], //小数点前的整数
Decimal = money.split(".")[1], //取小数点后面的小数
differ = Decimal[3 - len];
if (differ > 4) {
//五入的情况
if (len == 1) {
Decimal = parseInt(Decimal) + 10 + "";
if (Decimal.length > 3) {
//说明往整数位进1
Integer = parseInt(Integer) + 1 + "";
Decimal = Decimal[1] + Decimal[2];
} else {
Decimal = Decimal[0] + Decimal[1];
}
result = parseFloat(Integer + "." + Decimal);
} else if (len == 2) {
Decimal = parseInt(Decimal) + 100 + "";
if (Decimal.length > 3) {
//说明往整数位进1
Integer = parseInt(Integer) + 1 + "";
Decimal = Decimal[1];
} else {
Decimal = Decimal[0];
}
result = parseFloat(Integer + "." + Decimal);
} else if (len == 3) {
Integer = parseInt(Integer) + 1 + "";
Decimal = 0;
}
result = parseFloat(Integer + "." + Decimal);
} else {
//四舍的情况
if (len == 1) {
Decimal = Decimal[0] + Decimal[1];
} else if (len == 2) {
Decimal = Decimal[0];
} else if (len == 3) {
Decimal = 0;
}
result = parseFloat(Integer + "." + Decimal);
}
} catch (e) {
return parseFloat(money).toFixed(2); //如果过程中有出错就tofixed代替为解决
}
return result;
}