Java估计Double的表示错误

时间:2018-06-02 23:03:49

标签: java math double currency epsilon

我偶尔会看到一些舍入错误,这些错误是由于如下面两个例子中所示的一些值所致。

// floor(number, precision)

double balance = floor(0.7/0.1, 3) // = 6.999 
double balance = floor(0.7*0.1, 3) // = 0.069

问题当然是0.7/0.10.7*0.1并不完全是由于表示错误应该是的数字[请参阅下面的注释]。

一种解决方案可能是添加epsilon,以便在应用场地之前减轻任何表示错误。

double balance = floor(0.7/0.1 + 1e-10, 3) // = 7.0
double balance = floor(0.7*0.1 + 1e-10, 3) // = 0.07

我应该使用什么样的epsilon才能保证在所有情况下都能正常工作?除非我有一个很好的策略来选择正确的epsilon,这可能取决于我正在处理的数字,我觉得这个解决方案相当苛刻。

例如,如果有一种方法可以估算错误(如representation - number)或至少是它的符号(无论是否为representation > number),那么这将有助于在应用floor之前确定应该在哪个方向更正结果。

您可以想到的任何其他解决方法都非常受欢迎。

注意:我知道真正的问题是我正在使用双打并且它有表示错误。请不要说我应该将余额存储在一个很长的位置((long) Math.floor(3931809L/0.080241D)同样不稳定)。我也尝试过使用BigDecimal,但性能下降了很多(这是一个实时应用程序)。另外,请注意我并不十分关注随着时间的推移传播小错误,我做了很多像上面那样的计算,但我每次都从一个新的余额编号开始(在返回和重新开始之前我可能会执行其中3次操作)。

编辑:为了清楚起见,这是我唯一的操作,我在相同的余额上重复3次。例如,我在美元中取余额,然后将其转换为RUB,然后转换为JPY,然后转换为EUR,我将从余额开始重新开始(使用新的余额编号,即不会传播除了舍入错误这3个操作)。这些值不受限于它们是正数(即,在[0,+ inf)范围内)并且精度始终低于8(8位十进制数字,即0.00000001是我将要处理的最小余额)

2 个答案:

答案 0 :(得分:0)

  

我应该使用什么样的epsilon,以确保它能在所有情况下都能使用?

在所有 1 的情况下,没有任何epsilon可以保证有效。周期。

如果您分析(数学上 2 )您的应用程序正在执行的计算,那么可能可以找出适合您的epsilon值。

但请注意,反复出现危险"四舍五入"多步计算中的错误。你最终可能会得到错误的答案。这就是数学所说的。

最后,问问自己:如果仅进行基于epsilon的调整是合法/安全的,那么为什么(在50年后),典型的手持式计算器仍坚持 {{1} }是1.0 / 3 * 3

1 - 让我们说清楚。您没有尝试指定您的"案例"是。所以我假设你的意思是所有可能的计算。

2 - 由于 Real 数字与相应的浮动二进制表示(例如" double")之间的epsilon取决于二进制数量。

答案 1 :(得分:0)

二进制浮点数(双精度)具有53位精度或大约15.95十进制数。

  

设r为Real,d为最接近r

double      

epsilon(r)= | r - d |在0到r * 2 floor(log2(r))-53

的范围内

并且,如果您必须处理0到N范围内的数字,那么整个范围内的最大epsilon值将近似为:

  

N * 2 floor(log2(N)) - 53

执行计算时,需要估算计算中所有步骤的累积误差。加法,乘法和除法是相对安全的。例如乘法:

  

设r 1 = d 1 + e 1 和r 2 = d 2 < / sub> + e 2

     

r 1 * r 2 =(d 1 + e 1 )*(d 2 + e 2 )= d 1 * d 2 + d 2 * e 1 + d 1 * e 2 + e 1 * e 2

除非epsilon值已经很大,否则e 1 * e 2 项相对于其他项消失,而epsilon将≤2* max( | d 1 |,| d 2 |)* max(| e 1 |,| e 2 | )。

(我想。自从我上次愤怒地做这件事以来,很长很长一段时间。)

然而,减法具有令人讨厌的属性;看戈德堡论文的定理9!

您正在使用的floor功能也有点棘手。

  

设r = d + e

     

epsilon(floor(r))= | floor(r,3) - floor(d,3)|

≤max(| ceiling(e,3)|,10 -3