2013-09-05 8 views
13

Czy ktoś wie, dlaczego poniżej nie równa się 0?Dlaczego sin (180) nie jest zero podczas używania Pythona i Numpy?

import numpy as np 
np.sin(np.radians(180)) 

czyli

np.sin(np.pi) 

Kiedy wprowadzić go w python daje mi 1.22e-16.

+7

Błąd zaokrąglania punktu swobodnego. – Keith

+3

Pi nie może być reprezentowana dokładnie jako liczba zmiennoprzecinkowa, więc 'sin (pi)' nie będzie dokładnie zero. – Blender

+0

Czy jest poprawka, czy muszę ją przekonwertować na int? – MCF

Odpowiedz

13

Numer π nie może być dokładnie odwzorowywany jako liczba zmiennoprzecinkowa. Tak więc np.radians(180) nie daje π, daje 3.1415926535897931.

I sin(3.1415926535897931) jest w rzeczywistości czymś w rodzaju 1.22e-16.

Jak sobie z tym poradzić?

Trzeba wypracować, lub przynajmniej domyślać się, odpowiednich bezwzględnych i/lub względnych granicach błędu, a następnie zamiast x == y, piszesz:

abs(y - x) < abs_bounds and abs(y-x) < rel_bounds * y 

(oznacza to również, że trzeba zorganizować Twój obliczeń tak, że względny błąd jest większy w stosunku do y niż x. W twoim przypadku, ponieważ y jest stałą 0, że to banalne, po prostu zrób to w tył.)

Numpy oferuje funkcję, która robi to za ciebie po drugiej stronie cała tablica, allclose:

np.allclose(x, y, rel_bounds, abs_bounds) 

(To faktycznie sprawdza abs(y - x) < abs_ bounds + rel_bounds * y), ale to prawie zawsze jest wystarczający, i można łatwo zreorganizować swój kod, gdy tak nie jest.)

W twoim przypadku:

np.allclose(0, np.sin(np.radians(180)), rel_bounds, abs_bounds) 

Więc, skąd wiesz, jakie są właściwe granice? Nie ma sposobu, aby nauczyć cię wystarczająco dużo analiz błędów w odpowiedzi na SO. Propagation of uncertainty w Wikipedii daje ogólny przegląd. Jeśli naprawdę nie masz pojęcia, możesz użyć wartości domyślnych, które są bezwzględne i są względne oraz względne i 1e-8.

+2

W rzeczywistości mam dobrą znajomość analizy błędów, więc jest to bardzo pomocne. – MCF

+2

Błąd w tym konkretnym miejscu będzie prawie dokładnie równy błędowi w np.radians (180).Błąd ten wynosi prawdopodobnie około 0,5 do 1,0 ULP (jednostki w ostatnim miejscu), lub około 3,14 * DBL_EPSILON, lub około 7e-16. Mój szacunek błędu był najgorszym oszacowaniem, więc nie jest zaskakujące, że faktyczny błąd jest nieco mniejszy. Przeczytaj ten artykuł, aby poznać szczegóły (i niektóre przemyślenia na temat tego, jak cudownie jest to fajne): https://randomascii.wordpress.com/2014/10/09/intel-underestimates-error-bounds-by- 1-3-kwintillion/ –

-3

Problem nie jest błędem zaokrąglania pi. Należy zauważyć, że problem nie pojawia się na cosinus:

In [2]: np.sin(np.pi) 
    Out[2]: 1.2246467991473532e-16 != 0. 
    In [3]: np.cos(np.pi) 
    Out[3]: -1.0     == -1. 

Problem jest o wiele bardziej skomplikowana .... Jest to związane z precyzją pi wewnątrz procesora. Zostało to odkryte i wyjaśnione tutaj: https://randomascii.wordpress.com/2014/10/09/intel-underestimates-error-bounds-by-1-3-quintillion/

+1

Poza tym, jak ten artykuł (mój artykuł, jak się okazuje) wyjaśnia błąd zaokrąglania Pi jest dużą częścią problemu. Jeśli sin (double (pi)) zwraca zero, twoja funkcja sin jest zepsuta. Błąd, który wskazuję w tym artykule, jest taki, że sin (double (pi)) na niektórych komputerach zwraca * nieprawidłową * niezerową liczbę. Cos działa, ponieważ błąd jest poniżej progu dokładności dla 1,0, który jest związany z rachunkiem różniczkowym (nachylenie cos (pi) wynosi zero, nachylenie sin (pi) wynosi 1) i wielkość odpowiedzi. –

Powiązane problemy