toFixed()计算财务金额导致了四舍五入不正确,该怎么解决?

写了一个计算金额的需求,用了toFixed()保留两位小数,但是测出来一个bug,就是当四舍五入的时候,没有进位,比如19.775计算成了19.77,但应该是19.78的。 针对这个问题我查了一下,找到了一个更好的方法,就是用字符串的方式转成小数,绕过四舍五入的陷阱。

之前使用了toFixed的计算方法:

let value = 19.775;
const result = parseFloat((Math.round(value*100)/100).toFixed(2));// 四舍五入

更正后的计算方法:

let value = 19.775;
const factor = Math.pow(10, 2); // 通过字符串运算避免浮点精度问题
const result = Math.round(Number(value+ 'e' + 2)) / factor; // 四舍五入
步骤分解:
1. 数值转字符串拼接:19.775 + 'e' + 2"19.775e2"
2. 科学计数法转数值:Number("19.775e2") = 1977.5 // 精确的十进制转换
3. 四舍五入:Math.round(1977.5) = 1978 // 正确结果
4. 缩小回原比例:1978 / 100 = 19.78
绕过二进制转换:直接通过字符串操作保持十进制精度。
科学计数法的优势:"19.775e2" 等效于数学上的 19.775×10的平方 ,但避免了直接计算时的二进制舍入误差。

总结
对比直接运算和字符串运算的区别:

方法 步骤分解 结果
直接运算 19.775 * 100 → 1977.4999999999998 19.77(错误)
字符串拼接 'e' Number("19.775e2") → 1977.5 19.78(正确)

按照19.775举例:
需要解释IEEE 754标准导致的问题,比如0.1这样的数无法精确表示。在处理小数的时候,直接运算可能会有误差,比如19.775在二进制中可能无法准确存储,导致乘100后变成1977.4999999999998,这样Math.round就会得到1977而不是1978,最后除以100得到19.77而不是正确的19.78。

更正后的计算方式是:
将数字转换为字符串,加上指数,然后转换成数字,这样可以绕过直接进行乘法时的精度丢失。
例如使用 Math.round(Number(19.775 + 'e' + 2)) / Math.pow(10, 2) 的 字符串拼接
e 的操作,是为了 绕过二进制浮点数的精度陷阱,确保数学运算的准确性。
e 的作用:将数值转换为科学计数法的字符串,确保十进制精度不丢失。
适用场景:对精度要求高的计算(如财务、货币),避免浮点数陷阱。
替代方案:使用 decimal.js 等库处理高精度数学运算
其他场景验证:

输入值 直接运算(错误) 字符串拼接(正确)
1.005 1.00 1.01
0.635 0.63 0.64
2.675 2.67 2.68
posted @   码磊姐姐  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示