Как я могу создать указанное количество случайных значений, которые все равны указанному числу в PHP?

Например, я говорю "10" для суммы значений и "10000" для общей суммы.

Сценарий должен был бы рандомизировать 10 различных чисел, которые все равны до 10000. Не больше, не меньше.

Но это также должно быть динамичным. Например, иногда я мог бы ввести "5" или "6" или даже "99" для количества значений и любое число (до миллиарда или даже больше) в качестве общей суммы.

Как бы я поступил так?

РЕДАКТИРОВАТЬ: я должен также отметить, что все числа должны быть положительными целыми числами

6 ответов

Решение

Правильный ответ здесь невероятно прост.

Просто представьте белую линию, скажем, 1000 единиц в длину.

Вы хотите разделить линию на десять частей, используя красные метки.

ОЧЕНЬ ПРОСТО, ВЫБЕРИТЕ ДЕВЯТЬ СЛУЧАЙНЫХ ЧИСЕЛ и нанесите красную отметку на каждой из этих точек.

Это так просто. Вы сделали!

Таким образом, алгоритм имеет вид:

(1) выбрать девять случайных чисел от 0 до 1000 (2) поместить девять чисел, ноль и 1000 в массив (3) отсортировать массив (4), используя вычитание, получить десять "расстояний" между значениями массива

Вы сделали

(Очевидно, что если вы хотите, чтобы в конечном наборе не было нулей, в части (1) просто выберите другое случайное число, если вы столкнулись.)

В идеале, как программисты, мы можем "видеть" такие визуальные алгоритмы в наших головах - стараться визуально мыслить, что бы мы ни делали!


Сноска - для любого непрограммиста, читающего это, просто для ясности, пожалуйста, обратите внимание, что это как "первое, что вы когда-либо узнаете, изучая информатику!" то есть я не получаю никакого кредита на это, я просто набрал ответ, так как я наткнулся на странице. Нет, слава мне!

Просто для записи еще один общий подход (в зависимости от желаемого результата, будь вы имеете дело с действительными или целыми числами и другими ограничениями) также очень "ах, ха!" элегантный. Все, что вы делаете, это: получить 10 случайных чисел. Добавьте их. Удивительно просто, просто: умножьте или разделите их все на некоторое число, чтобы итоговая сумма была желаемой! Это так просто!

Может быть что-то вроде этого:

установить максимальное количество, оставшееся до целевого числа

цикл от 1 до количества значений, которые вы хотите - 1

получить случайное число от 0 до максимальной оставшейся суммы

установить новую максимальную сумму, оставшуюся до старой максимальной суммы, оставшейся минус текущее случайное число

повторить цикл

в итоге вы получите "остаток", поэтому последнее число определяется тем, что осталось, чтобы составить исходный итог.

Я считаю, что ответ, предоставленный @JoeBlow, в значительной степени правильный, но только если желаемая "случайность" требует равномерного распределения. В комментарии к этому ответу @Artefacto сказал следующее:

It may be simple but it does not generate uniformly distributed numbers... 
Itis biased in favor of numbers of size 1000/10 (for a sum of 1000 and 10 numbers).

Это вызывает вопрос, который был упомянут ранее относительно желаемого распределения этих чисел. Метод JoeBlow гарантирует, что элемент 1 имеет такую ​​же вероятность быть номером x, что и элемент 2, что означает, что он должен быть смещен в сторону чисел размера Max/n. Вопрос о том, хотел ли ОП более вероятный выстрел по одному элементу, приближающемуся к Максу, или требовал равномерного распределения, не был ясен в этом вопросе. [Извинения - я не уверен с точки зрения терминологии, дает ли это "равномерное распределение", поэтому я ссылаюсь на него только в терминах непрофессионала]

В целом, неверно говорить, что "случайный" список элементов обязательно распределен равномерно. Отсутствующий элемент, как указано в других комментариях выше, является желаемым распределением.

Чтобы продемонстрировать это, я предлагаю следующее решение, которое содержит последовательные случайные числа случайного шаблона распределения. Такое решение было бы полезно, если бы первый элемент имел одинаковый шанс на любое число от 0 до N, а каждое последующее число имеет равный шанс на любое число от 0 до [Оставшееся общее количество]:

[Pseudo code]:
Create Array of size N
Create Integer of size Max
Loop through each element of N Except the last one
    N(i) = RandomBetween (0, Max)
    Max = Max - N(i)
End Loop
N(N) = Max

Может быть необходимо взять эти элементы и рандомизировать их порядок после того, как они были созданы, в зависимости от того, как они будут использоваться [в противном случае средний размер каждого элемента уменьшается с каждой итерацией].

Генерация 10 случайных чисел до 10000 . Сортируйте их от большого к маленькому: от g0 до g9

g0 = 10000 - r0
g1 = r0 - r1
...
g8 = r8 - r9
g9 = r9

Это даст 10 случайных чисел во всем диапазоне, что в сумме составит 10000 .

Связанный: http://www.mathworks.cn/matlabcentral/newsreader/view_thread/141395

Смотрите этот пакет MATLAB. Он сопровождается файлом с теорией реализации.

Эта функция генерирует случайные, равномерно распределенные векторы, x = [x1,x2,x3,...,xn]', которые имеют указанную сумму s и для которых у нас есть <= xi <= b, для указанных значений a и б. Полезно рассматривать такие векторы как точки, принадлежащие n-мерному евклидову пространству и лежащие в n-1-мерной гиперплоскости, ограниченной суммой s. Поскольку для всех a и b проблема может быть легко изменена на случай, когда a = 0 и b = 1, в дальнейшем мы будем предполагать, что это так, и что мы работаем в единичном n-мерном "куб".

Это реализация (© Roger Stafford):

function [x,v] = randfixedsum(n,m,s,a,b)

% Rescale to a unit cube: 0 <= x(i) <= 1
s = (s-n*a)/(b-a);

% Construct the transition probability table, t.
% t(i,j) will be utilized only in the region where j <= i + 1.
k = max(min(floor(s),n-1),0); % Must have 0 <= k <= n-1
s = max(min(s,k+1),k); % Must have k <= s <= k+1
s1 = s - [k:-1:k-n+1]; % s1 & s2 will never be negative
s2 = [k+n:-1:k+1] - s;
w = zeros(n,n+1); w(1,2) = realmax; % Scale for full 'double' range
t = zeros(n-1,n);
tiny = 2^(-1074); % The smallest positive matlab 'double' no.
for i = 2:n
 tmp1 = w(i-1,2:i+1).*s1(1:i)/i;
 tmp2 = w(i-1,1:i).*s2(n-i+1:n)/i;
 w(i,2:i+1) = tmp1 + tmp2;
 tmp3 = w(i,2:i+1) + tiny; % In case tmp1 & tmp2 are both 0,
 tmp4 = (s2(n-i+1:n) > s1(1:i)); % then t is 0 on left & 1 on right
 t(i-1,1:i) = (tmp2./tmp3).*tmp4 + (1-tmp1./tmp3).*(~tmp4);
end

% Derive the polytope volume v from the appropriate
% element in the bottom row of w.
v = n^(3/2)*(w(n,k+2)/realmax)*(b-a)^(n-1);

% Now compute the matrix x.
x = zeros(n,m);
if m == 0, return, end % If m is zero, quit with x = []
rt = rand(n-1,m); % For random selection of simplex type
rs = rand(n-1,m); % For random location within a simplex
s = repmat(s,1,m);
j = repmat(k+1,1,m); % For indexing in the t table
sm = zeros(1,m); pr = ones(1,m); % Start with sum zero & product 1
for i = n-1:-1:1  % Work backwards in the t table
 e = (rt(n-i,:)<=t(i,j)); % Use rt to choose a transition
 sx = rs(n-i,:).^(1/i); % Use rs to compute next simplex coord.
 sm = sm + (1-sx).*pr.*s/(i+1); % Update sum
 pr = sx.*pr; % Update product
 x(n-i,:) = sm + pr.*e; % Calculate x using simplex coords.
 s = s - e; j = j - e; % Transition adjustment
end
x(n,:) = sm + pr.*s; % Compute the last x

% Randomly permute the order in the columns of x and rescale.
rp = rand(n,m); % Use rp to carry out a matrix 'randperm'
[ig,p] = sort(rp); % The values placed in ig are ignored
x = (b-a)*x(p+repmat([0:n:n*(m-1)],n,1))+a; % Permute & rescale x

return

Обновление: @Joe Blow имеет идеальный ответ. В моем ответе есть особенность генерации кусков примерно одинакового размера (или, по крайней мере, разницы не более (10000 / 10)), и поэтому он остается на месте.

Самый простой и быстрый подход, который приходит мне в голову:

  • Разделите 10000 на 10 и сохраните значения в массиве. (В 10 раз больше 10000)

  • Пройдите через каждый из 10 элементов в for петля.

  • Из каждого элемента вычтите случайное число между (10000/10).

  • Добавьте этот номер к следующему элементу.

Это даст вам несколько случайных значений, которые при добавлении приведут к конечному значению (игнорируя проблемы с плавающей запятой).

Должно быть на полпути легко осуществимо.

В какой-то момент вы достигнете максимального целочисленного предела PHP. Не уверен, как далеко это может быть использовано для ценностей в миллиард и более.

Другие вопросы по тегам