Generatore lineare congruenziale
In matematica il generatore lineare congruenziale (LCG dall'inglese Linear Congruential Generator) è un algoritmo per la generazione di numeri pseudo-casuali vecchio e molto conosciuto. La teoria sulla quale poggia è semplice da capire e da implementare; inoltre ha il vantaggio di essere computazionalmente leggero.
Il generatore è definito ricorsivamente:
dove è un valore della successione dei numeri pseudocasuali e
- — il "modulo"
- — il "moltiplicatore"
- — l'"incremento" (nel caso speciale in cui si parla di generatore Park-Miller RNG o moltiplicativo)
- — il "seme" o il "valore iniziale"
Il periodo di un LCG è al più m, e per alcune scelte di a può essere molto più piccolo. Il LCG ha un periodo pieno se e solo se:
- e sono coprimi
- è divisibile per tutti i fattori primi di ,
- è un multiplo di 4 se è un multiplo di 4.[1]
Nonostante gli LCG siano generalmente in grado di produrre numeri pseudocasuali decenti, la loro qualità è molto sensibile alla scelta dei coefficienti c, m ed a.
Storicamente, scelte sbagliate hanno portato a implementazioni inefficienti di LCG. Un esempio significativo è RANDU che è stato usato largamente nei primi anni '70 e ha portato a dei risultati che attualmente sono messi in dubbio a causa dell'uso di un LCG di scarsa qualità[2].
Se un generatore congruenziale lineare è inizializzato con un carattere e iterato, il risultato è un semplice cifrario classico chiamato cifrario affine; questo cifrario è facilmente forzabile con un'analisi frequentista standard.
Esempi
[modifica | modifica wikitesto]Generatori di base
[modifica | modifica wikitesto]Un esempio di generatore di base può essere dato da
Ossia:
La sequenza generata è:
Il periodo è uguale a quattro.
Esempi di utilizzo
[modifica | modifica wikitesto]Il generatore congruenziale lineare più efficiente ha m uguale a una potenza di 2, spesso m = 232 o m = 264 perché questo consente di calcolare l'operazione modulo semplicemente troncando i 32 o i 64 bit meno significativi. La seguente tabella lista i parametri degli LCG di uso comune, inclusa le funzioni rand() di alcuni compilatori.
Source | m | a | c | output bits of seed in rand() / Random(L) |
---|---|---|---|---|
Numerical Recipes | 232 | 1664525 | 1013904223 | |
Borland C/C++ | 232 | 22695477 | 1 | bits 30..16 in rand(), 30..0 in lrand() |
glibc (usato da GCC)[3] | 232 | 1103515245 | 12345 | bits 30..0 |
ANSI C: Watcom, Digital Mars, CodeWarrior, IBM VisualAge C/C++ | 232 | 1103515245 | 12345 | bits 30..16 |
Borland Delphi, Virtual Pascal | 232 | 134775813 | 1 | bits 63..32 of (seed * L) |
Microsoft Visual/Quick C/C++ | 232 | 214013 | 2531011 | bits 30..16 |
Apple CarbonLib | 231 − 1 | 16807 | 0 | see Park–Miller RNG |
MMIX di Donald Knuth | 264 | 6364136223846793005 | 1442695040888963407 | |
VAX's MTH$RANDOM,[4] old versions of glibc | 232 | 69069 | 1 | |
Random class nelle API di Java | 248 | 25214903917 | 11 | bits 48...17 |
Come mostrato sopra, LCG non usa sempre tutti i bit che produce. L'implementazione Java produce 48 bit ad ogni iterazione ma sono ritornati come risultato solo i 32 bit più significativi. Questo poiché i bit più significativi hanno un periodo più lungo. Gli algoritmi che usano questa soluzione sono migliori.
Vantaggi e svantaggi
[modifica | modifica wikitesto]I generatori congruenziali lineari richiedono una memoria minima (tipicamente 32 o 64 bit) per memorizzare lo stato.
Gli LCG non dovrebbero essere usati in applicazioni dove è critico l'utilizzo dell'alta casualità.
Per esempio, non sono adatti per simulazioni Monte Carlo poiché hanno una correlazione tra di loro. Non devono essere usati in crittografia.
Inoltre questi algoritmi tendono ad avere alcuni difetti. Per esempio, se un LCG è usato per scegliere i punti in uno spazio n-dimensionale, i punti giacciono su iperpiani al massimo m1/n-dimensionali (teorema di Marsaglia). Questo è dovuto ad una correlazione tra valori successivi della successione.
Un altro problema è che negli LCG i bit meno significativi della sequenza generata hanno un periodo più corto di quello della sequenza se m è posto ad essere una potenza di 2. In generale, la n-esima cifra meno significativa nella base b della sequenza prodotta, dove per qualche intero k, si ripete con un periodo al più .
Nonostante ciò, gli LGC possono essere una buona scelta in alcuni contesti, come per esempio nei sistemi embedded, dove la memoria disponibile è spesso molto limitata; anche nel caso di un videogioco, prendere un piccolo numero dei bit più significativi potrebbe essere sufficiente. I bit meno significativi di un LCG dove m è una potenza di 2 non dovrebbero mai essere usati.
Confronto con altri metodi
[modifica | modifica wikitesto]Se è necessario avere numeri pseudocasuali di qualità e una certa memoria è disponibile (~ 2 kilobytes), allora l'algoritmo Mersenne Twister fornisce un periodo molto maggiore (2^19937-1)
Note
[modifica | modifica wikitesto]- ^ Knuth 1997, pp. 17-19
- ^ Press, William H., et al., Numerical Recipes in Fortran 77: The Art of Scientific Computing, 2nd, 1992, ISBN 0-521-43064-X.
- ^ La funzione rand() in stdlib.h nella libreria GNU del C usa un semplice (a singolo stato) generatore congruenziale lineare solo nel caso che lo stato sia dichiarato a 8 byte. Se lo stato è più grande (un array) il generatore diventa un generatore additivo a controreazione e il periodo incrementa. Vedere il codice semplificato che riproduce la sequenza casuale della libreria.
- ^ GNU Scientific Library: Other random number generators
Voci correlate
[modifica | modifica wikitesto]- Numeri pseudo-casuali
- Generatore di Fibonacci ritardato
- Generatore hardware di numeri casuali
- Mersenne Twister
- Funzione periodica
Collegamenti esterni
[modifica | modifica wikitesto]- Generazione di numeri casuali (PDF) [collegamento interrotto], su www-tlc.deis.unibo.it.
- Generatore di numeri casuali (Regione Emilia-Romagna), su regione.emilia-romagna.it.