Problem z NaN

Awatar użytkownika
Vigl
Użytkownik
Użytkownik
Posty: 283
Rejestracja: 28 wrz 2007, o 12:19
Płeć: Mężczyzna
Lokalizacja: Krosno/Kraków
Podziękował: 13 razy
Pomógł: 67 razy

Problem z NaN

Post autor: Vigl »

Wprowadzenie:
F1(N) - stablicowana funkcja (dokładniej wygenerowany, znormalizowany rozkład gaussa N(0,4)), N=500
F2(N) - funkcja F2=F1'+constF1=\(\displaystyle{ \frac{F(i-1)-2F(i)+F(i+1)}{h^2}+CF1}\) (trójpunktowy wzór na drugą pochodną)
Teraz zapiszę skrótowo kod, z którym jest problem w "pseudo-fortranie":

Kod: Zaznacz cały

PROGRAM

DO i=1,N !pętla po wszystkich elementach (wartościach funkcji)
             DO t=0.0,Kdt,dt !pętla "czasowa" - krok dt, K iteracji
                        F1=F1-F2 !olbrzymi skrót - tu oczywiście korzystam z procedury, by    dokonać czasowej ewolucji funkcji F1, w tym celu również ewoluuję F2
              END DO
              WRITE F1 !wypisanie "wyewoluowanej" F1 po K iteracjach
END DO
Od pewnej ilości kroków czasowych (niewielkiej; już od K=5 się sypie), OD pewnego elementu tablicy F1 dostaję NaN (czym wyższe K, tym wcześniej się sypie).
Moje pytania to oczywiście: dlaczego i jak sobie z tym poradzić?

Moje badanie:
F2 z powodu małego kroku h jak i małego licznika mogłoby powodować ≈ 0/0, a więc symbol nieoznaczony, czyli NaN. Ten problem też się pojawił, ale go wyeliminowałem - teraz F2 - przed wywołaniem procedury ewolucji sprawuje się wyśmienicie (więc warunki początkowe są OK).
SUBROUTINE: F1=F1-F2 - dla pewnych wartości działa dobrze (np. gdy ewoluuję F1 w x=0), nie powinno też generować żadnych NaN-ów, bo to tylko różnica dwóch małych liczb, a więc najwyżej powinienem dostać ładne zaokrąglone 0.
Problem siedzi więc (chyba) w dalszych ewolucjach F2, dla naprawdę małych wartości F1 (trochę dalej od maksimum krzywej w x=0)

Jakby to ciachnąć?
Problemem jest zapewne ograniczona precyzja liczb zmiennoprzecinkowych - może zwiększyć REAL na DOUBLE PRECISION? (choć sprawdzałem wcześniej jak to się zmienia w różnych przypadkach i mała poprawa...)
Może zmniejszyć przedział obliczeń? Prowadzę je dla x=[-250;250] - wiem, że to straszne biorąc pod uwagę funkcję jaką się zajmuję, ale takie były jednak odgórne polecenia (btw, h=1.0).
Mój faworyt: może przeskalować tego Gaussa - wartości x 100 np.?

Help.

Zaznaczam, powyżej to pseudokod (nieprecyzyjny - jedynie obrazowy) - wszystko się dobrze kompiluje, nie ma warnów, szczególiki są sprawdzone, warunki brzegowe (zerowanie F1 i F2 dla granic przedziału) i początkowe dobre, i poprawnie nałożone.
Jeżeli ktoś się zainteresuje i będzie chciał zobaczyć jak to naprawdę wygląda, to oczywiście udostępnię kod. Nie zrobiłem tego teraz, żeby nie straszyć - trochę tego jest, trochę skomplikowane, a ponadto z pewnością dalekie od programistycznej estetyki.
soku11
Użytkownik
Użytkownik
Posty: 6607
Rejestracja: 16 sty 2007, o 19:42
Płeć: Mężczyzna
Podziękował: 119 razy
Pomógł: 1823 razy

Problem z NaN

Post autor: soku11 »

Podejrzewam, że poprzez zmianę dzielenia przez zero na dzielenie przez 0.00001 dostajesz kosmicznie duże liczby. Dodając takie liczby również można dostać NaN:


Pozdrawiam.
Awatar użytkownika
Vigl
Użytkownik
Użytkownik
Posty: 283
Rejestracja: 28 wrz 2007, o 12:19
Płeć: Mężczyzna
Lokalizacja: Krosno/Kraków
Podziękował: 13 razy
Pomógł: 67 razy

Problem z NaN

Post autor: Vigl »

Dzięki, że przebrnąłeś przez to moje wypracowanie.
To fakt, NaN może tak powstać, ale ja nigdzie nie dzielę przez 0. A przynajmniej nieświadomie...

-- 5 lutego 2010, 15:18 --

Dobra, zrozumiałem pewną głupotę, którą miałem w kodzie - która właśnie mogła robić ogromne liczby i NaNa. Skoro już mam h=1.0, to po co trzymać go jako stałą i dzielić? Wywaliłem to po prostu, teraz w F2 nie ma dzielenia. Wynik: jest lepiej, ale NaNy się pojawiają - tyle, że od dalszych elementów tablicy.-- 5 lutego 2010, 20:17 --Dobra, wyeliminowałem różne opcje likwidacji problemu. Zidentyfikowałem jego clue. Problem jest z poniższym kodem, który generuje (czym większa ilość elementów tablic - tym "szybciej") najpierw to co chcę, później cholendarnie wielkie liczby, na NaNach kończąc.

Kod: Zaznacz cały

DO i=201,301
	
	!evolution
	DO tl=0,K
	call evol(psi_l(i),Hpsi_l(i))

	call evol(psi_l(i-1),Hpsi_l(i-1))
	call evol(psi_l(i+1),Hpsi_l(i+1))
	Hpsi_l(i)=Hpsi(psi_l(i),psi_l(i-1),psi_l(i+1),V_l,dx)

	END DO !evolution over

	WRITE(*,*) psi_l(i)
	END DO
psi_l to stablicowane F1
Hpsi_l to stablicowane F2
V_l to tablica stałych
Ewolucja:

Kod: Zaznacz cały

SUBROUTINE evol(psi,Hpsi)
	REAL psi,Hpsi

	psi=psi-Hpsi 

	END
Sypie się już dla K>=2.

Skąd się biorą te schizy i jak to ruszyć?
soku11
Użytkownik
Użytkownik
Posty: 6607
Rejestracja: 16 sty 2007, o 19:42
Płeć: Mężczyzna
Podziękował: 119 razy
Pomógł: 1823 razy

Problem z NaN

Post autor: soku11 »

Nie wiem co to za język, ale nie ma to tego jakiegoś debuggera? Tak to trudno odgadnąć jakie te wartości są i co może powodować błąd. Jak nie ma, to podaj chociaż wartości tych tablic F1 i F2, bo nie chce mi się tego liczyć na kartce

Pozdrawiam.
Awatar użytkownika
Vigl
Użytkownik
Użytkownik
Posty: 283
Rejestracja: 28 wrz 2007, o 12:19
Płeć: Mężczyzna
Lokalizacja: Krosno/Kraków
Podziękował: 13 razy
Pomógł: 67 razy

Problem z NaN

Post autor: Vigl »

To jest fortran 77 (zresztą żadna różnica czy 77,90,03 ). A kompiluję go korzystając z GCC dla fortrana, także mam tylko wykaz błędów i warnów w konsoli.

Tablice F1 i F2:



Pzdr.
soku11
Użytkownik
Użytkownik
Posty: 6607
Rejestracja: 16 sty 2007, o 19:42
Płeć: Mężczyzna
Podziękował: 119 razy
Pomógł: 1823 razy

Problem z NaN

Post autor: soku11 »

Skoro kompilujesz z użyciem gcc, to jest tam flaga -g. Później tylko robisz gdb a.out i powinien debugger się włączyć. Albo możesz spróbować użyć nakładki ddd, która umożliwia graficzny podgląd. Ogólnie trudno powiedzieć co jest nie tak. Liczby są małe, więc nie powinno być jakichś dziwnych błędów przy odejmowaniu. Nie wiem tylko co robi ta linijka:

Kod: Zaznacz cały

Hpsi_l(i)=Hpsi(psi_l(i),psi_l(i-1),psi_l(i+1),V_l,dx)
To jakiś konstruktor obliczający średnią z podanych liczb? Co to jest to V_l i dx?

Pozdrawiam.
Awatar użytkownika
Vigl
Użytkownik
Użytkownik
Posty: 283
Rejestracja: 28 wrz 2007, o 12:19
Płeć: Mężczyzna
Lokalizacja: Krosno/Kraków
Podziękował: 13 razy
Pomógł: 67 razy

Problem z NaN

Post autor: Vigl »

Ok, pobawię się później tym debuggerem. Muszę coś o tym poczytać, bo nie za bardzo wiem jak się taki debugger obsługuje i co on może mi ciekawego powiedzieć.

Hpsi_l[N] to ta tablica F2 (w tej pętli ona jest co iteracje na nowo wypełniania, bo psi_l się zmienia).

Kod: Zaznacz cały

	REAL  FUNCTION Hpsi(psi,psi1,psi2,V)
	REAL  psi,psi1,psi2,V

	Hpsi=-(psi1-2.*psi+psi2)+V*psi
dx już nie ma, bo jak stwierdziłem, żeby było równe jeden, to je całkiem mogłem wywalić.
V_l[N] to stałe - dla 50 centralnych elementów V_l=0.1, dla pozostałych po prostu 0 (to jest studnia potencjału jakby co ).
ODPOWIEDZ