Convertire codice Fortran in Python – 1

Si può fare ma c’è qualche aspetto da considerare.

Intanto le abitudini di una volta, complice una possibilità del Fortran non presente in Python. Nel Fortran (parlo delle versioni vecchie 77 e precedenti; il 77 è tuttora usato per quel che ne so) ci sono due tipi di sottoprogrammi: le funzioni e le subroutines. Queste ultime, affini alle funzioni C di tipo void erano di gran lunga le preferite. C’è una giustificazione: le variabili sono passate per indirizzo (reference, non so se i due termini sono rigorosamente equivalenti, questi erano quelli correnti). Esempio:

N = 8
CALL DOPPIO (N)
PRINT* N

SUBROUTINE DOPPIO (N)
N = 2 * N
END

Il risultato che ottengo è 16, cioè il valore di N modificato nella subroutine viene conservato nel main, è cambiato il valore memorizzato all’indirizzo della variabile e questo è quello che ho passato al sottoprogramma. Con Python (per quel che ne so) questo non è possibile, ecco qua:

$ py3
>>> def doppio (n):
...   n = 2 * n
...   print('in doppio:', n)
...
>>> n = 8
>>> doppio (n)
in doppio: 16
>>> print (n)
8

alla funzione doppio ho passato il valore 8 e al di fuori di questa il valore di n resta 8 indipendentemente da quanto avvenuto nel sottoprogramma. Ovvia la soluzione, la stesa da sempre, in Fortran:

N = 8
N = IDOPPIO (N)
PRINT* N

FUNTION IDOPPIO (N)
N = 2 * N
RETURN (N)
END

Notare che ho cambiato il nome alla funzione, variabili e funzioni sono di default REAL*4 tranne quelle il cui nome inizia con le lettere dell’intervallo [I..N] che sono INTEGER*2 o INTEGER*4 a seconda della versione e delle opzioni di compilazione. Caratteristico del Fortran è che la precisione viene espressa in byte e non in bit.

In Python  la funzione può ritornare una lista, torna comoda per le subroutines:

$ py3
>>> def pot(a, b, p):
...   a = a ** p
...   b = b ** p
...   return a, b
...
>>> r = pot(3, 4, 2)
>>> print(r)
(9, 16)
>>> # ovviamente
... a, b = pot(3, 4, 2)
>>> print(a)
9
>>> print(b)
16

Quindi una prima regola pratica: scrivere funzioni che ritornano i valori delle variabili che ci servono. Ma ci sono dei casi in cui questa pratica non basta, il caso di arrays e matrici di dimensioni rilevanti.

In Fortran c’è l’istruzione COMMON:

COMMON /DATI/ A, B(10), C, D
COMMON /MAT/ P(20, 20), R(10, 10, 10)

Ogni funzione o subroutine che usi A, B, C o D dovrà dichiarare il COMMON /DATI/, idem per il caso di /MAT/.

In Python si ottiene un risultato simile (meno granulare, meno raffinato ma forse meno soggetto a bug) con le variabili globali:

$ py3
>>> #a = 0
>>> b = []
>>>
>>> def popola_dati():
...   global a
...   a = 42
...   for c in range(10):
...     b.append(c ** 2)
...
>>>
>>> popola_dati()
>>> print('a =', a)
a = 42
>>> print('b =', b)
b = [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

OK, notare che a devo dichiararla global nella funzione a differenza di b che dev’essere inizializzato nel main e diventa automaticamente globale. b è una lista, non esattamente l’equivalente degli arrays e matrici del Fortran. Le liste sono versatili ma onerose, da modificare, in un post successivo, pausa 😎

Posta un commento o usa questo indirizzo per il trackback.

Trackback

Lascia un commento

Questo sito utilizza Akismet per ridurre lo spam. Scopri come vengono elaborati i dati derivati dai commenti.