Ich schreibe ein Programm, in dem ich doppelte Punkte löschen muss, die in einer Matrix gespeichert sind. Das Problem ist, dass MATLAB bei der Überprüfung, ob sich diese Punkte in der Matrix befinden, diese in der Matrix nicht erkennen kann, obwohl sie vorhanden sind.
Im folgenden Code intersections
erhält die Funktion die Schnittpunkte:
[points(:,1), points(:,2)] = intersections(...
obj.modifiedVGVertices(1,:), obj.modifiedVGVertices(2,:), ...
[vertex1(1) vertex2(1)], [vertex1(2) vertex2(2)]);
Das Ergebnis:
>> points
points =
12.0000 15.0000
33.0000 24.0000
33.0000 24.0000
>> vertex1
vertex1 =
12
15
>> vertex2
vertex2 =
33
24
Zwei Punkte ( vertex1
und vertex2
) sollten aus dem Ergebnis entfernt werden. Dies sollte mit den folgenden Befehlen erfolgen:
points = points((points(:,1) ~= vertex1(1)) | (points(:,2) ~= vertex1(2)), :);
points = points((points(:,1) ~= vertex2(1)) | (points(:,2) ~= vertex2(2)), :);
Danach haben wir dieses unerwartete Ergebnis:
>> points
points =
33.0000 24.0000
Das Ergebnis sollte eine leere Matrix sein. Wie Sie sehen können, ist das erste (oder zweite?) Paar von[33.0000 24.0000]
eliminiert, aber nicht das zweite.
Dann habe ich diese beiden Ausdrücke überprüft:
>> points(1) ~= vertex2(1)
ans =
0
>> points(2) ~= vertex2(2)
ans =
1 % <-- It means 24.0000 is not equal to 24.0000?
Worin besteht das Problem?
Überraschenderweise habe ich ein neues Skript erstellt, das nur die folgenden Befehle enthält:
points = [12.0000 15.0000
33.0000 24.0000
33.0000 24.0000];
vertex1 = [12 ; 15];
vertex2 = [33 ; 24];
points = points((points(:,1) ~= vertex1(1)) | (points(:,2) ~= vertex1(2)), :);
points = points((points(:,1) ~= vertex2(1)) | (points(:,2) ~= vertex2(2)), :);
Das Ergebnis wie erwartet:
>> points
points =
Empty matrix: 0-by-2
quelle
1.2 - 0.2 - 1 == 0
und1.2 - 1 - 0.2 == 0
. Überraschend, nicht wahr? Wenn Sie mit Gleitkommazahlen arbeiten, ist die Reihenfolge der Operationen von Bedeutung.Antworten:
Das Problem, das Sie haben, hängt damit zusammen, wie Gleitkommazahlen auf einem Computer dargestellt werden. Eine detailliertere Diskussion der Gleitkomma-Darstellungen erscheint gegen Ende meiner Antwort (Abschnitt "Gleitkomma-Darstellung"). Die TL; DR- Version: Da Computer über einen begrenzten Speicher verfügen, können Zahlen nur mit endlicher Genauigkeit dargestellt werden. Daher ist die Genauigkeit von Gleitkommazahlen auf eine bestimmte Anzahl von Dezimalstellen beschränkt (etwa 16 signifikante Stellen für Werte mit doppelter Genauigkeit , die in MATLAB verwendete Standardeinstellung).
Tatsächliche vs. angezeigte Präzision
Nun das spezielle Beispiel in der Frage zu befassen ... während
24.0000
und24.0000
werden angezeigt in der gleichen Weise, stellt sich heraus , dass sie tatsächlich durch sehr kleine Dezimal - Beträge in diesem Fall unterscheiden. Sie sehen es nicht, da MATLAB standardmäßig nur 4 signifikante Stellen anzeigt , wodurch die Gesamtanzeige sauber und ordentlich bleibt. Wenn Sie die volle Genauigkeit sehen möchten, sollten Sie entweder denformat long
Befehl ausgeben oder eine hexadezimale Darstellung der Zahl anzeigen :>> pi ans = 3.1416 >> format long >> pi ans = 3.141592653589793 >> num2hex(pi) ans = 400921fb54442d18
Initialisierte Werte vs. berechnete Werte
Da es nur eine endliche Anzahl von Werten gibt, die für eine Gleitkommazahl dargestellt werden können, kann eine Berechnung zu einem Wert führen, der zwischen zwei dieser Darstellungen liegt. In einem solchen Fall muss das Ergebnis auf einen von ihnen gerundet werden. Dies führt zu einem kleinen Fehler bei der Maschinengenauigkeit . Dies bedeutet auch, dass das Initialisieren eines Werts direkt oder durch eine Berechnung leicht unterschiedliche Ergebnisse liefern kann. Beispielsweise hat der Wert
0.1
keine exakte Gleitkommadarstellung (dh er wird leicht abgerundet), sodass Sie aufgrund der Art und Weise, wie sich Rundungsfehler ansammeln, kontraintuitive Ergebnisse wie diese erhalten:>> a=sum([0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1]); % Sum 10 0.1s >> b=1; % Initialize to 1 >> a == b ans = logical 0 % They are unequal! >> num2hex(a) % Let's check their hex representation to confirm ans = 3fefffffffffffff >> num2hex(b) ans = 3ff0000000000000
Wie man Gleitkomma-Vergleiche richtig handhabt
Da sich Gleitkommawerte um sehr kleine Beträge unterscheiden können, sollten Vergleiche durchgeführt werden, indem überprüft wird, ob die Werte innerhalb eines Bereichs (dh einer Toleranz) voneinander liegen und nicht genau gleich sind. Zum Beispiel:
a = 24; b = 24.000001; tolerance = 0.001; if abs(a-b) < tolerance, disp('Equal!'); end
zeigt "Gleich!" an.
Sie können dann Ihren Code in Folgendes ändern:
points = points((abs(points(:,1)-vertex1(1)) > tolerance) | ... (abs(points(:,2)-vertex1(2)) > tolerance),:)
Gleitkomma-Darstellung
Ein guter Überblick über Gleitkommazahlen (und insbesondere den IEEE 754-Standard für Gleitkomma-Arithmetik ) sollte jeder Informatiker über Gleitkomma-Arithmetik von David Goldberg wissen .
Eine binäre Gleitkommazahl wird tatsächlich durch drei ganze Zahlen dargestellt: ein Vorzeichenbit
s
, einen Signifikanten (oder Koeffizienten / Bruch)b
und einen Exponentene
. Beim Gleitkommaformat mit doppelter Genauigkeit wird jede Zahl durch 64 Bit dargestellt, die wie folgt im Speicher angeordnet sind:Der reale Wert kann dann mit der folgenden Formel ermittelt werden:
Dieses Format ermöglicht Zahlendarstellungen im Bereich von 10 ^ -308 bis 10 ^ 308. Für MATLAB erhalten Sie diese Grenzwerte von
realmin
undrealmax
:>> realmin ans = 2.225073858507201e-308 >> realmax ans = 1.797693134862316e+308
Da es eine endliche Anzahl von Bits gibt, die zur Darstellung einer Gleitkommazahl verwendet werden, gibt es nur so viele endliche Zahlen, die innerhalb des oben angegebenen Bereichs dargestellt werden können. Berechnungen führen häufig zu einem Wert, der nicht genau mit einer dieser endlichen Darstellungen übereinstimmt. Daher müssen die Werte gerundet werden. Diese Maschinengenauigkeitsfehler machen sich auf unterschiedliche Weise bemerkbar, wie in den obigen Beispielen erläutert.
Um diese Rundungsfehler besser zu verstehen, ist es nützlich, die relative Gleitkomma-Genauigkeit der Funktion zu betrachten
eps
, die den Abstand von einer bestimmten Zahl zur nächstgrößeren Gleitkomma-Darstellung quantifiziert:>> eps(1) ans = 2.220446049250313e-16 >> eps(1000) ans = 1.136868377216160e-13
Beachten Sie, dass die Genauigkeit relativ zur Größe einer bestimmten dargestellten Zahl ist. Größere Zahlen haben größere Abstände zwischen Gleitkommadarstellungen und daher weniger Genauigkeitsstellen nach dem Dezimalpunkt. Dies kann bei einigen Berechnungen eine wichtige Überlegung sein. Betrachten Sie das folgende Beispiel:
>> format long % Display full precision >> x = rand(1, 10); % Get 10 random values between 0 and 1 >> a = mean(x) % Take the mean a = 0.587307428244141 >> b = mean(x+10000)-10000 % Take the mean at a different scale, then shift back b = 0.587307428244458
Beachten Sie, dass wir einen Wert erhalten, der sich für die letzten 3 signifikanten Stellen unterscheidet , wenn wir die Werte von
x
vom Bereich[0 1]
in den Bereich verschieben[10000 10001]
, einen Mittelwert berechnen und dann den Mittelwertversatz zum Vergleich subtrahieren. Dies zeigt, wie ein Versatz oder eine Skalierung von Daten die Genauigkeit der daran durchgeführten Berechnungen ändern kann, was bei bestimmten Problemen berücksichtigt werden muss.quelle
Schauen Sie sich diesen Artikel an: Die Gefahren des Gleitkommas . Obwohl seine Beispiele in FORTRAN sind, hat es Sinn für praktisch jede moderne Programmiersprache, einschließlich MATLAB. Ihr Problem (und die Lösung dafür) wird im Abschnitt "Sichere Vergleiche" beschrieben.
quelle
Art
Dieser Befehl zeigt den vollständigen Wert der Zahl an. Es ist wahrscheinlich so etwas wie 24.00000021321! = 24.00000123124
quelle
Versuche zu schreiben
Warnung: Sie könnten über das Ergebnis überrascht sein!
quelle
Vielleicht sind die beiden Zahlen wirklich 24.0 und 24.000000001, aber Sie sehen nicht alle Dezimalstellen.
quelle
Überprüfen Sie die Matlab EPS-Funktion .
Matlab verwendet Gleitkomma-Mathematik mit einer Genauigkeit von bis zu 16 Stellen (nur 5 werden angezeigt).
quelle