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 ?
Réponses
Trop de publicités?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é.
En plus de strictfp
il y a aussi StrictMath
qui exige que les résultats soient prévisibles pour les fonctions transcendantales et autres.
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);
}
}