正確なN面サイコロ
概要
6面のサイコロの一般的な実装例はrand() mod 6 + 1など単に余剰演算を使ったものが多いが、これには問題がある。 (RAND_MAX+1)は6で割り切れないので、(RAND_MAX+1) mod 6 だけ対応する面が出る確率が少しだけ増えてしまう。
同様に確からしいN面サイコロを振るには、(RAND_MAX + 1) mod N より小さい値が出たら振り直す必要がある。
ソースコード
namespace ExRandom.Discrete {
public class DiceRandom : Random{
readonly MT19937 mt;
readonly UInt32 sides, cut;
public DiceRandom(MT19937 mt, int sides = 6) {
if(mt == null) {
throw new ArgumentNullException();
}
if(sides < 1) {
throw new ArgumentException();
}
this.mt = mt;
this.sides = (UInt32)sides;
this.cut = (UInt32.MaxValue % this.sides + 1) % this.sides;
}
public override int Next() {
UInt32 r;
do {
r = mt.Next();
} while(r < cut);
return (int)(r % sides);
}
}
}
関連項目
メルセンヌ・ツイスタ
各種確率分布サンプリング基本クラス