看过我上篇文章点击跳转到文章应该知道toFixed到底有多坑,下面就来真正实现银行家舍入算法,有详细注释:
function bankerRound (number, size) {
// abs代表结果的正(1)负(-1)
let abs = 1
if (number < 0) abs = -1
// 为便于计算,将number转为整数,最后返回时再加符号
number = Math.abs(number)
// numArr为分割小数点的数组,即整数部分和小数部分
const numArr = number.toString().split('.')
const factor = Math.pow(10, size)
// 如果有小数部分,并且小数部分的长度大于要保留的位数
if (numArr.length === 2 && numArr[1].length > size) {
// 下面是判断保留位数的后一位是否为5,
// 5后非零就进一,5后为零看奇偶,5前为偶应舍去,5前为奇要进一
if (numArr[1].substring(size, size + 1) === '5') {
// sizeChar为5前一位,如1.8845保留3位,则sizeChar为4
let sizeChar = numArr[1].substring(size - 1, size);
// 如果size为0,则需要取个位
if (size === 0) {
sizeChar = numArr[0].slice(-1);
}
if (!checkIsZero(numArr[1], size)) {
// 5后非零就进一
return ((Math.round(number * factor) / factor) * abs).toFixed(size)
} else if (Number(sizeChar) % 2 === 0) {
// 5前为偶应舍去
return ((Math.trunc(number * factor) * abs) / factor).toString()
} else {
// 5前为奇要进一
return (((Math.trunc(number * factor) + 1) * abs) / factor).toString()
}
} else {
// 不为5,直接按照四舍五入进位
return ((Math.round(number * factor) / factor) * abs).toFixed(size)
}
} else {
// 如果没有小数部分,或者小数部分的长度小于等于要保留的位数,则只需要补0就行了
return (number * abs).toFixed(size)
}
}
function checkIsZero (numStr, size) {
for (let i = size + 1; i < numStr.length; i++) {
if (numStr[i] !== '0') {
return false
}
}
return true
}
// 下面是我贴心的准备了一些验证的数据
// 如果没有小数部分,或者小数部分的长度小于等于要保留的位数
console.log(bankerRound(2.25, 3));
console.log(bankerRound(-2.25, 3));
console.log(bankerRound(2, 3));
console.log(bankerRound(-2, 3));
// 如果有小数部分,并且小数部分的长度大于要保留的位数
console.log(bankerRound(2.55, 0));
console.log(bankerRound(-2.55, 0));
console.log(bankerRound(3.5, 0));
console.log(bankerRound(-3.5, 0));
console.log(bankerRound(2.5455, 2));
console.log(bankerRound(-2.5455, 2));
console.log(bankerRound(3.1875000, 3));
console.log(bankerRound(-3.1875000, 3));
console.log(bankerRound(3.1865000, 3));
console.log(bankerRound(-3.1865000, 3));
console.log(bankerRound(3.1865000, 2));
console.log(bankerRound(-3.1865000, 2));
console.log(bankerRound(3.1845000, 2));
console.log(bankerRound(-3.1845000, 2));
<----------------------------------------------------2023/12/7更新---------------------------------------------------------->
今天使用公司一个输入框组件时,意外发现这个组件自带一个四舍五入,(是真正意义上的四舍五入),就去看了组件源码,发现是使用BigNamber实现的,下面就对这个实现“银行家舍入”和“四舍五入”方法:
// 安装
npm install bignumber.js
// vue中引入
import BigNumber from "bignumber.js";
// methods
//银行家舍入
bigRound1(num, size) {
let bn = new BigNumber(num);
return bn.toFormat(size, BigNumber.ROUND_HALF_EVEN);
}
// 四舍五入
bigRound2(num, size) {
let bn = new BigNumber(num);
return bn.toFormat(size, BigNumber.ROUND_HALF_UP);
}
已更新到公司知识库