我正在开发一种工具,可以在最坏的情况下计算可以接近1e-25
的数字,并在Java中将它们进行比较。我显然使用双精度。
我已在another answer中读到,我不应期望超过1e-15
到1e-17
精度,this other question处理在“更好的“订单。
哪种双精度操作更容易在整个过程中失去精度?我应该尝试使用尽可能大或尽可能小的数字吗?在乘法之前先进行除法吗?
我宁愿不使用BigDecimal
类或等效类,因为代码已经足够慢了;)(当然,除非它们不会对速度造成太大影响)。
非常感谢任何信息!
编辑:数字在绝对值(1e-25)中“小”的事实并不重要,因为double可以降至1e-324。但重要的是,当它们非常相似时(均在1e-25中),我必须比较,比如说4.64563824048517606458e-21到4.64563824048517606472e-21(差异是第19和第20位数)。当计算这些数字时,差异非常小,我可能会遇到“舍入误差”,其中余数用随机数填充。
问题是:“如何对计算进行排序,以便最大限度地减少这种精度损失?”。它可能在乘法之前进行除法,或者先加法。
答案 0 :(得分:3)
如果获得正确答案很重要,则应使用BigDecimal。它比双倍慢,但在大多数情况下它足够快。我想不出很多情况下你用如此小的数字进行大量的计算,如果答案是正确的并不重要 - 至少用Java。
如果这是一个超级性能敏感的应用程序,我会考虑使用其他语言。
答案 1 :(得分:1)
感谢@John指出关于浮点算术的very complete article。
事实证明,当需要精确度时,操作应该重新排序,并且公式适合于避免精度损失,如Cancellation章节中所述:比较非常接近的数字时(这是我的情况),可能会发生“灾难性取消”,导致精确度的巨大损失。通常,根据您对操作数值的à-priori 知识重新编写公式或重新排序操作可以在微积分中实现更高的准确性。
我将从这篇文章中记得:
对于后一种情况,请记住,计算(x - y) * (x + y)
会提供比x * x - y * y
更准确的结果。