2009年06月15日

乱数

こんにちは、イワムーですわーい(嬉しい顔)

今日はゲームで使用される乱数について書きたいと思いますパンチ

ゲーム制作において、敵の行動の選択、アイテムの出現確率など、乱数を使用する場面は多いと思います。

現実世界でのサイの目の出現確率などとは違い、コンピューターで扱う乱数は、疑似乱数です。

つまり、乱数のようにみえるけれど、実際は論理式があり次に発生する数が求められますペン

この疑似乱数であるということに、注意が必要な場合がありますexclamation×2

C言語標準ライブラリにはrand()という関数があります。
この関数を用いて乱数を発生させている方も多いのではないでしょうか?

この関数の内部は線形合同法というアルゴリズムが用いられていますひらめき
このアルゴリズムですが、下位ビットの精度が悪いことで有名ですバッド(下向き矢印)
最下位ビットの周期は2で、0と1が交互に現れてしまいますたらーっ(汗)
その後上位ビットになるつれ、周期が4,8,16、・・・と上がっていきます。

if (rand() & 1) {
  if (rand() & 1) {
    printf("A");
  } else {
    printf("B");
  }
} else {
  if (rand() & 1) {
    printf("C");
  } else {
    printf("D");
  }
}

↑このプログラムではBとCしか出力されず、AとDは一切出力されません。
(※処理系によりrand()の実装が異なるため、結果が異なる場合があります)

さらに、線形合同法の問題点として、ある乱数が得られたら次に得られる乱数が限られることが挙げられますexclamation

例えば、2次元のベクトルの各要素を rand() で求めるような場合、得られる組み合わせが限られてしまうことになります。

(※処理系によっては、上位16ビットを右シフトし、下位の15ビットを返すものもあり、上記の限りではありませんが、乱数の返す値が0〜32767となり、精度が足りなくなる問題があります。単に精度の問題なのであれば rand()*rand() とするなどで対処可能な場合もあります)


では精度が高く、周期の長い乱数を得るにはどうすれば良いのでしょうかexclamation&question

ここはメルセンヌツイスターの出番ですよね手(グー)

623次均等分布かつ、10進数で6000桁以上の長周期性と、自然乱数近似を得たいのであれば、真っ先に挙げられるソリューションではないかと思います位置情報
(内部のワーキングメモリが32bit版で2496バイト必要になるので、使用の際は注意してください)

さて、rand()の使用上の注意や、メルセンヌツイスターの簡単な紹介をしてきましたが、ゲームで乱数を使う場合は、その用途に応じて適切なアルゴリズムを選択することが最も重要だと思いますわーい(嬉しい顔)

処理速度やメモリが切迫していて、精度をそこまで求めない場合は、rand() も十分候補に挙がるでしょうし、単純なタイマーでも代替可能かもしれません。

また、乱数の偏りが一概に悪いとは言いきれないときもあるのではと思います。
それがそのゲームの良い味になっていたりするんですよねわーい(嬉しい顔)

ゲームで乱数を使用する時は、意識してみてください手(パー)

posted by 管理人 at 16:55 | Comment(0) | プログラミング
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
※ブログオーナーが承認したコメントのみ表示されます。