57 votes

Les opérations en virgule flottante sur la JVM donneront-elles les mêmes résultats sur toutes les plateformes ?

J'utilise Java dans une application fonctionnant sur plusieurs machines, et toutes les machines doivent obtenir les mêmes résultats pour les opérations mathématiques. Est-il prudent d'utiliser les primitives à virgule flottante de Java ? Ou dois-je simplement utiliser une bibliothèque mathématique à virgule fixe ?

56voto

Jon Skeet Points 692016

Pas en général, non. Cependant, vous pouvez utiliser strictfp expressions :

Dans une expression FP-strict, toutes les valeurs intermédiaires doivent être des éléments de l'ensemble de valeurs float ou de l'ensemble de valeurs double, ce qui implique que les résultats de toutes les expressions FP-strict doivent être ceux prédits par l'arithmétique IEEE 754 sur des opérandes représentés à l'aide des formats simple et double.

Dans une expression qui n'est pas stricte au niveau de la PF, une certaine marge de manœuvre est accordée pour qu'une implémentation utilise une plage d'exposants étendue pour représenter les résultats intermédiaires ; l'effet net, en gros, est qu'un calcul peut produire "la bonne réponse" dans des situations où l'utilisation exclusive de l'ensemble de valeurs flottantes ou de l'ensemble de valeurs doubles pourrait entraîner un dépassement de capacité ou un dépassement de capacité.

27voto

ajb Points 11197

En plus de strictfp il y a aussi StrictMath qui exige que les résultats soient prévisibles pour les fonctions transcendantales et autres.

9voto

Mishax Points 1562

La JVM doit mettre en œuvre la spécification IEEE de manière cohérente et cette spécification est très technique et précise. Les primitives à virgule flottante float et double sont les mêmes sur toutes les plateformes.

La différence réside uniquement dans le traitement des résultats intermédiaires, et dans le fait que l'implémentation de la machine virtuelle peut utiliser les formats float-extended-exponent et double-extended-exponent lors de l'évaluation d'expressions impliquant des locals dans le même cadre d'exécution.

Donc si vous avez un code comme :

double d1 = 0.342;
double d2 = 1.328479;
double d3 = 4.99384728796;
System.out.println(d1 * d2 / d3);

et ce n'est pas dans un contexte strictfp, il est possible que vous ayez des différences entre les différentes JVM au moment de l'exécution. En effet, lors de l'évaluation de l'expression d1*d2/d3, le résultat intermédiaire de d1*d2 est utilisé dans l'expression "résultat intermédiaire"/d3 et la JVM peut utiliser les formats float-extended-exponent et double-extended-exponent pour stocker le "résultat intermédiaire".

Pour contourner ce problème, vous pouvez utiliser strictfp ou StrictMath comme d'autres ont répondu ici, OU éviter d'utiliser des résultats intermédiaires dans vos expressions. Une façon de le faire est de stocker tout résultat intermédiaire sur le tas. Par exemple, comme suit :

class MyClass {
    static double d1 = 0.342;
    static double d2 = 1.328479;
    static double d3 = 4.99384728796;
    static double intermediate_result = 0d;
    public static void main(String[] args) {
        intermediate_result = d1 * d2;
        System.out.println(intermediate_result / d3);
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X