2011-11-14 9 views
6

Potrzebuję twojej pomocy i proszę dać mi radę. Od programowania perły wiem, że aby wygenerować losowy 30 bitową liczbę całkowitą powinniśmy napisać to tak:wygenerować losową 64-bitową liczbę całkowitą

RAND_MAX*rand()+rand() 

Ale co mogłem zrobić, aby nie generować 30, ale 64-bitowa liczba całkowita zamiast losowych? Myślę, że jest to bardzo nieefektywna metoda, jeśli pomnożę dwie 30-bitowe liczby całkowite, a następnie pomnożę ponownie 4-bitową liczbę całkowitą, więc jakiej metody powinienem użyć? Używam teraz popcount_1 innej metody dla 64-bitowej i chciałbym przetestować ją na losowych liczbach całkowitych (ja również mierzę czas, który każdy z nich wykonuje, aby wykonać zadanie)

+0

możesz również przesunąć i dodać je .. – duedl0r

Odpowiedz

3

To może być rozwiązanie, bez mnożenia:

r30 = RAND_MAX*rand()+rand() 
s30 = RAND_MAX*rand()+rand() 
t4 = rand() & 0xf 

res = (r30 << 34) + (s30 << 4) + t4 
+1

Zakłada się, że "RAND_MAX" to 1 << 15. Jeśli założysz to, dlaczego nie: 'rand() + rand() << 15 + rand() << 30 + rand() << 45 + (rand() i 0xf) << 60'? Bez multiplikacji. – MSalters

+1

Dlaczego po prostu nie wykonuj czegoś takiego jak 'return ((unsigned long long) rand() << 48) | ((unsigned long long) rand() << 32) | ((unsigned long long) rand() << 16) | ((unsigned long long) rand() i 0xffff); '? Tutaj nie masz żadnych multiplikacji, tylko zmiany. –

+0

Chociaż tak, można wygenerować 64 bity Wydawałoby się, że rozdzielczość wygenerowanej liczby losowej nie może być większa niż liczba losowa. – Cris

2

Losowy 64-bitowy int jest w zasadzie 64 losowe bity interpretowane jako int.

Wypełnij tablicę bajtów o długości 8 bajtami losowymi (see here for how) i zinterpretuj je jako int (see here for how).

+3

Mam podejrzenie, że z większością implementacji 'rand() 'ty * nie otrzymasz * szczególnie jednorodnej dystrybucji dzięki temu. – Flexo

3

Jeśli opcja jest boost, można użyć boost random.

+0

czy jesteś pewien, że może wygenerować 64-bitowy? Twój link stwierdza otherweise: "mt19937 tworzy liczby całkowite z zakresu [0, 2^32-1]." – duedl0r

+0

Spójrz na różne generatory (http://www.boost.org/doc/libs/1_47_0/doc/html/boost_random/reference.html#boost_random.reference.generators), na przykład w 'ranlux64_3'. –

+1

@ duedl0r Jeśli generuje on dobrą losową wartość w całym przedziale '[0, 2^32-1]', to powinno być dość trywialnie połączyć dwa połączenia, aby wygenerować dobrą 64-bitową losową wartość. (Dla wystarczająco luźnej definicji "dobra", oczywiście podstawowy generator nadal potrzebuje okresu 2^64 lub więcej, albo będzie wiele wartości, które nigdy nie zostaną wygenerowane.) –

7

Po pierwsze, mam wątpliwości co do rozwiązania publikowanych na 30 bitowym całkowitej. RAND_MAX samo w sobie może być wartością 31-bitową, a RAND_MAX * rand() + rand() prawdopodobnie przepełni się, tworząc niezdefiniowane zachowanie (aw praktyce wartości ujemne).

Jeśli potrzebujesz wartość większą niż gwarantowanego minimum RAND_MAX lub o to chodzi, że nic nie jest znacząco mniejszy niż RAND_MAX, jedynym rozwiązaniem będzie wykorzystanie kolejnych połączeń do rand() i połączyć wartości, ale musisz to zrobić ostrożnie, a następnie sprawdź poprawność wyników. (. Większość implementacje rand() użytku liniowych przystających generatorów, które jednocześnie wystarczające dla niektórych zadań, nie są szczególnie dobre w tym przypadku) W każdym razie, coś jak:

unsigned 
rand256() 
{ 
    static unsigned const limit = RAND_MAX - RAND_MAX % 256; 
    unsigned result = rand(); 
    while (result >= limit) { 
     result = rand(); 
    } 
    return result % 256; 
} 

unsigned long long 
rand64bits() 
{ 
    unsigned long long results = 0ULL; 
    for (int count = 8; count > 0; -- count) { 
     results = 256U * results + rand256(); 
    } 
    return results; 
} 

(Kod w rand256 ma na celu wyeliminowanie skądinąd nieuniknione stronniczość uzyskać podczas mapowania RAND_MAX wartości do 256 wartości)

+0

Jak kontrolować precyzję w tym kodzie. Powiedzmy, że chcę wygenerować 61-bitowe liczby losowe zamiast 64-bitowych. Myślę, że jeśli zacznę liczyć od 7 zamiast 8, otrzymam 56-bitową liczbę losową. Czy mam rację? – arunmoezhi

+2

@arunmoezhi Jeśli możesz wygenerować 64 losowe bity, możesz wygenerować 61, generując 64, i wyrzucając 3; na przykład przez maskowanie trzech pierwszych bitów. –

+0

ma sens. Dzięki. Twoje rozwiązanie wygląda ładnie. Ale byłoby lepiej, gdybyś mógł dodać do niego kilka wyjaśnień. Zajęło mi trochę czasu, aby zrozumieć, co robisz. – arunmoezhi

1

Ogólny rozwiązanie.

template <unsigned long long I> struct log2 { 
    static const int result = 1 + log2<I/2>::result; 
}; 
template <> struct log2<1> { 
    static const int result = 0; 
}; 

template <typename UINT> UINT genrand() { 
    UINT result = 0; 
    int bits = std::numeric_limits<UINT>::digits; 
    int rand_bits = log2<RAND_MAX>::result; 
    while (bits > 0) { 
    int r = rand(); 
    while (r >= (1<<rand_bits)) r = rand(); // Retry if too big. 
    result <<= rand_bits; 
    result += r; 
    bits -= rand_bits; 
    } 
    return result; 
} 

Zastosowanie: unsigned long long R = genrand<unsigned long long>();.

Licznik bits śledzi liczbę bitów, które są jeszcze potrzebne.

0

'Zwraca całkowitą pseudolosową wartość od 0 do RAND_MAX (w tym 0 i RAND_MAX).' - http://en.cppreference.com/w/cpp/numeric/random/rand

Powinieneś użyć RAND_MAX + 1 (to jak generowanie cyfry po cyfrze, a następnie konwertowanie jej do bazy 10) zamiast RAND_MAX. W ten sposób możesz generować liczby z jedną, dwiema, trzema itd. Cyframi w bazie RAND_MAX + 1 (prawdopodobnie z wiodącymi zerami) i konwertować je do bazy 10 i uzyskać dowolnie duże liczby.

Wszystko, co uzyskasz powyżej MAX_VALUE, może zostać odrzucone, a wciąż masz 1/(MAX_VALUE + 1) prawdopodobieństwo otrzymania każdego numeru.

Należy pamiętać, że ta metoda może chwilę potrwać, zwłaszcza jeśli żądana wartość MAX_VALUE jest dużo mniejsza niż maksymalna wartość, którą można uzyskać przed odrzuceniem liczb, które nie są pożądane, jako oczekiwaną liczbę kroków do uzyskania losowego liczba w [0, MAX_VALUE] z tym algorytmem wynosi: (MAX_OBTAINABLE_VALUE + 1)/(MAX_VALUE + 1)

Powiązane problemy