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 |
点个赞吧
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现