Frage

Ich schreibe ein Programm, in dem ich in einer Matrix gespeichert doppelte Punkte löschen muß. Das Problem ist, dass, wenn es zu überprüfen kommt, ob diese Punkte in der Matrix sind, MATLAB sie in der Matrix nicht erkennen kann, obwohl sie vorhanden ist.

Im folgenden Code, intersections Funktion ruft 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 eliminiert werden. Es sollte durch die folgenden Befehle ausgeführt werden:

points = points((points(:,1) ~= vertex1(1)) | (points(:,2) ~= vertex1(2)), :);
points = points((points(:,1) ~= vertex2(1)) | (points(:,2) ~= vertex2(2)), :);

Nachdem das zu tun, haben wir dieses unerwartete Ergebnis:

>> points
points =
   33.0000   24.0000

Das Ergebnis sollte eine leere Matrix. Wie Sie sehen können, die erste (oder zweite?) Paar [33.0000 24.0000] beseitigt wurde, aber nicht die zweite.

Dann überprüfte ich diese beiden Ausdrücke:

>> points(1) ~= vertex2(1)
ans =
     0
>> points(2) ~= vertex2(2)
ans =
     1   % <-- It means 24.0000 is not equal to 24.0000?

Was ist das Problem?


Noch überraschender, habe ich ein neues Skript, das nur diese Befehle hat:

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
War es hilfreich?

Lösung

Das Problem betrifft die Sie haben, wie Gleitkommazahlen Zahlen auf einem Computer dargestellt werden. Eine detailliertere Diskussion der Gleitkommadarstellungen erscheint gegen Ende meiner Antwort (Der „Floating-Point-Darstellung“ Abschnitt). Die TL; DR Version: weil Computer endliche Mengen an Speicher haben, Zahlen können nur mit endlicher Genauigkeit dargestellt werden. Somit kann die Genauigkeit von Gleitkommazahlen ist beschränkt auf eine bestimmte Anzahl von Dezimalstellen (etwa 16 signifikante Ziffern double-precision Werte , die Standard in MATLAB verwendet wird).

Tatsächliche vs. Anzeigegenauigkeit

Nun das spezielle Beispiel in der Frage zu befassen ... während 24.0000 und 24.0000 sind angezeigt in der gleichen Weise, stellt sich heraus, dass sie tatsächlich durch sehr kleine Dezimal-Beträge in dieser abweichen Fall. Sie sehen es nicht, weil MATLAB zeigt 4 signifikante Stellen standardmäßig , die gesamte Anzeige sauber und ordentlich zu halten. Wenn Sie die volle Präzision sehen möchten, sollten Sie entweder den format long Befehl oder eine hexadezimale Darstellung der Zahl:

>> pi
ans =
    3.1416
>> format long
>> pi
ans =
   3.141592653589793
>> num2hex(pi)
ans =
400921fb54442d18

initialisierten Werte vs. berechnete Werte

Da es nur eine endliche Anzahl von Werten, die für eine Fließkommazahl dargestellt werden können, ist es möglich, für eine Berechnung in einem Wert zu führen, die zwischen zwei diesen Darstellungen fallen. In einem solchen Fall muss das Ergebnis einer von ihnen werden abgerundet. Dies führt einen kleinen Maschinengenauigkeit Fehler . Dies bedeutet auch, dass ein Wert, der direkt oder durch eine Berechnung der Initialisierung leicht unterschiedlichen Ergebnissen führen können. Zum Beispiel ist der Wert 0.1 nicht hat eine genau Gleitkommadarstellung (dh abgerundet wird leicht), und so am Ende mit kontra-intuitiven Ergebnissen wie dies auf den Weg nach oben rund- off Fehler akkumulieren:

>> 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 Sie sich richtig behandeln Gleitkommazahlen Vergleiche

Da Gleitkommawerte um sehr kleine Beträge unterscheiden können, sollten alle Vergleiche durch Überprüfung durchgeführt werden, dass die Werte innerhalb eines gewissen Bereichs (d.h. Toleranz) voneinander, im Gegensatz zu genau gleich zueinander sind. Zum Beispiel:

a = 24;
b = 24.000001;
tolerance = 0.001;
if abs(a-b) < tolerance, disp('Equal!'); end

zeigt "Equal".

Sie können dann Ihren Code etwas ändern wie:

points = points((abs(points(:,1)-vertex1(1)) > tolerance) | ...
                (abs(points(:,2)-vertex1(2)) > tolerance),:)

Gleitkommadarstellung

Eine gute Übersicht über Gleitkommazahlen (und insbesondere die IEEE 754-Standard für Gleitkomma-Arithmetik ) ist Was jeder Informatiker wissen sollten über Schwimmdock -Punkt Arithmetik von David Goldberg.

Eine binäre Gleitkommazahl ist tatsächlich von drei ganzen Zahlen repräsentiert: ein Vorzeichenbit s eine Mantisse (oder Koeffizient / Fraktion) b und ein Exponent e. Für Doppelte Genauigkeit wird jede Zahl durch 64 Bits dargestellt fest out im Speicher wie folgt:

 image description hier

Der tatsächliche Wert kann dann mit der folgenden Formel gefunden werden:

eingeben Bildbeschreibung hier

Dieses Format ermöglicht Zahlendarstellungen im Bereich von 10 ^ -308 bis 10 ^ 308. Für MATLAB können Sie diese Grenzen von realmin und realmax :

>> realmin
ans =
    2.225073858507201e-308
>> realmax
ans =
    1.797693134862316e+308

Da es eine endliche Anzahl von Bits verwendet, um eine Fließkommazahl zu repräsentieren, gibt es nur so viele endlichen Zahlen, die innerhalb des oben angegebenen Bereichs dargestellt werden können. Berechnungen wird oft in einem Wert führen, die nicht genau einer dieser endlichen Vorstellungen entsprechen, so müssen die Werte abgerundet. Diese Maschinengenauigkeit Fehler sich auf unterschiedliche Weise evident zu machen, wie in den obigen Beispielen diskutiert.

Um besser zu verstehen, diesen Rundungsfehler ist es nützlich bei der relativ zu sehen Genauigkeit Gleitkommazahlen durch die Funktion zur Verfügung gestellt

Andere Tipps

Sehen Sie in diesem Artikel: The Perils of Floating Point . Obwohl seine Beispiele in Fortran sind, hat es Sinn, für nahezu jede moderne Programmiersprache, einschließlich MATLAB. Ihr Problem (und Lösung für sie) in "Safe Vergleiche" beschrieben.

Typ

format long g

Mit diesem Befehl wird den vollen Wert der Zahl zeigen. Es ist wahrscheinlich so etwas wie 24,00000021321 sein! = 24,00000123124

Versuchen Schreiben

  

0,1 + 0,1 + 0,1 == 0,3.

Achtung: Sie könnten über das Ergebnis überrascht sein

Vielleicht sind die beiden Zahlen sind wirklich 24.0 und 24,000000001 aber Sie sehen nicht alle Dezimalstellen.

Schauen Sie sich die Matlab EPS Funktion .

Matlab Gleitkomma math bis zu 16 Ziffern Präzision verwendet (nur 5 werden angezeigt).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top