View Single Post
Old 17-02-2016, 11:41   #1
tmpuser
Member
 
Iscritto dal: Nov 2009
Messaggi: 72
[ForTran] Passare funzione come argomento ad una subroutine

Sto buttando giù un semplice programmino in fortran per la determinazione dello zero di una funzione col metodo di bisezione.
Niente di complicato quindi.

Però vorrei organizzarlo in modo un po' "modulare".
- Una "function" per definire la funzione f(x) di cui vogliamo cercare gli zeri.
- Una "subroutine" per determinare due valori x1 e x2, tali per cui f(x1)*f(x2)<0
- Una subroutine per determinare lo zero della funzione prendendo in considerazione come punti di partenza x1 e x2 (determinati in precedenza...)

Quello che vorrei fare è richiamare la subroutine con, tra gli argomenti anche la funzione f(x).

Avrei pensato che la cosa più naturale fosse definire "f" come intent(in) nella subroutine, invece non è così perchè da come ho capito f non è ancora definita nel programma principale...
Ho risolto definendola "external" e non mettendola fra gli intent(*).
Ma ci deve essere un modo più pulito.

Ho letto in una discussione su stackoverflow che la via migliore sarebbe utilizzare le "interfaces". Ma ci ho capito un po' poco... quando avevo studiato io il fortran non erano state trattate a dovere.

Vi posto il mio tentativo che funzionare funziona, ma come spiegato non è questo il punto... La domanda vuole essere un po' più generale.
Il programma ha qualche bug, quindi non prendetelo come oro colato, in può fare casini nel trovare x1 e x2 (diciamo che lì in mezzo potrebbero esserci anche più zeri, dipende da come è fatta la funzione e dal parametro dx, passo con cui si "scansiona" il segno della funzione).
Ad ogni modo, tanto per dare un'idea...

Codice:
program zerofunction
        real:: y, y1, y2
        external:: f
        call findopp(f, y1, y2)
        call findzero(f, y1, y2, y)
        print *, 'Risultato:'
        print *, 'La funzione si annulla per y =', y
end program

subroutine findopp(fx,x1,x2)
      ! Trova due valori della var indipendente
      ! tali che f(x1)*f(x2)<0
      ! Si entra con x e fx e vengono restituiti
      ! x1 e x2
      !
      real:: fx
      real, intent(out) :: x1,x2
      real, parameter:: dx=0.6
      x1=0
      x2=x1
      do
        if ( fx(x1)*fx(x2) < 0 ) exit
        x1=x2
        x2=x2+dx
      enddo
end subroutine findopp

subroutine findzero(fx,x1o,x2o,x)
        ! Trova gli zeri della funzione
        ! Si passano i valori di partenza
        ! e la funzione e viene restituito
        ! lo zero della stessa.
        !
        real,intent(in) :: x1o, x2o
        real:: fx,x1,x2
        real,intent(out) :: x
        x1=x1o
        x2=x2o
        do
                x=(x1+x2)/2
                if ( abs(fx(x)) < 0.0001 ) exit
                if ( fx(x1)*fx(x) > 0 ) then
                        x1=x
                else
                        x2=x
                end if
        end do
end subroutine findzero

function f(y)
      real::y,f
      f=y-2+(0.5)*(5*y+2*(y**2))/(5+(4*y))
      return
end function
La domanda ripeto è:
qual è il modo migliore per passare come argomento una funzione ad una subroutine?

Vorrei passarla come argomento per tenere la subroutine più possibile generica.
E questo perchè la funzione vorrei passarla da riga di comando, in una prossima versione del programmino. Ma non mettiamo troppa carne al fuoco...

Grazie in anticipo, spero che qui ci sia qualche programmatore che conosca il fortran, in modo da fare due chiacchiere in italiano sulla faccenda.

PS.
Se vi pare il caso, sarebbe anche gradito un consiglio su quale possa essere un'eventuale altro "canale" possibilmente in lingua italiana in cui poter chiedere. Grazie ancora.
tmpuser è offline   Rispondi citando il messaggio o parte di esso