问题描述
编辑:这不是关于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);
}
我在这里想念什么?为什么在循环内时起作用,而直接调用函数时却不起作用?以及如何以健壮和可靠的方式来计算呢?
解决方法
对此进行分析:
const amount = 329;
const decimal = Math.trunc(100 * ((amount / 100) % 1).toFixed(2));
-
(((329/100) % 1).toFixed(2))
返回 STRING"0.29"
- 如果将其转换回数字,则将其扫描到最接近的浮点数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!