Как сгенерировать три случайных числа, сумма которых равна 1? - PullRequest
12 голосов
/ 06 апреля 2011

Мне нужно сгенерировать 3 случайных числа, количество которых равно 1.

Моя реализация не поддерживает равномерное распределение.(

Ответы [ 8 ]

23 голосов
/ 06 апреля 2011

Просто получите 3 случайных числа, а затем рассчитайте коэффициент, который равен 1 / [сумма ваших чисел].Наконец, умножьте каждое из случайных чисел на этот коэффициент.Сумма будет 1.

9 голосов
/ 20 июля 2011

Это на самом деле сложный вопрос. Прежде всего: Решение
Дарена не является равномерным, поскольку оно не поддерживает наличие двух чисел> 1/3. Решение
Симена не является единообразным, если предположить, что «выбрать случайное число» происходит из равномерного распределения, но это немного более тонко. Он, по крайней мере, симметричен между переменными (т. Е. Вероятность [a, b, c] такая же, как и вероятность любой перестановки этого), но он сильно предпочитает решения, близкие к (1/3, 1/3, 1 / 3). Подумайте об этом так, рассматривая крайние случаи: (1/3, 1/3, 1/3) мог прийти из любого (a, a, a), где диапазон от 0 до 1. (1, 0, 0), одинаково допустимая тройка, должна происходить из (1, 0, 0).

Одно решение: Множество положительных чисел, которые складываются с 1, образуют равносторонний треугольник в трехмерном пространстве с координатами (1,0,0), (0,1,0), (0 , 0,1). Расширьте это до параллелограмма - например, добавив точку (1,1, -1) в качестве четвертой точки. Эта двойная область - отобразите вторую область на первую, чтобы было достаточно выбрать случайную точку в этом параллелограмме.

Параллелограмм может быть отобран равномерно с помощью (0,0,1) + A (1,0, -1) + B (0,1, -1), где A и B находятся в диапазоне от 0 до 1.

-A

3 голосов
/ 06 апреля 2011

Генерация двух случайных чисел от 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
1 голос
/ 03 октября 2013

Существует простой способ сделать это, но вы должны иметь возможность генерировать равномерное случайное число.

Пусть X равномерно на (0,2 / 3).Если X <1/3, пусть Y = X + 1/3.В противном случае пусть Y = X - 1/3.Пусть Z = 1 - X - Y. </p>

При этой настройке X, Y и Z будут суммироваться до 1, все они будут иметь одинаковые равномерные (0, 2/3) маргинальные распределения и все три попарнокорреляции будут - (1/2).

1 голос
/ 06 апреля 2011

Небольшое отклонение от ответа Марникса:

  1. Генерация случайного числа a из [0,1]
  2. Генерация двух случайных чисел. x из [0, a] и y из [a, 1]
  3. Установить результаты как x, y-x, 1-y
0 голосов
/ 05 сентября 2014

1/2 методы:

  • Создайте список случайных чисел, каждое от 0 до 1 длины ЧАСТЕЙ.
  • Суммирование списка
  • Разделение каждого элемента на сумму
  • Округление каждого элемента
  • Учет математики с плавающей запятой путем редактирования первого элемента

Извините, не знаю C #, вот этот питон:

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

yeilds:

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
0 голосов
/ 05 сентября 2014

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
0 голосов
/ 06 апреля 2011

UPDATE

  1. Создать вектор3 из 3 случайных чисел
  2. Нормализовать вектор
...