Fortran – Ultima puntata

Pointers
OK, adesso anche nel Fortran ci sono i puntatori (pointer). Siccome questi post sono legati a un programma specifico non ne parlerò adesso, forse in futuro.

Preprocessore
Come per il C è disponibile il preprocessore, quindi #ifdef, #ifndef &co. In realtà si usa GCC, sempre lui.

Ricorsività
Adesso una procedura può chiamare sé stessa ricorsivamente, cosa vietata fino al 77 compreso. Ecco per esempio il calcolo del fattoriale.

program nfact ! da Tanja van Mourik
implicit none

integer :: n
integer :: nfactorial

do n = 2, 9, 3
    print *, n, nfactorial(n)
end do

end program nfact

recursive function nfactorial(n) result(fac)
implicit none

integer :: fac
integer, intent(in) :: n

select case(n)
    case (0:1)
        fac = 1
    case default
        fac = n * nfactorial(n-1)
end select

end function nfactorial

Notare il select case e che la funzione dev’essere dichiarata recursive.

Operazioni sugli array
Gli array possono essere inizializzati sia con (/ e /) che con [ e ].
Possono essere copiati con una singola istruzione, evitando un do specifico.

program arr
implicit none

integer :: a(5) = (/1, 2, 3, 4, 5/)
integer :: b(5) = [1, 4, 9, 16, 25]

print *, 'inizio'
print "(5i3)", a, b

a = b ! copia dell'array
print "(/, 'dopo la copia')"
print "(5i3)", a

a(2:5) = a(1:4)
a(1) = 0
print  "(/, 'dopo lo spostamento')"
print "(5i3)", a

end

Il tentativo di invertire ‘al volo’ un array da errore, la copia funziona solo per slice (chissà come si dice da noi?).

program arr
implicit none

integer :: a(5) = (/1, 2, 3, 4, 5/)
integer :: b(5) = [1, 4, 9, 16, 25]

a(1:5) = b(5:1)
print "(5i3)", a, b

end


In questo caso si deve ricorrere al solito ciclo.

program arr
implicit none

integer :: a(5)
integer :: b(5) = [1, 4, 9, 16, 25]
integer :: i

do i = 1, 5
    a(i) = b(6 - i)
end do
print "(5i3)", a, b

end


Array dinamici
Copiando da Tanja: alle volte la dimensione di un array non è nota fino all’esecuzione del programma, ecco allora gli array dinamici.

program dynarr
implicit none

real, allocatable :: a(:,:)
integer :: dim1, dim2
integer :: i, j

write(*, fmt = '("Give dimensions DIM1 and DIM2: ")', &
                advance = "NO")
read(*, *) dim1, dim2

! now that the size of a is know, allocate memory for it
allocate(a(dim1,dim2))
do i = 1, dim2
    do j = 1, dim1
        a(j,i) = i*j
        write(*, fmt = '("a(",i2,",",i2,") = ", f6.2)') &
              j, i, a(j, i)
    end do
end do
deallocate(a)

end


Domanda di G. (ripetuta, ecco la risposta): si può continuare a usare quello che si usava una volta? Certo, ecco:

program oldstyle
implicit none
common /mydat/ numero

integer :: i, numero, molt

i = 5
numero = 3

print *, i, molt(i)

end

integer function molt(n)
implicit none
common /mydat/ mul

integer n, d, mul

d = mul * n

molt = d
return !non serve ma si usava

end


Il common è comunque sconsigliato, usare i moduli. Con questi posso importare selettivamente le variabili che mi servono effettivamente, anche con nomi differenti.

program es_only
use m_only, only: alpha,  b => beta
! b è beta del modulo

implicit none

integer :: gamm, delta
! gamm e delta NON sono quelli del modulo

print *, alpha, b, gamm, delta

end

module m_only
implicit none

integer :: alpha = 1, beta = 2, gamm = 3
integer, private :: delta = 4

end module


OK, con questo credo di aver elencato (quasi) tutti le nuove caratteristiche del linguaggio, rispetto al 77. In realtà ho saltato quelle che non credo saranno utilizzate in un caso reale che partirà a breve. Probabilmente posterò ancora un elenco di domande tipiche, tipo questa:
D: con il formato libero puoi mettere i commenti con una C in prima colonna?
R: prova ma no, ecco:

program c_com

C questi una volta 
c sarebbero stati commenti

i = 42

print *, i

end


Beh, ce ne sono anche di meno banali 😉

Posta un commento o usa questo indirizzo per il trackback.

Lascia un commento

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