2011-07-31 10 views
6

Biorąc pod uwagę, że PI/2 nigdy nie może być przedstawiony dokładnie w postaci zmiennoprzecinkowej, czy można bezpiecznie założyć, że cos (a) nigdy nie zwróci dokładnego zera?Czy cos (a) kiedykolwiek równa się 0 w zmiennoprzecinkowej

Jeśli tak jest, to po pseudo-kod będzie nigdy wprowadzić blok (i to może być bezpiecznie usunięty):

... 
y = h/cos(a); 
if (!isfinite(a)) 
{ 
    // handle infinite y 
} 
+0

Czasami system może go zmusić zero, gdy "a" jest ok. równy 'pi/2'. – ja72

Odpowiedz

4

Zero jest jedną z kilku wartości, które można dokładnie przedstawić. Wiele systemów ma tabelę odnośników dla wspólnych wartości grzechu i cos, więc nie jest wykluczone, że dokładnie zero może zostać zwrócone.

Ale jesteś bezpieczniejszy używając delta porównania, przed wykonaniem podziału:

if (Abs(cos(a)) < 0.0000001) 
{ 

} 
+2

Jeden z "kilku"? Nie sądzę, bym użył terminu "kilka" dla (2^64 - 2^53). –

+0

1/2, 1/4, 1/8, ..... –

+1

Każda skończona wartość zmiennoprzecinkowa może być przedstawiana dokładnie w zmiennoprzecinkowej (szokujące, wiem). Nie tylko 1/2, 1/4, ale także 0.333333333333333314829616256247390992939472198486338125 i 3.141592653589790007373494518105871975421905517578125. –

0

nie, to nie może być zagwarantowana, ponieważ cos sama jest obliczany z błąd, więc jego wartość może być dokładnie równa zero całkiem łatwo.

7

różny od zera, podwójną wartość dokładności, która pochodzi najbliżej dokładną wielokrotnością p/2 jest 6381956970095103 * 2^797 , która jest równa:

(an odd integer) * π/2 + 2.983942503748063...e−19 

Zatem dla wszystkich wartości double-precision x, mamy związanego:

|cos(x)| >= cos(2.983942503748063...e−19) 

Należy zauważyć, że jest to związane z matematycznie dokładną wartością, a nie z wartością zwracaną przez funkcję biblioteczną cos. Na platformie z biblioteką matematyczną dobrej jakości ta granica jest wystarczająco dobra, aby można powiedzieć, że cos(x) nie jest zerem dla jakiejkolwiek podwójnej precyzji x. W rzeczywistości okazuje się, że nie jest to jednoznacznie podwójne; ta właściwość dotyczy wszystkich podstawowych typów IEEE-754, jeśli cos jest wiernie zaokrąglona.

Nie można jednak powiedzieć, że to nigdy nie mogło wystąpić na platformie, która miała spektakularnie słabą implementację redukcji argumentów trygonometrycznych.

Co ważniejsze, jest to krytyczny zauważyć, że w przykładzie y może być nieskończony bezcos(a) zerowej:

#include <math.h> 
#include <stdio.h> 

int main(int argc, char *argv[]) { 
    double a = 0x1.6ac5b262ca1ffp+849; 
    double h = 0x1.0p1022; 
    printf("cos(a) = %g\n", cos(a)); 
    printf("h/cos(a) = %g\n", h/cos(a)); 
    return 0; 
} 

skompilować i uruchomić:

scanon$ clang example.c && ./a.out 
cos(a) = -4.68717e-19 
h/cos(a) = -inf 
+0

Chciałbym odpowiedzieć na to dokładnie, a oprócz tego daje wskazówki, dlaczego tolerancja taka jak 0.0000001 brzmi całkowicie arbitralnie, to nawet nie zapobiegnie przepełnieniu. Zabezpieczenie przed przepełnieniem powinno być czymś w rodzaju if (abs (cos (x)) <1);) –

Powiązane problemy