Java:Ajouter Double.MIN_NORMAL à un double ne change pas le nombre
-
21-12-2019 - |
Question
Je pensais que MIN_NORMAL était une valeur que vous pouviez ajouter à un double "normal" et le nombre changerait.Par exemple.ajoutez Double.MIN_NORMAL à 0,1d et vous obtenez une valeur différente de 0,1d, mais ma compréhension est fausse :
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);
}
Ce qui produit :
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
Quelqu'un explique ici ce qui va à l'encontre de ma logique, que même si j'ajoute MIN_NORMAL fois 1e50d, j'obtiens toujours le même nombre.
J'ai vérifié les représentations binaires et 1 * Double.MIN_NORMAL est différent de 2 * Double.MIN_NORMAL, mais les soustraire de tout sauf zéro ne change pas le nombre d'origine.
La solution
MIN_NORMAL
est, comme le dit le Javadoc, seulement le plus petit normalisé double
valeur.Mais cela ne veut pas dire que c'est quelque chose comme 1
pour int
s :Pour les valeurs à virgule flottante, il existe simplement Non "eps" standard que vous pouvez ajouter pour passer à la valeur représentable suivante - le "eps" dépend toujours de l'exposant de la valeur à virgule flottante donnée.C'est pourquoi on les appelle flottant des points, au final :)
Cependant, Java 1.6+ fournit Math.nextAfter()
qui renvoie, pour tout donné double
, le représentable suivant ou précédent double
.
Sur les anciennes versions de Java, vous pouvez toujours jouer avec Double.doubleToLongBits()
, incrémentant ou décrémentant son résultat, et reconvertissant en Double.longBitsToDouble()
;cela vous donne le représentable suivant ou précédent double
valeur -- dans la plupart des cas:il existe quelques cas particuliers (NaN, valeurs infinies), donc cela n'est pas recommandé aux débutants en virgule flottante :)
Autres conseils
Le double a une précision limitée.Min_normal est 2E-1022.Il sera chuté à moins que le numéro que vous ajoutez est également dans le ballpark de 2E-1000.