Generator liczb pseudolosowych (cz.2) – rozkład normalny
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)).