2015-10-08 32 views
12

Ho bisogno di generare interi casuali senza segno a 64 bit utilizzando C. Voglio dire, l'intervallo deve essere 0 a 18446744073709551615. RAND_MAX è 1073741823.Come generare un numero intero senza segno casuale a 64 bit in C

Ho trovato alcune soluzioni nei collegamenti che potrebbero essere possibili duplicati ma le risposte per lo più concatenano alcuni risultati rand() o eseguendo alcune operazioni aritmetiche incrementali. Quindi i risultati sono sempre di 18 cifre o 20 cifre. Voglio anche risultati come 5, 11, 33387, non solo 3771778641802345472.

A proposito, non ho molta esperienza con la C ma qualsiasi approccio, esempi di codice e idea potrebbero essere utili.

+9

** Non ** concatenate 'rand()', come avrete tutti i tipi di effetti di autocorrelazione, e la distribuzione non lo farà essere uniforme Date un'occhiata a questi: http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/C-LANG/c-lang.html – Bathsheba

+12

'Voglio anche risultati come 5 , 11, 33387' => ci sono 10 volte più numeri tra 1000000000000000000 e 9999999999999999999 che tra 0 e 1000000000000000000 ... quindi non aspettarti di vedere numeri come 5 presto –

+1

Sembra che tu sia confuso riguardo le cifre in base 10 (0. ..9) e bit (base-2 cifre). Tieni questi separati nel tuo pensiero, per una migliore comprensione. – hyde

risposta

-1
#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
#include <time.h> 

unsigned long long int randomize(unsigned long long int uint_64); 

int main(void) 
{ 
    srand(time(0)); 

    unsigned long long int random_number = randomize(18446744073709551615); 

    printf("%llu\n",random_number); 

    random_number = randomize(123); 

    printf("%llu\n",random_number); 

    return 0; 

} 

unsigned long long int randomize(unsigned long long int uint_64) 
{ 
    char buffer[100] , data[100] , tmp[2]; 

    //convert llu to string,store in buffer 
    sprintf(buffer, "%llu", uint_64); 

    //store buffer length 
    size_t len = strlen(buffer); 

    //x : store converted char to int, rand_num : random number , index of data array 
    int x , rand_num , index = 0; 

    //condition that prevents the program from generating number that is bigger input value 
    bool Condition = 0; 

    //iterate over buffer array 
    for(int n = 0 ; n < len ; n++) 
    { 
     //store the first character of buffer 
     tmp[0] = buffer[n]; 
     tmp[1] = '\0'; 

     //convert it to integer,store in x 
     x = atoi(tmp); 


     if(n == 0) 
     { 
      //if first iteration,rand_num must be less than or equal to x 
      rand_num = rand() % (x + 1); 

      //if generated random number does not equal to x,condition is true 
      if(rand_num != x) 
       Condition = 1; 

      //convert character that corrosponds to integer to integer and store it in data array;increment index 
      data[index] = rand_num + '0'; 
      index++; 
     } 
     //if not first iteration,do the following 
     else 
     { 
      if(Condition) 
      { 
       rand_num = rand() % (10); 

       data[index] = rand_num + '0'; 

       index++; 
      } 
      else 
      { 
       rand_num = rand() % (x + 1); 

       if(rand_num != x) 
        Condition = 1; 

       data[index] = rand_num + '0'; 

       index++; 
      } 
     } 
    } 

    data[index] = '\0'; 

    char *ptr ; 

    //convert the data array to unsigned long long int 
    unsigned long long int ret = _strtoui64(data,&ptr,10); 

    return ret; 
} 
+0

In che modo soddisfa il requisito di un int in modo casuale a 64 bit senza segno? –

+0

Bene, ho provato il tuo codice e stampato 1000 risultati. I risultati sono come questo; 04951651604868241121, 00651604895168241121, 03943165433604438241, 00160434265465541121 ... quindi suppongo che non possiamo avere ciò di cui ho bisogno con questo metodo. –

+0

vuoi dire, non vuoi gli zeri iniziali? –

1

Iff avete una sufficientemente buona fonte di byte casuali (come, ad esempio,/dev/random o/dev/urandom su una macchina Linux), si può semplicemente consumare 8 byte da quella sorgente e concatenare. Se sono indipendenti e hanno una distribuzione lineare, sei pronto.

Se non lo fai, puoi scappare facendo lo stesso, ma è probabile che ci siano alcuni artefatti nel tuo generatore pseudo-casuale che ti dà una presa per tutti i tipi di hi-jinx.

codice di esempio assumendo abbiamo un open binario FILE *source:

/* Implementation #1, slightly more elegant than looping yourself */ 
uint64_t 64bitrandom() 
{ 
    uint64_t rv; 
    size_t count; 

    do { 
    count = fread(&rv, sizeof(rv), 1, source); 
    } while (count != 1); 
    return rv; 
} 

/* Implementation #2 */ 
uint64_t 64bitrandom() 
{ 
    uint64_t rv = 0; 
    int c; 

    for (i=0; i < sizeof(rv); i++) { 
    do { 
     c = fgetc(source) 
    } while (c < 0); 
    rv = (rv << 8) | (c & 0xff); 
    } 
    return rv; 
} 

Se si sostituisce "Leggi byte casuali da un dispositivo di casualità" con "get byte da una chiamata di funzione", tutto ciò che dovete fare è quello di regola i cambiamenti nel metodo # 2.

È molto più probabile che si ottenga un "numero con più cifre" rispetto a uno con "un piccolo numero di cifre" (di tutti i numeri compresi tra 0 e 2 ** 64, circa il 95% ha 19 o più cifre decimali , quindi in realtà questo è ciò che sarà per lo più ottenere

+0

Che cos'è "hi-jinx"? =) –

-2

Se hai 32 o 16 bit valore casuale -. generare 2 o 4 randoms e combinarle a uno a 64 bit con << e |

+0

la cosa è il valore casuale dell'OP ha solo 30 bit –

3

per quanto riguarda ". Quindi i risultati sono sempre di 18 cifre o 20 cifre. "

Vedere @Thomas comment. Se si genera un numero casuale Se il codice è lungo abbastanza, il codice creerà quelli come 5, 11 e 33387. Se il codice genera 1.000.000.000 di numeri/secondo, potrebbe essere necessario un anno come numeri molto piccoli < 100.000 sono così rari tra tutti i numeri a 64 bit.


rand() bit semplici restituiti a caso. Procedimento semplicistico tira 1 bit alla volta

uint64_t rand_uint64_slow(void) { 
    uint64_t r = 0; 
    for (int i=0; i<64; i++) { 
    r = r*2 + rand()%2; 
    } 
    return r; 
} 

Supponendo RAND_MAX è una potenza di 2 - 1 come nel caso del PO 1073741823 == 0x3FFFFFFF, trarre vantaggio che 30 bit sono generati ogni volta. Il seguente codice chiamerà rand() 3 volte - un po 'dispendioso. Invece i bit spostati potrebbero essere salvati per il prossimo numero casuale, ma ciò porta ad altri problemi. Lascia stare per un altro giorno.

uint64_t rand_uint64(void) { 
    uint64_t r = 0; 
    for (int i=0; i<64; i += 30) { 
    r = r*((uint64_t)RAND_MAX + 1) + rand(); 
    } 
    return r; 
} 

Procedimento numero di loop portatile evita i 30

#if RAND_MAX/256 >= 0xFFFFFFFFFFFFFF 
    #define LOOP_COUNT 1 
#elif RAND_MAX/256 >= 0xFFFFFF 
    #define LOOP_COUNT 2 
#elif RAND_MAX/256 >= 0x3FFFF 
    #define LOOP_COUNT 3 
#elif RAND_MAX/256 >= 0x1FF 
    #define LOOP_COUNT 4 
#else 
    #define LOOP_COUNT 5 
#endif 

uint64_t rand_uint64(void) { 
    uint64_t r = 0; 
    uint64_t r = 0; 
    for (int i=LOOP_COUNT; i > 0; i--) { 
    r = r*(RAND_MAX + (uint64_t)1) + rand(); 
    } 
    return r; 
} 

Gli effetti autocorrelazione commentato here sono causati da un debole rand(). C non specifica un particolare metodo di generazione di numeri casuali. Quanto sopra si basa su rand() buono. Se rand() è sotto-par, il codice dovrebbe utilizzare altri generatori per questo e rand().

+2

Questa risposta è come una poesia. Intendo le spiegazioni. Ho capito perfettamente tutto ciò che riguarda la mia domanda. –

0

Ho provato questo codice here e sembra funzionare bene lì.

#include <time.h> 
#include <stdlib.h> 
#include <math.h> 

int main(){ 
    srand(time(NULL)); 
    int a = rand(); 
    int b = rand(); 
    int c = rand(); 
    int d = rand(); 
    long e = (long)a*b; 
    e = abs(e); 
    long f = (long)c*d; 
    f = abs(f); 

    long long answer = (long long)e*f; 

    printf("value %lld",answer); 
    return 0; 
} 

mi corse un paio di iterazioni e ottengo le seguenti uscite:

valore 1869044101095834648
valore 2104046041914393000

valore 1587782446298476296
valore 604.955.295.827,51625 milioni
valore 41152208336759610
valore 57792837533816000

0

Se non ti dispiace una sequenza casuale ripetitiva pseudo (hey, per 64 bit non si sta andando a notare la ripetizione nella vostra vita;) e si può fare con un valore inferiore all'intervallo richiesto (0 non sta per accadere), un LCG o MCG è una soluzione sorprendentemente semplice. Wikipedia: Linear congruential generator Passare a here per generare un paio di numeri primi e utilizzarne uno per il modulo e l'altro per il moltiplicatore riportato di seguito. (Avvertimento: questa sequenza sarà da indovinare e quindi non è sicuro)

#include <stdio.h> 
#include <stdint.h> 

uint64_t 
mcg64(void) 
{ 
    static uint64_t i = 1; 
    return (i = (164603309694725029ull * i) % 14738995463583502973ull); 
} 

int 
main(int ac, char * av[]) 
{ 
    for (int i = 0; i < 10; i++) 
     printf("%016p\n", mcg64()); 
} 
Problemi correlati