FrontPage

正規乱数(ガウス乱数)を生成する

正規乱数とは、生成結果が正規分布に従うような乱数である。(対義語は一様乱数)
その生成の方法は数種類あるが、今回はボックス-ミューラー法(Box-Muller transform)をC++言語で表現する。
ボックス-ミューラー法の最大の特長は、オーバーヘッドの大きいrand()関数の呼出し回数が少ないことである。
従って、12個の一様乱数の平均値をもって近似させる方法に比べて高速である場合が多い。

C++言語による正規乱数の生成

gaussianRand.cpp

#include        <stdio.h>                                       //  標準入出力                                    //
#include        <stdlib.h>                                      //  標準ライブラリ                                //
#include        <math.h>                                        //  数理ライブラリ                                //
#include        <time.h>                                        //  時間計測のため                                //
                                                                //                                                //
const double    PI =        3.14159265358979;                   //  円周率                                        //
                                                                //                                                //
double gaussianRand( double vd_stdev, double vd_meanValue );    //  正規乱数発生関数                              //
                                                                //                                                //
/* Rand Test **************************************************//*  正規乱数発生ドライバ                          */
int main( void )                                                //                                                //
{                                                               //                                                //
    clock_t start, end;                                         //  時間計測用                                    //
    unsigned int cnt;                                           //  ループカウンタ                                //
    double randNum = 0.0;                                       //  乱数取得用                                    //
                                                                //                                                //
    start = clock();                                            //  時間計測スタート                              //
    srand( (unsigned int)time( NULL ) );                        //  乱数の種を設定                                //
                                                                //                                                //
    for( ; ; )                                                  //  無限ループ                                    //
    {                                                           //                                                //
        for( cnt = 0; cnt < 10; cnt++ )                         //  何回か発生させて表示する                      //
        {                                                       //                                                //
            randNum = gaussianRand( 1.0, 0.0 );                 //  正規乱数の取得                                //
            printf( "%02d: %f\n", cnt, randNum );               //  画面表示                                      //
        }                                                       //                                                //
                                                                //                                                //
        end = clock();                                          //  時間計測ストップ                              //
        printf( "%d msかかりました\n", end-start );             //  画面表示                                      //
                                                                //                                                //
        break;                                                  //  処理終了                                      //
    }                                                           //                                                //
                                                                //                                                //
    return( 0 );                                                //  処理終了                                      //
}                                                               //                                                //
//*Rand Test **************************************************//*  正規乱数発生ドライバ                          */
/* Gaussian Rand **********************************************//*  正規乱数発生処理                              */
double gaussianRand( double vd_stdev,                           //  引数01: 標準偏差                              //
                     double vd_meanValue )                      //  引数02: 平均値                                //
{                                                               //                                                //
    double rtnNum = 0.0;                                        //  リターン用                                    //
    static int sw = 0;                                          //  リターンの切替用                              //
                                                                //                                                //
    double randNum_1;                                           //  乱数その1                                    //
    double randNum_2;                                           //  乱数その2                                    //
    double whiteGaussianNoise_1;                                //  ホワイトガウスノイズその1                    //
    static double whiteGaussianNoise_2;                         //  ホワイトガウスノイズその2                    //
                                                                //                                                //
    if( sw == 0 )                                               //  スイッチが0か                                 //
    {                                                           //  スイッチが0なら                               //
        sw = 1;                                                 //  スイッチ切替え                                //
        randNum_1 = ((double)rand()) / RAND_MAX;                //  (0,9]の乱数取得                               //
        randNum_2 = ((double)rand()) / RAND_MAX;                //  (0,9]の乱数取得                               //
                                                                //                                                //
        whiteGaussianNoise_1 = vd_stdev * sqrt( -2.0 * log( randNum_1 ) ) *    //  正規乱数1                     //
                                   cos( 2.0 * PI * randNum_2 ) + vd_meanValue; //                                 //
        whiteGaussianNoise_2 = vd_stdev * sqrt( -2.0 * log( randNum_1 ) ) *    //  正規乱数2                     //
                                   sin( 2.0 * PI * randNum_2 ) + vd_meanValue; //                                 //
                                                                //                                                //
        rtnNum = whiteGaussianNoise_1;                          //  リターンに正規乱数1を設定                    //
    }                                                           //                                                //
    else                                                        //  スイッチが0以外の場合                         //
    {                                                           //                                                //
        sw = 0;                                                 //  スイッチ切替え                                //
                                                                //                                                //
        rtnNum = whiteGaussianNoise_2;                          //  リターンに正規乱数2を設定                    //
    }                                                           //                                                //
                                                                //                                                //
    return( rtnNum );                                           //  生成した正規乱数を返して終了                  //
}                                                               //                                                //
//*Gaussian Rand **********************************************//*  正規乱数発生処理                              */

表示結果:

>gaussianRand.exe
00: 0.977696
01: 1.646302
02: 2.349632
03: 0.509217
04: 1.080539
05: -0.208485
06: -1.016973
07: -0.839387
08: 0.177065
09: 0.619993
8 msかかりました

修正履歴


課題

  • 備考

これ、1個目と2個目の平均と標準偏差が違う場合に問題がある。 標準正規乱数でとっておいて2を出力する際に平均を足して標準偏差をかける方がいい。

参考ページ

Wikipedia


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2011-01-26 (水) 14:02:52 (3285d)