Как сгенерировать три случайных числа, сумма которых равна 1?
Мне нужно сгенерировать 3 случайных числа, сумма которых равна 1.
моя реализация не поддерживает равномерное распределение. :(
8 ответов
просто получите 3 случайных числа, а затем вычислите коэффициент, который равен 1 /[сумма ваших чисел]. Наконец, умножьте каждое из случайных чисел с этим фактором. Сумма будет равна 1.
Это на самом деле сложный вопрос. Прежде всего:
Даренрешение не является однородным, потому что оно не поддерживает наличие двух чисел > 1/3.
Сименрешение неоднородно, если предположить, что" выбрать случайное число " рисует из равномерного распределения, но это немного более тонко. Он, по крайней мере, симметричен между переменными (т. е. вероятность [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, образуют N равносторонний треугольник в трех пространствах с координатами (1,0,0), (0,1,0), (0,0,1). Расширьте это до параллелограмма - например, добавив точку (1,1,-1) в качестве четвертой точки. Этот удвоение-это площадь-сопоставьте вторую область с первой, так что достаточно выбрать случайную точку в этом параллелограмме.
параллелограмм можно попробовать равномерно через (0,0,1) + а(1,0,-1) + в (0,1,-1), где A и B равномерно от 0 до 1.
- A
сгенерировать два случайных числа между 0 и 1. Разделить эти каждый по 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
небольшое изменение в ответе Марникса:
- генерировать случайное число
a
из [0,1] - генерация двух случайных чисел.
x
из [0,a] иy
из [a, 1] - установить результаты как
x
,y-x
,1-y
есть простой способ сделать это, но вам нужно иметь возможность генерировать равномерное случайное число.
пусть X будет равномерным на (0,2/3). Если X
при этой настройке X, Y и Z будут суммироваться до 1, все они будут иметь одинаковые равномерные (0, 2/3) предельные распределения, а все три попарные корреляции будут -(1/2).
1/2 методы:
- Создайте список случайных чисел, каждое от 0 до 1 из частей длины.
- сумме
- разделить каждый элемент на сумму
- круглый каждый элемент
- учет математики с плавающей запятой путем редактирования первого элемента
извините, не знаю 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 методов:
- создать список случайных чисел от 0 до 1; масштабируется до общего
- сортировка списка от малого до большого
- создать новый список, измеряя пространство между каждым элементом первый список
- округлить каждый элемент в новом списке
- заменить первый элемент для учета с плавающей запятой
Извините, я не знаю 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