usar personalizar java floating-point epsilon

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



tabbed java (2)

Estoy tratando de determinar el epsilon de la máquina double en Java, utilizando la definición de que es el valor double x más pequeño que se puede representar, de modo que 1.0 + x != 1.0 , al igual que en C / C ++. Según wikipedia, esta máquina épsilon es igual a 2^-52 (siendo 52 el número de bits de mantisa double - 1).

Mi implementación usa la función Math.ulp() :

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 los que esperaba.

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

Hasta ahora tan bueno. Sin embargo, si compruebo que la eps dada es, de hecho, la x más pequeña , de manera que 1.0 + x != 1.0 , parece haber una más pequeña, también conocida como el valor double anterior según Math.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 una épsilon más pequeña que la máquina, la cual, sumada a 1, no produce 1, en contradicción con la definición.

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

EDIT: Gracias a los comentaristas, finalmente lo tengo. ¡Realmente 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 - que eps no es la x más pequeña con 1.0 + x != 1.0 , sino más o menos el doble de ese valor: La adición de 1.0 + Math.nextAfter(eps/2) se redondea a 1.0 + eps .


utilizando la definición de que es el valor doble x más pequeño que se puede representar, de modo que 1.0 + x! = 1.0, al igual que en C / C ++

Esta nunca ha sido la definición, ni en Java ni en C ni en C ++.

La definición es que la máquina epsilon es la distancia entre uno y el flotador más pequeño / doble más grande que uno.

Su "definición" es incorrecta por un factor de casi 2 .

Además, la ausencia de strictfp solo permite un rango de exponente mayor y no debería tener ningún impacto en la medición empírica de épsilon, ya que se calcula a partir de 1.0 y su sucesor, cada uno de los cuales y la diferencia de los cuales se pueden representar con el exponente estándar. distancia.


No estoy seguro de que su método / teoría experimental sea acertado. La documentación para la clase de matemáticas establece:

Para un formato de punto flotante dado, una ulp de un valor de número real específico es la distancia entre los dos valores de punto flotante que marcan ese valor numérico

La documentación para el método ulp dice:

Una ulp de un valor doble es la distancia positiva entre este valor de punto flotante y el valor doble siguiente mayor en magnitud

Entonces, si desea el valor de eps más pequeño, de manera que 1.0 + eps != 1.0 , su eps debería ser generalmente menor que Math.ulp(1.0) , ya que al menos para cualquier valor mayor que Math.ulp(1.0) / 2 , El resultado se redondeará.

Creo que el valor más pequeño será dado por Math.nextAfter(eps/2, 1.0) .