C語言所產生的隨機亂數為均勻(Uniform)亂數,假如我們想要產生常態(Normal)亂數怎麼辦呢?我們先來看WiKi的Normal Distribution。
The red line is the standard normal distribution

- Gaussian function: where parameter μ is the mean (location of the peak) and σ 2 is the variance (the measure of the width of the distribution). The distribution with μ = 0 and σ 2 = 1 is called the standard normal.
接著看到8 Generating values from normal distribution這個欄位:
X = sqrt( -2 ln(U) ) * cos(2 * PI * V)
Y = sqrt( -2 ln(U) ) * sin(2 * PI * V)
若想推廣到期望值和標準差可控制的狀況:
X‘ = sqrt( -2 ln(U) ) * cos(2 * PI * V) * std + mean
Y‘ = sqrt( -2 ln(U) ) * sin(2 * PI * V) * std + mean
Z是標準常態分佈~Gaussian(0, 1),而Z’是~Gaussian(mean, std^2),則Z’轉換為Z的公式為:
Z = (Z’ – mean) / std
Z’ = Z * std + mean
接下來就是程式時間囉:
/**
Theme: Normal Distribution
Date: 100/04/07
compiler: Dev C++ 4.9.9.2
Author: ShengWen
Blog: https://cg2010studio.wordpress.com/
*/
#include <iostream>
#include <cmath>
#define NR_SAMPLES 10
using namespace std;
int main(){
srand(time(NULL));//隨機亂數種子
double mean = 0;//期望值
double std = 1;//標準差
double u, v;//uniform distribution
double x, y;//normal distribution
for(int i=0; i<NR_SAMPLES; i++){
u = rand() / (double)RAND_MAX;//RAND_MAX=32767
v = rand() / (double)RAND_MAX;
x = sqrt(-2 * log(u)) * cos(2 * M_PI * v) * std + mean;//M_PI=3.14159
y = sqrt(-2 * log(u)) * sin(2 * M_PI * v) * std + mean;
cout<<x<<endl;
cout<<y<<endl;
}
system("pause");
return EXIT_SUCCESS;
}
輸出結果,產生[-6,6]的常態亂數:
0.660637
1.4813
-1.03885
2.4052
-0.693071
-0.629039
-0.336342
0.535143
-0.473172
1.13721
-0.693372
-0.543814
-0.901281
1.99972
0.887202
-0.277707
0.463112
-0.826414
0.258715
0.424439
請按任意鍵繼續 . . .
參考:用C產生常態分佈的數值。
Comments on: "[C++] 均勻亂數轉常態亂數 (Uniform to Normal)" (3)
[…] [C++] 均勻亂數轉常態亂數 (Uniform to Normal) […]
讚讚
請問如果當u=0時 這樣log(u)不就不存在了嗎? 此時亂數該如何產生
讚讚
嗯……好問題,我的解決方法是限制u不要等於0,若u真的要等於0,就讓log(u)也等於0。
但若為了科學的正確性,你可能要再查些資料。
讚讚