Il Fortran, dal IV al 77

Oggi Fortran. Fermi lì, niente panico, è semplice, davvero!

Quando io ho cominciato a lavorare, alla fine degli anni ’70 era usuale avere sul computer (ma allora si chiamava calcolatore o macchina) il compilatore Fortran e basta. A meno che uno fosse particolarmente ricco e allora c’era PL/I o Algol. Naturalmente i gestionali usavano il Cobol, ma è tutta un’altra cosa e noi li snobbavamo.

Con Google si scopre che ci sono millanta manuali di Fortran sul Web, sembra che lo usino ancora i fisici e gli ingegneri. Di sicuro ci sono state delle codifiche recenti, anche se in questo post racconterò delle origini; poi in futuro, chissà, capace che mi aggiorno.
Il Fortran ha origine sull IBM 704, come IBM Mathematical FORmula TRANslation System, John Backus, 1954.

Seguono poi versioni successive fino alla standardizzazione come FORTRAN IV del 1966, che qualcuno chiama Fortran 66. E il Fortran IV, o meglio varianti con estensioni rimase lo standard di fatto ben oltre l’avvento della versione successiva, Fortran 77, 1978.

Nel mondo Linux esiste, ovviamente, un ottimo compilatore fortran, installabile (almeno per Ubuntu) con il comando

sudo apt-get install gfortran

Un esempio pratico, cucinato secondo le diverse scuole di pensiero
Nota: purtroppo WordPress non supporta il fortran al pari di C/C++ e Python :-(
Seguendo la tradizione inizieremo con il classico “Hello world”.

print*, "Hello World!"
end

che compiliamo

* : /media/algol/lab/OKp/fortran $ gfortran -o hw --free-form hw.f
* : /media/algol/lab/OKp/fortran $

e eseguiamo

* : /media/algol/lab/OKp/fortran $ ./hw
 Hello World!
* : /media/algol/lab/OKp/fortran $

Ma mi sembra troppo poco. Propongo di verificare per alcuni casi la congettura di Collatz, dettagliatamente descritta qui. Nella versione italiana della stessa pagina è presente il codice Python che faccio mio con piccolissime modifiche

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys

def collatz(n):
	print n,
	if n > 1:
		if n % 2 == 0:
			n /= 2
		else:
			n = 3*n+1
		collatz(n)

# main
num = int(sys.argv[1])
collatz(num)
print

Provandolo si ottiene:

* : /media/algol/lab/OKp/fortran $ python collatz.py 12
12 6 3 10 5 16 8 4 2 1
* : /media/algol/lab/OKp/fortran $

Ma si diceva del Fortran. Quando io iniziai a lavorare avrei prodotto qualcosa come


C23456--ok fino a 72 compresa--
10    PRINT*,'NUMERO'
      READ(*,*,ERR=10) N
20    PRINT*, N
      IF(N.EQ.1) GOTO 999
      I=IDISP(N)
      IF(I.EQ.0) GOTO 30
C     CASO DISPARI
      N=3*N+1
      GOTO 20
30    CONTINUE
C     CASO PARI
      N=N/2
      GOTO 20
999   CONTINUE
C     FINITO
      END

      FUNCTION IDISP(K)
C     RITORNA 1 SE K E' DISPARI, 0 SE PARI
      J=K/2
      L=K-2*J
      IDISP=L
      END

dove:

  • la prima riga è un commento (inizia con C in colonna 1);
  • la riga 5 controlla se la variabile N è uguale a 1 (.EQ. significa equal), se sì salta all’istruzione con l’etichetta (label) 999;
  • la riga 6 setta la variabile I chiamando la funzione IDISP(), definita sotto alle righe 19..24;
  • se I vale 0 si salta all’istruzione con etichetta 30 altrimenti si esegue l’istruzione 9 e si salta all’istruzione con etichetta 20, etc, etc…;
  • la riga 19 definisce la funzione IDISP() il cui corpo è rappresentato dalle righe 21 e 22;
  • la funzione ritorna alla riga 23.

:-( sì, lo so, mancano i numeri di riga :-(

Notare che, siccome trattiamo sempre valori interi, tutte le variabili devono iniziare con una lettera compresa tra I e N (iniziali di integer). Tutte le variabili e le istruzioni devono essere MAIUSCOLE. In 24 righe di programma ci sono 4 GOTO: non male!
Inoltre dobbiamo rispettare la convenzione del formato fisso delle colonne:
i commenti devono essere su una riga a se stante in cui ci sia C in colonna 1;
le etichette (label) devono essere numeriche e inserite nelle colonne 1..5;
le istruzioni devono stare tra le colonne 7..72;
la colonna 6 è riservata al flag di continuazione: se un’istruzione è troppo lunga può essere interrotta e ripresa sulla riga successiva, inserendo un carattere a piacere in colonna 6. 0 (zero) non vale, viene considerato come spazio.
Secondo le convenzioni del tempo non ho inserito spazi inutili.
compilando ed eseguendo si ottiene:

* : /media/algol/lab/OKp/fortran $ gfortran -o CIV CIV.f
* : /media/algol/lab/OKp/fortran $ ./CIV
 NUMERO
12
          12
           6
           3
          10
           5
          16
           8
           4
           2
           1
* : /media/algol/lab/OKp/fortran $

Ma un vecchio avrebbe scritto qualcosa di diverso. Già allora c’erano delle istruzioni sconsigliate ma c’erano le abitudini vecchie anche di 15 anni.
Inoltre la mia versione ha una stranezza: usa una funzione. In Fortran esistono da sempre le funzioni che ritornano un valore, come in C o Python e le subroutines, sottoprogrammi, che non ritornano esplicitamente un valore ma solo come side effect. Qui entra in gioco una caratteristica del Fortran: tutti gli argomenti passati a funzioni e subroutines sono passati per indirizzo; se vengono modificati quando si torna al modulo chiamante i loro valori sono cambiati (come quando in pascal si usa var). Per qualche ragione che non ho mai capito il programmatore fortran IV serio (PF4S) non amava le funzioni; alle volte capitava che il capo mi facesse cambiare il mio codice per depurarlo di quelle schifezze.

La prima versione del PF4S usa il GOTO calcolato, riga 7. Il GOTO calcolato va all’istruzione con la prima label se la variabile di controllo vale 1, all’istruzione con la seconda etichetta se la variabile di controllo vale 2 e così via.

C23456--ok fino a 72 compresa--
10    PRINT*,'NUMERO'
      READ(*,*,ERR=10) N
20    PRINT*, N
      IF(N.EQ.1) GO TO 999
      CALL DISP(N,K)
      GOTO(30,50) K+1
C     CASO DISPARI
50    N=3*N+1
      GOTO 20
30    CONTINUE
C     CASO PARI
      N=N/2
      GOTO 20
999   CONTINUE
C     FINITO
      END

      SUBROUTINE DISP(K,L)
C     RITORNA L=1 SE K E' DISPARI, L=0 SE PARI
      J=K/2
      L=K-2*J
      END

La seconda versione del PF4S usa l’IF aritmetico. Il programma salta all’istruzione con la prima, seconda o terza label in funzione del valore della variabile di controllo, rispettivamente minore, uguale o maggiore di zero.

C23456--ok fino a 72 compresa--
10    PRINT*,'NUMERO'
      READ(*,*,ERR=10) N
20    PRINT*, N
      CALL DISP(N,K)
      IF(K) 999,30,50
C     CASO DISPARI
50    N=3*N+1
      GOTO 20
30    CONTINUE
C     CASO PARI
      N=N/2
      GOTO 20
999   CONTINUE
C     FINITO
      END

      SUBROUTINE DISP(K,L)
C     RITORNA L=1 SE K E' DISPARI, L=0 SE PARI
C     RITORNA L=-1 SE K=1
      L=-1
      IF(K.EQ.1) RETURN
      J=K/2
      L=K-2*J
      END

Poi alla fine del ’78 viene codificata la nuova versione del Fortran, il mitico Fortran 77. C’è da dire che parecchie novità erano false novità, già implementate dai singoli produttori, spesso in forme non compatibili con il nuovo standard. Ma c’erano in ogni caso parecchie cose nuove: l’IF non più limitato a una sola riga, ma nella forma IF THEN / [[ELSE IF] / [ELSE]] / END IF, la gestione delle stringhe, delle variabili logiche e dei files, il ciclo DO (quello che da tutte le altre parti si chiama for) migliorato e altro ancora.
Naturalmente parecchi PF4S si rifiutarono di usarlo. Una volta uno mi ha ricordato che per andare sulla Luna, e tornarci anche parecchie volte, il Fortran IV si era dimostrato più che sufficiente.
In ogni caso io adesso il programma l’avrei scritto così:

      program collatz
*23456--ok fino a 72 compresa--
10    print*,'numero'
      read(*,*,err=10) n
20    print*, n
      if(n.eq.1) go to 999
      if (mod(n, 2).eq.1) then
c       caso dispari
        n=3 * n + 1
      else
c       caso pari
        n = n / 2
      end if
      goto 20
999   continue
c     finito
      end

Questo standard non sarebbe stato modificato (pesantemente) fino al ’90.

Per chi vuole saperne di più

La prima immagine è presa da qui dove c’è un mucchio di cose interessanti. La seconda è pura nostalgia (il primo amore non si scorda mai).

Un manuale online (lo sto leggendo e mi sembra OK) in italiano qui.

Un altro, devo ancora vederlo qui, su questo sito trovate tanta di quella roba che poi vi perdete.

In futuro, forse, continua…

About these ads
Post a comment or leave a trackback: Trackback URL.

Trackbacks

  • By Ancora Fortran « Ok, panico on 20 agosto 2010 at 10:44

    [...] Questa è la continuazione dal post precedente. Poi basta, c’è parecchia altra roba più interessante in [...]

  • By newLISP « Ok, panico on 28 agosto 2010 at 11:11

    [...] script, esattamente come Python. Eccone uno, silly, per la congettura di Collatz, ne ho parlato qui. Lo script è didascalico, primitivo, un lispista lo farebbe molto diverso. Forse, in futuro, [...]

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...

Iscriviti

Ricevi al tuo indirizzo email tutti i nuovi post del sito.

Unisciti agli altri 73 follower

%d blogger cliccano Mi Piace per questo: