乱数を 3 つ生成する必要があり、その量は 1 です。
私の実装では均一な配布がサポートされていません。:(
3 つの乱数を取得し、1 / [数値の合計] である係数を計算します。最後に、各乱数にその係数を掛けます。合計は 1 になります。
これは実際には難しい質問です。まず第一に、
Darenの解は 1/3 を超える 2 つの数値をサポートしていないため、均一ではありません。
Simenの解決策は、「乱数を選ぶ」が一様分布から引き出されると仮定すると一様ではありませんが、これはもう少し微妙です。変数間で少なくとも対称的です (つまり、[a, b, c] の確率は、その順列の確率と同じです) が、(1/3, 1/3, 1/ 3)。極端なケースを見て、このように考えてみてください: (1/3, 1/3, 1/3) は、任意の (a, a, a) に由来する可能性があり、a の範囲は 0 から 1 です。(1, 0, 0)、同等に有効なトリプルは、(1, 0, 0) から来ている必要があります。
1 つの解決策:加算して 1 になる正の数のセットは、座標 (1,0,0)、(0,1,0)、(0,0,1) を持つ 3 空間で正三角形を形成します。それを平行四辺形に拡張します。たとえば、点 (1,1,-1) を 4 番目の点として追加します。この double は面積です -- 2 番目の面積を最初の面積にマッピングして、この平行四辺形のランダムな点を選択するだけで十分です。
平行四辺形は、(0,0,1) + A(1,0,-1) + B (0,1,-1) によって均一にサンプリングできます。ここで、A と B の範囲は 0 から 1 まで均一です。
-A
0 と 1 の間の 2 つの乱数を生成します。それらをそれぞれ 3 で割ります。3 番目は、1 と 2 つのランダムな 3 分の 1 の差です。
void Main()
{
Random r = new Random();
double d1 = r.NextDouble() / 3.0;
double d2 = r.NextDouble() / 3.0;
double d3 = 1.0 - d1 - d2;
System.Console.WriteLine(d1);
System.Console.WriteLine(d2);
System.Console.WriteLine(d3);
System.Console.WriteLine(d1 + d2 + d3);
}
これにより、LINQPad で次のように出力されます。
0.0514050276878934
0.156857372489847
0.79173759982226
1
これを行う簡単な方法がありますが、一様乱数を生成できる必要があります。
X を (0,2/3) で一様とする。X < 1/3 の場合、Y = X + 1/3 とします。それ以外の場合は、Y = X - 1/3 とします。Z = 1 - X - Y とします。
この設定では、X、Y、および Z の合計は 1 になり、それらはすべて同じ一様な (0, 2/3) 周辺分布を持ち、3 つのペアワイズ相関はすべて -(1/2) になります。
アップデート
Marnix の回答のわずかなバリエーション:
a
[0,1] から乱数を生成するx
[0,a] およびy
[a,1] からx
、y-x
、として設定1-y
半分の方法:
申し訳ありませんが、C# はわかりません。Python は次のとおりです。
import random
import time
PARTS = 5
TOTAL = 10
PLACES = 3
def random_sum_split(parts, total, places):
a = []
for n in range(parts):
a.append(random.random())
b = sum(a)
c = [x/b for x in a]
d = sum(c)
e = c
if places != None:
e = [round(x*total, places) for x in c]
f = e[-(parts-1):]
g = total - sum(f)
if places != None:
g = round(g, places)
f.insert(0, g)
log(a)
log(b)
log(c)
log(d)
log(e)
log(f)
log(g)
return f
def tick():
if info.tick == 1:
start = time.time()
alpha = random_sum_split(PARTS, TOTAL, PLACES)
log('********************')
log('***** RESULTS ******')
log('alpha: %s' % alpha)
log('total: %.7f' % sum(alpha))
log('parts: %s' % PARTS)
log('places: %s' % PLACES)
end = time.time()
log('elapsed: %.7f' % (end-start))
収量:
Waiting...
Saved successfully.
[2014-06-13 00:01:00] [0.33561018369775897, 0.4904215932650632, 0.20264927800402832, 0.118862130636748, 0.03107818050878819]
[2014-06-13 00:01:00] 1.17862136611
[2014-06-13 00:01:00] [0.28474809073311597, 0.41609766067850096, 0.17193755673414868, 0.10084844382959707, 0.02636824802463724]
[2014-06-13 00:01:00] 1.0
[2014-06-13 00:01:00] [2.847, 4.161, 1.719, 1.008, 0.264]
[2014-06-13 00:01:00] [2.848, 4.161, 1.719, 1.008, 0.264]
[2014-06-13 00:01:00] 2.848
[2014-06-13 00:01:00] ********************
[2014-06-13 00:01:00] ***** RESULTS ******
[2014-06-13 00:01:00] alpha: [2.848, 4.161, 1.719, 1.008, 0.264]
[2014-06-13 00:01:00] total: 10.0000000
[2014-06-13 00:01:00] parts: 5
[2014-06-13 00:01:00] places: 3
[2014-06-13 00:01:00] elapsed: 0.0054131
2/2 メソッド:
申し訳ありませんが、C# はわかりません。Python では次のようになります。
import random
import time
PARTS = 5
TOTAL = 10
PLACES = 3
def random_sum_split(parts, total, places):
a = [0.0, total]
for i in range(parts-1):
a.append(random.random()*total)
a.sort()
b = []
for i in range(1,(parts+1)):
b.append(a[i] - a[i-1])
if places != None:
b = [round(x, places) for x in b]
c = b[-(parts-1):]
d = total - sum(c)
if places != None:
d = round(d, places)
c.insert(0, d)
log(a)
log(b)
log(c)
log(d)
return c
def tick():
if info.tick == 1:
start = time.time()
alpha = random_sum_split(PARTS, TOTAL, PLACES)
log('********************')
log('***** RESULTS ******')
log('alpha: %s' % alpha)
log('total: %.7f' % sum(alpha))
log('parts: %s' % PARTS)
log('places: %s' % PLACES)
end = time.time()
log('elapsed: %.7f' % (end-start))
収量:
Waiting...
Saved successfully.
[2014-06-13 00:01:00] [0.0, 1.3005056784596913, 3.0412441135728474, 5.218388755020509, 7.156425483589107, 10]
[2014-06-13 00:01:00] [1.301, 1.741, 2.177, 1.938, 2.844]
[2014-06-13 00:01:00] [1.3, 1.741, 2.177, 1.938, 2.844]
[2014-06-13 00:01:00] 1.3
[2014-06-13 00:01:00] ********************
[2014-06-13 00:01:00] ***** RESULTS ******
[2014-06-13 00:01:00] alpha: [1.3, 1.741, 2.177, 1.938, 2.844]
[2014-06-13 00:01:00] total: 10.0000000
[2014-06-13 00:01:00] parts: 5
[2014-06-13 00:01:00] places: 3
[2014-06-13 00:01:00] elapsed: 0.0036860