COMMON LISP JP > Archives > 2011/10/16

2011/10/16 19:26:03 UTCmasatoi
#
失礼します。randomの挙動について質問があります。
#
例えば(0.25 0.25 0.25 0.25)のような、全体で1となる確率分布のリストを引数にとって、その確率分布に従う乱数を発生させる関数を書きたいのですが、
#
(defun sampler (prob-list)
  (position-if (lambda (x)
		 (< (random 1.0) x)) (cumulo-prob-list prob-list)))
#
cumulo-prob-list prob-listは(0.25 0.25 0.25 0.25)を(0.25 0.5 0.75 1)のように要素の値を累積させていく関数です。
2011/10/16 19:37:17 UTCmasatoi
#
(sampler '(0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1))を1万回実行して結果のヒストグラムをつくってみたのですが、 http://twitpic.com/71egvt のように一様分布になりません。
2011/10/16 19:40:41 UTCshiro
#
私もそのようなコードを最初に思いついてACLで今実行してみたら、確かに一様にならないですね。あれー何か見落としてるかなあ。
2011/10/16 19:43:15 UTCmasatoi
#
randomの問題かと思ってメルセンヌツイスタ(mt19937)でもやってみたのですが、結果は同じでした。
2011/10/16 19:51:06 UTCshiro
#
あーわかった。position-ifで条件判断をする度にrandomを発生させてるからだ。
#
(defun sampler (prob-list)
  (let ((r (random 1.0)))
    (position-if (lambda (x) (< r x)) (cumulo-prob-list prob-list))))
#
でどうですか。
#
検査の度にrandomしちゃうと、例えば一回目のrandomが0.9で二回めが0.0だった時、それは最初の区分ではなく次の区分にカウントされちゃいます。
2011/10/16 19:54:51 UTCmasatoi
#
あーなるほど。これでうまくいきました。ありがとうございます!