Hier ist, was in binären los ist. Wie wir wissen, können einige Gleitkommawerte nicht genau binär dargestellt werden, selbst wenn sie genau dezimal dargestellt werden können. Diese 3 Zahlen sind nur Beispiele für diese Tatsache.
Mit diesem Programm gebe ich die hexadezimalen Darstellungen jeder Zahl und die Ergebnisse jeder Addition aus.
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);
}
}
Die printValueAndInHex
Methode ist nur ein Hex-Drucker-Helfer.
Die Ausgabe ist wie folgt:
403787ae147ae148: 23.53
4017851eb851eb85: 5.88
4031a3d70a3d70a4: 17.64
4047866666666666: 47.05
--------
403d68f5c28f5c29: 29.41
4047866666666666: 47.05
--------
404495c28f5c28f6: 41.17
4047866666666667: 47.050000000000004
Die ersten 4 Zahlen sind x
, y
, z
und s
hexadezimalen Darstellungen s‘. In der IEEE-Gleitkomma-Darstellung repräsentieren die Bits 2-12 den binären Exponenten , dh die Skala der Zahl. (Das erste Bit ist das Vorzeichenbit und die verbleibenden Bits für die Mantisse .) Der dargestellte Exponent ist tatsächlich die Binärzahl minus 1023.
Die Exponenten für die ersten 4 Zahlen werden extrahiert:
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
Erster Satz von Ergänzungen
Die zweite Zahl ( y
) ist kleiner. Wenn Sie diese beiden Zahlen addieren x + y
, werden die letzten 2 Bits der zweiten Zahl ( 01
) außerhalb des Bereichs verschoben und nicht in die Berechnung einbezogen.
Der zweite Zusatz fügt x + y
und z
und fügt zwei Zahlen derselben Skala hinzu.
Zweiter Satz von Ergänzungen
Hier x + z
tritt zuerst auf. Sie haben den gleichen Maßstab, aber sie ergeben eine Zahl, die höher ist:
404 => 0|100 0000 0100| => 1028 - 1023 = 5
Die zweite Addition fügt x + z
und hinzu y
, und jetzt werden 3 Bits entfernt y
, um die Zahlen ( 101
) hinzuzufügen . Hier muss es eine Runde nach oben geben, da das Ergebnis die nächste Gleitkommazahl ist: 4047866666666666
für den ersten Satz von Ergänzungen vs. 4047866666666667
für den zweiten Satz von Ergänzungen. Dieser Fehler ist signifikant genug, um im Ausdruck der Gesamtsumme angezeigt zu werden.
Seien Sie abschließend vorsichtig, wenn Sie mathematische Operationen an IEEE-Zahlen ausführen. Einige Darstellungen sind ungenau und werden noch ungenauer, wenn die Skalen unterschiedlich sind. Addiere und subtrahiere Zahlen ähnlichen Maßstabs, wenn du kannst.
(2.0^53 + 1) - 1 == 2.0^53 - 1 != 2^53 == 2^53 + (1 - 1)
. B. ). Daher ja: Seien Sie vorsichtig bei der Auswahl der Reihenfolge der Beträge und anderer Operationen. Einige Sprachen bieten eine integrierte Funktion zum Ausführen von "hochpräzisen" Summen (z. B. Pythonsmath.fsum
). Daher sollten Sie diese Funktionen möglicherweise anstelle des naiven Summenalgorithmus verwenden.