Java: double machine epsilon n'est pas le plus petit x tel que 1+x!= 1?
je suis en train de déterminer l' double
lavable en epsilon en Java, en utilisant la définition de celui-ci étant le plus petit représentable double
valeur x
tels que 1.0 + x != 1.0
, comme en C / C++. Selon wikipedia, cette machine epsilon est égale à 2^-52
(52) étant le nombre de double
bits de mantissa-1).
mon implémentation utilise le Math.ulp()
fonction:
double eps = Math.ulp(1.0);
System.out.println("eps = " + eps);
System.out.println("eps == 2^-52? " + (eps == Math.pow(2, -52)));
et les résultats sont ce que je attendu:
eps = 2.220446049250313E-16
eps == 2^-52? true
jusqu'ici, tout va bien. Cependant, si je vérifie que le donné eps
est en effet le plus petitx
tels que 1.0 + x != 1.0
, il semble y avoir un plus petit, alias le page précédentedouble
valeur selon 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));
ce Qui donne:
epsPred = 2.2204460492503128E-16
epsPred < eps? true
1.0 + epsPred == 1.0? false
comme nous le voyons, nous avons un epsilon plus petit que machine qui, ajouté à 1, produit non 1, en contradiction avec la définition.
Donc quel est le problème avec la valeur communément acceptée pour machine epsilon selon cette définition? Ou ai-je raté quelque chose? Je soupçonne un autre aspect ésotérique des maths à virgule flottante, mais je ne vois pas où je me suis trompé...
EDIT: grâce aux commentaires, j'ai enfin compris. J'ai effectivement utilisé la définition de l'erreur! eps = Math.ulp(1.0)
calcule la distance jusqu'au plus petit double représentatif > 1.0
, mais -- et c'est le point --eps
le plus petit x
1.0 + x != 1.0
, mais plutôt à propos de deux fois valeur: Ajouter 1.0 + Math.nextAfter(eps/2)
est arrondie 1.0 + eps
.
2 réponses
en utilisant la définition de lui étant la plus petite valeur Double représentable x telle que 1.0 + x != 1,0, comme en C / C++
Cela n'a jamais été la définition, pas en Java et en C et pas en C++.
la définition est que la machine epsilon est la distance entre un et le plus petit flotteur/double plus grand qu'un.
Votre "définition" est mal par un facteur de près de 2.
aussi, l'absence strictfp
permet seulement une plus grande plage d'exposant et ne devrait pas avoir d'impact sur la mesure empirique d'epsilon, puisque cela est calculé à partir de 1.0
et son successeur, dont chacun et la différence peuvent être représentés avec la gamme standard de l'exposant.
Je ne suis pas sûr que votre méthode expérimentale / théorie soit solide. La documentation pour la classe de mathématiques indique:
pour un format à virgule flottante donné, un ulp d'une valeur numérique réelle spécifique est la distance entre les deux valeurs à virgule flottante encadrant cette valeur numérique
La documentation ulp
méthode dit:
un ulp d'une valeur double est la distance positive entre cette valeur à virgule flottante et la valeur double suivant plus grand dans la grandeur
Donc, si vous voulez le plus petit eps
valeur 1.0 + eps != 1.0
, votre eps devrait vraiment généralement être Math.ulp(1.0)
depuis, au moins, pour toute valeur supérieure à Math.ulp(1.0) / 2
, le résultat sera arrondi.
je pense que la plus petite de ces valeurs sera donnée par Math.nextAfter(eps/2, 1.0)
.