最近在做一个财务项目,这个项目的金额计算需要用到四舍六入五留双,然后去百度了一下,发现js语言自带的 toFixed 的算法就是四舍六入五留双,然后就高高兴兴的拿来用了,直到过了一段时间,测试那边报bug,金额汇总的时候 会有几分钱的差值
一开始我还以为是后端的问题,就没看,直到后端那边说是前端传的金额有问题,我才屁颠屁颠的检查代码,在检查了九九八十一天之后,最终才发现是toFixed 计算的问题,具体问题我举个例子:
比如我计算单价乘数量 9.673 * 5 ,金额应该是48.365 四舍六入五留双后应该是48.36才对 但是toFixed之后却是48.37,具体你们可以打开控制台浏览器看下试下,但是你用48.565 去toFixed 他又是对的给你48.56,但但是你用48.765又是错了返回48.77 ???????
项目很多地方都是用的toFixed 方法去格式化,现在封装方法一个个去改太麻烦了,只能去修改Number原型的toFixed方法了,具体修改代码如下:
/** 重写toFixed 方法实现 四舍六入五成双 */
Number.prototype.toFixed = function (digits) {
if (typeof digits !== 'number' || digits < 0 || !Number.isInteger(digits)) {
throw new Error('toFixed() digits argument must be a non-negative integer');
}
const multiplier = Math.pow(10, digits);
const value = (this as number) * multiplier;
const epsilon = 1e-8; // 定义一个足够小的误差范围来解决浮点数精度问题
let adjustedValue = Math.floor(value + epsilon);
const decimalPart = value - adjustedValue;
// 使用epsilon来调整判断条件,避免直接比较带来的精度问题
if (decimalPart > 0.5 + epsilon || (decimalPart >= 0.5 - epsilon && adjustedValue % 2 !== 0)) {
adjustedValue += 1;
}
let result = (adjustedValue / multiplier).toString();
// 确保结果有正确的小数位数
if (result.indexOf('.') === -1) {
result += '.';
}
while (result.split('.')[1].length < digits) {
result += '0';
}
return result;
};
注:初步封装,未经测试,有问题自行修改解决