Newsgroup: it.comp.lang.c++
Titolo: random float(s)

Ciao,
domandina da newbie... Mi serve ottenere dei valori random di tipo float e
non ho molta dimestichezza con rand(). Questi valori devono essere compresi
tra (- range) e (+range) inclusi, cioè l'intervallo deve essere chiuso. Ora
ho a disposizione due statements che credo facciano proprio ciò che mi serve
però mi chiedo se non esiste per caso qualcosa di più elegante, espressivo
ed affidabile:
R = 2.0 * range * ( (float)rand() / RAND_MAX - 0.5 );
R = 2.0 * range * ( (float)rand() / RAND_MAX ) - range;
La prima l'ho letta su del codice di un amico che ho sottomano al momento,
mentre la seconda l'avevo pensata da me qualche minuto prima. Ciò che mi
impensierisce è che ho visto altre volte usare il denominatore (RAND_MAX+1)
e non mi è chiaro perchè si dovrebbe dividere per una unità oltre RAND_MAX.
Mi chiarite le idee, please?
Grazie.
fabio de francesco
 
 
 
--------------------------------
Inviato via 
http://arianna.libero.it/usenet/


Forse ho una traccia(?). facendo delle prove ho notato che operare
"(float)rand()/(RAND_MAX + 1)" mi fa ottenere numeri negativi compresi tra 0
e -1 (ma non ho capito se gli estremi sono compresi...).
Interessante, si direbbe che si sta operando sui bits più significativi e
forse questa è la motivazione che fa preferire il suddetto utilizzo. E così?
Mi sono perso qualcosa?
A questo punto farei:
R = range + ( 2.0 * range * (float)rand() / (RAND_MAX + 1) );
Aspetto commenti, grazie ancora.


 non ho molta dimestichezza con rand().
Dalla FAQ:
12) Come posso generare numeri casuali?
R)  La libreria standard del C (e quindi del C++) prevede le
    funzioni srand() e rand().
    La prima serve a inizializzare il generatore di numeri casuali,
    la seconda invece restituisce un numero casuale nell'intervallo
    0..RAND_MAX. Se vuoi ottenere valori inferiori a RAND_MAX
    e` importante non utilizzare l'operatore di modulo:
    int random_fra_0_e_99() {
      return rand() % 100;
    }
    poiche` in questo modo otterresti una sequenza di qualita`
    assai scarsa... molto meglio utilizzare
    int un_po_meglio_fra_0_e_99() {
      static const double divisore = (1.0 + RAND_MAX)/100.0;
      return static_cast<int>(rand()/divisore);
    }
    RAND_MAX, srand() e rand() sono dichiarate in stdlib.h
13) Come mai ottengo sempre la stessa sequenza di numeri casuali?
R)  Ti sei ricordato di effettuare l'inizializzazione del generatore
    di numeri casuali? Hai evitato di inizializzarlo sempre con
    lo stesso seme? Un buon modo di fare tutto cio` e`:
    #include <stdlib.h>
    #include <time.h>
    /* ... */
    srand(static_cast<unsigned>(time(0)));
14) La sequenza generata da rand() non e` molto buona, dove posso
    trovare generatori di numeri casuali piu` validi?
R)  Il generatore fornito dalla libreria standard non e` solitamente
    di alta qualita`, anche se ha il pregio di essere veloce... Se hai
    esigenze piu` spinte, questo piccolo elenco comprende sia testi
    di teoria, sia software gia` fatto, sia informazioni sui
    generatori hardware (non pseudo, ma VERI numeri casuali)
    accessibili via rete.
 
http://csep1.phy.ornl.gov/rn/rn.html
 
http://random.mat.sbg.ac.at/
 
http://www.math.keio.ac.jp/~matumoto/emt.html
 
http://www.taygeta.com/random.xml
 
http://www.fourmilab.ch/hotbits/
 
http://random.mat.sbg.ac.at/ftp/pub/data/winrand.zip
 
http://webnz.com/robert/nzc_nr02.html
 
http://www.math.keio.ac.jp/~matumoto/emt.html
 
http://www.boost.org/libs/random/index.html
EMG
--
EMAG Software Homepage:     
http://www.emagsoftware.it
The EMG's ZX-Spectrum Page: 
http://www.emagsoftware.it/spectrum
The Best of Spectrum Games: 
http://www.emagsoftware.it/tbosg
The EMG Music page:         
http://www.emagsoftware.it/emgmusic

 EMG
Ciao Enrico,
Prima di dare inizio al thread ho riletto come sempre le FAQ, ma purtroppo
mi sembra che non forniscono le risposte alle mie specifiche domande.
Please, dai ancora un'occhiata ai miei due messaggi per verificare.
Riassumo un paio delle domande poste:
1) Quale dei tre diversi costrutti che ho mostrato assicura la generazione
di numeri tipo float in uno specifico intervallo chiuso, cioè comprendente
gli estremi, nel modo più efficiente e affidabile? E' forse la terza
versione la più adatta allo scopo?
2) Perchè di solito si preferisce addizionare una unità a RAND_MAX, cioè
"RAND_MAX + 1", da usarsi come divisore di rand()? Questa operazione si fa
per ottenere di modificare i bits alti della variabile che conterrà il
valore di ritorno? (Preciso che ho pensato a questa eventualità dopo avere
osservato che "rand()/(MAX_RAND+1)" restituisce valori negativi e se la
logica non mi tradisce... E' davvero così o mi sto perdendo qualche pezzo
della storia?)
Grazie in anticipo a tutti quelli che interverranno sugli argomenti.
fabio de francesco
(fabiomdf)


 osservato che "rand()/(MAX_RAND+1)" restituisce valori negativi
Valori negativi? Forse mi sfugge qualcosa ma come può una divisione tra
positivi dare come risultato un negativo?


 EMG
Ricorda che la CPU non fa nessuna differenza e distinguere tra positivi e
negativi è solo frutto di una convenzione.
Ad esempio se In un campo di storage di 32 bit, ogni numero compreso tra 0 e
7FFFFFFF è considerato positivo mentre da 80000000 fino a FFFFFFFF ogni
numero è considerato positivo. La cosidetta rappresentazione a "complemento
a due" permette alla CPU di operare sui bits senza sapere se sta manipolando
numeri minori o maggiori di zero.
In pratica se ad una variabile di tipo "int" che contiene il valore 7FFFFFFF
(in decimale 
2147483647
) sommi una unità ottieni 80000000 che non è più
considerato positivo e rappresenta il numero decimale -
2147483648
.
Bene quest'ultimo valore è proprio ciò che ottieni come somma di RAND_MAX +
1. Quindi la divisione di un numero positivo per uno negativo restituisce un
numero minore di zero.
Spero di essere stato chiaro. Rimango sempre in attesa di risposte alle mie
domande...
Buon lavoro,
fabio de francesco


 numero minore di zero.
No, aspetta: la somma non è con 1 ma con 1.0 che è ben diverso. Devo
continuare? :-)


 EMG
Ah già, per qualche motivo continuavo a ricordare che la somma fosse con "1"
anzichè "1.0" ottenendo un overflow e da li è seguito tutto il discorso.
Beh, scusami per la lezione non richiesta e non necessaria sullo storage dei
numeri.
In ogni caso non posso utilizzare l'esempio in FAQ così come è perchè mi
servono dei float nell'intervallo chiuso [-range/2,+range/2], quindi se non
ci sono(?) controindicazioni userò la seguente.
float range;
float R = ( range * (float)rand() / RAND_MAX ) - range/2;
Sei d'accordo che non posso dividere per RAND_MAX + 1.0 altrimenti non
otterrei mai il valore massimo del range?
Grazie.


 otterrei mai il valore massimo del range?
A naso (ma posso certamente sbagliare), non mi sembra un granché come
generatore di float.
