Sei sulla pagina 1di 5

yaC-Primer: Congruenze Lineari (Rev. 2.0.

1)
1 Metodo delle Congruenze Lineari (Rev. 2.0.1)
Tra tutti i generatori di numeri random quelli di numeri random uniformi in un intervallo
rivestono un ruolo di primo piano in quanto praticamente tutti i generatori di numeri random
con distribuzioni di probabilit`a non uniformi sfruttano uno o pi` u generatori di numeri random
con distribuzione uniforme in qualche intervallo.
Numeri random con distribuzione uniforme nellintervallo [a, b] sono numeri random iid che
possono assumere con la stessa probabilit`a qualsiasi valore nellintervallo [a, b], di conseguenza
la loro distribuzione di probabilit`a p(x) `e:
p(x) =

1
b a
a x b
0 altrimenti
In particolare i numeri random con distribuzione uniforme nellintervallo chiuso [0, 1] sono
numeri che possono prendere con la stessa probabilit`a un valore qualsiasi tra 0 e 1, per i quali
si ha quindi
p(x) =

1 0 x 1
0 altrimenti
Gli estremi dellintervallo possono essere inclusi od esclusi a seconda che la distribuzione sia
in un intervallo chiuso [a, b], aperto (a, b) o semi-aperto (a, b] o [a, b):
[a, b] a x b
(a, b) a < x < b
[a, b) a x < b
(a, b] a < x b
Il modo pi` u semplice di generare una sequenza di numeri pseudo-random con distribuzione
uniforme `e con un generatore basato sulle congruenze lineari. Un generatore che utilizza le
congruenze lineari produce una sequenza di numeri interi I
1
, I
2
, I
3
,... con valore tra 0 e m1
inclusi usando la formula di ricorrenza
I
n+1
= a I
n
+ c (mod m)
dove
m := modulo
a := moltiplicatore
c := incremento
La sequenza viene iniziata inizializzando il generatore attraverso la scelta di un seme
(seed) che ssa il valore del primo numero della sequenza I
0
. Una volta ssato I
0
le successive
chiamate del generatore produrranno la sequenza I
1
, I
2
, I
3
, ...
1
yaC-Primer: Congruenze Lineari (Rev. 2.0.1)
La sequenza di numeri generata in questo modo `e periodica e si ripete con un periodo non
pi` u grande di m. Il valore iniziale I
0
ssa il punto di partenza lungo il ciclo. La lunghezza
del periodo dipende dalla scelta dei parametri a, c, m ed, eventualmente, anche da I
0
perch`e
scelte diverse del punto di partenza possono generare sequenze cicliche diverse con periodi
non necessariamente uguali, anche se minori di m.
`
E possibile mostrare sotto quali condizioni
la scelta dei parametri a, c, m produce sequenze di periodo massimo m. In questo caso la
scelta del valore iniziale I
0
`e chiaramente irrilevante perch`e si ha un solo ciclo.
I generatori basati sulle congruenze lineari sono molto semplici da scrivere, come mostra il
seguente modulo randu.c.
Header: randu.h

/****************************************************************
- Definizioni per randu.c
- Funzioni :
void srandu(unsigned int seed);
int randu(void);
double drandu(void);
- Descrizione :
srandu() -> Inizializza il generatore
randu(); -> Numero intero uniforme tra 0 e RANDU_MOD -1
drandu(); -> Numero double uniforme in [0,1)
- $Id: randu.h v 1.1 23.10.04 AC
*****************************************************************/
extern void srandu ( unsigned int seed ) ;
extern int randu ( void ) ;
extern double drandu ( void ) ;


Modulo: randu.c

/****************************************************************
- Descrizione : Generatore Numeri Uniformi
Congruenze lineari
- $Id: randu.c v 1.1 23.10.04 AC
*****************************************************************/
#define RANDUMULT 1103515245UL
#define RANDU INC 12345UL
#define RANDUMOD 32768UL
/*
* Variabile globale privata del modulo che contiene
* lultimo numero generato
*/
2
yaC-Primer: Congruenze Lineari (Rev. 2.0.1)
static unsigned long next=1;
extern int randu ( void )
{
next = ( next RANDU_MULT + RANDU_INC ) % RANDU_MOD ;
return next ;
}
extern double drandu ( void )
{
return ( randu ( ) / ( double ) RANDU_MOD ) ;
}
extern void srandu ( unsigned int seed )
{
next = seed ;
return ;
}
#undef RANDUMULT
#undef RAND INC


La sequenza viene inizializzata dalla funzione srandu() che inizializza il generatore ssando
il primo numero della sequenza I
O
uguale a al valore del seme seed. Ogni valore di seed
produce una sequenza dierente di numeri pseudo-random o un punto di partenza diverso di
una sequenza ciclica. Tuttavia lo stesso valore di seed produrr`a sempre la stessa sequenza di
numeri pseudo-random. Se il generatore non viene inizializzato con la funzione srandu() il
generatore produce la sequenza di numeri che avrebbe generato dopo essere stato inizializzato
con un seed di valore 1.
Per generare la sequenza di numeri pseudo-random, dopo aver inizializzato il generatore, si
chiama ripetutamente la funzione randu() come mostrato nel seguente programma di prova
del modulo. Ogni chiamata della funzione ritorna il numero successivo nella sequenza generata
a partire da I
0
. Il modulo utilizza la variabile privata next per memorizzare lultimo numero
generato. I numeri generati da randu() sono interi con valori compresi tra 0 e 32767 inclusi.
Se si desiderano dei numeri uniformi nellintervallo [0, 1) si pu`o usare la funzione drandu().
Esempio: Test di randu.c

/****************************************************************
- Descrizione : test per randu.c
- $Id: test-randu.c v 1.0 24.10.04 AC
*****************************************************************/
#include <s t di o . h>
#include <s t dl i b . h>
/*
* Usa modulo randu.c
*/
#include "randu.h"
3
yaC-Primer: Congruenze Lineari (Rev. 2.0.1)
int main ( void )
{
int i , n ;
srandu ( 12345) ;
n = 10000;
for ( i = 0; i < n ; ++i) {
printf ( "%d %f\n" , randu ( ) , drandu ( ) ) ;
}
return 0;
}


Sebbene generatori di numeri random basati sulle congruenze lineari possano produrre delle
sequenze di numeri raggionevolmente random, spesso la scelta dei parametri produce gener-
atori di numeri random piuttosto questionabili. Un problema tipico `e dovuto al fatto che
spesso il valore di m non `e molto grande. Lo standard C richiede che m sia almeno uguale a
2
15
= 32768, scelta che pu`o rivelarsi un disastro se servono sequenze molto lunghe come ad
esempio nellintegrazione con il metodo Monte Carlo dove spesso si usano sequenze di 10
6
o
pi` u numeri random.
Un altro svantaggio degli generatori di numeri random basati sulle congruenze lineari sono
le correlazioni che vi sono tra i numeri della sequenza I
1
, I
2
, I
3
, ... generati dalle chiamate
successive del generatore. Se le sequenze di k numeri successivi I
i
, I
i+1
, ..., I
i+k1
sono usate
per fare un graco k-dimensionale i punti non tendono a riempire uniformemente lo spazio
ma piuttosto si dispongono su piani di dimensione k 1. Ci sono al massimo m
1/k
piani,
ma se i parametri non sono scelti bene questi possono essere molto di meno. Ad esempio se
m = 32678 = 2
15
in tre dimensioni si hanno al massimo 32 piani.
Forse lesempio pi` u noto `e il generatore di numeri RANDU utilizzato per anni sui computer
IBM. Questo utilizza un algoritmo di congruenze lineari con a = 65539, m = 2
31
e c = 0.
Con questa scelta il numero di piani in tre dimensioni si riduce a 11.
Le correlazioni tra i numeri generati non sono lunico punto debole dei generatori di numeri
random basati sulle congruenze lineari. Spesso infatti questi generatori producono sequenze
di numeri i cui bits meno signicativi sono molto meno random, ossia hanno un periodo pi` u
corto, dei bits pi` u signicativi. Di conseguenza se ad esempio si vuole generare dei numeri
distribuiti uniformemente tra 1 e 10 si deve usare
j = 1 + ( int ) ( 10. 0 randu ( ) / ( double ) RANDU_MOD ) ;
in modo da utilizzare i bits pi` u signicativi e non
j = 1 + ( randu ( ) % 10) ;
che invece usa quelli meno signicativi.
Park e Miller hanno proposto un generatore di numeri random basato sulle congruenze lineari
con la scelta
a = 7
5
= 16807, m = 2
31
1 = 2147483647, c = 0
4
yaC-Primer: Congruenze Lineari (Rev. 2.0.1)
e mostrato che questo soddisfa dei requisiti minimi di bont`a per un generatore di numeri
random. Sebbene questo generatore, chiamato Minimal Standard, abbia passato i tests non
`e tuttavia un generatore perfetto.
1.1 rand(), srand(), RAND MAX
Lo Standard C fornisce il generatore di numeri random di sistema rand()
#include <s t dl i b . h>
int rand ( void ) ;
void srand ( unsigned int seed ) ;
Successive chiamate della funzione rand() generano una sequenza di numeri interi pseudo-
random di tipo int con distribuzione uniforme nellintervallo 0 e RAND MAX. Il valore della
macros RAND MAX denito nel le stdlib.h rappresenta il valore dellintero pi` u grande che la
funzione rand() pu`o generare. Lo standard C richiede che RAND MAX sia almeno 32767, ma
su molti sistemi questo `e pi` u grande.
La funzione srand() inizializza il generatore utilizzando il valore del seme seed. Il valore del
seme identica in maniera univoca la sequenza di numeri pseudo-random generati dalle chia-
mate successive del generatore. Di conseguenza se la funzione srand() viene richiamata con
lo stesso seme con cui il generatore `e stato inizializzato dopo che questo ha prodotto una se-
quenza di numeri pseudo-random da questo punto in poi il generatore riprodurr`a esattamente
la stessa sequenza di numeri pseudo-random.
Se la funzione srand() non viene chiamata prima di utilizzare il generatore rand() questo
generer`a la sequenza di numeri pseudo-random che avrebbe generato se fosse stato inizializzato
con la funzione srand() con il seed uguale 1.
Su molti sistemi il generatore di numeri random di sistema rand() non `e basato sulle con-
gruenze lineari ma su algoritmi che forniscono sequenze di numeri pseudo-random com pro-
priet`a statistiche migliori.
Esercizi
1. Utilizzare triplette di numeri ottenuti con il generatore randu() e gracare i risultati
sui piani xy, xz, e yz e confrontare il risultato con il graco ottenuto utilizzando il
generatore di sistema rand().
2. Calcolare il valore medio e la varianza dei numeri generati dal generatore drandu()
al variare della lunghezza della sequenza usata. Vericare che allaumentare della
lunghezza della sequenza questi tendono valori teorici aspettati 1/2 e 1/12.
3. Fare un istogramma dei numeri generati dal generatore drandu() e confrontarlo con la
distribuzione di probabilit`a dei numeri random con distribuzione uniforme nellintervallo
[0, 1]. Cosa succede al variare della lunghezza della sequenza di numeri usata?
4. Ripetere gli esercizi precedenti cambiando i parametri del generatore di numeri random.
c AC 2003
5