一端に偏った連続的な重み付きランダム分布


28

現在、ゲームのパーティクルシステムに貢献し、エミッタシェイプを開発しています。

線または長方形の領域に沿った私の一様なランダム分布は問題なく動作します-問題ありません。

しかし今、私はこの分布に1次元の勾配のようなものを持ちたいです。これは、たとえば、低い値は高い値よりも一般的であることを意味します。

この問題に適切な数学用語が何であるかはわかりませんので、この検索スキルでは私の検索スキルはかなり役に立ちません。パーティクルシステムは効率的である必要があるため、計算が簡単なものが必要です。



誰も微積分学に言及しませんか?
アレックティール

回答:


42

この写真を見てください:

曲線マッピング

(ランダムな)値を曲線にマッピングするプロセスを示しています。0から1の範囲の一様に分布したランダムな値Xを生成するとします。この値を曲線にマッピングすることで、つまりXの代わりにf(X)を使用して、好きな方法で分布を歪めることができます。 。

この図では、最初の曲線がより高い値を示しています。2番目は、より低い値をより可能にします。3番目の値は、値を中央にクラスター化します。曲線の正確な公式は重要ではなく、好きなように選択できます。

たとえば、最初の曲線は平方根に少し似ており、2番目の曲線は正方形に似ています。3つ目はキューブに似ており、翻訳のみです。平方根が遅すぎると考えると、最初の曲線もf(X)= 1-(1-X)^ 2-平方の反転のように見えます。または、双曲線:f(X)= 2X /(1 + X)。

4番目の曲線が示すように、事前に計算されたルックアップテーブルを使用できます。曲線としてはいように見えますが、おそらくパーティクルシステムには十分でしょう。

この一般的な手法は非常にシンプルで強力です。必要な分布が何であれ、曲線マッピングを想像するだけで、すぐに数式を考案できます。または、エンジンにエディターがある場合は、曲線のビジュアルエディターを作成するだけです!


非常に徹底的でわかりやすい説明をありがとうございます。他のすべての投稿も非常に役に立ちましたが、あなたの投稿を最も簡単かつ迅速に理解できました。それは紀元前に突き出た、それは本当に物事を理解するためのスポットを打つ。そして、あなたが説明している側面はまさに私が探していた(またはさまよっていた)ものです!将来、多くの場合にこれを使用できるようになります。再びthx !!! ところで、私はそれらのあなたの曲線のいくつかで遊んで、それは魅力のように動作します。
ディディート

5
参考までに、これらは分位関数と呼ばれます:en.wikipedia.org/wiki/Quantile_function
ニールG

8

より長い説明:

要求される勾配@diditoなどの希望する確率分布がある場合、関数として記述することができます。0での確率が0.0である三角分布が必要で、0から1までの乱数を選択するとします。y= xと書くことができます。

次のステップは、この関数の積分を計算することです。この場合、それはです。0〜1で評価され、½です。それは理にかなっています—それは底辺1と高さ1の三角形なので、その面積は½です。x=1x2

次に、0からエリア(この例では½)まで均一にランダムなポイントを選択します。これをzと呼びましょう。(累積分布から均一に選択しています。)

次のステップは、xのどの値(x̂と呼ぶ)がzの領域に対応するかを見つけるために、後方に移動することです。0からx̂まで評価され、zに等しいを探しています。を解くと、が得られます。x=1x21x̂2=zx̂=2z

この例では、zを0から½の範囲で選択し、目的の乱数はです。簡略化すると、として記述できます。eBusinessが推奨するとおりです。2zrand(0,1)


価値ある入力のためのthx。私は常に、熟練した人々が問題を解決する方法を聞きたいです。しかし、私はまだ...正直に言うと、それのまわりで私の頭をラップする必要があります
didito

これはすごい。私はいつもsqrt(random())生涯を過ごしましたが、経験的にやって来ました。乱数を曲線に結び付けようとしても、うまくいきました。数学がもう少し上手になったので、なぜそれが機能するかを知ることは非常に貴重です!
グスタボマシ

5

おそらく、指数システムを利用することで、必要なものに近い近似値を取得できます。

1-(rnd ^ value)のようなものに基づいてxを作成します(rndが0から1の間であると仮定します)。使用するものに基づいて、左から右へのスキューのいくつかの異なる動作が得られます。値を大きくすると、より偏った分布になります

オンライングラフ作成ツールを使用して、さまざまな方程式がそれらを配置する前に提供する動作に関するいくつかの大まかなアイデアを得ることができます。

編集

パーティクルあたりのCPU時間が非常に重要なパーティクルシステムのようなものでは、Math.Pow(または同等の言語)を直接使用すると、パフォーマンスが低下する可能性があります。より多くのパフォーマンスが必要で、実行時に値が変更されない場合は、x ^ 2ではなくx * xなどの同等の関数に切り替えることを検討してください。

(フラクショナル指数は問題になる可能性がありますが、私よりも数学の背景が強い人は、おそらく近似関数を作成する良い方法を思いつくことができます)


1
これは特殊なケースであるため、グラフ作成プログラムを使用する代わりに、ベータ分布をプロットするだけです。指定されたのvalue場合、これはBeta(value、1)です。
ニールG

THX。いくつかのグラフをプロットしてみたところ、どこにでも行けると思う
ディディート

@Neil G「ベータ版配布」のヒントに感謝します-これは興味深く、便利に聞こえます...私はそのトピックについていくつかの研究をします
ディディト

3

あなたが探している用語はですWeighted Random Numbers、私が見たアルゴリズムのほとんどはtrig関数を使用していますが、効率的な方法を見つけたと思います:

ランダム関数の乗数値を保持するテーブル/配列/リスト(何でも)を作成します。手動またはプログラムで記入してください...

randMulti= {.1,.1,.1,.1,.1,.1,.2,.2,.3,.3,.9,1,1,1,} 

...次にrandom、ランダムに選択されrandMulti、最後に分布の最大値を掛けます...

weightedRandom = math.random()*randMulti[Math.random(randMulti.length)]*maxValue

これはsqrt、またはその他の計算が複雑な関数を使用するよりもはるかに高速で、より多くのカスタムグループ化パターンが可能になると考えています。


2
メモリを犠牲にできる場合、100個の事前に計算された値のテーブルの方が高速です(そしてわずかに正確です)。ユーザーが完全版と事前計算版を区別できるとは思わない。
ダニエルブレゼック

@Danielの方が高速ですが、100個のランダムな値を使用すると、繰り返しパターンが見やすくなります。
AttackingHobo

繰り返しパターンがあるように見えるからといって、それがランダムではないというわけではありません。ランダム性の本質はその予測不能性です。これは文字通り、パターンが存在しないことを予測できない限り、(少なくとも短時間)パターンが存在する可能性があることも予測できないことを意味します。いくつかのテストを行う必要がありますが、異なるシードを使用して複数のテストでパターンを見つけた場合は、擬似乱数を生成するためのアルゴリズムを確認する必要があります。
ランドルフリチャードソン

@AttackingHobo thxのトリック。LUTの使用が好きです。数式は非常に理解しやすいです。以前はこのように考えていませんでした。木のために木を見ていない... :)また、私は繰り返しパターンを避けるべきだと思いますが、おそらくこの場合はとにかく認識されないでしょう。それでも、すべての値を事前計算すると、視覚的なエクスペリエンスが損なわれます。とにかく、これはランダム性の話題に考慮すべき要因であることを私に思い出させるためのTHXは...
didito

また、用語「ランダムな数字」を表示してくれてありがとう!
ディディト

2

あなたが求めるのは平方根関数を使用して達成される分布だと思います。

[position] = sqrt(rand(0, 1))

これにより[0, 1]、位置の確率がその位置に等しい単一次元フィールドの分布、つまり「三角分布」が得られます。

代替の平方根フリー生成:

[position] = 1-abs(rand(0, 1)-rand(0, 1))

最適な実装の平方根は、分岐のない少数の乗算および合計コマンドです。(参照:http : //en.wikipedia.org/wiki/Fast_inverse_square_root)。これらの2つの関数のどちらが速いかは、プラットフォームとランダムジェネレーターによって異なります。たとえば、x86プラットフォームでは、2番目の方法を遅くするために、ランダムジェネレーターで予測不可能な分岐を数個しか必要としません。


位置の確率は位置と等しくなりません(数学的に不可能です-自明なことですが、関数の領域と範囲には0.50と0.51の両方が含まれます)。また、三角形の分布でもありません。(en.wikipedia.org/wiki/Triangular_distribution

1
sqrtはいくつかの興味深いパターンを提供しますが、パーティクルシステムは一般にパーティクルごとに非常にCPUを軽くする必要があるため、可能な限り平方根(計算が遅い)を避けることをお勧めします。事前に計算するだけで済むこともありますが、時間が経つにつれて粒子に顕著なパターンが現れることがあります。
ルニン

1
@Joe Wreschnig、そのウィキペディアの記事を自分で読んで、生成式にa = 0、b = 1、c = 1を詰め込み、私の投稿でその式を取得しました。
aaaaaaaaaaaa

3
@Lunin、あなたが答えに指数を持っているのに、なぜあなたは平方根について不平を言っていますか?
aaaaaaaaaaaa

1
@Lunin:パフォーマンス理論はかなり無視された分野で、30年前にALUが大きく高価で遅かった頃、人々が知っていると思う多くのことです。かなり遅い算術関数であることがわかった指数関数でさえ、非常に重要なパフォーマンスの罪人になることはめったにありません。分岐(ifステートメントを使用)とキャッシュミス(現在キャッシュに存在しないデータの一部を読み取る)は、通常、最もパフォーマンスが低下します。
aaaaaaaaaaaa

1

ベータ版を使用するだけです:

  • Beta(1,1)はフラットです
  • Beta(1,2)は線形勾配です
  • Beta(1,3)は2次です

2つの形状パラメーターは整数である必要はありません。


あなたの助けのためのTHX。上記のように、ベータ版の配布は興味深いようです。しかし、まだウィキペディアのページの内容を理解することはできません。または式/コード。まあ、私は今、さらに調査する時間がありません:siは、boostがベータ配布用のコードを持っていることを確認しますが、これはやり過ぎです。まあ、私は最初にそれを通り抜けてから、自分の簡易版を書く必要があると思います。
ディディト

1
@ディディト:それほど難しくありません。uniform_generator()通話をに置き換えますgsl_ran_beta(rng, a, b)。ここを参照してください:gnu.org/software/gsl/manual/html_node/...
ニール・G

ヒントのthx。私はGSLを使用していません(実際にそれについて聞いたことがありません)が、良い電話です。ソースを確認します!
ディディト

@didito:その場合、私はLuninのソリューションを使います。がんばろう。
ニールG

0

さらに簡単に、ランダムジェネレーターの速度に応じて、2つの値を生成して平均することができます。

あるいは、もっと単純で、Xは、RNGの結果であり、まずdouble y = double(1/x);x = y*[maximum return value of rng];。これは、数値を低い数値に指数関数的に重み付けします。

より多くの値を生成して平均化し、値を中心に近づける可能性を高めます。

もちろん、これは標準のベル曲線分布またはその「折り畳まれた」バージョン*でのみ機能しますが、高速ジェネレーターを使用すると、sqrtなどのさまざまな数学関数を使用するよりも速く簡単になります。

サイコロのベルカーブについて、これに関するあらゆる種類の研究を見つけることができます。実際、Anydice.comは、サイコロを転がすさまざまな方法のグラフを生成する優れたサイトです。RNGを使用していますが、前提も結果も同じです。そのため、コーディングする前に配布を確認するのに適した場所です。

*また、軸を取得し、平均化された結果を減算してから軸を追加することにより、軸に沿って結果分布を「折り畳む」ことができます。たとえば、より低い値をより一般的にし、15を最小値、35を最大値、20の範囲にしたい場合、20の範囲の2つの値を生成して平均します(必要な範囲の2倍)、20を中心としたベルカーブが得られます(最後に5を引いて、範囲を20から40から15から35にシフトします)。生成された数値XとYを取得します。

最終番号

z =(x+y)/2;// average them
If (z<20){z = (20-z)+20;}// fold if below axis
return z-5;// return value adjusted to desired range

ゼロが最小値である場合、さらに良い場合は、代わりにこれを行い、

z= (x+y)/2;
If (z<20){z = 20-z;}
else {z = z - 20;}
return z;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.