La generazione di un numero casuale tra [-1, 1] in C?

Ho visto un sacco di domande sul MODO su questo particolare argomento, ma nessuno di loro ha una risposta per me, così ho pensato di chiedere a questa domanda.

Volevo generare un numero casuale tra [-1, 1]. Come posso fare questo?

  • Dal momento che non è stato specificato o float int, restituisce 0.
InformationsquelleAutor itsaboutcode | 2009-10-12



7 Replies
  1. 18

    Utilizzare -1+2*((float)rand())/RAND_MAX

    rand() genera numeri interi compresi nell’intervallo [0,RAND_MAX] inclusive pertanto, ((float)rand())/RAND_MAX restituisce un numero in virgola mobile in [0,1]. Otteniamo numeri casuali da [-1,1] aggiungendo -1.

    EDIT: (con l’aggiunta di parti rilevanti della sezione di commento)

    Sui limiti di questo metodo:

    ((float)rand())/RAND_MAX restituisce una percentuale (una frazione da 0 a 1). Quindi, dato che l’intervallo tra -1 e + 1 è di 2 numeri interi, ho moltiplicare la frazione con 2 e poi aggiungere il numero minimo che si desidera, -1. Questo si spiega anche la qualità del numeri casuali in quanto si avrà solo RAND_MAX unica di numeri casuali.

    • Questa è la creazione di errore. “Expression previsto prima float” e quando io rimuovere il galleggiante intorno rand, si generano sempre -1.
    • Sembra problematico, in quanto non creare una sovrapposizione casuale di frazioni decimali, ma un discreto set di RAND_MAX numeri.
    • Scusate, dimenticavo si utilizza C. float(x) è utilizzato in C++. Prova il nuovo codice che utilizza ((float)x)
    • rand() restituisce un intero. Ma la suddivisione per RAND_MAX ci dà una frazione che usiamo per generare un numero casuale compreso tra -1 e 1.
    • wow, funziona, grazie. Ma mi puoi dire perché si moltiplicano con il “2”
    • Pensate in questo modo: ((float)rand())/RAND_MAX restituisce una percentuale (una frazione di 0 to 1). Quindi, dato che l’intervallo tra -1 e + 1 è di 2 numeri interi, ho moltiplicare la frazione con 2 e poi aggiungere il numero minimo che si desidera, -1. Questo si spiega anche la qualità del numeri casuali in quanto si avrà solo 32767 unica numeri casuali dal RAND_MAX = 32767
    • hmm. Grazie uomo.
    • Nessun problema, felici di aiutarti!
    • eyalm è giusto che non generare tutti i possibili valori a virgola mobile tra -1 e 1. Si genererà RAND_MAX differenti (e RAND_MAX è di solito 65535, in modo che potrebbe non essere sufficiente per una particolare applicazione). Ancora, per molti scopi, questo è sufficientemente continuo.
    • L’insieme di tutti i possibili valori a virgola mobile non è uniformemente distribuito. Se il più piccolo (positivo) galleggiante è di 10^-37, per esempio, circa la metà dei possibili valori a virgola mobile si trovano tra -(10^-18) e 10^-18.
    • float(x) non è utilizzato in C++, static_cast è.
    • Ho spiegato che la limitazione nella mia risposta a itsaboutcode. @GMan: Grazie, hai ragione. Volevo dire float(x) è valida solo in C++.
    • Si noti che la funzione rand() restituisce i numeri interi da 0 a RAND_MAX incluso, in modo che in realtà si dovrebbe dividere per (RAND_MAX+1), per essere esatti. La differenza non conta molto quando RAND_MAX è dire, 2147483647 (caso in cui nota che RAND_MAX+1 overflow), ma può essere significativo quando RAND_MAX è solo 32767.
    • Quindi vuoi dire che [0; 1] + { – 1} <=> [-1; 1] ?
    • Supponendo che l’OP notazione era intenzionale (utilizzando le parentesi quadre per dire inclusive su entrambe le estremità), non si vuole dividere per RAND_MAX+1; così facendo si renderebbe impossibile generare il inclusiva punto finale, 1.0. Se si voleva in esclusiva su entrambe le estremità, si sarebbe in realtà vuole fare qualcosa di simile -1 + 2 * ((double)rand() + 1) / ((double)RAND_MAX + 2), aggiungendo uno al numeratore (per escludere -1.0) e dividendo per RAND_MAX + 2 (per escludere 1.0, mentre la contabilità per il + 1, che lo ha escluso -1.0).

  2. 9

    Se tutto quello che hai è la libreria C Standard, quindi le risposte sono sensibili. Se si dispone di POSIX funzionalità disponibili per voi, prendere in considerazione utilizzando il drand48() famiglia di funzioni. In particolare:

    #define _XOPEN_SOURCE 600  /* Request non-standard functions */
    #include <stdlib.h>
    
    double f = +1.0 - 2.0 * drand48();
    double g = -1.0 + 2.0 * drand48();

    Di notare che il manuale dice:

    Il drand48() e erand48 funzioni di() deve restituire un valore non negativo, in doppia precisione, i valori in virgola mobile, distribuito uniformemente sull’intervallo [0.0,1.0).

    Se strettamente necessario [-1.0,+1.0] (invece di [-1.0,+1.0)), allora si faccia un delicato problema di come estendere la gamma.

    Il drand48() funzioni di dare notevolmente più casualità che la tipica implementazione di rand(). Tuttavia, se avete bisogno di crittografia casualità, nessuno di questi sono appropriati, è necessario guardare per ‘crittograficamente forte PRNG’ (PRNG = pseudo-random number generator).

    • Er, una distribuzione uniforme su [-1,1] è matematicamente identica per una distribuzione uniforme su [-1,1). La probabilità di ottenere esattamente “1” è a 0 in entrambi i casi.
    • err, se il generatore dice ‘[0.0,1.0)’, significa che c’è una piccola ma finita la possibilità di ottenere il risultato 0.0, ma non c’è nessuna possibilità di 1.0 – esso non apparirà mai. Il tuo ragionamento avrebbe dovuto applicare per la fascia bassa della gamma troppo. È anche interessante che il mio ‘f’ conterrà i valori nell’intervallo (-1.0,+1.0] e il mio ‘g’ conterrà i valori nell’intervallo [-1.0,+1.0).
    • Beh, una distribuzione uniforme, la possibilità di ottenere un particolare valore esatto è 0 (non “piccola ma finita”). Naturalmente, una implementazione potrebbe non corrispondere alla definizione matematica (per esempio, molte implementazioni di ritorno numeri razionali con probabilità 1, mentre al di sotto di una effettiva distribuzione uniforme l’insieme dei numeri razionali è numerabile e quindi ha misura 0) — allora mi chiedo che cosa esattamente “distribuzione uniforme” significa a tutti qui. Si potrebbe dire che, per ogni x in [0,1) o [0,1], la probabilità di ottenere un numero ≤ x è x. In questo caso, di nuovo, entrambi sono la stessa cosa.
    • stai giocando in un matematici puri mondo; questo sito è di circa la programmazione di computer. Stai spaccando i capelli inutilmente. Per esempio, che tutti i valori sono intrinsecamente numeri razionali; non ci sono numeri trascendenti memorizzati in loro, solo (poveri) approssimazioni di numeri trascendenti.
    • Naturalmente so che, che è ciò che ho detto nel mio commento precedente. Per ribadire/riformulare: per qualsiasi buona definizione di distribuzione uniforme (buon w.r.t programmazione di computer), se si prende la [0,1] o [0,1) o (0,1] o (0,1) non importa, perché i punti estremi 0 e 1 non dovrebbe verificarsi con qualsiasi rilevabile probabilità. È anche per questo che ho con voto positivo la tua risposta prima di commentare, perché (contrariamente al commento in it) dare esattamente che la domanda chiede. 🙂
    • Per esempio, una possibile definizione di una distribuzione uniforme (per la programmazione) potrebbe essere: si consideri l’insieme di tutti i numeri in [0,1), che possono essere rappresentati esattamente un double valore, e di definire la distribuzione uniforme su questa (discreto) set. Ora, se si prende [0,1] o (0,1) non c’è nessun test statistico è in grado di distinguere tra i due all’interno di (diciamo) il ciclo di vita della civiltà umana. Così le due distribuzioni non sono diversi sia praticamente o matematicamente, così come si differenziano? “Moralmente”?
    • OK – ho più o meno quello che stai ricevendo in. Con un numero intero a base di soluzione e RAND_MAX di 32767 o 65535, quindi la distinzione è se il termine di punti è misurabile; se avete a che fare con spettro completo doppie, probabilmente non lo è.
    • Hmm sì, sono d’accordo con te. Questo è ovvio, col senno di poi: gli oggetti matematici sono gli stessi, quindi più le funzioni sono l’ideale, è difficile distinguere tra di loro. Quando usiamo RAND_MAX e interi, sono, infatti, molto diverso! Io non avevo pensato.

  3. 8

    Avevo una domanda simile un po ‘ indietro e ho pensato che potrebbe essere più efficiente genera solo la parte frazionaria direttamente. Ho fatto qualche ricerca e sono imbattuto in un interessante veloce floating point rand che non usa la divisione in virgola mobile o di moltiplicazione o un int->float cast può essere fatto con alcuni la conoscenza intima la rappresentazione interna di un float:

    float sfrand( void )
    {
        unsigned int a=(rand()<<16)|rand();  //we use the bottom 23 bits of the int, so one
                                             //16 bit rand() won't cut it.
        a=(a&0x007fffff) | 0x40000000;  
    
        return( *((float*)&a) - 3.0f );
    }

    La prima parte genera un casuale float [2^1,2^2), sottrarre 3 e si è [-1, 1). Questo, naturalmente, potrebbe essere troppo intimo per alcune applicazioni e sviluppatori, ma era proprio quello che stavo cercando. Questo meccanismo funziona bene per qualsiasi intervallo che è una potenza di 2 di larghezza.

    • Questo è davvero cool!
    • se RAND_MAX è il max di un corto con il bit di segno sempre positivo solo 15 bit sarà casuale in int restituiti. Io non sono bravo con bit saggio operazioni di sicurezza, ma dal tuo commento che potrebbe essere un problema.
    • La soluzione è quello di utilizzare solo il primo byte 1 da ciascuna delle 4 chiamate a rand() .
  4. 6

    Per cominciare, avrete bisogno di funzione della libreria C rand(). Questo è il stdlib.h file di intestazione, così si dovrebbe mettere:

    #include <stdlib.h>

    vicino all’inizio del codice. rand() genera un numero intero casuale compreso tra zero e RAND_MAX quindi, dividendo per RAND_MAX /2 vi darà un numero tra zero e 2 all inclusive. Sottrarre uno, e siete sul vostro target range da -1 a 1.

    Tuttavia, se semplicemente non int n = rand() /(RAND_MAX /2), vi accorgerete che non si ottiene la risposta che ci si aspetta. Questo perché sia rand() e RAND_MAX /2 sono numeri interi, in modo che l’intero aritmetica è utilizzato. Per evitare questo problema, alcune persone utilizzare un galleggiante in ghisa, ma mi sento di raccomandare di evitare i cast moltiplicando per 1.0.

    Si dovrebbe anche seme il generatore di numero casuale con il srand() funzione. Al fine di ottenere un risultato diverso ogni volta, la gente spesso il seme del generatore basato sull’orologio del tempo, facendo srand(time(0)).

    Così, in generale abbiamo:

    #include <stdlib.h>
    srand(time(0);
    double r = 1.0 * rand() / (RAND_MAX / 2) - 1;
    • Moltiplicando per 1.0 non evitare il cast, rende solo implicita. Io non sono sicuro di quello che si pensa si sta guadagnando da “evitare” il cast.
    • Certamente ancora esegue una conversione di tipo, ma non per via di un cast, come il cast di costruire “(float)” è stato rimosso. Perché questo è meglio? Bene, in primo luogo “un unsuffixed galleggiante costante di tipo doppio”, quindi mi sto facendo l’aritmetica in virgola mobile in doppia, piuttosto che galleggiare. In secondo luogo, utilizzando un cast di costruire disattiva gli avvisi del compilatore, e quindi dovrebbe essere evitato per quanto possibile. Per esempio, se è stato digitato correttamente la funzione rand() come un’altra funzione che restituisce un puntatore, il compilatore ti avvisano se si tenta di moltiplicare che da 1.0. Tuttavia, se si maschera con un cast che si perde utile avvertenze.
    • che non è un utile avviso, dato che si sono, infatti, di voler convertire un int a float.
  5. 3

    Mentre accettati risposta è eccellente in molti casi, lascerà “ogni altro numero”, perché è l’espansione di un intervallo di valori discreti da 2 a coprire il [-1, 1] intervallo. In modo simile, se si ha un generatore di numeri casuali, che potrebbe generare un numero intero compreso tra [0, 10] e si desidera generare [0, 20], semplicemente moltiplicando per 2 di estensione della gamma, ma non essere in grado di coprire la gamma (sarebbe lasciare fuori tutti i numeri dispari).

    Probabilmente non ha sufficientemente grana fine per le vostre esigenze, ma non hanno questo inconveniente, che potrebbe essere statisticamente significativa (e dannoso) in molte applicazioni, in particolare simulazioni monte carlo e sistemi di dipendenza sensibile dalle condizioni iniziali.

    Un metodo che è in grado di generare qualsiasi rappresentabile numero in virgola mobile da -1 a 1 inclusive dovrebbe fare affidamento sulla generazione di una sequenza a1.a2 a3 a4 a5 … fino al limite della vostra precisione in virgola mobile, che è l’unico modo per essere in grado di generare qualsiasi possibile galleggiare nell’intervallo. (cioè in seguito alla definizione dei numeri reali)

    • Sì, ho provato a spiegare che nei miei commenti.
    • In realtà, questo è definizione dei numeri reali 🙂 Ci sono un po ‘ diverse. Anche se quello che circoscrizionali attraverso la notazione decimale è utilizzato da Knuth, quindi dovremmo preferire rispetto a tutti gli altri 🙂
    • Infatti, è il più immediatamente applicabili ai metodi computazionali. en.wikipedia.org/wiki/Construction_of_the_real_numbers
  6. 1

    Dalla “Libreria Standard C”

    int rand(void) – Restituisce il numero pseudo-casuale nell’intervallo 0 per RAND_MAX

    RAND_MAX – Massimo valore restituito da rand().

    Così:

    rand() restituirà un numero pseudo-casuale nell’intervallo 0 per RAND_MAX

    rand() /RANDMAX restituirà un numero pseudo-casuale nell’intervallo 0 per 1

    2*( rand() /RANDMAX ) restituirà un numero pseudo-casuale nell’intervallo 0 per 2

    2*( rand() /RANDMAX ) -1 restituirà un numero pseudo-casuale nell’intervallo -1 per 1

    • Dal momento che non hai mai gettato il risultato di rand(), la divisione di RAND_MAX sarà sempre 0.
    • Tranne nel caso di rand() == RAND_MAX
  7. 0

    Come altri già notato, tutti i tentativi di semplicemente trasformare la gamma di rand()’ funzione [0, RAND_MAX] in la [-1, +1] produrrà un generatore di numero casuale che può generare solo un insieme discreto di valori a virgola mobile. Per una virgola generatore la densità di questi valori potrebbe essere insufficiente in alcune applicazioni (se l’attuazione di un valore definito dall’di RAND_MAX non è sufficientemente grande). Se questo è un problema, può aumentare la suddetta densità in modo esponenziale con l’utilizzo di due o più ‘rand()’ chiama invece di uno.

    Per esempio, combinando i risultati di due chiamate consecutive a ‘rand()’ si può ottenere un numero pseudo-casuale nell’intervallo [0, (RAND_MAX + 1)^2 – 1] gamma

    #define RAND_MAX2 ((RAND_MAX + 1ul) * (RAND_MAX + 1) - 1)
    
    unsigned long r2 = (unsigned long) rand() * (RAND_MAX + 1) + rand();

    e poi utilizzare lo stesso metodo per trasformarlo in un numero a virgola mobile in [-1, +1] gamma

    double dr2 = r2 * 2.0 / RAND_MAX2 - 1;

    Utilizzando questo metodo si può costruire come molti ‘rand()’ chiama come necessario, mantenere un occhio su di integer overflow, naturalmente.

    Come nota a margine, questo metodo di combinare consecutivi”, rand()’ chiamate non produce molto di alta qualità pseudo-generatori di numero casuali, ma potrebbe funzionare perfettamente bene per molti scopi.

    • Qualsiasi tentativo di trasformare qualsiasi cosa in qualsiasi intervallo su un computer che permetterà di produrre un insieme discreto di razionale valori a virgola mobile o altro.

Lascia un commento