业务中需要转换为固定位数,使用toFiexd踩坑。
1.585.toFixed(2) // 1.58
银行家舍入法
保留位数的后一位如果是5,而且5后面不再有数,要根据应看尾数“5”的前一位决定是舍去还是进入: 如果是奇数则进入,如果是偶数则舍去。例如5.215保留两位小数为5.22; 5.225保留两位小数为5.22。 ——维基百科
5.215.toFixed(2) // 5.21
1.215.toFixed(2) // 1.22 不符合银行家舍入
可以说toFixed不是银行家舍入法!
Math.round
Math.round()
函数返回一个数字四舍五入后最接近的整数。
function numFixed(number, length) {
return Math.round(Math.pow(10, length) * number) / Math.pow(10, length);
}
console.log(numFixed(5.215,2)) //5.22
// 看起来没问题 我换个数
console.log(numFixed(321405.595, 2)); // 321405.59
由于二进制存储对小数的精度丢失
创建prototype.js 文件对Number.prototype.toFixed进行重写
// 转换为字符串 整数相除
function accDiv(arg1, arg2) {
let t1 = 0
let t2 = 0
try {
t1 = arg1.toString().split('.')[1].length
} catch (e) {}
try {
t2 = arg2.toString().split('.')[1].length
} catch (e) {}
const r1 = Number(arg1.toString().replace('.', ''))
const r2 = Number(arg2.toString().replace('.', ''))
return (r1 / r2) * Math.pow(10, t2 - t1)
}
// 转换为字符串 整数相乘
function accMul(arg1, arg2) {
let m = 0
const s1 = arg1.toString()
const s2 = arg2.toString()
try {
m += s1.split('.')[1].length
} catch (e) {}
try {
m += s2.split('.')[1].length
} catch (e) {}
return (
(Number(s1.replace('.', '')) * Number(s2.replace('.', ''))) /
Math.pow(10, m)
)
}
/* eslint-disable no-extend-native */ // 规避eslint不可修改原型报错
Number.prototype.originalToFixed = Number.prototype.toFixed // 保留原方法
Number.prototype.toFixed = function(length) {
let decLength
const num = Number(this)
const pow = Math.pow(10, length) // 保留缩进位数
const mul = accMul(pow, num) // 放大
let div = accDiv(Math.round(mul), pow) // 使用Math.round对一位小数进行进准的四舍五入,后缩小
try {
decLength = div.toString().split('.')[1].length
} catch (e) {}
for (let i = 0; i < length - decLength; i++) {
div = div.toString() + '0' // 保留指定小数位,后面是0的话补0
}
return div
}