mk-mode BLOG

このブログは自作の自宅サーバに構築した Debian GNU/Linux で運用しています。
PC・サーバ構築等の話題を中心に公開しております。(クローンサイト: GitHub Pages

ブログ開設日2009-01-05
サーバ連続稼働時間
Reading...
Page View 合計
Reading...
今日
Reading...
昨日
Reading...

Ruby - 正規乱数(ボックス=ミューラー法)!

[ プログラミング, 数学 ] [ Ruby ]

こんばんは。

先日は、正規乱数をボックス=ミューラー法で生成して正規分布を検証する C++ によるアルゴリズムを紹介しました。

今日は、同じアルゴリズムを Ruby で実現してみました。 アルゴリズムについては、上記リンクの記事を参照してください。

実際、ほとんど同じです。

以下、Ruby によるサンプルスクリプトです。

記録

0. 前提条件

  • Cygwin 1.7.15
  • Ruby 1.9.3-p194

1. Ruby スクリプト作成

今回作成した Ruby ソースは以下の通りです。

【 ファイル名: rndnum_box_muller.rb 】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#*********************************************
# ボックス=ミューラー法法による正規乱数生成
#*********************************************
class RndnumBoxMuller
  # 各種定数
  M  = 10            # 平均
  S  = 2.5           # 標準偏差
  N  = 10000         # 発生させる乱数の個数
  PI = 3.1415926535  # 円周率
  SCALE = N / 100.0  # ヒストグラム用スケール

  # 計算クラス
  class Calc
    # コンストラクタ
    def initialize
      # 件数格納用配列初期化
      @hist = Array.new( M * 5, 0 )
    end

    # 正規乱数生成
    def generate_rndnum
      # N 回乱数生成処理を繰り返す
      0.upto( N - 1 ) do |i|
        # 整数乱数を2個生成
        res = rnd

        # 整数乱数をカウント
        @hist[res[0]] += 1
        @hist[res[1]] += 1
      end
    end

    # 整数乱数
    def rnd
      # 一様乱数
      # ( (0,1] の実数乱数 )
      r_1 = rand
      r_2 = rand

      # 正規乱数計算
      x = S * Math.sqrt(-2 * Math.log(r_1)) * Math.cos(2 * PI * r_2) + M
      y = S * Math.sqrt(-2 * Math.log(r_1)) * Math.sin(2 * PI * r_2) + M

      # 2個の正規乱数を整数化して配列でリターン
      return [ x.to_i, y.to_i ]
    end

    # 結果表示
    def display
      # 0 ~ M * 2 を表示
      0.upto( M * 2 ) do |i|
        # 件数表示
        printf("%3d:%4d | ", i, @hist[i])

        # ヒストグラム表示
        1.upto( @hist[i] / SCALE ) { |j| print "*" }
        puts
      end
    end
  end

  # メイン処理
  begin
    # 計算クラスインスタンス化
    obj_calc = Calc.new

    # 正規乱数生成
    obj_calc.generate_rndnum

    # 結果表示
    obj_calc.display
  rescue => e
    # エラーメッセージ
    puts "[例外発生] #{e}"
  end
end

2. 実行

実際に実行して検証してみる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ ruby rndnum_box_muller.rb
  0:   2 |
  1:  13 |
  2:  48 |
  3: 113 | *
  4: 298 | **
  5: 609 | ******
  6:1178 | ***********
  7:1954 | *******************
  8:2701 | ***************************
  9:3205 | ********************************
 10:3032 | ******************************
 11:2614 | **************************
 12:1892 | ******************
 13:1167 | ***********
 14: 669 | ******
 15: 327 | ***
 16: 127 | *
 17:  36 |
 18:  11 |
 19:   2 |
 20:   1 |

4. 判定

出力されたヒストグラムを確認してみると、綺麗な山になっているので正規乱数が正規分布になっていると言えるでしょう。


乱数生成回数をもっと増やしたり、乱数生成時の定数を変更してみたりすると、もっと一様になるのではないでしょうか?

以上。

Comments