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

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

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

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

Как мне это сделать?

EDIT: Следует также упомянуть, что все числа должны быть положительным целым числом

Ответы

Ответ 1

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

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

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

ОЧЕНЬ ПРОСТО, ВЫБРАТЬ NINE RANDOM NUMBERS и поместите красную метку краски в каждую из этих точек.

Это просто так просто. Все готово!

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

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

Вы закончили.

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

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


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

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

Ответ 2

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

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

для 1 для количества нужных значений - 1

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

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

цикл повторения

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

Ответ 3

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

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

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

Ответ 4

Я считаю, что ответ, предоставленный @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. Независимо от того, хотел ли OP более вероятный выстрел в один элемент, приближающийся к Максу или желающий равномерного распределения, в вопросе не было ясно. [Извинения - я не уверен с точки зрения терминологии, является ли это "равномерным распределением", поэтому я обращаюсь к нему только в условиях непрофессионала]

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

Чтобы продемонстрировать это, я предлагаю следующее решение, которое содержит последовательные случайные числа случайного шаблона распределения. Такое решение было бы полезно, если первый элемент должен иметь равные шансы при любом числе между 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

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

Ответ 5

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

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

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

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

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

  • Добавьте это число в следующий элемент.

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

Должно быть реализовано на полпути.

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

Ответ 6

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

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

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