Domanda

Sto scrivendo un programma di cui ho bisogno di eliminare i punti duplicati memorizzati in una matrice. Il problema è che, quando si tratta di verificare se questi punti sono nella matrice, MATLAB può non riconoscerli nella matrice, anche se esistono.

Nel seguente codice, funzione intersections ottiene i punti di intersezione:

[points(:,1), points(:,2)] = intersections(...
    obj.modifiedVGVertices(1,:), obj.modifiedVGVertices(2,:), ...
    [vertex1(1) vertex2(1)], [vertex1(2) vertex2(2)]);

Il risultato:

>> points
points =
   12.0000   15.0000
   33.0000   24.0000
   33.0000   24.0000

>> vertex1
vertex1 =
    12
    15

>> vertex2    
vertex2 =
    33
    24

due punti (vertex1 e vertex2) dovrebbero essere eliminati dal risultato. Dovrebbe essere fatto dai comandi di seguito:

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

Dopo aver fatto questo, abbiamo questo risultato inatteso:

>> points
points =
   33.0000   24.0000

Il risultato dovrebbe essere una matrice vuota. Come si può vedere, la prima (o seconda?) Coppia di [33.0000 24.0000] è stata eliminata, ma non il secondo.

Poi ho controllato queste due espressioni:

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

Qual è il problema?


Più sorprendentemente, ho fatto un nuovo script che ha solo questi comandi:

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)), :);

Il risultato come previsto:

>> points
points =  
   Empty matrix: 0-by-2
È stato utile?

Soluzione

Il problema che stai avendo riferisce a come floating-point numeri sono rappresentati su un computer. Una discussione più dettagliata delle rappresentazioni in virgola mobile appare verso la fine della mia risposta (La sezione "rappresentazione in virgola mobile"). Il TL; DR Versione: perché i computer hanno una quantità finita di memoria, i numeri possono essere rappresentati soltanto con precisione finita. Pertanto, la precisione di numeri in virgola mobile è limitata ad un certo numero di cifre decimali (circa 16 cifre significative per valori in doppia precisione , il default usato in MATLAB).

vs. effettivi visualizzata precisione

Ora per affrontare l'esempio specifico nella domanda ... mentre 24.0000 e 24.0000 sono visualizzato nella stessa maniera, si scopre che in realtà differiscono di molto piccole quantità decimali in questo Astuccio. Non si vede perché MATLAB visualizza solo 4 cifre significative di default , mantenendo il display complessiva pulito e ordinato. Se volete vedere la massima precisione, si dovrebbe rilasciare il comando format long o visualizzare una esadecimale rappresentazione del numero:

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

inizializzato valori vs. calcolati i valori

Poiché ci sono solo un numero finito di valori che possono essere rappresentati da un numero in virgola mobile, è possibile per un calcolo al risultato in un valore che rientra tra due di queste rappresentazioni. In tal caso, il risultato deve essere arrotondato a uno di loro. Questo introduce un piccolo errore della macchina precisione . Questo significa anche che inizializzazione direttamente o da un calcolo un valore può dare risultati leggermente differenti. Ad esempio, il valore 0.1 non ha un esattamente virgola mobile rappresentazione (cioè viene leggermente arrotondato), e così si finisce con risultati contro-intuitivo come questo a causa del modo round- gli errori si accumulano off:

>> 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

Come gestire correttamente i confronti in virgola mobile

Poiché i valori in virgola mobile possono differire da quantità molto piccole, ogni confronto dovrebbe essere fatto verificando che i valori sono entro qualche intervallo (cioè tolleranza) l'una dall'altra, al contrario di pari esattamente a vicenda. Ad esempio:

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

visualizzerà "Equal!".

È quindi possibile modificare il codice a qualcosa di simile:

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

virgola mobile rappresentazione

Una buona panoramica di numeri in virgola mobile (e in particolare la IEEE 754 standard per virgola mobile ) è Quello che ogni Computer Scientist dovete sapere su galleggiante -Point aritmetica da David Goldberg.

Un numero a virgola mobile binario è effettivamente rappresentata da tre numeri interi: un bit di segno s, una significante (o coefficiente / frazione) b, e un esponente e. Per doppia precisione formato a virgola mobile , ogni numero è rappresentato da 64 bit di cui in memoria come segue:

 entrare descrizione dell'immagine qui

Il valore reale può essere trovato con la formula seguente:

enter image description qui

Questo formato consente di rappresentazioni numeriche nell'intervallo 10 ^ -308 a 10 ^ 308. Per MATLAB è possibile ottenere questi limiti dalla realmin e realmax :

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

Poiché ci sono un numero finito di bit utilizzati per rappresentare un numero in virgola mobile, ci sono solo tante numeri finiti che possono essere rappresentati all'interno della sopra determinato intervallo. Calcoli spesso risultare in un valore che non corrisponde esattamente una di queste rappresentazioni finite, per cui i valori sono arrotondati. Questi errori macchina precisione si rendono evidenti in diversi modi, come discusso negli esempi precedenti.

Per meglio comprendere questi errori di arrotondamento è utile osservare la precisione in virgola mobile rispetto fornita dalla funzione eps , che quantifica la distanza da un determinato numero all'altro grande rappresentazione in virgola mobile:

>> eps(1)
ans =
     2.220446049250313e-16
>> eps(1000)
ans =
     1.136868377216160e-13

Si noti che la precisione è relativa alla dimensione di un dato numero essere rappresentato; grandi numeri avranno grandi distanze tra rappresentazioni in virgola mobile, e avranno così meno cifre di precisione dopo il punto decimale. Questa può essere una considerazione importante con alcuni calcoli. Si consideri il seguente esempio:

>> 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

Si noti che quando passiamo i valori x dalla gamma [0 1] alla gamma [10000 10001], calcolare una media, quindi sottrarre l'offset per il confronto medio, otteniamo un valore che differisce per le ultime 3 cifre significative. Questo illustra come un ridimensionamento offset o dei dati può cambiare l'accuratezza dei calcoli effettuati su di esso, che è qualcosa che deve essere contabilizzata con alcuni problemi.

Altri suggerimenti

un'occhiata a questo articolo: I rischi della virgola mobile . Anche se i suoi esempi sono in FORTRAN ha senso per praticamente qualsiasi linguaggio di programmazione moderno, tra cui MATLAB. Il vostro problema (e la soluzione per esso) è descritta nella sezione "Confronti sicurezza".

Tipo

format long g

Questo comando mostrerà l'intero valore del numero. E 'probabile che sia qualcosa come 24,00000021321! = 24,00000123124

Provare a scrivere

  

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

Attenzione: Potreste essere sorpresi del risultato

Forse i due numeri sono davvero 24,0 e 24,000,000001 millions, ma non riesci a vedere tutte le cifre decimali.

Controlla la Matlab funzione EPS .

Matlab usa matematiche in virgola mobile fino a 16 cifre di precisione (vengono visualizzati solo 5).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top