toFixed方法详解
2017-12-13
最近做的项目涉及到金额的计算,有一种方式就是进行四舍五入的规则进行小数点后面的尾数处理,以前一直以为 toFixed 方法就是四舍五入的,直到测试测出金额计算的 bug 我才如梦初醒,才深究了下 toFixed 这个方法。 toFixed 方法在 IE10 及以上里面是正常的四舍五入,但是别的浏览器里面就不一样了,它不是正常的四舍五入,比如:
1 2 3 4 var a = 1.335 ;console .log(a.toFixed(2 ));
其他的浏览器我没去一一测试,所以如果大家用了其他浏览器的还是需要去实际测试一下,我这里就说说 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 ) { var result = 0 ; 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 ) { 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 ) { 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 ); } return result; }