真假四舍五入?对toFixed重写

业务中需要转换为固定位数,使用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
}
登入分享下感受吧~
未命名
2023-03-22·IP属地厦门市
123
未命名32152
2023-05-18·IP属地厦门市
嗷嗷(・ω・)ノ