Ottenere grandi numeri casuali in C/C++

Standard rand() funzione dà i numeri non sono abbastanza grandi per me: ho bisogno di unsigned long long quelli. Come possiamo ottenere davvero grandi numeri casuali? Ho provato la modifica di una semplice funzione di hash, ma è troppo grande, richiede troppo tempo per la sua esecuzione e non produce numeri, che sono meno di 1e5!!

  • Quanto “GRANDI” numeri che si desidera?
  • Come circa usando la funzione rand() per ottenere insiemi di bit casuali, e la compilazione di ogni int-ampio numero di bit in un momento in unsigned long long utilizzo di maschere di bit.
  • “non produce numeri, che sono meno di 1e5” – come l’ha definita “mai”? Ci si aspetterebbe che perfettamente numeri casuali non occupano che molto spesso, data la gamma completa che stai chiedendo.
  • come il fatto di abbandonare rand() e l’utilizzo di alcuni dei migliori Rng c++ fornisce en.cppreference.com/w/cpp/numeric/random
  • MOLTO grande, molto di più di 1e7
  • Hai visto stackoverflow.com/questions/8120062/…?
  • Sto solo non sono sicuro se questi numeri fit in unsigned long long

InformationsquelleAutor ForceBru | 2015-01-23

 

6 Replies
  1. 8

    Ecco un portatile C99 soluzione che restituisce un casuale numero a 64 bit:

    unsigned long long llrand() {
        unsigned long long r = 0;
    
        for (int i = 0; i < 5; ++i) {
            r = (r << 15) | (rand() & 0x7FFF);
        }
    
        return r & 0xFFFFFFFFFFFFFFFFULL;
    }

    Spiegazione: rand() restituisce numeri interi compresi nell’intervallo da 0 a RAND_MAX e RAND_MAX è garantito per essere almeno di 32.767 (15 bit casuali). long long è garantita a 64 bit, ma potrebbe essere più grande.

    • Essere davvero stanco di questo. Può sembrare ragionevole, ma i numeri che produce non può (in realtà, probabilmente non) superare molti test statistici di casualità.
    • Bello, ma si può spiegare perché r & 0xFFFFFFFFFFFFFFFFULL;?, sembra un NOOP
    • Come ho detto, long long potrebbe essere superiore a 64 bit. Se è a 64 bit, il compilatore dovrebbe essere un ” noop.
    • Wooow, ok, ora ho capito, grazie
    • nella maggior parte dei moderni compilatori RAND_MAX == INT_MAX con int 32 bit, in modo che solo return rand() << 32 | rand(); è abbastanza
    • Anche se RAND_MAX == INT_MAX, questo non avrebbe funzionato dal rand() restituisce solo il 31 bit casuali.
    • Ho dimenticato che non restituisce un valore negativo. Ma anche in quel caso hai solo bisogno di 3 rand chiamate, non 5
    • MSVC (che ha una ragionevole quota di mercato) ha #define RAND_MAX 0x7fff
    • si può fornire una citazione o un esempio di una prova che questo avrebbe fallito su (che rand() di per sé il pass)
    • chiedi a te stesso se ogni possibile unsigned long long numero può essere generato da llrand e se alcuni numebrs sono più o meno probabile. Si supponga che rand() & 0x7FFF è distribuito uniformemente per gli scopi di questo esperimento.
    • Puoi fare una prova con una suite come dieharder. Scommetto che non riuscirà diversi test.
    • Ancora non vedendo il problema; supponendo che la funzione rand() è distribuita in modo uniforme, non vedendo alcun numero che non può essere generato o che sarebbe generato più o meno spesso. Detto questo, corse contro dieharder 3.31.1; c’erano due “buoni” test tornato debole [fallito] (piuttosto che semplicemente utilizzando l’uscita di rand(), che ha avuto molti fallimenti, presumibilmente a causa di rand() non restituisce 32 bit di casualità alla volta, o con uchar x = rand() % 256 e l’output di 8 bit alla volta; solo 1 sospetto di prova tornato debole (il resto è passato)
    • per la cronaca, i due che è venuto di nuovo debole erano un rgb_lagged_sum per ntuple=28 e uno dei sts_serials per ntuple=8. Questa è una srand(1) su un 64bit per Linux.
    • Ack, nell’interesse di non intasamento questo rispondo più, ha pubblicato questo come seguire in questione: stackoverflow.com/questions/29366721/… Notare che quando ho ri-eseguito il test, il 8 bit alla volta la versione è tornato con una debolezza, non sono sicuro se mi è sfuggito che l’ultima volta o se qualcosa è cambiato tra le corse che mi manca

  2. 16

    Si può facilmente fare questo con uniform_int<unsigned long long>.

    Semplice esempio di codice (preso da qui, modificato per l’utilizzo unsigned long long):

    #include <random>
    #include <iostream>
    
    int main()
    {
        std::random_device rd;
        std::mt19937 gen(rd());
        std::uniform_int_distribution<unsigned long long> dis(lowerBorder, upperBorder);
    
        for (int n=0; n<10; ++n)
            std::cout << dis(gen) << ' ';
        std::cout << '\n';
    }

    Di notare che la semina di mersenne twister come fatto qui per scopi dimostrativi non è perfetto, per esempio vedere qui.

    • Che dovrebbe essere una risposta corretta. Inoltre, si richiede di C++11 di supporto.
    • Penso che si dovrebbe usare std::mt19937_64 per meglio casualità.
    • No, che non migliora la casualità. Si può provare se migliora la velocità al tipo di ambiente, che potenzialmente potrebbero lavorare.
  3. 2

    Se si desidera solo per produrre unsigned long long dal valore restituito dalla funzione rand() e non si preoccupano le caratteristiche del risultato si consideri la seguente funzione che deve essere la versione del compilatore e indipendente dalla piattaforma (perché no “numeri magici” sono utilizzati):

    //this header has RAND_MAX value
    #include <stdlib.h>  
    //and this header has ULLONG_MAX
    #include <limits.h>
    
    unsigned long long ullrand()
    //Produces pseudo-random numbers from 0 to ULLONG_MAX
    //by filling all bits of unsigned long long integer number
    //with bits of several "small" integer numbers generated by rand()
    {
        unsigned long long myrndnum = 0; //at the beginning just zero
        unsigned long long counter = ULLONG_MAX; //at the beginning we have all bits set as 1
        //... and while at least one bit is still set to 1
        while(counter > 0) {
               myrndnum = (myrndnum * (RAND_MAX + 1)) + rand(); //fill some bits from rand()
               counter /= (RAND_MAX + 1); //decrease number of 1-bits in counter
            }
        //Return the result
        return myrndnum;
    }

    Ma se volete una sequenza di numeri casuali con determinate caratteristiche predeterminate, si dovrebbe guardare in alcune guide o libri di matematica. E. g. https://www.gnu.org/software/gsl/manual/html_node/Random-number-generator-algorithms.html

  4. 0

    Non avete chiesto uno specifico sistema operativo e le risposte qui sono veramente buoni, ma su Linux (e probabilmente anche su altri Sistemi operativi troppo) si può anche leggere da un dispositivo casuale.

    Esempio:

    #include <stdio.h>
    #include <assert.h>
    
    #define RANDDEV "/dev/urandom"
    
    unsigned long long bigrand(void) {
        FILE *rdp;
        unsigned long long num;
    
        rdp = fopen(RANDDEV, "rb");
        assert(rdp);
    
        assert(fread(&num, sizeof(num), 1, rdp) == 1);
    
        fclose(rdp);
    
        return num;
    }

    Scritto sul mobile, può avere dei bug. 😛

    • Forse si dovrebbe disattivare il buffer, o utilizzare read(), per evitare di sprecare byte casuali?
  5. 0

    È inoltre possibile utilizzare la libreria boost (tratto da link):

    #include <ctime>            //std::time
    #include <boost/random/mersenne_twister.hpp>
    #include <boost/random/linear_congruential.hpp>
    #include <boost/random/uniform_real.hpp>
    #include <boost/random/variate_generator.hpp>
    #include <boost/generator_iterator.hpp>
    
    
    int main()
    {
        long long my_min = 1;
        long long my_max = 1e5;
    
        boost::mt19937 generator(static_cast<unsigned int>(std::time(0)));
        boost::variate_generator<boost::mt19937&, boost::uniform_real<> >
            die_gen(generator, boost::uniform_real<> (my_min, my_max));
    
        boost::generator_iterator<boost::variate_generator<boost::mt19937&, boost::uniform_real<> > > die(&die_gen);
    
        std::cout<<"Generated random numbers: \n";
        for (int i=0; i <10 ; i++)
        {
            std::cout<< static_cast<long long>(*die++) << std::endl;
        }
    
        return 0;
    }
  6. -1

    provare questo:

    long N=1000000;
    long randNumber;
    for(long i=0;i<N;i++)
    randNumber=i+rand()
    • Mentre questo codice può rispondere alla domanda, sarebbe meglio includere alcuni contesto, spiegando come funziona e quando di usarlo. Solo codice risposte non sono utili nel lungo periodo.
    • Questo è un pessimo metodo per generare numeri casuali. E ‘ lento, mal distribuito, e determina un comportamento indefinito a causa firmato overflow.

Lascia un commento