3

モンテカルロ ヒットまたはミス シミュレーションを使用するランダマイザーを作成しようとしています。

ID と確率値を表す Key-Value ペアがあります。

ID - Value
2  - 0.37
1 - 0.35
4 - 0.14
3 - 0.12

これらの値をすべて追加すると、合計は 1.0 になります。

これらの値は、「ホイール」上の「スライス」の総面積として想像できます (例: ID 2 はホイールの 37% を占め、ID 3 はホイールの 12% しか占有しません)。「範囲」に変換すると、次のようになります。

ID - Value - Range
2  - 0.37 - 0 to 37
1 - 0.35 - 37 to 72
4 - 0.14 - 72 to 86
3 - 0.12- 86 to 100

現在、Random.NextDouble() を使用して、0.0 から 1.0 の間のランダム値を生成しています。そのランダムな値は、ホイールの「スピン」と見なされます。たとえば、ランダマイザーが 0.35 を返すと、ID 2 が選択されます。

double の配列がある場合、これを実装する最良の方法は何ですか?

4

5 に答える 5

4

多くの場合、最も単純なソリューションが最適です。範囲が設計上 0 ~ 100 (または別の扱いやすい小さな数値) である場合は、int[]作成した範囲のテーブルを割り当てて使用し、対応するインデックスで ID を入力することができます。 " は次のようになります。

int randomID = rangesToIDs[random.nextInt(rangesToIDs.length)];

ところで、ID を範囲サイズでソートする必要はありません。ランダムは一様に分布していると想定されるため、ルックアップ テーブルのどこに範囲が配置されていてもかまいません。エントリの数が ID をスローするチャンスに比例することだけが重要です。

于 2009-11-18T09:06:33.790 に答える
1

初期データが配列 D[n] として表されていると仮定しましょう。ここで、D[i] = (id, p) および sum(D[i].p for i=0..n-1) == 1 です。

P[i] = (q, id): P[i] = (sum(D[j].p for j in 0..i), D[j].id となるように、2 番目の配列 P[n] を作成します。 ) -- つまり、各スライス i の個々の確率を、i に先行するすべてのスライスの累積確率 (包括的) に変換します。定義により、この配列 P はフィールド q によって (つまり、累積確率によって) 順序付けられることに注意してください。

これで、二分探索を使用して、乱数 r (0 <= r <= 1) によって選択されたスライスを見つけることができます。

P[i].q <= r となる最高の i を見つけます。P[i].id はあなたのスライスです。

確率範囲を固定グリッドでハッシュすることにより、ルックアップをさらに高速化することができます。誰かが興味を持っているなら、私はこれについてもっと詳しく書くことができます。

于 2009-11-18T09:27:44.377 に答える
0
boundaries = [37, 72, 86, 100]
num = 100 * random
for i in boundaries:
  if num < i then return i
于 2009-11-18T10:13:22.510 に答える
0

jk が書いたように、ソートされた辞書は問題ないはずです。

次のような辞書を持っているとしましょう:

0.37 2
0.72 1
0.86 4
1.00 3

xx = 0.66 をロールします。xx < dict[i].key が dict[i].value を返す場合、最小の数字 (つまり 0.37) から辞書を繰り返します。

または、私の頭に浮かぶ別の解決策は、下限と上限と値を含むカスタムオブジェクトのリストです。次にリストを反復処理し、ロールされた数が上限と下限の範囲内にあるかどうかを確認します。

于 2009-11-18T09:19:58.240 に答える
0

「値」をキー、「ID」を値としてソートされたマップ/辞書を使用すると、現在の範囲の上限をすばやく見つけて、その範囲の ID を検索できます。

辞書で許可されていると仮定すると、上限を見つけるには、辞書全体を処理するよりも二分探索の方が適しています。

于 2009-11-18T08:58:55.553 に答える