Java: Добавление Double.MIN_NORMAL к double не меняет число

1

Я думал, что MIN_NORMAL - это значение, которое вы можете добавить к "нормальному" двойнику, и число изменится. Например, добавьте Double.MIN_NORMAL в 0.1d, и вы получите значение, отличное от 0.1d, однако мое понимание неверно:

public static void test(double val) {
    if (val == (val - Double.MIN_NORMAL*1e50d))
        System.out.printf("val == (val - Double.MIN_NORMAL*1e50d) for val=%.20f\n", val);
    else
        System.out.printf("val != (val - Double.MIN_NORMAL*1e50d) for val=%.20f\n", val);
}

Что производит:

test(0.0d);
> val != (val - Double.MIN_NORMAL*1e50d) for val=0.00000000000000000000

test(1.0d);
> val == (val - Double.MIN_NORMAL*1e50d) for val=1.00000000000000000000

test(0.1d);
> val == (val - Double.MIN_NORMAL*1e50d) for val=0.10000000000000000000

Кто-то pls объясняет, что идет против моей логики здесь, что, даже если я добавлю MIN_NORMAL раз 1e50d, я все равно получаю тот же номер.

Я проверил двоичные представления и 1 * Double.MIN_NORMAL отличается от 2 * Double.MIN_NORMAL, но вычитание из ничего, кроме нуля, не изменяет исходный номер.

  • 0
    Документы четко определяют его как 2 в степени -1022 . Итак, ваш 1e50d ничто по сравнению.
  • 3
    MIN_NORMAL гарантированно будет иметь эффект при добавлении / вычитании из 0 , но в противном случае вы не можете полагаться на то, что он будет иметь эффект. В частности, он не собирается ничего делать со сравнительно гигантскими числами, такими как 1.0 или 0.1 .
Показать ещё 2 комментария
Теги:
double
epsilon
double-precision

2 ответа

2
Лучший ответ

MIN_NORMAL, как говорит Javadoc, имеет только наименьшее нормированное double значение. Но это не значит, что это что-то вроде 1 для int s: для значений точки с плавающей запятой просто нет стандартного "eps", который вы можете добавить, чтобы перейти к следующему представляемому значению - "eps" всегда зависит от показателем данного значения с плавающей запятой. Вот почему их называют плавающими точками, в конце концов :)

Однако Java 1. 6+ предоставляет Math.nextAfter() который возвращает для любого заданного double следующего или предыдущего представляемого double.

На старых версиях Java вы всегда можете Double.doubleToLongBits() с Double.doubleToLongBits(), увеличивая или уменьшая его результат и возвращая обратно Double.longBitsToDouble(); это дает вам следующее или предыдущее представляемое double значение - в большинстве случаев: есть несколько особых случаев (NaN, бесконечные значения), поэтому это не рекомендуется для новичков с плавающей запятой :)

  • 0
    Спасибо за Math.nextAfter (), я меняю принятый ответ!
2

Двойник имеет ограниченную точность. MIN_NORMAL - 2e-1022. Он будет удален, если только вы не добавите его, также находится на стадионе 2e-1000.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню