Le code suivant renvoie des résultats différents sur Java 8 et Java 11.
val = 1.000003058823805100000000
Java 8:
val = 1.000003058823805400000000
Java 11: (le même résultat que Python, Rust)
class Playground { public static void main(String[ ] args) { long x = 29218; long q = 4761432; double ret = Math.pow(1.0 + (double) x / q, 0.0005); System.out.println("val = " + String.format("%.24f", ret)); } }
Les questions sont les suivantes:
Math.pow()
Java 8 en Python?3 Réponses :
Si nous utilisons simplement Double.toString () pour imprimer les réponses, les deux résultats différents seraient
1.000033518c576 1.000033518c575
Les chiffres supplémentaires à la fin ne sont qu'un facteur de String.format (). Nous voyons que les nombres ne diffèrent que par le dernier chiffre décimal significatif. Conversion des deux nombres en hexadécimal
1.0000030588238054 1.0000030588238051
donc les représentations binaires ne diffèrent que d'une unité à la dernière place (ulp).
En lisant la spécification de Math.pow, nous trouvons
"Le résultat calculé doit être à 1 ulp du résultat exact."
La vraie valeur est proche de 1.000003058823805246468 ( WolframAlpha ) quelque part entre les deux réponses, donc les deux sont dans la spécification.
Tout ce qui s'est passé, c'est que la bibliothèque a subi un léger changement d'algorithme, peut-être pour la rendre plus rapide.
J'aurais pu sauter mon travail si vous étiez encore un peu plus rapide. Mais de toute façon, deux manières d'expliquer la même chose ne sont pas forcément mauvaises. Je vous salue et +1 pour avoir répondu le plus rapidement…
Merci, mais ma question est sans réponse.
Notez que
1.0000030588238054 JDK  8 1.000003058823805246⦠Wolfram Alpha 1.0000030588238051 JDK 11
est un mélange inutile de formatage de style printf
, concaténation de chaînes et println
. Vous pouvez utiliser printf
en premier lieu:
1.000003058823805246â¦
Cependant, il est inutile de demander 24 chiffres décimaux, lorsque la double
précision ne fournit même pas à distance autant de chiffres. Lorsque vous utilisez
double d1 = 1.0000030588238051, d2 = 1.0000030588238054; System.out.println((d2 - d1) == Math.ulp(d1));
au lieu de cela, il utilisera par défaut les chiffres réellement disponibles, ce qui donne
val = 1.0000030588238051
pour Java 8 et
val = 1.0000030588238054
pour Java 11.
Donc, la différence n'est que dans le dernier chiffre. Ou plus précisément
System.out.println("val = " + ret);
imprime true
, donc la distance entre ces deux valeurs est la plus petite possible avec double
. Il n'y a pas d'autre double
valeur entre eux. La spécification de pow
dit :
Le résultat calculé doit être à moins de 1 ulp du résultat exact.
Puisque le code ci-dessus a montré que les deux résultats ont une distance d'un ulp, les deux résultats seraient corrects lorsque le résultat exact se situe entre les deux résultats. Wolfram Alpha dit, le résultat exact commence par
System.out.printf("val = %.24f%n", ret);
C'est donc entre ces deux résultats. Les deux résultats sont donc corrects selon la spécification.
Pour une comparaison plus facile:
System.out.println("val = " + String.format("%.24f", ret));
Merci, mais ma question est sans réponse.
Ensuite, «votre question» n'est pas la question que vous avez postée. Vous avez demandé une «documentation décrivant ce genre de comportement» et vous l'avez obtenue.
Google le mot-clé strictfp
et c'est la réponse.
Après quelques recherches, la réponse rapide est strictfp
. réf: https://en.wikipedia.org/wiki/Strictfp
Dans java8, le comportement par défaut est d'utiliser le FPU x87 sur les machines x86, qui utilisera le double étendu (80 bits) comme valeurs intermédiaires. Ainsi, le résultat ne sera pas garanti d'avoir la même valeur sur une autre plateforme.
Dans java11 ou java13, le comportement par défaut utilise IEEE double (64 bits) comme valeurs intermédiaires.
Puisque presque tous les langages modernes garantissent des résultats stables via les flotteurs IEEE, ce comportement est difficile à imiter dans d'autres langages ou dans le nouveau java. L'assemblage FPU x87 en ligne peut aider.
Est-ce une valeur différente ou est-ce que
String.format()
se comporte différemment?valeur différente
Comment savez-vous que c'est une valeur différente?
Ces java sont-ils tous les deux sur la même machine?
Une question, pourquoi le dernier chiffre est-il important? Pour la plupart des applications, les 16 chiffres décimaux significatifs fournis sont plus que suffisants. Vous voudrez peut-être plus de chiffres de précision, mais dans ces cas, vous voudriez une technique différente, par exemple une bibliothèque effectuant tous les calculs en utilisant des doubles longs avec plus de 30 chiffres décimaux.
@Salixalba Lorsque vous devez être strictement cohérent avec les anciens programmes.
Lorsque vous avez besoin de résultats strictement cohérents, votre programme doit avoir utilisé
StrictMath.pow(…)
en premier lieu. Essayer d'obtenir une «cohérence stricte» avec une implémentation particulière de l'API non stricte n'a aucun sens.@Holger Je n'écris pas de programmes java. J'ai besoin de copier le comportement dans une autre langue.
Pourquoi? Il n'y a toujours pas de sens dans cette tâche.
@Holger Dans la programmation quotidienne, on ne rencontre jamais cela. Mais lorsque vous devez copier le comportement d'un ancien programme ou système et que toutes les anciennes données générées doivent être reproductibles, vous devez l'implémenter. Donc, avec un assemblage 8087, je l'ai fait.