Java: Adding/Subtracting Math.ulp() vs. Math.nextAfter()

This program:

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

outputs:

false
true

The difference between consecutive doubles changes at each normal integer power of two, including 1.0. One of the tests must fail, because it assumes constant difference. Math.ulp(double) is defined to return "the positive distance between this floating-point value and the double value next larger in magnitude" so the subtract proposition is false when the distance is different.


The immediate cases I'd think to check are 0, +infinity and -infinity and 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

Output:

      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

That the expressions aren't equal in the NaN case isn't surprising (by the definition of NaN); but these expressions also aren't true for +infinity and -infinity (see the last column).

This answer is not intended to provide an exhaustive list of problematic values, but rather to show that some problematic values do exist.