Java:Adicionar Double.MIN_NORMAL a um duplo não altera o número
-
21-12-2019 - |
Pergunta
Achei que MIN_NORMAL era um valor que você poderia adicionar a um duplo "normal" e o número mudaria.Por exemplo.adicione Double.MIN_NORMAL a 0,1d e você obterá um valor diferente de 0,1d, porém meu entendimento está errado:
public static void test(double val) {
if (val == (val - Double.MIN_NORMAL*1e50d))
System.out.printf("val == (val - Double.MIN_NORMAL*1e50d) for val=%.20f\n", val);
else
System.out.printf("val != (val - Double.MIN_NORMAL*1e50d) for val=%.20f\n", val);
}
O que produz:
test(0.0d);
> val != (val - Double.MIN_NORMAL*1e50d) for val=0.00000000000000000000
test(1.0d);
> val == (val - Double.MIN_NORMAL*1e50d) for val=1.00000000000000000000
test(0.1d);
> val == (val - Double.MIN_NORMAL*1e50d) for val=0.10000000000000000000
Alguém, por favor, explique o que está indo contra minha lógica aqui, que mesmo se eu adicionar MIN_NORMAL vezes 1e50d, ainda obterei o mesmo número.
Verifiquei as representações binárias e 1 * Double.MIN_NORMAL é diferente de 2 * Double.MIN_NORMAL, mas subtraí-las de qualquer coisa, exceto zero, não altera o número original.
Solução
MIN_NORMAL
é, como diz o Javadoc, apenas o menor normalizado double
valor.Mas isso não significa que seja algo como 1
para int
é:Para valores de ponto flutuante, simplesmente existe não "eps" padrão que você pode adicionar para alterar o próximo valor representável - o "eps" sempre depende do expoente do valor de ponto flutuante fornecido.É por isso que eles são chamados flutuando pontos, no final :)
No entanto, Java 1.6+ fornece Math.nextAfter()
que retorna, para qualquer dado double
, o próximo ou anterior representável double
.
Em versões mais antigas do Java, você sempre pode mexer Double.doubleToLongBits()
, aumentando ou diminuindo seu resultado e convertendo de volta por Double.longBitsToDouble()
;isso dá a você o próximo ou anterior representável double
valor -- na maioria dos casos:existem alguns casos especiais (NaN, valores infinitos), então isso não é recomendado para iniciantes em ponto flutuante :)
Outras dicas
Double tem uma precisão limitada.MIN_NORMAL é 2e-1022.Ele será descartado, a menos que o número ao qual você o adicionou também esteja próximo de 2e-1000.