Java: добавление /Substracting Math.ulp() vs. Math.nextAfter()

Я пытаюсь понять операции с плавающей запятой в Java более подробно. Если я правильно прочитал документацию, для любого заданного двойного x будет выполнено следующее:

x - Math.ulp(x) == Math.nextAfter(x, Double.NEGATIVE_INFINITY);
x + Math.ulp(x) == Math.nextAfter(x, Double.POSITIVE_INFINITY);

Вопрос: Это всегда так или есть некоторые исключительные случаи, в которых результаты будут отличаться?

Ответ 1

Эта программа:

public class Test {
  public static void main(String[] args) {
    double x = 1;
    System.out.println(x - Math.ulp(x) == Math.nextAfter(x, Double.NEGATIVE_INFINITY));
    System.out.println(x + Math.ulp(x) == Math.nextAfter(x, Double.POSITIVE_INFINITY));
  }
}

выходы:

false
true

Разница между последовательными удвоениями изменяется при каждой нормальной целочисленной мощности двух, включая 1.0. Один из тестов должен потерпеть неудачу, поскольку он предполагает постоянную разницу. Math.ulp(double) определяется как "положительное расстояние между этим значением с плавающей запятой и двойным значением, которое больше по величине", поэтому вычесть предложение ложно, когда расстояние отличается.

Ответ 2

Непосредственные случаи, которые я думаю проверить: 0, + бесконечность и -infinity и NaN:

static void check(double x) {
  double a, b;
  System.out.printf(
      "%9s %9s %23s %5s%n",
      x, a = x - Math.ulp(x), b = Math.nextAfter(x, Double.NEGATIVE_INFINITY), a == b);
  System.out.printf(
      "%9s %9s %23s %5s%n",
      x, a = x + Math.ulp(x), b = Math.nextAfter(x, Double.POSITIVE_INFINITY), a == b);
  System.out.println();
}

public static void main(String[] args) throws java.lang.Exception {
  check(0);
  check(Double.POSITIVE_INFINITY);
  check(Double.NEGATIVE_INFINITY);
  check(Double.NaN);
}

Ideone demo

Вывод:

      0.0 -4.9E-324               -4.9E-324  true
      0.0  4.9E-324                4.9E-324  true

 Infinity       NaN  1.7976931348623157E308 false
 Infinity  Infinity                Infinity  true

-Infinity -Infinity               -Infinity  true
-Infinity       NaN -1.7976931348623157E308 false

      NaN       NaN                     NaN false
      NaN       NaN                     NaN false

То, что выражения не равны в случае NaN, неудивительно (по определению NaN); но эти выражения также неверны для + бесконечности и -инфекции (см. последний столбец).

Этот ответ не предназначен для предоставления исчерпывающего списка проблемных значений, а скорее для того, чтобы показать, что существуют некоторые проблемные значения.