2016-03-18 11 views
0

Angenommen, wir (a + b) auf zwei verschiedene Arten berechnet werden sollen, dasszwei gleiche Gleitkommazahlen in MATLAB Subtrahieren nicht gleich 0

  1. ist (a + b) * (a + b)

  2. ein + 2 ab + b

Jetzt , angenommen a = 1.4 und b = -2.7. Wenn wir diese beiden Zahlen in den Formeln mit format long Stecker erhalten wir in beiden Fällen 1.690000000000001, das heißt, wenn ich das folgende Skript ausführen:

a = 1.4; 
b = -2.7; 

format long 

r = (a + b) * (a + b) 

r2 = a^2 + 2*a*b + b^2 

abs_diff = abs(r - r2) 

I erhalten

r = 1.690000000000001 

r2 = 1.690000000000001 

abs_diff = 6.661338147750939e-16 

Was ist hier los? Ich könnte verschiedene Ergebnisse für r oder r2 Vorschau (weil Matlab würde verschiedene Gleitkommaoperationen ausführen), aber nicht für den absoluten Wert ihrer Differenz Vorschau.

Ich habe auch bemerkt, dass der relative Fehler von r und r2 verschieden sind, das heißt, wenn ich

rel_err1 = abs(1.69 - r)/1.69 
rel_err2 = abs(1.69 - r2)/1.69 

I erhalten

rel_err1 = 3.941620205769786e-16 

rel_err2 = 7.883240411539573e-16 

Dieses nur mich denken lässt, dass r sind nicht wirklich das gleiche r2. Gibt es eine Möglichkeit, sie dann vollständig zu sehen, wenn sie wirklich anders sind? Wenn nicht, was passiert?

Auch beide relative Fehler sind nicht weniger als eps/2, bedeutet dies, dass ein Überlauf passiert ist? Wenn ja, wo?


Hinweis: Dies ist ein spezieller Fall. Ich habe verstanden, dass es sich um Gleitkommazahlen und Rundungsfehler handelt. Aber ich möchte sie besser verstehen, indem ich dieses Beispiel durchführe.

+1

Es ist wahrscheinlich wegen die Tatsache, dass Gleitkommafehler abhängig sind ds auf dem * Auftrag *, * Typ * und * Anzahl * von Operationen. Ihre zwei Methoden haben unterschiedliche Anzahl und Arten von Operationen. Der mit [mehr Additionen führt theoretisch ein] (http://floating-point-gui.de/errors/propagation/) mehr Gleitkommafehler. Außerdem verursachen mehr Operationen eine größere Fehlerausbreitung. – Suever

+0

@Suever Meine Intuition war, dass, da beide Methoden tatsächlich unterschiedlich implementiert sind, d. H. Verschiedene Gleitkommaoperationen verwenden, wir unterschiedliche Ergebnisse erhalten würden, und dies würde erklären, dass ihr Unterschied von 0 (auf jeden Fall) verschieden ist. Aber Matlab repräsentiert anscheinend "r" und "r2" in der gleichen Weise, also sollte ihr Unterschied 0 sein ... – nbro

+0

was in Ihrem Beitrag zeigt, dass MATLAB 'r' und' r2' auf die gleiche Weise darstellt? – Suever

Antwort

1

Floating point arithmetic is not associative.

Während mathematisch diese beiden gleich sind, sind sie nicht in Fließkomma-Mathematik.

r = (a + b) * (a + b) 

r2 = a^2 + 2*a*b + b^2 

Die Reihenfolge Operationen in Fließkomma-Mathematik ausgeführt wird, ist sehr relevant. Deshalb müssen Sie, wenn Sie Fließkomma-Berechnungen durchführen, sehr genau auf die Reihenfolge Ihrer Multiplikationen achten, besonders wenn Sie mit sehr großen Zahlen zusammen mit sehr kleinen Zahlen arbeiten.

+0

Ok, aber wenn 'r' und' r2' im Speicher scheinbar mit der gleichen Nummer vertreten sind, ist ihre absolute Unterschied wäre gleich Null ... – nbro

3

Verlassen Sie sich nicht auf die Ausgabe von format long zu dem Schluss, dass zwei Zahlen gleich sind ...

a = 1.4; 
b = -2.7 
r1 = (a + b) * (a + b); 
r2 = a^2 + 2*a*b + b^2; 
r3 = (a+b)^2; 

Stattdessen können Sie ihre hexadezimale Darstellung prüfen mit:

>> num2hex([r1 r2 r3]) 
ans = 
3ffb0a3d70a3d70d 
3ffb0a3d70a3d710 
3ffb0a3d70a3d70d 

oder die printf Familie von Funktionen:

>> fprintf('%bx\n', r1, r2, r3) 
3ffb0a3d70a3d70d 
3ffb0a3d70a3d710 
3ffb0a3d70a3d70d 

oder sogar:

>> format hex 
>> disp([r1; r2; r3]) 
    3ffb0a3d70a3d70d 
    3ffb0a3d70a3d710 
    3ffb0a3d70a3d70d 
+0

Was ist mit dem Vorschlag, 'fprintf' zu verwenden, um eine Gleitkommazahl mit so vielen Dezimalstellen zu drucken, wie wir wollen, zB' fprintf ('%. 60f', mein_float); ' ? – nbro

+0

Ich würde immer der hexadezimalen Repräsentation mehr vertrauen, weil das die tatsächlichen 1's und 0's sind, keine Rundung involviert ... Ganz zu schweigen davon, wie weit wirst du mit 'fprintf' gehen, wenn' my_float = realmin' zum Beispiel? – Amro