Например, скажем, я ввожу «10» для количества значений, а «10000» – в общую сумму.
Скрипт должен будет рандомизировать 10 разных чисел, которые равны до 10000. Нет больше, не меньше.
Но он также должен быть динамичным. Как и в случае, иногда я могу ввести «5» или «6» или даже «99» для количества значений и любое число (до миллиарда или даже выше) в качестве общей суммы.
Как мне это сделать?
EDIT: Я должен также упомянуть, что все числа должны быть положительными целыми числами
Правильный ответ здесь невероятно прост.
Представьте себе белую линию, скажем, 1000 единиц.
Вы хотите разделить линию на десять частей, используя красные метки.
ОЧЕНЬ ПРОСТО, ВЫБРАТЬ NINE RANDOM NUMBERS и поместите красную метку краски в каждую из этих точек.
Все просто. Все готово!
Таким образом, алгоритм:
(1) выбрать девять случайных чисел между 0 и 1000 (2) положить девять чисел, нуль и 1000, в массиве (3) сортировать массив (4), используя вычитание, получить десять «расстояний» между значениями массива
Все готово.
(Очевидно, что если вы хотите иметь нули в своем конечном наборе, часть (1) просто повторно выбирает другое случайное число, если вы получаете столкновение.)
В идеале, как программисты, мы можем «видеть» визуальные алгоритмы, подобные этому в наших головах, – старайтесь визуально визуально видеть, что мы делаем!
Сноска – для любых не-программистов, читающих это, просто чтобы быть понятным, обратите внимание, что это похоже на «первое, что вы когда-либо узнали, изучая информатику!» т.е. я не получаю к этому никаких заслуг, я просто набрал ответ, так как я наткнулся на страницу. Мне не нравится!
Только для записи другой общий подход (в зависимости от желаемого результата, независимо от того, имеете ли вы дело с реальными или целыми числами и другими ограничениями) также очень «ах, ха!». элегантный. Все, что вы делаете, это: получить 10 случайных чисел. Добавьте их. Замечательно просто: просто: умножьте или разделите их на какое-то число, так что общее количество – это нужная сумма! Это так просто!
может быть, что-то вроде этого:
установить максимальную сумму, оставшуюся до целевого номера
loop для 1 к числу желаемых значений – 1
получить случайное число от 0 до максимальной оставшейся суммы
установите новую максимальную сумму, оставшуюся до оставшейся старой максимальной суммы минус текущее случайное число
цикл повторения
вы получите «остаток», поэтому последнее число будет определяться тем, что осталось, чтобы составить исходную сумму.
Создайте 10 случайных чисел до 10000. Сортируйте их от большого до малого: от g0 до g9
g0 = 10000 - r0 g1 = r0 - r1 ... g8 = r8 - r9 g9 = r9
Это даст 10 случайных чисел во всем диапазоне, которые составляют до 10000.
Я считаю, что ответ, предоставленный @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
Может быть необходимо взять эти элементы и рандомизировать их порядок после их создания, в зависимости от того, как они будут использоваться [в противном случае средний размер каждого элемента уменьшается с каждой итерацией].
Обновление: @Joe Blow имеет прекрасный ответ. У моего ответа есть особая особенность генерации кусков примерно того же размера (или, по крайней мере, разница не больше (10000/10)), оставив его на месте по этой причине.
Самый легкий и быстрый подход, который приходит мне на ум:
Разделите 10000 на 10 и сохраните значения в массиве. (В 10 раз больше 10000
)
Пройдите через каждый из 10 элементов в цикле for
.
Из каждого элемента вычитайте случайное число между (10000/10).
Добавьте это число в следующий элемент.
Это даст вам ряд случайных значений, которые при добавлении приведут к конечному значению (игнорируя проблемы с плавающей запятой).
Должно быть на полпути легко реализовать.
Тем не менее, вы достигнете максимального целочисленного предела PHP. Не уверен, насколько это можно использовать для ценностей в миллиард и более.
Связанный: 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 = (sn*a)/(ba); % 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)*(ba)^(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(ni,:)<=t(i,j)); % Use rt to choose a transition sx = rs(ni,:).^(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(ni,:) = 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 = (ba)*x(p+repmat([0:n:n*(m-1)],n,1))+a; % Permute & rescale x return