
W poprzednim odcinku otrzymaliśmy całkiem przyzwoity generator liczb o rozkładzie równomiernym. Teraz uzupełnimy naszą klasę o metodę do pobierania wartości z rozkładu normalnego, zwanego też rozkładem Gaussa.
Zastosowanym algorytmem do generowania liczb losowych z rozkładu normalnego jest implementacja metody Kindermana i Monahana, zwanej ROU (ratio-of-uniforms method). Szczegóły tej metody można znaleźć w książce Wieczorkowskiego i Zielińskiego[2]
Moja implementacja w języku C++ zawarta jest w metodzie getFromNormalDistribution()
klasy RandomNumberGenerator
i wygląda następująco:
double RandomNumberGenerator::getFromNormalDistribution() { bool ok = false; double limit = sqrt(2/2.718281828); double X; do { // generuj U o rozkładzie równomiernym U(0,1) double U = getFromUniformDistribution(); // generuj V o rozkładzie równomiernym // U(-sqrt(2/e),sqrt(2/e)) double V = 2 * limit * getFromUniformDistribution() - limit; X = V / U; if (X*X <= 2*(3-U*(4+U))) { ok = true; } else if (X*X <= 2/U - 2*U) { if (X*X <= -4*log(U)) { ok = true; } } } while (!ok); return X; }
Jak widać używa on metody getFromUniformDistribution()
zdefiniowanej wcześniej a zwracającej nam dwie liczby z rozkładu równomiernego, jedna z przedziału (0,1) a druga z (-sqrt(2/e), sqrt(2/e)).