2015-10-08 16 views
12

Potrzebuję wygenerować losowe 64-bitowe liczby całkowite bez znaku przy użyciu C. Mam na myśli, zakres powinien być od 0 do 18446744073709551615. RAND_MAX jest 1073741823.Jak wygenerować losową 64-bitową liczbę całkowitą bez znaku w C

Znalazłem kilka rozwiązań w linkach, które mogą być możliwe duplikaty, ale odpowiedzi w większości łączą niektóre wyniki rand() lub wykonują pewne przyrostowe operacje arytmetyczne. Zatem wyniki zawsze mają 18 cyfr lub 20 cyfr. Chcę również wyników takich jak 5, 11, 33387, a nie tylko 3771778641802345472.

Nawiasem mówiąc, naprawdę nie mam tak dużego doświadczenia z C, ale każde podejście, próbki kodu i pomysł mogą być korzystne.

+9

** Nie ** concatenate 'rand()' jak będziesz miał wszystkie rodzaje efektów autokorelacji i dystrybucja nie będzie być jednolity. Spójrz na te: http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/C-LANG/c-lang.html – Bathsheba

+12

'Chcę również wyników takich jak 5 , 11, 33387' => istnieje 10 razy więcej liczb między 1000000000000000000 a 9999999999999999999 niż między 0 a 1000000000000000000 ... więc nie oczekuj, że cyfry takie jak 5 wkrótce –

+1

Wydaje się, że jesteś zdezorientowany z powodu cyfr dziesięciocyfrowych (0. ..9) i bitów (2 cyfry). Trzymaj je oddzielnie w swoim myśleniu, dla lepszego zrozumienia. – hyde

Odpowiedz

-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

W jaki sposób spełnia to wymaganie dla losowego 64-bitowego unsigned int? –

+0

Próbowałem twojego kodu i wydrukowałem 1000 wyników. Wyniki są podobne; 04951651604868241121, 00651604895168241121, 03943165433604438241, 00160434265465541121 ... więc sądzę, że nie możemy mieć tego, czego potrzebuję w tej metodzie. –

+0

masz na myśli, że nie chcesz zer wiodących? –

1

Iff masz wystarczająco dobre źródło losowych bajtów (jak, powiedzmy,/dev/random lub/dev/urandom na maszynie Linux), można po prostu zużywają 8 bajtów z tego źródła i złączyć je. Jeśli są niezależne i mają rozkład liniowy, jesteś ustawiony.

Jeśli tego nie zrobisz, MOŻESZ odejść, robiąc to samo, ale w twoim pseudolosowym generatorze prawdopodobnie pojawią się jakieś artefakty, które dają chwyt dla wszystkich rodzajów hi-jinx.

Przykład kodu zakładając mamy otwartą binarny 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; 
} 

Jeśli zastąpić „czytać losowych bajtów z urządzenia przypadkowości” z „get bajtów z wywołania funkcji”, wszystko co musisz zrobić, to dostosować przesunięcia w metodzie # 2.

Znacznie częściej uzyskuje się "liczbę z wieloma cyframi" niż jedną z "małą liczbą cyfr" (wszystkich liczb od 0 do 2 ** 64, około 95% ma 19 lub więcej cyfr dziesiętnych tak naprawdę to, co będzie głównie dostać

+0

Co to jest "hi-jinx"? =) –

-2

Jeśli masz 32 lub 16-bitową wartość losową. - generować 2 lub 4 randoms i połączyć je do jednej 64-bitowej z << i |

+0

rzecz jest losowa wartość PO ma tylko 30 bitów –

3

chodzi ". Zatem wyniki zawsze mają 18 cyfr lub 20 cyfr. "

Zobacz @Thomas comment. Jeśli generujesz liczbę losową s wystarczająco długo, kod utworzy takie jak 5, 11 i 33387. Jeśli kod generuje 1 000 000 000 numerów/sekundę, może to potrwać rok jako bardzo małe liczby. < 100 000 jest tak rzadkich spośród wszystkich 64-bitowych liczb.


proste zwroty losowe. Uproszczony sposób pociąga 1 bit w czasie

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

Zakładając RAND_MAX pewna siła 2 - 1, jak w przypadku OP 1073741823 == 0x3FFFFFFF, ma tę zaletę, że 30 bitów są generowane za każdym razem. Poniższy kod zadzwoni rand() 3 razy - odrobinę marnotrawstwa. Zamiast tego przesunięte bity można zapisać dla następnej losowej liczby, ale to powoduje inne problemy. Pozostaw to na inny dzień.

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; 
} 

przenośny sposób unika się licznik pętli 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; 
} 

Efekty autokorelacji komentuje here są spowodowane słabą rand(). C nie określa konkretnej metody generowania liczb losowych. Powyższe dotyczy rand() jest dobre. Jeśli rand() jest podrzędny, wówczas kod powinien używać innych generatorów do tego i rand().

+2

Ta odpowiedź jest jak wiersz. Mam na myśli wyjaśnienia. Zupełnie zrozumiałem wszystko, co wiąże się z moim pytaniem. –

0

Próbowałem tego kodu here i wygląda na to, że działa dobrze.

#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; 
} 

wpadłem kilka iteracji i otrzymuję następujące wyjścia:

wartość 1869044101095834648
wartość 2104046041914393000

wartość 1587782446298476296
wartość 604955295827516250
wartość 41152208336759610
wartość 57792837533816000

0

Jeśli nie przeszkadza powtarzającą pseudolosowej sekwencji (hej, do 64 bitów nie jesteś odnotuje powtórzenia w swoim życiu;) i można sobie z jednej wartość mniejsza niż żądany zakres (0 nie nastąpi), LCG lub MCG jest zdumiewająco prostym rozwiązaniem. Wikipedia: Linear congruential generator Przejdź do here, aby wygenerować kilka liczb pierwszych i użyj jednego dla modułu, a drugiego dla mnożnika poniżej. (Uwaga: ta sekwencja będzie odgadnięcia, a więc to nie jest bezpieczne)

#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()); 
} 
Powiązane problemy