Newsgroup: it.scienza.fisica
Titolo: Fortran e i numeri casuali

Potrebbe sembrare OT, ma a quanto so il FORTRAN è ormai usato al 90% per
applicazioni fisiche, per cui confido di trovare in questo newsgroup chi
potrà rispondere al mio semplice quesito:
come si fa a generare in fortran delle serie di numeri random
(pseudo-random) che non siano sempre uguali?
Mi spiego. Ho scritto un programmino che nel corso della sua esecuzione
chede una serie di numeri casuali. Finchè lo eseguo la prima volta tutto ok,
i numeri della serie sembrano essere effettivamente random. Ma quando lo
rieseguo, ho la spiacevole sorpresa di constatare che la nuova serie è
esattamente identica alla prima!
Ciò ovviamente non mi serve a molto: ogni volta che lancio il programma (che
simula l'andamento casuale di un processo descritto dalla probabilità
Poissoniana) ho chiaramente bisogno di serie di numeri random sempre
diverse.
Ora, io ho usato per generare i miei numeri l'istruzione
RAND( )
lasciando vuoto l'argomento.
Non conosco bene le potenzialità di questa istruzione (l'ho scoperta per
caso, tanto si chiamano sempre allo stesso modo), né so se ve ne siano di
altre più adatte allo scopo (spero proprio di sì!). Mi rimetto dunque alle
vostre indicazioni, che spero arrivino numerose :)
Grazie anticipatamente,
Antonio

 vostre indicazioni, che spero arrivino numerose :)
Io programmavo in FORTRAN 77 (con estensioni Digital VMS) molti anni fa, e
non conosco gli attuali sviluppi, e purtroppo i listati sono in cantina (o
nella pancia di qualche roditore). 
Comunque facevo come ora ti descriverò, ma devi verificare sul manuale che
la tua RAND si comporti come faceva la mia: so che è una funzione molto
dipendente dalla specifica implementazione del compilatore
..
Il trucco è proprio quello di "riempire" l'argomento, di solito chiamato
ISEED di tipo INTEGER*4. Mi ricordo che il manuale diceva che ISEED poteva
essere un qualunque intero grande dispari. Ogni qualvolta chiami
F=RAND(ISEED) oltre al valore in F viene modificato il valore ISEED con un
nuovo numero che sarà la base per calcolare il successivo random alla
prossima chiamata.
In pratica ad inizio programma prendevo dall'orologio di sistema il numero
di secondi trascorsi dalla mezzanotte (0<=IT<†399), lo moltiplicavo per
24800, e aggiungevo 1. Questa costante è calcolata in modo da ottenere il
grande numero dispari che però non vada mai in overflow.
Poi, facevo girare un po' di volte il generatore a vuoto e oplà, numeri
random sempre diversi!
Più o meno:
	INTEGER*4 ISEED, IT, I, J
	REAL DUMMY, RN
	IT = ITIME() ;QUESTA FUNZIONE RESTITUISCE I SECONDI DALLA MEZZANOTTE
	ISEED = IT*24800+1 ; ECCO UN GRANDE NUMERO DISPARI
	DO 1 J=1,10000		; UN'ULTERIORE RIMESCOLATA AI DADI
		DUMMY = RAND(ISEED)
1	CONTINUE
	DO 2 I= quello che ti pare	;QUESTO E' IL TUO PROGRAMMA
		RN=RAND(ISEED)	;E RN E' IL TUO NUMERO CASUALE
2	CONTINUE
	END
 
Ripeto, devi cercare una funzione tempo del tuo compilatore ed adattare il
preriempimento di ISEED. Nota che una volta precaricato non devi più
toccarlo: ci pensa la funzione a modificarselo.
Ciao, e grazie di avermi dato l'occasione di riprendere in mano per un
attimo il mio grande amore di gioventù...
 
--
Roberto Rosoni
<roberto...@liberoLock.it> (Remove the Lock in your replies)
 
Programmatore: chi ti risolve, in modo incomprensibile, un problema che non sapevi di avere.
 

Ciao!
Anche da noi (Astronomia Padova) il programma più usato per i calcoli è F90.
Allora, per quanto ne so (non molto per la verità) tutto gira attorno al
valore di iseed: dev'essere un numero grande e dispari.
Ho fatto delle prove sia con un valore iseed variabile ad ogni esecuzione
che con un valore dichiarato. Il risultato era in entrambi i casi la
generazione di numeri casuali. E' chiaro allora che è meglio usare un iseed
assegnato all'interno del programma, in modo da non far sprecare tempo in
utile in calcoli che, seppur veloci, sono solo superflui. (correggetemi se
sbaglio!).
Ti faccio un esempio
PROGRAM numeri_random
IMPLICIT NONE
INTEGER, PARAMETER:: ndati=30
INTEGER:: i
REAL:: x(ndati)
! Generazione numeri casuali compresi tra 0 e 5
iseed=12345
DO i=1, ndati
    x(i)=RAN(iseed)*5
    WRITE(*,*) x(i)
END DO
END PROGRAM numeri_random

Chiaramente anche iseed andava inizializzato come variabile intera.
Saluti,
H A L

 [...]
Non capisco perche' hai bisogno di avere serie di numeri sempre diverse:
se la serie segue la distribuzione che vuoi non ti basta? Comunque se vuoi
rieseguire il calcolo ti basta memorizzare il valore del seme finale
e ripartire da quello.
Considera ad ogni modo che ci sono algoritmi migliori dello standard RAND,
dai uno sguardo al capitolo 7 di "numerical recipes":
http://lib-www.lanl.gov/numerical/bookfpdf.html
Ciao.
Fabrizio.
--------------------------------
Inviato via 
http://usenet.libero.it

 sbaglio!).
Attenzione: ti sei dimenticato che l'esplicita richiesta di Uras era che per
ogni run potesse avere sequenze diverse: per questo faccio inizializzare
ISEED tramite l'orologio di sistema: per averlo diverso ad ogni run. Il
primo ciclo nel mio pseudolistato serve per combattere l'eventuale sfiga di
essere andato a prendere un ISEED "strano". Probabilmente è del tutto
inutile, ma così mi sento più tranquillo lasciando "assestare" la funzione
RAN.
Se invece ti va bene una sequenza ripetuta identica ad ogni run, non devi
far altro che lanciare la RAN() senza argomenti. ISEED diventa implicito e
si arrangia il compilatore.
Ciao!
 
--
Roberto Rosoni
<roberto...@liberoLock.it> (Remove the Lock in your replies)
 
As easy as 3.14159265358979323846264338327950288419716
 

 esattamente identica alla prima!
Tieni presente pero che questo "it's not a bug, it's a feature"
come dicono gli imbarazzati addetti all'assistenza di certo
software:-) Infatti avere la possibilita' (non l'obbligo, come
altri ti hanno gia' detto) di ripetere la stessa identica
sequenza e' utile.
Per esempio, immagina di avere un programma che usa numeri
casuali (es. un Montecarlo) e che tu sappia che funzione
correttamente, magari perche' ci hai fatto dei calcoli di milioni
di step. Adesso vuoi cambiare l'algoritmo per renderlo piu'
efficiente. Lo fai e vuoi controllare di non aver introdotto bug.
Se lo fai girare con una sequenza diversa di numeri casuali avrai
risultati diversi: e' un effetto del cambio di sequenza o
l'effetto di un bug? Come fai a saperlo? Ripeti il milione di
step di cui sopra? Se invece la sequenza e' esattamente la stessa
bastano poche decine di step, in cui controlli che i risultati
siano esattamente gli stessi di prima, a meno di errori di
troncamento.
-- 
Enrico Smargiassi
http://www-dft.ts.infn.it/~esmargia

Vi ringrazio tutti per i consigli...
In questi giorni ho comunque ricevuto indicazioni anche dal prof, che non
ero riuscito a contattare in precedenza.
Ecco cosa ho risolto:
pare che FORTRAN abbia una subroutine implicita chiamata SRAND( ), che ha
bisogno di un arogmento (il famoso ISEED, o come altrimenti lo si voglia
chiamare). La subroutine in questione ha l'effetto, quando invocata, di
stabilire da quale serie casuale la funzione RAND( ) estrarrà da quel punto
del programma in poi i numeri casuali. Ovviamente l'argomento di SRAND( )
indica proprio la serie casuale che verrà scelta. Quindi io inserisco
all'inizio del listato le istruzioni:
      time = secnds(130.0)
      time = 1000*time
      iseed = 2*(INT(time)) + 1
      CALL SRAND(iseed)
la cui sintassi è un po' ridondante ma rende l'idea. L'argomento
dell'istruzione SECNDS (che mi dà un tempo, preso da non so quale
riferimento temporale) non so se abbia limitazioni, comunque quello che ho
messo funziona. Le istruzioni che portano dal valore di TIME al valore di
ISEED sono dovute al fatto che ISEED dev'essere un numero intero, dispari e
possibilmente molto grande. Quindi ogni volta che eseguo il mio programma
l'istruzione RAND( ) prenderà i numeri dalla serie che sarà stata scelta
(casualmente) all'inizio dalla subroutine SRAND(ISEED). L'argomento di
RAND( ) lo lascio vuoto e funziona: se ci metto qualcosa dentro, non mi
compila il programma.
IMPORTANTE: se la subroutine SRAND( ) non viene invocata, o viene invocata
con argomento vuoto, FORTRAN sottintende che sia stata chiamata con
argomento 1. Questo spiega perchè l'istruzione RAND( ) funzionasse comunque
e mi desse sempre gli stressi numeri.
Vi trovate con questa soluzione?
Ancora grazie a tutti.
Antonio

 pare che FORTRAN abbia una subroutine implicita chiamata SRAND( ), 
...
No. Non e' esattamente cosi'. Lo standard del fortran 77 NON prevede una
funzione intrinseca per numeri casuali. (Puoi verificare su
http://www.fortran.com/fortran/F77_std/rjcnf0001-sh-15.html#sh-15.10
 )
Su molti sistemi Unix c'e' la possibilita' di chiamare una function
srand con le caratteristiche che descrivi. In genere e' un' interfaccia
alla routine standard con lo stesso nome del C e del C++. 
Per lavori seri non sono granche' (puoi trovare una discussione a
riguardo in
http://www.coyotegulch.com/algorithm/libcoyote/TwistedRoad/TwistedRoad.html
).
Una scelta migliore generalmente accessibile su sistemi unix e' la
drand48 (man drand48 per maggiori dettagli). Comunque, una ricerca in
rete permette di trovare sorgenti di ottimi generatori.
Il Fortran 90/95 invece ha una subroutine standard (RANDOM_NUMBER con la
collegata RANDOM_SEED ).
Dovrebbe essere decente ma non ne ho un' esperieza diretta.
Vorrei inoltre aggiungere un commento sulla questione di come generare
numeri in un run successivo che non riproducano sempre la stessa serie
di dati. La mia esperienza e' che il modo migliore  e' di lasciar
perdere procedure di interfacciamento all' ora locale o altre sorgenti
di "casualita'"  ma piuttosto di "continuare" la generazione della
successione di numeri random del run precedente. Col meccanismo, fornito
da tutti i generatori, di un seed per innescare la sequenza, basta farsi
scrivere alla fine di un run il valore in questione ed usarlo come seed
per l' inizio del run successivo. 
Se il generatore e' buono si continuera' nella (sperabilmente lunga
sequanza di numeri random) e, in caso di necessita' (debug), la sequenza
e' deterministicamente riproducibile.
Giorgio