2012-08-05 8 views
5

Sto lavorando a un progetto che deve implementare alcuni metodi numerici in FORTRAN. Per questo, ho bisogno di scrivere alcune funzioni ricorsive. Ecco il mio codice.Funzioni 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 

Per questo programma l'uscita è:

  NaN 
     1 

Se cambio l'ordine delle istruzioni di stampa (linea 30 & 31), l'uscita sarà:

  1 
-19.000000 

uscita dovrebbe essere (per l'ordine di estratto conto originale):

120 
    -19 

Ho preso la funzione fattoriale dalla pagina Wikipedia Fortran 95 language features. Sono nuovo in FORTRAN, non so cosa c'è di sbagliato nel mio codice. Per favore aiutami ragazzi.

  • Compiler: gfortran 4.5.3 con Cygwin
  • IDE: Netbeans 7.0.1
  • Piattaforma: Windows 7

Grazie in anticipo.

+0

Molto buona domanda, mostrando una funzione di funzione ricorsiva e attenzione ai dettagli. GRAZIE. –

risposta

8

Le tue funzioni sono state scritte correttamente. Il problema è nel programma principale, dove non si dichiara esplicitamente il tipo di funzioni integrate e factorial, quindi si ha una digitazione implicita, nel qual caso si assume factorialREAL e si assume integrateINTEGER. Per qualche ragione, il tuo compilatore non ti ha avvisato della mancata corrispondenza di tipo. Il mio ha fatto:

$ 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)) 

Si dovrebbe modificare il programma principale per:

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

Avviso linea IMPLICIT NONE. Questa dichiarazione disabilita qualsiasi digitazione implicita e il compilatore genera un errore se non tutte le variabili e le funzioni sono esplicitamente dichiarate. Questa è una linea molto importante in ogni programma Fortran e, se ce l'avessi, avresti capito da solo il tuo problema, perché ti costringerebbe a dichiarare esplicitamente ogni cosa nel tuo programma.

L'output ora è:

  120 
    -19.0000000000000  

come previsto.

Come nota a margine, la dichiarazione del tipo DOUBLE PRECISION non è flessibile come utilizzare REAL con il parametro KIND specificato, ad es. uno REAL(KIND=myRealKind). Consulta le risposte a questa domanda su come utilizzare correttamente KIND: Fortran 90 kind parameter.

+0

Grazie @ IRO-bot, ha funzionato molto bene, grazie. –

+0

@SajithJanaprasad Prego. Si noti che quando la risposta di qualcuno è utile, è possibile anche fare un voto facendo clic sulla freccia su nell'angolo in alto a sinistra della risposta. – milancurcic

+0

Sì, lo so. Ho fatto clic sulla freccia rivolta verso l'alto, ma non riesco a fare una deviazione, perché non ho 15 reputazione. Scusa amico. Grazie ancora per la nota a margine. –

10

Come uno dei commenti menziona, una soluzione migliore è inserire le subroutine e le funzioni in un modulo, quindi utilizzare quel modulo dal programma principale. Ciò renderà nota l'interfaccia di tali procedure al chiamante, "esplicita" nella terminologia di Fortran.Non solo il compilatore gestirà correttamente il tipo di funzione, ma sarà in grado di controllare la concordanza tra gli argomenti nella chiamata e gli argomenti nel callee ("argomenti fittizi") per coerenza.

Se si utilizza il maggior numero possibile di opzioni di debug, il compilatore aiuterà a trovare gli errori. Con gfortran, prova: -O2 -fimplicit-none -Wall -Wline-truncation -Wcharacter-truncation -Wsurprising -Waliasing -Wimplicit-interface -Wunused-parameter -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 

Probabilmente si scoprirà che è possibile calcolare solo fattoriali di numeri interi molto piccoli mediante moltiplicazione diretta utilizzando numeri interi regolari. Una soluzione è quella di utilizzare una più grande tipo intero, per esempio,

integer, parameter :: BigInt_K = selected_int_kind (18) 

Proprio come si potrebbe modernizzare e utilizzare selected_real_kind invece di doppia precisione.

+2

Grazie per il suggerimento "use module", mi ha aiutato a risolvere un altro problema. –

+0

I moduli sono il modo migliore per scrivere la maggior parte delle funzionalità. – Zeus

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

1. Assicurarsi che la funzione abbia un'interfaccia esplicita con il programma chiamante. Questo può essere ottenuto mettendo la funzione in un modulo e l'associazione USE. Questo è spiegato nella risposta di cui sopra. 2. puoi usare INTERFACE per costruire un'interfaccia esplicita con il programma di chiamata principale, questo è utile quando hai pochissimi numeri di funzioni che hanno un'interfaccia implicita, come nel tuo caso. L'esempio è riportato di seguito.

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 

nota è sempre meglio definire parametri genere e quindi utilizzando la clausola TIPO come spiegato da @milancurcic

C'è un altro modo molto semplice per risolvere il problema: Basta definire fattoriale e itegrate nel programma principale come segue e siete pronti per andare

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

END PROGRAM main