2010-08-28 4 views
23

Итак, вот сделка: Я хочу (например) сгенерировать 4 псевдослучайных числа, которые при объединении будут равны 40. Как это может быть купол в python? Я мог бы генерировать случайное число 1-40, затем генерировать другое число между 1 и остальным и т. Д., Но тогда у первого числа будет больше шансов «захватить» больше.Создайте несколько случайных чисел, чтобы они равны значению в python

+0

После того, как у вас есть желаемый ответ, нажмите на галочкой и стрелку вверх рядом с ответом, чтобы принять его. :) –

ответ

12
b = random.randint(2, 38) 
a = random.randint(1, b - 1) 
c = random.randint(b + 1, 39) 
return [a, b - a, c - b, 40 - c] 

(я предполагаю, что вы хотели целые числа, так как вы сказали, «1-40», но это может быть легко обобщается на поплавках)

Вот как это работает:.

  • сократить общий диапазон в двух случайно, это б. Нечетный диапазон - это то, что они будут по крайней мере на 2 ниже середины и не менее 2 выше. (Это зависит от вашего 1 минимума от каждого значения).
  • разрезать каждый из этих диапазонов в двух случайных порядке. Опять же, оценки должны учитывать 1 минимум.
  • вернуть размер каждого фрагмента. Они составят до 40.
+0

только то, что мне нужно, спасибо! –

+0

Я думаю, вам нужно 'a = random.randint (1, b-1)' и 'c = random.randint (b + 1, 39)', чтобы убедиться, что вы не получаете нулей в выходном списке. Кроме того, это имеет слегка своеобразное распределение: результаты формы «[1, 1, x, 38-x]» значительно чаще возникают, чем для равномерного распределения. –

+0

@Mark: Я считаю, что вы правы. У меня было несколько отключенных ошибок. –

5

Сформировать 4 случайных чисел, вычислить их сумму, разделить каждый на сумму и умножить на 40.

Если вы хотите типа Integer, то это потребует немного неслучайности.

1

Предполагая, что вы хотите, чтобы они были равномерно распределены, и если вы не хотите, Повтор

addends = [] 
picks = range(1, 34) 
while sum(addends) != 40: 
    addends = random.sample(picks, 3) 
    if sum(addends) > 39: 
     continue 
    addends.append(40 - sum(addends)) 
+2

-1: множество волшебных чисел! – msw

+7

Поддельный -1 на себя? –

3

Существует только 37^4 = 1,874,161 расположения четырех целых чисел в диапазоне [1,37] (с допустимыми повторами). Перечислите их, сохраните и подсчитайте перестановки, которые составляют до 40. (Это будет намного меньшее число, N).

Нарисуйте равномерно распределенные случайные целые числа K в интервале [0, N-1] и верните K-ю перестановку. Это легко увидеть, чтобы гарантировать равномерное распределение по пространству возможных исходов, причем каждая позиция последовательности одинаково распределена. (Многие из ответов, которые я вижу, будут иметь окончательный выбор, предвзятый ниже, чем первые три!)

63

Вот стандартное решение. Это похоже на ответ Лоуренса Гонсалвеса, но имеет два преимущества перед этим ответом. (1) Это единообразно: каждая комбинация из 4 положительных целых чисел, добавляющая до 40, в равной степени может придумать эту схему, и (2) легко адаптироваться к другим итоговым значениям (7 чисел, добавляющих до 100 и т. Д.):

import random 

def constrained_sum_sample_pos(n, total): 
    """Return a randomly chosen list of n positive integers summing to total. 
    Each such list is equally likely to occur.""" 

    dividers = sorted(random.sample(xrange(1, total), n - 1)) 
    return [a - b for a, b in zip(dividers + [total], [0] + dividers)] 

Примеры выходов:

>>> constrained_sum_sample_pos(4, 40) 
[4, 4, 25, 7] 
>>> constrained_sum_sample_pos(4, 40) 
[9, 6, 5, 20] 
>>> constrained_sum_sample_pos(4, 40) 
[11, 2, 15, 12] 
>>> constrained_sum_sample_pos(4, 40) 
[24, 8, 3, 5] 

Пояснение: есть взаимно однозначное соответствие одному между (1) 4-кортежей (a, b, c, d) положительных целых чисел, таких, что a + b + c + d == 40, и (2) тройки целых чисел (e, f, g) с 0 < e < f < g < 40, и его легко произвести, используя random.sample. Соответствие задается (e, f, g) = (a, a + b, a + b + c) в одном направлении и (a, b, c, d) = (e, f - e, g - f, 40 - g) в обратном направлении.

Если вы хотите неотрицательных целых чисел (т., что позволяет 0) вместо положительных, то есть простое преобразование: если (a, b, c, d) - это целые числа неотрицательных чисел, суммирующие 40, то (a+1, b+1, c+1, d+1) представляют собой положительные целые числа, суммирующие 44, и наоборот. Используя эту идею, мы имеем:

def constrained_sum_sample_nonneg(n, total): 
    """Return a randomly chosen list of n nonnegative integers summing to total. 
    Each such list is equally likely to occur.""" 

    return [x - 1 for x in constrained_sum_sample_pos(n, total + n)] 

Графическая иллюстрация constrained_sum_sample_pos(4, 10), благодаря @FM. (Немного ред.)

0 1 2 3 4 5 6 7 8 9 10 # The universe. 
|     | # Place fixed dividers at 0, 10. 
| |  |  | | # Add 4 - 1 randomly chosen dividers in [1, 9] 
    a b  c d # Compute the 4 differences: 2 3 4 1 
+0

+1 Это было информативно - спасибо. Я отредактировал ваш ответ, добавив графическую иллюстрацию, которая помогла мне разобраться с алгоритмом. Обычно я бы не хотел этого делать, но я думал, что другие могут оказаться полезными. Не стесняйтесь изменять или отменять мое редактирование. – FMc

+0

Капитан, я обнаруживаю большие выигрыши в этом секторе! +1 –

+0

@FM: Спасибо; приятный дополнение. Я немного отредактировал его в соответствии с моим обзором вселенной на основе 0; Надеюсь, это не повлияет на ясность. –

3
from numpy.random import multinomial 
multinomial(40, [1/4.] * 4) 
Смежные вопросы