首页 > 解决方案 > Javascript 浮点数会根据您输入变量的方式改变准确性

问题描述

编辑:这不是关于 JS 中的浮点实现有多好或多坏的讨论。这是一个非常具体的案例,因此请不要将其标记为与浮点讨论的重复。

这是我用来计算以美分表示的金额的小数部分的脚本(例如 3.34 是 334 美分):

const amount = 334;
const decimal = Math.trunc(100 * ((amount / 100) % 1).toFixed(2));

console.log(decimal); //34

到目前为止,一切都很好。如果将金额更改为 329,则会得到 28,这是错误的:

const amount = 329;
const decimal = Math.trunc(100 * ((amount / 100) % 1).toFixed(2));

console.log(decimal); //28

这是因为 ,(329/100) % 1 = 0.29000000000000004而不是0.30, 因为 JS 浮点很烂?

但是对我来说真正疯狂的是,在开发一个循环来查看该脚本使用 FOR 中断的情况时,它并没有在 329 上中断!:

for(let x = 325; x < 335; x++) {
  
  const r = Math.trunc((100 * (( x / 100) % 1)).toFixed(2));
  console.log(x, r);

}

我在这里想念什么?为什么在循环内工作而直接调用函数时不工作?您如何以稳健可靠的方式进行计算?

标签: javascriptfloating-pointprecision

解决方案


对此进行分析:

const amount = 329;
const decimal = Math.trunc(100 * ((amount / 100) % 1).toFixed(2));
  • (((329/100) % 1).toFixed(2))返回字符串 "0.29"
  • 如果将其转换回 ta 数字,则将其扫描到最接近的可能浮点数 0.289999999999999980。您可以通过以下方式证明:(+(((329/100) % 1).toFixed(2))).toPrecision(18)
  • 然后将结果乘以 100 并截断,得到正确的值 28。

toFixed()类似或的函数toPrecision()旨在为最终输出格式化数字,但不适用于数学计算。

为您解决问题:

const amount = 329;
const decimal = amount % 100;

...或者如果数量可以是带有分数的浮点数。

const decimal = math.round(amount) % 100;

最后一点:这是关于浮点实现以及如何使用它的讨论;不仅适用于 JS!


推荐阅读