int main() {
srand48(time(NULL));
double x = drand48();
double y = drand48();
printf("Ecco due numeri pseudocasuali: %lf %lf\n", x, y);
return 0;
}
```
```bash
$ ./es_drand48_2
Ecco due numeri pseudocasuali: 0.653414 0.670506
$ ./es_drand48_2
Ecco due numeri pseudocasuali: 0.524217 0.375096
```
Data la sua definizione, time
restituisce valori diversi solo se chiamata a più di un secondo di distanza
---
# Ottenere numeri pseudocasuali in un intervallo
* Vogliamo che i numeri siano distribuiti nell'intervallo `[min, max)`
* Se servono interi possiamo usare due metodi equivalenti
* Ricordando che `drand48()` restituisce un `double` $\in [0, 1)$
* Ricordando che `lrand48()` restituisce un `long int` $\in [0, 2^{31})$
* Se servono `double` è più comodo usare `drand48()`
```C [1-3|5-7]
// se vogliamo interi
int d_x = drand48() * (max - min) + min; // il double viene troncato e diventa int
int l_x = lrand48() % (max - min) + min;
// se vogliamo numeri razionali
double d_x = drand48() * (max - min) + min;
double l_x = (lrand48() / (double) RAND_MAX) * (max - min) + min;
```
RAND_MAX
è una costante simbolica (macro) definita in stdlib.h
---
# Esempio di generazione di numeri in un intervallo
* `X % Y` dà come risultato un numero intero tra `0` e `Y - 1`
* Aggiungiamo `min` per ottenere un numero tra `min` e `max = min + Y - 1`
```C [|10,11]
#include <stdio.h>
#include <stdlib.h>
int main() {
srand48(598232); // non dimenticatelo!
int i, r1;
double r2;
for(i = 0; i < 10; i++) {
r1 = lrand48() % 100 + 50;// [50, 150)
r2 = 2. * drand48() - 1.; // [-1.0, 1.0)
printf("%d %lf\n", r1, r2);
}
return 0;
}
```
```bash
$ ./es_drand48_intervallo
103 -0.374985
61 -0.376888
93 0.094238
63 0.892177
113 0.250517
82 -0.576272
61 0.141966
111 0.478965
131 0.186313
108 0.434002
```
---
# Come funzionano `drand48` / `lrand48`?
* La sequenza generata è composta da interi
* Il valore $(n+1)$-esimo è calcolato a partire dall'$n$-esimo tramite questa relazione:
$$
X_{n + 1} = (aX_n + c) \\, \\% \\, m
$$
* $m$, $c$ e $a$ sono costanti
* $X_0 = $ `seed`, cioè il primo elemento della sequenza è il seed
* Nel caso di `drand48`, l'output della funzione è $X_{n + 1}$ / `RAND_MAX`
Questo tipo di algoritmo è detto algoritmo lineare congruenziale
Se $X_n = X_k$ con $k < n$, $X_{n+1} = X_{k+1}$: la sequenza si ripete!
---
# Dettagli dell'implementazione
I valori di default delle costanti usate dalla libreria standard del C sono
* $m = 2^{48}$ (valori grandi minimizzano la probabilità di ripetere la sequenza)
* $c = $0xB$ = 11$
* $a = $0x5DEECE66D$ = 25214903917$
La funzione rand()
usa $m = 2^{31}$ e quindi genera sequenze che si ripetono più spesso: meglio non usarla
Esistono altri tipi di generatori di numeri pseudocasuali più complessi e con proprietà migliori, ma drand48
va benissimo per ciò che faremo noi