Java-максимальная потеря точности в одном двойном сложении / вычитании

можно ли установить, даже приблизительно, что максимальная потеря точности будет при работе с двумя double значения в java (добавление/вычитание)? Вероятно, худший сценарий-это когда два числа не могут быть представлены точно, а затем выполняется операция над ними, что приводит к значению, которое также не может быть представлено точно.

3 ответов


посмотреть Math.ulp(double). The ulp of a double - Дельта следующего по величине значения. Например, если вы добавляете к числам, и один меньше, чем ulp другого, вы знаете, что добавление не будет иметь никакого эффекта. Если вы умножите два двойника, вы можете умножить их ulps, чтобы получить максимальную ошибку результата.


в худшем случае это все точность может быть потеряна. Это может, например, произойти, если результат больше наибольшего представимого конечного числа. Затем он будет сохранен как POSITIVE_INFINITY (или NEGATIVE_INFINITY).

Что касается вашего обновления, это может произойти с добавлением.

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

результат:

1.7976931348623157E308
Infinity

посмотреть его в интернете: ideone

В общем случае размер ошибки представления относительно размер ваших номеров.


вы можете взглянуть на фактическую точность ваших входов, например, код ниже выходов:

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));
}

вам все равно нужно будет оценить потери в результате вашей операции. И это не работает с угловыми случаями (вокруг Бесконечности, NaN и т. д.).