Szybsza pseudolosowość

Szybsza pseudolosowość
P9
  • Rejestracja:około 14 lat
  • Ostatnio:ponad 11 lat
  • Postów:21
0

Witam.
Piszę w C++ pewien algorytm randomizowany, który w bardzo krótkich odstępach czasu potrzebuje nowych liczb pseudolosowych. I tutaj pojawia się problem - otóż funkcja

Kopiuj
rand()

przy tak krótkich odstępach czasu zwraca bardzo bliskie sobie wartości. Jak można zwiększyć ową pseudolosowość?

Gwoli ścisłości: dokładnie raz w main() wywołuję

Kopiuj
srand(time(NULL));

, więc błąd tutaj nie polega na tym, że robiłbym to za każdym razem przed losowaniem kolejnej liczby.

Być może ma znaczenie również to, że potrzebuję liczb z przedziału [0; 1), więc instrukcja losowania nowej liczby wygląda u mnie tak:

Kopiuj
x = double(rand()) / RAND_MAX;
Sopelek
to jest właśnie losowość... Może wypaść każda
ZJ
BTW ta instrukcja daje [0; 1]. Do [0; 1) powinna być rand()/(RAND_MAX + 1.0)
tubbs
czym się różni [0; 1] od [0; 1)? w tym pierwszym losujemy do 1 włącznie?
Sopelek
Tak. To są podstawy zapisu określającego zbiór...
hauleth
Moderator
  • Rejestracja:ponad 17 lat
  • Ostatnio:7 dni
0

Bo LCG jest dość cienki. Użyj MT lub innego dość mocnego i dającego lepszy szum.


msm
Administrator
  • Rejestracja:około 16 lat
  • Ostatnio:6 miesięcy
0

@up - LCG ma różne wady, ale zwracanie przy krótkich odstępach bardzo bliskie sobie wartości do nich nie należy.

@patry93 - Jesteś pewien że sranda używasz tylko raz? Jesteś pewien że problem leży w tym że rand zwraca bliskie sobie wartości? Jaki kompilator/środowisko i system?

Endrju
  • Rejestracja:około 22 lata
  • Ostatnio:prawie 2 lata
0

W C++ właśnie po to jest <random>. Zapoznaj się z tym: http://en.cppreference.com/w/cpp/numeric/random

Oczywiście jeszcze kompilator musi to obsługiwać.


"(...) otherwise, the behavior is undefined".
vpiotr
Zapomniałeś dodać - w C++11... nie każdy to ma lub używa
adf88
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 12 lat
1

Jedno jest pewne - w przypadku rand czas nie ma nic do gadania.

edytowany 4x, ostatnio: adf88
DA
  • Rejestracja:około 17 lat
  • Ostatnio:prawie 12 lat
0

jeżeli piszesz pod linuksem, to możesz czytać pseudolosowe dane z plików /dev/random i /dev/urandom


#define if(x) if(rand()%6 && (x)) u mad? <img src="http://e.deviantart.net/emoticons/t/trollface.png" alt="user image" />
Zobacz pozostałe 2 komentarze
ZJ
/dev/urandom też jest zrobiony dla zastosowań kryptograficznych, tylko o gorszej jakości, nie nadaje się do zastosowań długoterminowych, czyli np. klucze RSA (I tak pewnie nie da się tej sekwencji odróżnić od losowej z prawdopodobieństwem większym niż 2<sup>-80). Do innych zastosowań niekryptograficznych, szczególnie wymagających dużej ilości zmiennych losowych należy użyć generatorów, które są do tego stworzone (rand() przy 10</sup>10 losowań dawał wyraźnie różne wyniki symulacji niż MT, mimo to, że MT był 2 razy wolniejszy, to i tak było to tylko 15 % czasu wykonania programu).
ZJ
Wiki podaje, że FreeBSD używa tego samego algorytmu dla /dev/random i /dev/urandom, ze względu na to, że współczesne CSPRNG są wystarczająco bezpieczne.
Endrju
To trzeba szum z przetworników AD/DA karty dźwiękowej wykorzystywać! ;-) To powinno być dobre źródło - teoretycznie błąd kwantyzacji ma rozkład równomierny o wariancji q^2/12, gdzie q - wielkość kwantu. Np. tego nauczyła mnie polibuda! ;-)
Azarien
@Zjarek: spodziewałbym się że we FreeBSD narzut na /dev/random będzie znacznie mniejszy niż pod Linuksem, kwestia czy sam algorytm będzie szybszy.
Azarien
PS. zrobiłem test dd if=/dev/urandom bs=1 of=/dev/null count=10240000, wynik 11 sekund FreeBSD 9, 19 sekund Linux Mint 13 na tej samej maszynie.
MarekR22
Moderator C/C++
  • Rejestracja:ponad 17 lat
  • Ostatnio:minuta
1

Czas, tak jak pisze adf88, w przypadku generatorów liczb losowych nie ma znaczenia.
Jeśli masz problemy czasowe to znaczy, że "srand(time(NULL));" umieściłeś wewnątrz pętli.

Standardowy generator jest kiepski. Kolejne pary liczb wykazują pewną korelację, ale nie jest to korelacja na zasadzie, że liczby są sobie bliskie.
Przykładowo wypełniając jedynkami kwadratową szachownicę o rozmiarze RAND_MAX+1, w ten sposób, że nieskończona pętlą ustawia jedynkę dla współrzędnych (rand(), rand()), nigdy nie uzyskasz pełnego wypełnienia. W takim wypadku zobaczysz wzorek, jedynki będą się układać wzdłuż równoległych bliskich sobie prostych. Taka natura tego generatora pseudolosowego!
Z tego powodu ten generator nie jest najlepszy do poważnych obliczeń Monte Carlo, poszukaj alternatywnych generatorów liczb pseudolosowych (patrz na sugestię winerfresh).


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
0

Standardowy rand() jest słaby i chyba do tego wolny, bo używa dzielenia, a to jest dość kosztowna operacja.
Wystarczy mnożenie, dodawanie, xor, itp.

np. taki prosty generator spełnia wszystkie standardowe kryteria dla generatorów i będzie pewnie znacznie szybszy:

Kopiuj
uint xor128(void) {

  uint t = x ^ (x << 11);

  x = y; y = z; z = w;
  return w = w ^ (w >> 19) ^ (t ^ (t >> 8));

}

cztery zmienne statyczne: x,y,z,w, należy wcześniej ustawić.

adf88
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 12 lat
1

Do dziś pamiętam moje zdziwko kiedy do wykonania jakiegoś testu użyłam użyłem bibliotecznego rand. Jakoś sumowałem liczby losowe, po 256 sztuk czy podobnie, wszystkie wyniki były identyczne...

edytowany 1x, ostatnio: adf88
3
adf88 napisał(a):

Do dziś pamiętam moje zdziwko kiedy do wykonania jakiegoś testu użyłam bibliotecznego rand. Jakoś sumowałem liczby losowe, po 256 sztuk czy podobnie, wszystkie wyniki były identyczne...

Eeee?

msm
Ech, czepiacze :>
adf88
Niefortunna literówka

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.