2012-01-22 15 views
6

Próbuję porównać tablicę podwójnych do skalarnego podwójnego dla równości, ale równość nigdy nie jest rozpoznawana w pewnych okolicznościach. Podejrzewam, że ma to związek ze sposobem reprezentacji podwójnej (np. 1.0 vs 1.00), ale nie mogę tego rozgryźć.podwójne porównanie matlab

Na przykład, mam generowane tablicę złożoną z tysięcy wartości podwójnych, ostatnie kilka, które w pewnym momencie w czasie podane przez

10.6000 
-11.0000 
10.2000 
22.6000 
3.4000 

Gdybym przetestować dla równości do 10.2 (lub 10.2000) komendą array==10.2 (lub array=10.2000) zwracam tablicę 0s. Jeśli ręcznie wstawię podane wartości do tablicy (np. array=[10.6000 -11.0000 10.2000 22.6000 3.4000]), polecenie zakończy się pomyślnie (tj. array==10.2 zwraca 0 0 1 0 0). Czy ktoś mógłby wyjaśnić, dlaczego równość się powiedzie, jeśli wprowadzę wartości ręcznie, ale nie powiedzie się, jeśli tablica zostanie wygenerowana w kontekście programu? Jestem w stanie naprawić błąd porównania, używając raczej przybliżonego niż dokładnego porównania (np. (array<10.20001) & (array>10.19999)), ale wydaje się to niesatysfakcjonujące.

Edytuj: Wartości w tablicy są generowane przez wielokrotne dodawanie lub odejmowanie stałego podwójnego (np. 0.2). Moduł tej tablicy przez 0.2 powinien więc być wszędzie równy 0. W rzeczywistości moduł każdego elementu jest równa albo 0 lub 0.2, jak pokazano poniżej dla powyższej sekwencji liczb w tablicy:

mod(array,0.2) 
... 
0.2000 
    0 
0.2000 
0.2000 
    0 

Ponownie, jeśli wartości są umieszczone w układzie ręcznego i modułu zostanie pobrana oczekiwana wartość wszystkich 0 s.

Odpowiedz

6

Powodem jest to, że MATLAB skracała liczby w tablicy, aby zachować zachowanie tylko 4 cyfr po przecinku podczas wyświetlania. Oznacza to, że prawdziwą wartością twojej tablicy może być [10.600000000001, -10.99999999999, ...]. Masz rację, wynika to z wewnętrznej reprezentacji liczb zmiennoprzecinkowych w komputerze, co może powodować małe błędy w obliczeniach.

Osobiście uważam, że istnieją dwa rozwiązania, jeden jest przybliżonym dopasowaniem, tak jak zrobiłeś, podczas gdy drugi ma zaokrąglić pierwszą tablicę (powiedzmy, z this tool z FileExchange), a następnie dokładnie dopasować.

+0

Bardzo pomocna. Jednym z dalszych pytań jest to, że moje liczby zostały wygenerowane przez dodanie lub odjęcie stałej wartości (np. "0,2") przez wiele cykli w pętli, więc w matematyce liczby w tablicy powinny wynosić 0, gdy modulo 0.2 ('mod (array) , 0,2) '). W rzeczywistości nie są. Są równe 0 lub 0,2. Jednak oczywiście, kiedy zastosuję modulo 0.2 do dowolnej liczby w tablicy, wpisując je ręcznie, podana jest oczekiwana wartość 0. Czy możesz wyjaśnić to zachowanie? Dzięki! – user001

+1

Dotyczy to sposobu, w jaki liczby zmiennoprzecinkowe są reprezentowane na komputerach. Dobrze znany jest fakt, że komputery używają raczej plików binarnych niż dziesiętnych. Jednak pojawia się problem z binarną, tj. Skończoną frakcją, np. 0,2 w systemie dziesiętnym nie może być reprezentowane przez skończone cyfry w systemie binarnym. Oznacza to, że binarna reprezentacja 0,2 w komputerze jest w rzeczywistości 0,001110011100111 ..., która jest nieskończona. Jednak MATLAB używa 64 bitów do reprezentowania 'Single', co może powodować błąd 2^(- 65). Ten błąd jest raczej niewielki, ale gdy pojawi się sporo iteracji, może się on gromadzić. – grapeot

+0

Cudowne wytłumaczenie. Dziękuję bardzo. – user001

2

Coś jest prawdopodobnie w pojedynczej precyzji gdzieś i podwójne w innym miejscu. Binarna reprezentacja np. 10,2 w każdej jest inna, ponieważ kończą się po innej liczbie bitów. W ten sposób są one różne:

>> if (single(10.2) == 10.2) disp('honk'); end 
>> if (single(10.2) == single(10.2)) disp('honk'); end 
honk 

Musisz sprawdzić równości wewnątrz jakiegoś małą różnicą:

eps = 0.001; 
result = abs(array-10.2) < eps; 

można znaleźć precyzję używany w tablicy za pomocą whos:

>> whos A 
    Name  Size   Bytes Class  Attributes 

    A   1x2     8 single  
+0

Dzięki @Alex. Czy możesz zobaczyć mój komentarz pod postem grapeot. Jeśli wezmę tablicę, wygenerowaną przez serię dodawania lub odejmowania 0,2 (podwójną) w kontekście pętli, modulo każdego elementu tablicy to 0 lub 0.2, co nie ma sensu. Sprawdziłem dokładność mojej tablicy za pomocą komendy 'whos' (thanks), i jest ona podwójna, tak jak moja skalarna zmienna porównawcza. – user001

+1

0.2 nie może być reprezentowany dokładnie tak jak binarny float (patrz http://www.h-schmidt.net/FloatApplet/IEEE754.html), jest to dalszy ułamek 0.1001 [1001 ...]. Dodanie 0,2 do czegoś może nie zrobić dokładnie tego, co myślisz. Jeśli dokładność jest ważna, pracuj w minimalnych jednostkach problemu, w tym przypadku najprawdopodobniej najprościej będzie pracować przy 10x i dodaj 2 do liczb, a następnie sprawdź mod (num, 2), a następnie przeprowadź przez 10 na końcu. – Alex

+0

Dziękuję bardzo. Problem rozwiązuje się przez dodanie/odjęcie 0,25, co ma sens, ponieważ 0.25 może być dokładnie odwzorowany jako binarny zmienny zgodnie z podanym apletem. Przypuszczam, że najlepszym miejscem do znalezienia większej ilości informacji byłby artykuł o liczbach zmiennoprzecinkowych. – user001

1

Utwórz plik funkcji MATLAB, który będzie akceptował wartości modulo (od 3 do 9, czyli od Z3 do Z9), a wyświetli najmniejszą możliwą wartość opisaną przez warunki modulo.

próbki Symulacja:

Z = [3 4 5]; % Modulo Z3, Z4 i Z5

r = [2 1 4]; Reszta% Wartości

najmniejszą możliwą wartość to 29.

Wejścia Z musi być matryca matryca ... gdzie można wpisać dowolną liczbę od 3 do 9 .... i można wpisz 3,4,5,6,7,8,9 w dowolnej kolejności, w dowolnych par lub grup ...

wejścia r powinna być równa liczbie wejść oo też ...

wyjście powinno dać najmniejszą możliwą wartość, chociaż warunki modulo ...