■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 -