Это означает, что ваш код использовал ссылочную переменную объекта, которая была установлена в нуль (т. е. она не ссылалась на экземпляр фактического объекта).
Чтобы предотвратить ошибку, объекты, которые могут быть пустыми, должны быть протестированы для null перед тем, как использовать.
if (myvar != null)
{
// Go ahead and use myvar
myvar.property = ...
}
else
{
// Whoops! myvar is null and cannot be used without first
// assigning it to an instance reference
// Attempting to use myvar here will result in NullReferenceException
}
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», но это можно легко обобщить для поплавков.)
Вот как это работает:
В диапазоне [1,37] (с разрешенными повторами) существует только 37 ^ 4 = 1,874,161 расположения четырех целых чисел. Перечислите их, сохраните и подсчитайте перестановки, которые составляют до 40. (Это будет намного меньшее число, N).
Нарисуйте равномерно распределенные случайные целые числа K в интервале [0, N-1] и верните K-ю перестановку. Это легко увидеть, чтобы гарантировать равномерное распределение по пространству возможных исходов, причем каждая позиция последовательности одинаково распределена. (Многие из ответов, которые я вижу, будут иметь окончательный выбор, предвзятый ниже, чем первые три!) [/ G1]
Создайте 4 случайных числа, вычислите их сумму, разделите каждую на сумму и умножьте на 40.
Если вам нужны целые числа, тогда для этого потребуется небольшая неслучайность.
Вот стандартное решение. Это похоже на ответ Лоуренса Гонсалвеса, но имеет два преимущества перед этим ответом. (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
Предполагая, что вы хотите, чтобы они были равномерно распределены, и предполагая, что вы не хотите повторений
addends = []
picks = range(1, 34)
while sum(addends) != 40:
addends = random.sample(picks, 3)
if sum(addends) > 39:
continue
addends.append(40 - sum(addends))
from numpy.random import multinomial
multinomial(40, [1/4.] * 4)