PDA

View Full Version : C e rand()


[kiriku]
07-06-2004, 00:54
gente, mi sono accorto che la funzione rand() restituisce sempre lo stesso valore... nel senso che, è vero, se faccio x esempio un ciclo for e faccio scrivere 100 volte il valore di rand() questo è sempre diverso, ma alla successiva esecuzione del programma i numeri sono gli stesis nello stesso ordine... come faccio a evitare la cosa e ad ottenere numeri diversi ad ogni esecuzione del programma?

graz

ciao

Luc@s
07-06-2004, 08:25
inizializza il seme con un bell srand(time(NULL)) cosi rand ha il seme dell tempo di sisema che è sempre diverso.
Poi per prendere un num fai rand()%N dove N è il numero massimo che vuoi ottenere :)


Ciao

[kiriku]
07-06-2004, 08:50
grazie funziona! :)

ciao

cionci
07-06-2004, 10:49
Una piccola nota rand()%N permette di ottenere interi fra 0 e N-1 ;)

Luc@s
07-06-2004, 10:50
Originariamente inviato da cionci
Una piccola nota rand()%N permette di ottenere interi fra 0 e N-1 ;)

hai ragione :P
Hai fatto bene a puntualizzare

kk3z
07-06-2004, 12:15
grazie mille, serve anche a me :rolleyes:

VegetaSSJ5
07-06-2004, 13:14
ragazzi scusate ma non è possibile che se il ciclo for è eseguito molto velocemente il srand(time(NULL)) restituisca sempre lo stesso valore, perchè il time(NULL) restituisce sempre lo stesso valore, o questo pericolo non sussiste?

cionci
07-06-2004, 13:20
Il pericolo sussiste...infatti srand(time(NULL)) va fatto una sola volta all'interno di tutto il programma !!! ;)

VegetaSSJ5
07-06-2004, 13:47
Originariamente inviato da cionci
Il pericolo sussiste...infatti srand(time(NULL)) va fatto una sola volta all'interno di tutto il programma !!! ;)
cionci una soluzione potrebbe essere fare srand(time(NULL) + i) dove i è il contatore del ciclo for??

cionci
07-06-2004, 13:54
No...la srand DEVE essere chiamata una sola volta nel programma in modo da sfruttare lo stesso seme per la generazioni di tutti i numeri random di un programma...altrimenti non sono più molto casuali (vabbè che non lo erano nemmeno prima, ma se lo chiami più volte lo sono meno ;))...

VegetaSSJ5
07-06-2004, 14:24
cionci dimmi se questo può andar bene .
.
int i=0;
srand(time(NULL)+i);
for (i=0; i<50; ++i) printf("%d", rand());
.
.va bene così? fammi capire una cosa. la srand cambia il seme per la generezione di numeri casuali. se io metto una costante lui mi genera sempre lo stesso numero. se io metto delle variabili tipo srand(time(NULL)+i) la rand() va a ricalcolarsi ogni volta l'output di time(NULL)+i oppure calcola l'output sempre a partire dall'input che ha ricevuto la prima volta (cioè quando si è chiamato srand(time(NULL)+i))?

Ziosilvio
07-06-2004, 15:34
Il seme del generatore di numeri casuali e' sempre lo stesso; srand lo inizializza con un valore specifico (eventualmente calcolato sul momento), mentre rand lo usa per calcolare il nuovo valore e lo aggiorna con questo.
Per cui, in una sequenza srand --- rand --- srand --- rand, la seconda rand parte dal valore impostato dalla seconda srand, non da quello impostato dalla prima rand.
Invece, in srand --- rand --- rand, la seconda rand parte dal valore impostato dalla prima rand.

Io chiamerei srand una volta sola, all'inizio del programma.
La teoria dice che la sequenza dei valori di rand a partire da un seme scelto "casualmente" e' "casuale"; ma non penso che questo valga anche per una serie di semi scelti piu' o meno "sequenzialmente".
Eventualmente, darei la possibilita' di chiamarla con un valore a scelta dell'utente anziche' con l'output di time, in modo da poter sia ottenere un comportamento impredicibile, sia replicare esattamente un esperimento.

cionci
07-06-2004, 16:11
Concordo con Ziosilvio ;)

VegetaSSJ5
07-06-2004, 16:15
se ho capito bene secondo quanto detto da ziosilvio la rand() oltre che a generare un valore partendo da un seme, aggiorna quel seme al valore appena calcolato, pertanto quando si fa una rand() è superfluo fare una srand() per aggiornare il seme quindi la srand() va fatta solo all'inizio del programma giusto?

cionci
07-06-2004, 16:20
Sì...

melanippe
13-09-2004, 15:46
Originariamente inviato da cionci
Una piccola nota rand()%N permette di ottenere interi fra 0 e N-1 ;)


Come posso fare per ottenere invece un random decimale, un float compreso tra 0 e 1?

cionci
13-09-2004, 15:56
Dipende....hai un numero di decimali prefissato che vuoi ottenere ?

Se non vuoi un numero di decimali prefissato basta dividere per RAND_MAX (è una costante che solitamente identifica il numero massimo positivo rappresentato sugli interi)...

(double)rand() / RAND_MAX

Il risultato è ovviamente un double...

Ubi-Wan
13-09-2004, 15:59
per usare sempre rand puoi fare cosi' per esempio:

float x;

x=(float)(rand()%101)/100.0;

cosi' ottieni un numero decimale compreso tra 0 e 1 con precisione di 2 zeri dopo la virgola

Ziosilvio
13-09-2004, 16:18
Originariamente inviato da cionci
Se non vuoi un numero di decimali prefissato basta dividere per RAND_MAX (è una costante che solitamente identifica il numero massimo positivo rappresentato sugli interi)...

(double)rand() / RAND_MAX
rand genera valori "casuali tra 0 e RAND_MAX inclusi, quindi sarebbe piu' giusto:
(double)rand() / (RAND_MAX+1)
che tuttavia potrebbe dare dei problemi di overflow, perche' RAND_MAX+1 ha il tipo di RAND_MAX e potrebbe essere negativo.
Il metodo "esatto" dovrebbe essere questo:
(double)rand() / (RAND_MAX+1U)
che e' il rapporto tra un valore double compreso tra 0 e RAND_MAX inclusi, e un valore intero senza segno, quindi sicuramente positivo.
A questo punto, una variabile aleatoria bernoulliana X di parametro p (che vale 1 con probabilita' p, 0 con probabilita' 1-p) si genera semplicemente ponendo:
X = ((double)rand() / (RAND_MAX+1U)) < p;

EDIT: ho corretto un RAND (sbagliato) in RAND_MAX(giusto)

melanippe
13-09-2004, 16:18
Originariamente inviato da Ubi-Wan
per usare sempre rand puoi fare cosi' per esempio:

float x;

x=(float)(rand()%101)/100.0;

cosi' ottieni un numero decimale compreso tra 0 e 1 con precisione di 2 zeri dopo la virgola


Grazie, è quello che cercavo di ottenere, anche se temo di non essermi espressa chiaramente!

Ziosilvio
13-09-2004, 16:23
Originariamente inviato da Ubi-Wan
per usare sempre rand puoi fare cosi' per esempio:

float x;

x=(float)(rand()%101)/100.0;

cosi' ottieni un numero decimale compreso tra 0 e 1 con precisione di 2 zeri dopo la virgola
Un generatore cosi' e' quasi sicuramente non uniforme, perche' RAND_MAX+1, il numero di possibili valori di output di rand, quasi certamente non e' multiplo di 101.

cionci
13-09-2004, 16:32
Originariamente inviato da Ziosilvio
rand genera valori "casuali tra 0 e RAND_MAX inclusi, quindi sarebbe piu' giusto:
Dipende se vuole fra 0 e 1 con 1 incluso o no...

melanippe
13-09-2004, 16:36
Originariamente inviato da Ziosilvio
A questo punto, una variabile aleatoria bernoulliana X di parametro p (che vale 1 con probabilita' p, 0 con probabilita' 1-p) si genera semplicemente ponendo:
X = ((double)rand() / (RAND_MAX+1U)) < p;


Il problema è che, più che una bernouilliana, vorrei generare una variabile aleatoria uniformemente distribuita tra 0 e 1, che assuma cioè con la stessa probabilità tutti i valori compresi tra questi due estremi, con una precisione di 2-3 cifre decimali.
Praticamente devo realizzare in C++ la funzione analoga del rand
di Matlab!

Ubi-Wan
13-09-2004, 16:36
Originariamente inviato da Ziosilvio
Un generatore cosi' e' quasi sicuramente non uniforme, perche' RAND_MAX+1, il numero di possibili valori di output di rand, quasi certamente non e' multiplo di 101.

Che cosa intendi con poco uniforme?

perche' qualcosa del genere non va bene?

#define PRECISIONE 1000U

srand(time(NULL));
x=(double)(rand()%(PRECISIONE+1U)) / (double)(PRECISIONE);

Ziosilvio
13-09-2004, 16:39
Originariamente inviato da melanippe
Praticamente devo realizzare in C++ la funzione analoga del rand
di Matlab!
Allora controlla bene se la funzione rand di Matlab puo' restituire il valore 1, perche' (come osservato da cionci) l'implementazione cambia un po':
- se 1 puo' essere restituito, fai (double)rand() / RAND_MAX;
- altrimenti fai (double)rand() / (RAND_MAX+1U).

cionci
13-09-2004, 16:39
Originariamente inviato da Ubi-Wan
Che cosa intendi con poco uniforme?

perche' qualcosa del genere non va bene?

#define PRECISIONE 1000U

srand(time(NULL));
x=(double)(rand()%(PRECISIONE+1U)) / (double)(PRECISIONE);
Il senso era che non essendo PRECISIONE+1U multiplo di RAND_MAX, la distribuzione non è uniforme a priori ;)

melanippe
13-09-2004, 16:47
Originariamente inviato da Ziosilvio
Allora controlla bene se la funzione rand di Matlab puo' restituire il valore 1

Fatto! No, 1 non può essere restituito, mentre 0 sì, almeno stando alle mie fonti!

Comunque adesso funziona e grazie a tutti per l'aiuto!
:D

Ziosilvio
13-09-2004, 16:47
Originariamente inviato da Ubi-Wan
Che cosa intendi con poco uniforme?
rand genera valori tra 0 e RAND_MAX inclusi.
Ora, supponiamo che RAND_MAX valga 65535: allora rand potra' restituire 65536 valori diversi.
Ma 65536 = 648*101 + 88, quindi rand()%101 restituira' ciascun valore tra 0 e 87 con probabilita' 649/65536, e ciascun valore tra 88 e 100 con probabilita' 648/65536.
perche' qualcosa del genere non va bene?

#define PRECISIONE 1000U

srand(time(NULL));
x=(double)(rand()%(PRECISIONE+1U)) / (double)(PRECISIONE);
Perche' non e' detto ne' che rand possa generare 1001 valori distinti, ne' che possa restituire un numero di valori che e' multiplo di 1001.

cionci
13-09-2004, 16:49
Comunque c'è sempre un trucchetto per ottenere il numero di decimali che si vuole in maniera uniforme:


(int)(((double)rand() / RAND_MAX)*1000.0)/1000.0

Con questo si hanno 3 decimali compresi con numero compreso fra 0 e 1... A parte errori di granularità (che con 3 decimali dovrebbero essere praticamente nulli) dovrebbe dare una distribuzione uniforme...

Ubi-Wan
13-09-2004, 16:55
Originariamente inviato da Ziosilvio
rand genera valori tra 0 e RAND_MAX inclusi.
Ora, supponiamo che RAND_MAX valga 65535: allora rand potra' restituire 65536 valori diversi.
Ma 65536 = 648*101 + 88, quindi rand()%101 restituira' ciascun valore tra 0 e 87 con probabilita' 649/65536, e ciascun valore tra 88 e 100 con probabilita' 648/65536.

Perche' non e' detto ne' che rand possa generare 1001 valori distinti, ne' che possa restituire un numero di valori che e' multiplo di 1001.

ok, grazie per la spiegazione :)