C# と VB.NET の質問掲示板

わんくま同盟

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト


(過去ログ 18 を表示中)
■7110 / )  Re[16]: Long型の乱数を生成する自作クラスをつくりたい
□投稿者/ れい (88回)-(2007/08/30(Thu) 12:42:05)
No7096 (ぼのぼの さん) に返信
> ■No7076 (れい さん) に返信
> >>ul = umin + ul Mod (umax - umin + 1UL)
>>
>>こうやって余りを計算してしまうと、
>どうしても偏りが出てしまいます。
>
> ということは、乱数が折り返しのときだけ
> サイコロを振りなおすようにする、とすると…
>

考え方は正解です。

どんなに大きなビット数の乱数でも、どんなに精度がよい乱数でも、
乱数の範囲を変えるときはかならず同じ問題に遭遇します。
普通乱数の実装は2進数の整数で組まれていますから、
任意の範囲に対して「振り直し無し」の方法は理論上ありません。

忘れがちですが、DoubleからInt型を作り出すときも同様で、
情報が足りなくならないよう気をつける必要があります。

せっかくMT使ってるのに、範囲変更でmoduloとっただけの実装をたまにみますが、
猫に小判ですね。
乱数を使うような場合、かなりの確率で統計的なデータ処理を行いますが、
このミスは統計的に効いてきます。

> こうかな。う〜んあってるのかな?

コードは…変です。

> ループが最も多く発生するのはumax-uminがUInt64.MaxValueの半分より
> ちょびっとだけ大きい値の場合だけど、
> NextBytesの一様性がある程度のものならこの場合でもNextBytesを呼ぶ回数は約2倍。
> と期待されるので、そんなに激しい性能劣化は無いと思われまする。

乱数が範囲内にある確率をAとすると、乱数を生成する回数の期待値Sは
S = A + (1-A)*(S+1) = 1/A
なので、ワーストケースでの期待値は約2回です。

NextBytesは1バイト毎にサイコロ振ってますので、
トータルで期待値として16回サイコロを振ってることになります。

> もっといい方法があるのでしょうか…

コード的にはいろいろあるでしょうが、
考え方はこれが最良です。
返信 編集キー/


管理者用

- Child Tree -