2015-05-31 13 views
5

Napisałem mały kod, aby upewnić się, że mogę uzyskać losowe liczby z naprawdę szerokiego zakresu, np. [0, 10^36), ponieważ zamierzam wykorzystać te szerokie zakresy później.Losowe liczby generowane przy użyciu jednolitej rzeczywistej dystrybucji w C++ nie są tak naprawdę rozproszone.

Mój kod wygląda następująco:

#include <iostream> 
#include <cmath> 
#include <random> 
#include <chrono> 

int main() 
{ unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); 
    double expo = pow(10,36); 
    std::uniform_real_distribution<double> dist(0,expo); 
    std::mt19937_64 rng(seed); 
    for (int i=0; i<10; i++) 
     std::cout << dist(rng) << std::endl; 
    return 0; 
} 

I Oto przykład wyjścia:

6.75507e+035 
4.01129e+035 
6.85525e+035 
8.85896e+035 
3.1455e+035 
3.04962e+035 
5.48817e+035 
3.54502e+035 
2.24337e+035 
2.23367e+035 

Jak widać, liczby losowe są naprawdę blisko górnego punktu końcowego danego przedziału. Próbowałem wielokrotnie uruchamiać program, zwiększałem również 10 liczb do 100, ale losowe liczby zawsze były zbliżone do górnego punktu końcowego przedziału (z wykładnikiem 35, a czasami 34).

Ponieważ używam std::uniform_real_distribution, spodziewam się mieć również, a czasami numery w zakresie [0, 1000] na przykład. Nie uważam tego za jednolitą dystrybucję. To jest dla mnie ważne, że liczba losowa nie jest blisko tylko do górnego punktu końcowego, ponieważ mam zamiar użyć liczby losowej później w if-oświadczenie:

if (random_number == 0) 
    //do some operations 

a górny punkt końcowy zostanie faktycznie użyty jako stawka, w której coś się pojawia. Wydaje się jednak, że liczba losowa nie ma czasami szansy na zero.

Nie wiem, dlaczego tak się dzieje i naprawdę doceniam każdy pomysł lub pomoc.

(Eclipse 4.4.1, Windows 7)

+0

Jeśli 'std :: uniform_real_distribution dist (0,1000) (rng)' zwraca (dokładnie) 1000.0, to jest błąd w implementacji i należy go zgłosić, ponieważ interwał ma być w połowie zamknięty : '[0, 1000)'. Zwrot 0 jest możliwy, ale prawdopodobieństwo jest mikroskopijne, prawdopodobnie mniejsze niż jeden w kwadrylionie. – rici

Odpowiedz

12

Jak widać, liczby losowe są bardzo blisko górnej końcowego danego przedziału.

Nie, nie są. Ten jeden, na przykład:

2.23367e+035 

Należy zauważyć, że w zakresie [0, 1e36], sub-range [1e35, 1e36] jest 9 razy większa od podzakresu [0, 1e35], więc o równomiernym rozkładzie, można oczekiwać, aby zobaczyć te numery 9 razy częściej. Od czasu do czasu zobaczysz liczby o wykładniku 34, ale wykładniki, które są niższe, są niezwykle rzadkie.

+2

Zgadza się! Nie myślałem o tym ... Więc to oznacza, że ​​jest to w rzeczywistości rozkład jednorodny. Dziękuję Benjamin! – azish

4

Odpowiedź Benjamina Lindleya jest dobra. Chciałbym dodać, że możesz szukać innego rodzaju dystrybucji zamiast jednolitej dystrybucji.Można napisać to tak:

#include <iostream> 
#include <cmath> 
#include <random> 
#include <chrono> 

int main() 
{ 
    unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); 
    std::uniform_real_distribution<double> dist(0, 36); 
    std::mt19937_64 rng(seed); 
    for (int i = 0; i < 20; i++) 
    { 
     std::cout << pow(10, dist(rng)) << std::endl; 
    } 
    return 0; 
} 

Program ten daje mi następujący wynik:

7.26972e+027 
5.97e+010 
3.50003e+034 
3.42446e+021 
2.93422e+035 
111.724 
2.73858e+019 
55641.4 
4.18253e+019 
7.47441e+007 
9.2706 
7.45588e+009 
3.26219e+007 
5.6794e+027 
4.67289e+026 
4.24672e+014 
3.97334e+010 
14.7511 
2.65037e+022 
85279.3 
+0

To jest dobry pomysł, ale jak już wspomniałem wcześniej, powinienem użyć górnego punktu końcowego później jako stawki, więc nie mogę tego zmienić. :/ Ale i tak dzięki! – azish

+0

Nie zmieniłem górnego punktu końcowego, który wciąż jest 10^36. Przypadkowo zmieniłem niższy punkt końcowy z 0 na 1. –

+0

Masz rację. Ale to, co mam na myśli ze wskaźnika w moim kodzie, to na przykład dla random_number = 1, prawdopodobieństwo, z jakim ta losowa liczba jest generowana, wynosi 1/10^36. Takie prawdopodobieństwo w twoim kodzie wynosi 1/35 * 1/10^dist (rng). Ponieważ właściwie to prawdopodobieństwo jest moim celem, a nie losowymi liczbami, nie mogłem użyć twojego kodu, chociaż uważam, że był to interesujący pomysł, gdybym nie miał ograniczenia rozważania prawdopodobieństwa. – azish

1

Jeśli spojrzeć na matematyce sytuacji, jest o wiele bardziej prawdopodobne, że liczba ta będzie mieć wykładnik 10^35 z powodu możliwych liczb w każdym zakresie:

  • Istnieje 9*10^34 różne numery w zakresie [1*10^35,1*10^36)
  • Istnieje 9*10^33 różne numery w zakresie [1*10^34,1*10^35)
  • Istnieje 1000 różne numery w zakresie [1,1000]

Więc widać, że jest 10 razy bardziej narażone na szereg mieć wykładnik 10^35 niż 10^34 i jest bardziej prawdopodobne, że liczba ma wykładnik 10^35 niż w zakresie [1,1000].

+0

Tak, właśnie o to mi chodziło! Dzięki Brendon! – azish

Powiązane problemy