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

わんくま同盟

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

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


(過去ログ 18 を表示中)
■7096 / )  Re[15]: Long型の乱数を生成する自作クラスをつくりたい
□投稿者/ ぼのぼの (81回)-(2007/08/30(Thu) 11:34:49)
No7076 (れい さん) に返信
>>ul = umin + ul Mod (umax - umin + 1UL)
> 
> こうやって余りを計算してしまうと、
> どうしても偏りが出てしまいます。
> 
> umin = 0
> umax = ULong.MaxValue*2/3
> 
> となるとULong.MaxValue/3を超える数と超えない数の出現確率は
> 倍違うことになります。

えーと、この状況をわかりやすく図示すると。

min               max
0|--------+--------|--------|MAX

こういう状態のときは、剰余分は折り返されるイメージだから、

min               max
0|--------+--------|         MAX
  --------|
     ↑ここが2倍になってしまう

ということですね。

max-minがもうちょっと小さい場合でも

min max
0|---|---|---|---|---|---|--|MAX

端数分を折り返すと
0|---|---|---|---|---|---|   MAX
  --|
  ↑ここだけ2倍になる

min    max
0|------|------+------+------|MAX

こういう風にぴったり分割される場合はOK。


ということは、乱数が折り返しのときだけ
サイコロを振りなおすようにする、とすると…

'乱数を範囲内に変換
If umin <> UInt64.MinValue OrElse umax <> UInt64.MaxValue Then
    Dim divVal As UInt64 = umax - umin + 1UL
    While UInt64.MaxValue Mod (divVal) <> (umax - umin) _
    AndAlso Convert.ToUInt64(ul / divVal) = Convert.ToUInt64(UInt64.MaxValue / divVal)
        _Random.NextBytes(b)
        ul = BitConverter.ToUInt64(b, 0)
    End While
    ul = umin + ul Mod divVal
End If

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

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

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

返信 編集キー/


管理者用

- Child Tree -