Voici ce qu'il se passe en binaire. Comme nous le savons, certaines valeurs à virgule flottante ne peut pas être représenté exactement en binaire, même si elles peuvent être représentées exactement en décimal. Ces 3 chiffres sont juste des exemples de ce fait.
Avec ce programme, j'ai sortie les représentations hexadécimales de chaque numéro et les résultats de chaque addition.
public class Main{
public static void main(String args[]) {
double x = 23.53; // Inexact representation
double y = 5.88; // Inexact representation
double z = 17.64; // Inexact representation
double s = 47.05; // What math tells us the sum should be; still inexact
printValueAndInHex(x);
printValueAndInHex(y);
printValueAndInHex(z);
printValueAndInHex(s);
System.out.println("--------");
double t1 = x + y;
printValueAndInHex(t1);
t1 = t1 + z;
printValueAndInHex(t1);
System.out.println("--------");
double t2 = x + z;
printValueAndInHex(t2);
t2 = t2 + y;
printValueAndInHex(t2);
}
private static void printValueAndInHex(double d)
{
System.out.println(Long.toHexString(Double.doubleToLongBits(d)) + ": " + d);
}
}
L' printValueAndInHex
méthode n'est qu'un hex-imprimante helper.
La sortie est comme suit:
403787ae147ae148: 23.53
4017851eb851eb85: 5.88
4031a3d70a3d70a4: 17.64
4047866666666666: 47.05
--------
403d68f5c28f5c29: 29.41
4047866666666666: 47.05
--------
404495c28f5c28f6: 41.17
4047866666666667: 47.050000000000004
Les 4 premiers numéros sont x
, y
, z
, et s
's des représentations hexadécimales. En virgule flottante IEEE de la représentation, les bits 2 à 12 représentent le binaire de l'exposant, qui est, à l'échelle de la nombre. (Le premier bit est le bit de signe, et le reste des bits pour la mantisse.) L'exposant représenté est en fait le nombre binaire moins 1023.
Les exposants pour les 4 premiers chiffres sont extraits:
sign|exponent
403 => 0|100 0000 0011| => 1027 - 1023 = 4
401 => 0|100 0000 0001| => 1025 - 1023 = 2
403 => 0|100 0000 0011| => 1027 - 1023 = 4
404 => 0|100 0000 0100| => 1028 - 1023 = 5
Première série d'ajouts
Le deuxième nombre (y
) est de plus petite ampleur. Lors de l'ajout de ces deux nombres pour obtenir de l' x + y
, les 2 derniers bits du deuxième nombre (01
) sont décalés hors de portée et ne figure pas dans le calcul.
La deuxième plus ajoute x + y
et z
et ajoute les deux nombres de la même échelle.
Deuxième série d'ajouts
Ici, x + z
se produit en premier. Ils sont de la même échelle, mais ils donnent un nombre qui est plus haut dans l'échelle:
404 => 0|100 0000 0100| => 1028 - 1023 = 5
La deuxième plus ajoute x + z
et y
, et maintenant 3 bits sont passé de y
la somme des nombres (101
). Ici, il doit y avoir un tour vers le haut, parce que le résultat est le prochain nombre à virgule flottante: 4047866666666666
de la première série d'ajouts vs 4047866666666667
pour la deuxième série d'ajouts. Cette erreur est assez importante pour montrer à l'impression du total.
En conclusion, être prudent lors de l'exécution d'opérations mathématiques sur les numéros IEEE. Certaines représentations sont inexactes, et ils deviennent encore plus inexact lorsque les échelles sont différentes. Ajouter et soustraire des nombres d'envergure comparable, si vous le pouvez.