将 257.78 乘以 100 的正确方法 - 浮点精度误差



伙计在javascript中浮点精度(我认为(乘以257.78 * 100给了我25777.999999999996.正确的方法是什么?我以某种方式使用Number.EPSILON吗?

目前我现在四舍五入:Math.round(257.78 * 100),但我认为以某种方式使用 EPSILON 可能更正确?

这里还有另一个问题,但没有给出考虑 EPSILON 的答案,他只是说 round - 我担心如果在乘法轮期间浮点误差加起来会失败 - Javascript 浮点乘以 100 仍然有错误

当你做乘法时,错误会累积起来。因此,误差将大于分数误差的幅度。但它通常仍然比 0.1 小很多,因此它通常不会导致Math.round以意想不到的方式行事。这段代码完全没问题(只要你不把它用于非常大/非常小的数字(。

证明:

一个数x与其(不精确(表示之间的最大舍入误差rd(x)满足公式| (x - rd(x)) / x | < 2 * E,或者换句话说:误差与我们的数x呈线性增长,并且将始终小于|x| * 2E(E是机器 Epsilon - 最大可能的相对误差(。

对于a*b的浮点乘法,结果是a*b = a*b*(1 + k),而k < E。因此,如果我们将表示误差和乘法的误差结合起来,我们最终会得到:

rd(rd(a) * rd(b))
= (a + e1)(b + e2)(1 + e3)

现在假设最坏的情况(e1|x| * 2E(,它会导致:

rd((a + |a| * 2E)(b + |b| * 2E))
= rd(a * b + a * |b| * 2E + b * |a| * 2E + |ab| * 2E)
= a * b + a * b * E + a * |b| * 2E + a * |b| * 3E + b * |a| * 2E + b * |a| * 3E + |ab| * 2E + |ab| * 3E
= a * b + |a * b| * (E + 2E + 3E + 2E + 3E + 2E + 3E)
= a * b + |a * b| * (15E)

也就是说,我们的相对舍入误差在最大值时15E。鉴于我们的舍入误差必须更小0.1才能使舍入正常工作,这将导致:

0.1 > |a * b| * (15E)
0.1 / 15E > |a * b|
30023997515803 > |a * b|

鉴于a = 100,我们得到b < 300239975158

请注意,这是最坏情况的估计。我检查了那个边界上方的几个数字,找不到任何东西。第一个计算出错是在最大安全整数范围之上,然后很明显结果不可能是正确的:

console.log(
Math.round(90071992547409.93 * 100) === 9007199254740993,
);

有关所用公式的证明,请参阅每个计算机科学家都应该了解的浮点运算。

如果它符合您的需求,您可以尝试此操作:

(257.78 * 100).toFixed(2)

如果您希望它是数字而不是字符串:

parseFloat((257.78 * 100).toFixed(2))

使用toFixed来解决这个问题。

toFixed() method设置浮点值中的小数位数。此方法将数字转换为字符串,并在小数点后具有指定的位数。如果没有值作为参数传递,则以 0 作为默认值,即不显示小数点。

以下是工作代码片段:

(257.78 * 100).toFixed() // if decimal is not required
(257.78 * 100).toFixed(2) // upto 2 decimal place

最新更新