避免浮点数舍入不精确

Avoiding float rounding imprecision

提问人: 提问时间:10/8/2022 更新时间:4/22/2023 访问量:410

问:

在用浮点数进行除法时,我经常会遇到不精确的情况(例如,等)。5.000000001

有没有办法在使用浮点数时不出现浮点不精确问题? 也许有更好的选择可以避免它?

提前感谢您的所有回答!

精密 浮动精度

评论

2赞 merryweather 10/8/2022
为什么不直接解决问题的根源并停止使用浮点数学呢?在此示例中,您可以将数字乘以 10 并得到正确的结果。尽管您得到的结果比应有的结果高出 10 倍,但它仍然比使用浮点数学准确 1000 倍。
1赞 Barmar 10/8/2022
如果你所有的浮点数都有分数,而你只是在加法和减法,这不应该发生。只有当你执行除法和得到分数时,你才会失去精度。.0
0赞 Barmar 10/8/2022
没有办法知道你是否失去了精确度,因为你不知道正确的结果应该是什么。例如,如果你这样做,将是正确的结果,但如果你这样做,它是错误的结果2.999992.0 + 0.999996.0 / 2.0
0赞 James 10/8/2022
在显示之前,只需适当地四舍五入即可。您的初始数字有两个有效数字。使输出与 .toPrecision 或 .toFixed 相同
2赞 axiac 10/8/2022
您无法知道结果是否丢失了精度,因为您无法知道确切的期望值是多少(您需要知道它才能检测精度损失)。如果你能知道确切的期望值,那么你一开始就不会遇到这个问题。

答:

-2赞 Guillaume Brunerie 10/8/2022 #1

你找不到这样的“不精确”,即使你可以,你也无法修复它们。例如,根本没有办法将 0.1 精确地表示为浮点数。这不是一个错误,它只是浮点数的工作方式(在任何语言中),你只需要解决它。

以下是一些解决方法:

  • 仅使用整数,因为它们不会受到舍入误差的影响(只要它们不是太大)。例如,如果您想处理小数点后只有两位数字的财务金额,您应该以美分存储您的金额,而不是以欧元/美元/...存储,以便只处理整数。
  • 如果你想使用任意分数,你应该使用一个专门为此设计的库。肯定有很多这样的库。或者你可以编写自己的,其中分数 a/b 表示为 (where 和 是整数,所以没有舍入错误),然后你在这个表示上实现加法、乘法、相等等,只负责操作整数。{numerator: a, denominator: b}ab
  • 如果您需要使用任意浮点数(例如,您正在编写一个检测两个移动形状碰撞的函数),只需记住永远不要使用相等。对于任意浮点数来说,相等是毫无意义的。您可以改用类似 where is selected of a way to a fit your application 的方式。Math.abs(b - a) < epsilonepsilon

评论

1赞 Eric Postpischil 10/8/2022
回复“只使用整数,因为它们不会受到四舍五入误差的影响(只要它们不是太大)”:2014 年 6 月 6 日,苹果股票的收盘价为每股 64557 美分。整数算术计算出拆分调整后的价格为每股 9222 美分,但目前的答案约为每股 9222.428571 美分。整数算术可能会出现舍入误差。
0赞 Eric Postpischil 10/8/2022
Re “对于任意浮点数来说,相等是毫无意义的”:人们通常不会计算任意浮点数;他们计算对其目的有意义的数字。在浮点运算中,没有适度量级导数的函数(包括检验相等性,因为它是不连续的)确实很难处理,但说它们总是毫无意义是不正确的。例如,测试函数参数是否处于奇点可能很有意义。
0赞 Guillaume Brunerie 10/8/2022
“但目前的答案是每股约9222.428571美分。整数算术会受到四舍五入误差的影响。我不知道你在说什么,9222.428571 不是整数,所以你不是在做整数算术。
0赞 Guillaume Brunerie 10/8/2022
“人们通常不会计算任意浮点数”他们绝对会这样做。例如,如果您使用 requestAnimationFrame 来计算动画,则从上一帧到当前帧的时间是任意浮点数,因此您从中计算的所有内容也将是(除非您四舍五入,但没有理由,任意浮点数都可以)。
0赞 Guillaume Brunerie 10/8/2022
“例如,测试函数参数是否处于奇点可能是有意义的。我完全不相信这一点。例如,如果您不想除以 0,您可能也不想除以 0.1+0.2-0.3,即使它不等于 0。