Java: double machine epsilon n'est pas le plus petit x tel que 1+x!= 1?

je suis en train de déterminer l' doublelavable 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 x1.0 + x != 1.0, mais plutôt à propos de deux fois valeur: Ajouter 1.0 + Math.nextAfter(eps/2) est arrondie 1.0 + eps.

18
demandé sur Franz D. 2015-02-26 16:11:44

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.

21
répondu Pascal Cuoq 2015-02-26 13:29:43

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).

7
répondu davmac 2015-02-26 15:53:40