2012-08-05 12 views
5

Pracuję nad projektem, który musi wdrożyć kilka metod numerycznych w FORTRAN. W tym celu muszę napisać funkcje rekursywne. Oto mój kod.Funkcje FORTRAN

!  
! File: main.F95 
! 

RECURSIVE FUNCTION integrate(n) RESULT(rv) 
    IMPLICIT NONE 
    DOUBLE PRECISION :: rv 
    INTEGER, INTENT(IN) :: n 
    DOUBLE PRECISION, PARAMETER :: minusone = -1.0 
    IF (n == 1) THEN 
     rv = 10 !exp(minusone) 
     RETURN 
    ELSE 
     rv = 1 - (n * integrate(n - 1)) 
     RETURN 
    END IF 
END FUNCTION integrate 

RECURSIVE FUNCTION factorial(n) RESULT(res) 
    INTEGER res, n 
    IF (n .EQ. 0) THEN 
     res = 1 
    ELSE 
     res = n * factorial(n - 1) 
    END IF 
END 

PROGRAM main 
    DOUBLE PRECISION :: rv1 
    PRINT *, factorial(5) 
    PRINT *, integrate(2) 

    !READ *, rv1 

END PROGRAM main 

dla tego programu wyjście jest:

  NaN 
     1 

Jeśli zmienić kolejność instrukcji print (linia 30 & 31), wyjście będzie:

  1 
-19.000000 

Output powinno być (dla oryginalnego polecenia drukowania):

120 
    -19 

Wziąłem funkcję silni ze strony Wikipedia Fortran 95 language features. Jestem nowy w FORTRAN, nie wiem, co jest nie tak w moim kodzie. Proszę, pomóżcie mi chłopaki.

  • Compiler: gfortran 4.5.3 z Cygwin
  • IDE: Netbeans 7.0.1
  • Platforma: Windows 7

Z góry dziękuję.

+0

Bardzo dobre pytanie, pokazujące funkcję funkcji rekursywnej i dbałość o szczegóły. DZIĘKUJĘ CI. –

Odpowiedz

8

Twoje funkcje są napisane poprawnie. Problem występuje w programie głównym, w którym nie jawnie zadeklarowano typu funkcji integrate i factorial, więc masz niejawne pisanie, w którym to przypadku zakłada się, że factorialREAL i integrate przyjmuje się jako INTEGER. Z jakiegoś powodu kompilator nie ostrzegł o niezgodności typów. Kopalnia zrobiła:

$ gfortran recurs.f90 
recurs.f90:26.22: 

    PRINT *, integrate(2) 
         1 
Error: Return type mismatch of function 'integrate' at (1) (INTEGER(4)/REAL(8)) 
recurs.f90:27.22: 

    PRINT *, factorial(5) 
         1 
Error: Return type mismatch of function 'factorial' at (1) (REAL(4)/INTEGER(4)) 

powinien zmienić swój główny program:

PROGRAM main 
    IMPLICIT NONE 
    DOUBLE PRECISION, EXTERNAL :: integrate 
    INTEGER, EXTERNAL :: factorial 
    PRINT *, factorial(5) 
    PRINT *, integrate(2) 
END PROGRAM main 

Zawiadomienie linii IMPLICIT NONE. Ta deklaracja deklaracji wyłącza wszelkie niejawne pisanie, a kompilator zgłosiłby błąd, gdyby nie wszystkie zmienne i funkcje zostały jawnie zadeklarowane. Jest to bardzo ważna kwestia w każdym programie Fortran, a gdybyś miał, to sam byś wymyślił swój problem, ponieważ zmusiłoby Cię to do jawnego zadeklarowania wszystkiego w twoim programie.

Wyjście teraz jest:

  120 
    -19.0000000000000  

jak oczekiwano.

Na marginesie, deklaracja typu DOUBLE PRECISION nie jest tak elastyczna, jak użycie parametru REAL z podanym parametrem KIND, np. REAL(KIND=myRealKind). Zobacz odpowiedzi na to pytanie dotyczące prawidłowego stosowania KIND: Fortran 90 kind parameter.

+0

Dziękuję @ IRO-bot, który działał bardzo dobrze, dziękuję. –

+0

@SajithJanaprasad Nie ma za co. Zauważ, że gdy czyjś odpowiedź jest przydatna, możesz również awansować, klikając strzałkę w górę w lewym górnym rogu odpowiedzi. – milancurcic

+0

Tak, wiem. Kliknąłem strzałkę w górę, ale nie mogę przegłosować, ponieważ nie mam 15 punktów reputacji. Wybacz, stary. Dziękuję ponownie za notatkę. –

10

Jako jeden z komentarzy wspomniałem, że lepszym rozwiązaniem jest umieszczenie podprogramów i funkcji w module, a następnie użycie tego modułu z głównego programu. Dzięki temu interfejs tych procedur będzie znany rozmówcy - "wyraźny" w terminologii Fortran.Kompilator nie tylko będzie poprawnie obsługiwał typ funkcji, ale także będzie w stanie sprawdzić zgodność między argumentami w wywołaniu a argumentami w adresie URL ("argumenty atrapa") w celu zachowania spójności.

Jeśli użyjesz jak największej liczby opcji debugowania, kompilator pomoże Ci znaleźć błędy. Z gfortran, spróbuj: -O2 -fimplicit-none -Wall -Wline-truncation-Character-truncation -Wurstrising -Waliasing -Wimplicit-interface -Programem użytym -fwhole-file -fcheck = all -std = f2008 -pedantic-fbacktrace

module factorial_procs 

    IMPLICIT NONE 

contains 

    RECURSIVE FUNCTION integrate(n) RESULT(rv) 
     DOUBLE PRECISION :: rv 
     INTEGER, INTENT(IN) :: n 

     IF (n == 1) THEN 
      rv = 10 
      RETURN 
     ELSE 
      rv = 1 - (n * integrate(n - 1)) 
      RETURN 
     END IF 
    END FUNCTION integrate 

    RECURSIVE FUNCTION factorial(n) RESULT(res) 
     INTEGER res, n 
     IF (n .EQ. 0) THEN 
      res = 1 
     ELSE 
      res = n * factorial(n - 1) 
     END IF 
    END 

end module factorial_procs 

PROGRAM main 

    use factorial_procs 

    implicit none 

    PRINT *, factorial(5) 
    PRINT *, integrate(2) 

END PROGRAM main 

Prawdopodobnie okaże się, że można obliczyć tylko silni bardzo małych liczb całkowitych przez proste mnożenie do przodu, używając zwykłych liczb całkowitych. Jedna poprawka jest użycie większej liczby całkowitej typu, np

integer, parameter :: BigInt_K = selected_int_kind (18) 

Tak jak można zmodernizować i wykorzystać selected_real_kind zamiast podwójnej precyzji.

+2

Dziękuję za wskazówkę "użytkowania modułu", pomógł mi rozwiązać inny problem. –

+0

Moduły to najlepszy sposób na zapisanie większości swoich funkcji. – Zeus

0
I would like to highlight some points while using RECURSIVE functions or non recursive function. 

1. Upewnij się, że funkcja ma jawny interfejs z programem wywołującym. Można to osiągnąć poprzez umieszczenie funkcji w module i powiązanie USE. Zostało to wyjaśnione we wspomnianej powyżej odpowiedzi. 2. można użyć interfejsu do budowania jawnego interfejsu z głównym programem wywołującym, jest to przydatne, gdy masz bardzo mało liczb funkcji, które mają niejawny interfejs, jak w twoim przypadku. Przykład podano poniżej.

PROGRAM main 
IMPLICIT NONE 
    INTERFACE 
    FUNCTION factorial(n) 
    INTEGER:: factorial 
    INTEGER, INTENT(IN):: n 
    END FUNCTION factorial 

    FUNCTION integrate(n) 
    DOUBLE PRECISION:: integrate 
    INTEGER, INTENT(IN):: n 
    END FUNCTION integrate 
END INTERFACE 

PRINT *, factorial(5) 
PRINT *, integrate(2) 

END PROGRAM main 

uwaga to zawsze lepiej, aby określić rodzaj parametru, a następnie za pomocą rodzaju klauzulę jak wyjaśnił @milancurcic

Jest jeszcze inny bardzo prosty sposób na rozwiązanie problemu: Wystarczy zdefiniować silni i itegrate w programie głównym w następujący sposób i jesteś gotowy do pracy

PROGRAM main 
IMPLICIT NONE 
    DOUBLE PRECISION :: integrate 
    INTEGER:: factorial 
    PRINT *, factorial(5) 
    PRINT *, integrate(2) 

END PROGRAM main