2012-06-16 23 views
5

Przede wszystkim przepraszam za zły tytuł:/nieoczekiwane wyniki z specyficzny tryb zaokrąglania

Próbuję odtworzyć wyniki referat w sprawie obliczania wartości własnych o tridiagonal macierz symetryczna. Określam górne i dolne granice niektórych wartości poprzez zaokrąglenie do nieskończoności plus i minus.

Zamiast zmieniać za każdym razem tryb zaokrąglania, używam tylko "sztuczki": fl⁻ (y) = -fl⁺ (-y), gdzie fl⁻ (y) jest wartością y przy użyciu minus tryb zaokrąglania nieskończoności i fl⁺ (y) to wartość y, gdy używa się trybu zaokrąglania do plus nieskończoności. Tak, mam następujący fragment kodu w C:

fesetround(FE_UPWARD); 
first = - (-d[i] + x); 
second = (- ((e[i-1]*e[i-1])/a_inf)); 
a_inf = first + second; 

first = d[i] - x; 
second = - ((e[i-1]*e[i-1])/a_sup); 
a_sup = first + second; 

i to działa dobrze z wyjątkiem jednego przykładu, w którym a_inf daje mi prawo wynik, ale a_sup daje zły wynik, choć obu pierwszych i drugich zmiennych wydają się mieć te same wartości.

Jeśli jednak zrobić tak:

fesetround(FE_UPWARD); 
    first = - (-d[i] + x); 
    second = (- ((e[i-1]*e[i-1])/a_inf)); 

    fesetround(FE_DOWNWARD); 
    first = - (-d[i] + x); 
    second = (- ((e[i-1]*e[i-1])/a_sup)); 

uzyskać odpowiednie wyniki. Tak więc, jeśli użyję sztuczki fl⁻ (y) = -fl⁺ (-y), otrzymam właściwe wyniki, jeśli zmienię tryb zaokrąglania i użyję oryginalnego wyrażenia, otrzymam błędne wyniki. Każdy pomysł, dlaczego?

W obu przypadkach pierwsze i drugie zmienne wartości są następujące:

first 1.031250000000000e+07, second -1.031250000000000e+07 
first 1.031250000000000e+07, second -1.031250000000000e+07 

a poprawne wartości dla a_inf i a_sup są -1.862645149230957e-09 i + 1.862645149230957e-09, odpowiednio, ale w pierwszy przypadek a_sup = 0, co jest nie tak

Co Zgaduję, że dzieje się to jakiś katastrofalny odwołania, ale nie mam pojęcia, w jaki sposób go rozwiązać w tym przypadku ...

Dzięki z postęp!

+0

Czy ten język jest niezobowiązujący? – Lion

+0

oops, zapomniałem, że: /, edytowałem, to jest C. –

+0

Proszę sprawdź, czy tryb zaokrąglania został pomyślnie ustawiony. Widziałem to wcześniej, że "fesetround" nie miał wpływu na tryb zaokrąglania. Coś jak 'test_rounding()' w [tutaj] (http://reliablecomputing.eu/rigorousLP.c). Proszę całkowicie wyłączyć optymalizację kompilatora, wiadomo, że zepsuje to. – Ali

Odpowiedz

1

Pierwszy problem polega na tym, że używasz tylko "sztuczki", aby uzyskać zaokrąglenie first w kierunku -inf, a nie second, więc nadal jest zaokrąglana w kierunku + inf.

Drugi problem polega na tym, że C nie daje żadnej gwarancji co do sposobu obliczeń zmiennoprzecinkowych. W szczególności, kompilator może dowolnie zmieniać kolejność i ponownie kojarzyć operacje, które uzna za odpowiednie do działania, nawet jeśli takie zmiany mogą zmienić zachowanie zaokrąglania programu. Więc kiedy mówisz:

first = - (-d[i] + x); 

kompilator może zmienić to i zrobić jeden odejmowanie, zamiast negować, dodawać negować, który odwraca kierunek zaokrąglania. Teraz możesz czasami sprawić, aby wszystko działało zgodnie z oczekiwaniami, wyłączając całą optymalizację, ale nawet z tym nie ma żadnej gwarancji.

+0

+1 To, co miałem na myśli w moim komentarzu, optymalizacja kompilatora może zepsuć rzeczy. – Ali

Powiązane problemy