这是一个有趣的问题。
Timons 回复背后的想法是您指定一个 epsilon,它代表合法双精度可以达到的最小精度。如果您在应用程序中知道您永远不需要低于 0.00000001 的精度,那么他的建议足以获得更接近事实的更精确结果。在他们预先知道其最大精度的应用程序中很有用(例如金融货币精度等)
然而,试图四舍五入的根本问题是,当你除以一个因子来重新调整它时,你实际上引入了另一种精度问题的可能性。任何对双精度数的操作都可能引入频率不同的不精确问题。特别是如果您尝试以非常有效的数字四舍五入(因此您的操作数 < 0),例如,如果您使用 Timons 代码运行以下代码:
System.out.println(round((1515476.0) * 0.00001) / 0.00001);
将导致1499999.9999999998
这里的目标是以 500000 为单位进行舍入(即我们想要 1500000)
实际上,完全确定您已经消除了不精确性的唯一方法是通过 BigDecimal 来缩减。例如
System.out.println(BigDecimal.valueOf(1515476.0).setScale(-5, RoundingMode.HALF_UP).doubleValue());
使用 epsilon 策略和 BigDecimal 策略的组合将使您能够很好地控制您的精度。epsilon 的想法让您非常接近,然后 BigDecimal 将消除由之后重新缩放引起的任何不精确性。尽管使用 BigDecimal 会降低应用程序的预期性能。
有人向我指出,当您可以确定最终除法没有输入值可以重新引入错误时,某些用例并不总是需要使用 BigDecimal 重新调整它的最后一步。目前我不知道如何正确确定这一点,所以如果有人知道如何确定,我会很高兴听到它。