Java - maximum loss of precision in one double addition/subtraction
Asked Answered
P

3

7

Is it possible to establish, even roughly, what the maximum precision loss would be when dealing with two double values in java (adding/subtracting)? 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.

Prittleprattle answered 20/11, 2012 at 10:2 Comment(3)
If precision loss is an issue, I would recommend to use BigDecimal instead of double.Disjunction
Yeah, the whole point of this question is to see how big the loss is. double takes up 8 bytes, while BigDecimal around 40, and I need to store a lot of data pointsPrittleprattle
When you do a lot of floating-point operations, the performance gain of using primitives instead of objects can be significant.Keeleykeelhaul
K
5

Have a look at Math.ulp(double). The ulp of a double is the delta to the next highest value. 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. If you multiply two doubles, you can multiply their ulps to get the maximum error of the result.

Keeleykeelhaul answered 20/11, 2012 at 10:37 Comment(1)
This is exactly what I wantedPrittleprattle
M
7

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).

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

In general the size of the representation error is relative to the size of your numbers.

Moeller answered 20/11, 2012 at 10:7 Comment(0)
K
5

Have a look at Math.ulp(double). The ulp of a double is the delta to the next highest value. 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. If you multiply two doubles, you can multiply their ulps to get the maximum error of the result.

Keeleykeelhaul answered 20/11, 2012 at 10:37 Comment(1)
This is exactly what I wantedPrittleprattle
S
0

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.).

Slam answered 20/11, 2012 at 10:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.