Java: A máquina dupla epsilon não é o menor x, de modo que 1 + x! = 1?
Estou tentando determinar odouble
epsilon máquina em Java, usando a definição de ser o menor representáveldouble
valorx
de tal modo que1.0 + x != 1.0
, assim como em C / C ++. De acordo com a wikipedia, esta máquina epsilon é igual a2^-52
(com 52 sendo o número dedouble
bits de mantissa - 1).
Minha implementação usa oMath.ulp()
função:
double eps = Math.ulp(1.0);
System.out.println("eps = " + eps);
System.out.println("eps == 2^-52? " + (eps == Math.pow(2, -52)));
e os resultados são o que eu esperava:
eps = 2.220446049250313E-16
eps == 2^-52? true
Por enquanto, tudo bem. No entanto, se eu verificar se o dadoeps
é de fato omenor x
de tal modo que1.0 + x != 1.0
, parece haver um menor, também conhecido comoanterior double
valor de acordo comMath.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));
Qual produz:
epsPred = 2.2204460492503128E-16
epsPred < eps? true
1.0 + epsPred == 1.0? false
Como vemos, temos um epsilon menor que o da máquina, que, adicionado a 1, não produz 1, em contradição com a definição.
Então, o que há de errado com o valor geralmente aceito para a máquina epsilon de acordo com esta definição? Ou eu perdi alguma coisa? Suspeito de outro aspecto esotérico da matemática de ponto flutuante, mas não consigo ver onde errei ...
EDITAR: Graças aos comentadores, finalmente consegui. Na verdade, usei a definição errada!eps = Math.ulp(1.0)
calcula a distância até o menor dobro representável>1.0
, mas - e esse é o ponto - queeps
énão o menorx
com1.0 + x != 1.0
, mas sim sobreduas vezes esse valor: Adicionando1.0 + Math.nextAfter(eps/2)
é arredondadoacima para1.0 + eps
.