Java: la máquina doble épsilon no es la x más pequeña, de modo que 1 + x! = 1?

Estoy tratando de determinar eldouble máquina épsilon en Java, usando la definición de ser el más pequeño representabledouble valorx tal que1.0 + x != 1.0, al igual que en C / C ++. Según wikipedia, esta máquina épsilon es igual a2^-52 (con 52 siendo el número dedouble bits de mantisa - 1).

Mi implementación usa elMath.ulp() función:

double eps = Math.ulp(1.0);
System.out.println("eps = " + eps);
System.out.println("eps == 2^-52? " + (eps == Math.pow(2, -52)));

y los resultados son lo que esperaba:

eps = 2.220446049250313E-16
eps == 2^-52? true

Hasta aquí todo bien. Sin embargo, si verifico que el dadoeps es de hecho elpequeñísimo x tal que1.0 + x != 1.0, parece haber uno más pequeño, también conocido comoanterior double valor de acuerdo aMath.nextAfter():

double epsPred = Math.nextAfter(eps, Double.NEGATIVE_INFINITY);
System.out.println("epsPred = " + epsPred);
System.out.println("epsPred < eps? " + (epsPred < eps));
System.out.println("1.0 + epsPred == 1.0? " + (1.0 + epsPred == 1.0));

Cuyos rendimientos:

epsPred = 2.2204460492503128E-16
epsPred < eps? true
1.0 + epsPred == 1.0? false

Como vemos, tenemos un épsilon más pequeño que la máquina, que, sumado a 1, no produce 1, en contradicción con la definición.

Entonces, ¿qué tiene de malo el valor comúnmente aceptado para la máquina épsilon según esta definición? ¿O me perdí algo? Sospecho otro aspecto esotérico de las matemáticas de punto flotante, pero no puedo ver dónde me equivoqué ...

EDITAR: Gracias a los comentaristas, finalmente lo entendí. ¡En realidad usé la definición incorrecta!eps = Math.ulp(1.0) calcula la distancia al doble representable más pequeño>1.0, pero, y ese es el punto, queeps esno el mas pequeñox con1.0 + x != 1.0, sino más bien sobredos veces ese valor: Agregar1.0 + Math.nextAfter(eps/2) es redondeadoarriba a1.0 + eps.

Respuestas a la pregunta(2)

Su respuesta a la pregunta