简体   繁体   English

Java - 一次双加/减的最大精度损失

[英]Java - maximum loss of precision in one double addition/subtraction

Is it possible to establish, even roughly, what the maximum precision loss would be when dealing with two double values in java (adding/subtracting)? 是否有可能建立甚至粗略地说,在java(加/减)中处理两个double值时最大精度损失是多少? Probably the worst case scenario is when two numbers cannot be represented exactly, and then an operation is performed on them, which results in a value that also cannot be represented exactly. 可能最坏的情况是两个数字无法准确表示,然后对它们执行操作,这导致一个值也无法准确表示。

The worst case is that all precision can be lost. 最糟糕的情况是所有精度都可能丢失。 This can for example happen if the result is larger than the largest representable finite number. 例如,如果结果大于最大可表示的有限数,则会发生这种情况。 Then it will be stored as POSITIVE_INFINITY (or NEGATIVE_INFINITY). 然后它将存储为POSITIVE_INFINITY(或NEGATIVE_INFINITY)。

Regarding your update, it can happen with addition. 关于您的更新,可以添加。

double a = Double.MAX_VALUE;
System.out.println(a);
double b = a + a;
System.out.println(b);

Result: 结果:

1.7976931348623157E308
Infinity

See it online: ideone 在线查看: ideone

In general the size of the representation error is relative to the size of your numbers. 通常,表示错误的大小与您的数字大小有关。

Have a look at Math.ulp(double) . 看看Math.ulp(double) The ulp of a double is the delta to the next highest value. double 精度的ulp是下一个最高值的增量。 For instance, if you add to numbers and one is smaller than the ulp of the other, you know that the addition will have no effect. 例如,如果您添加到数字而一个小于另一个的ulp,则您知道添加将不起作用。 If you multiply two doubles, you can multiply their ulps to get the maximum error of the result. 如果乘以两个双精度数,则可以将它们的ulps相乘以得到结果的最大误差。

You could have a look at the actual precision of your inputs, for example the code below outputs: 您可以查看输入的实际精度,例如下面的代码输出:

input: 0.01000000000000000020816681711721685132943093776702880859375
range: [0.0099999999999999984734433411404097569175064563751220703125 - 0.010000000000000001942890293094023945741355419158935546875]
range size: 3.4694469519536141888238489627838134765625E-18
input: 10000000000000000
range: [9999999999999998 - 10000000000000002]
range size: 4
public static void main(String[] args) {
    printRange(0.01);
    printRange(10000000000000000d);
}

private static void printRange(double d) {
    long dBits = Double.doubleToLongBits(d);
    double dNext = Double.longBitsToDouble(dBits + 1);
    double dPrevious = Double.longBitsToDouble(dBits + -1);
    System.out.println("input: " + new BigDecimal(d));
    System.out.println("range: [" + new BigDecimal(dPrevious) + " - " + new BigDecimal(dNext) + "]");
    System.out.println("range size: " + new BigDecimal(dNext - dPrevious));
}

You would still need to then estimate the loss on the result of your operation. 您仍然需要估算操作结果的损失。 And that does not work with corner cases (around Infinity, NaN etc.). 这不适用于角落情况(Infinity,NaN等)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM