【问题标题】:How can I create a specified amount of random values that all equal up to a specified number in PHP?如何创建指定数量的随机值,它们都等于 PHP 中的指定数字?
【发布时间】:2010-09-12 21:04:43
【问题描述】:

例如,假设我输入“10”作为值的数量,输入“10000”作为总数量。

脚本需要随机化 10 个不同的数字,它们都等于 10000。不多也不少。

但它也需要是动态的。例如,有时我可能会输入 '5' 或 '6' 甚至 '99' 作为值的数量,并输入任何数字(高达 10 亿甚至更高)作为总量。

我该怎么做呢?

编辑:我还应该提到所有数字都必须是正整数

【问题讨论】:

  • 你想要什么样的发行版?例如,满足您的问题的一个答案是,前 8 个值是 1000,然后是 999、1001 或 1001、999,概率相等。所以……你想要什么?正态分布的总和?标准差是多少?...您会发现目前无法回答您的问题。
  • @Artefacto 好吧,就目前而言,他不需要特定的分布和偏差 - 这使得问题可以回答。不是吗?
  • @Pekka 是的,它使它“可回答”。事实上,我给出了一个可能的答案。但是,这可能不是 OP 想要的。重点是:“随机”没有任何意义,除非您还指定了基础分布。
  • @Artefacto 我明白了!我可以看到这超出了我的数学知识方式(无论如何都接近于零:)
  • @Pekka 我给出了一个答案,以防他希望在一个范围内均匀分布数字。其他答案将产生更可能接近(总和)/(包裹数)的数字。

标签: php random


【解决方案1】:

这里的正确答案非常简单。

想象一条白线,假设有 1000 个单位长。

您想用红色标记将线条分成十部分。

非常简单,选择九个随机数字并在每个点上画一个红色标记。

就是这么简单。大功告成!

因此,算法是:

(1) 选择 0 到 1000 之间的九个随机数 (2) 将九个数字、一个零和一个 1000 放入一个数组中 (3) 对数组进行排序 (4) 用减法得到数组值之间的十个“距离”

你已经完成了。

(显然,如果您希望在最终集合中没有零,则在第 (1) 部分中,如果您遇到冲突,只需重新选择另一个随机数。)

理想情况下,作为程序员,我们可以在脑海中“看到”这样的视觉算法——无论我们做什么,都试着用视觉思考!


脚注 - 对于阅读本文的任何非程序员,为了清楚起见,请注意这就像“学习计算机科学时你学到的第一件事!”即我没有得到任何功劳,因为我偶然发现了这个页面,所以我只是输入了答案。不用夸我!

另一种常见的方法(取决于期望的结果,是处理实数还是整数,以及其他约束)也非常“啊哈!”优雅的。你所做的就是:获取 10 个随机数。把它们加起来。非常简单,只需:将它们全部乘以或除以某个数字,这样总和就是所需的总和!就是这么简单!

【讨论】:

  • +1 无疑是最好和最简单的答案; -0.9 吹嘘:P 仍然 +1。
  • 它可能很简单,但它确实不会生成均匀分布的数字...它偏向于大小为 1000/10 的数字(对于 1000 和 10 的总和)数字)。
  • Artefacto - 它绝对,绝对,生成统一的数字。可能是您在考虑算法时在头脑中犯了一个统一错误。如果您不相信,请尝试一些测试!
  • 我相信在这种方法下,每个元素中呈现的数字都有统一的机会成为特定值与任何其他元素的位置相比,但我不同意这是随机性的固有属性。请参阅下面的我的答案以获取其他信息。
【解决方案2】:

可能是这样的:

将剩余的最大数量设置为目标数量

循环 1 到你想要的值的数量 - 1

获取一个从0到剩余最大数量的随机数

将新的最大剩余量设置为旧的最大剩余量减去当前随机数

重复循环

你最终会得到一个“余数”,所以最后一个数字由剩余的任何东西决定,以构成原始总数。

【讨论】:

  • 好主意!比我的好。只有当你想要大约相同大小的“块”时,我的才更好。 +1
  • 我真的不明白你的意思。你能给我举个小例子吗?不需要精确,伪代码有效
  • 这不起作用。这是完全、完全、绝对、完全、100% 错误的。 (对不起!)您不会从中获得随机数。具体来说,您会得到一个从大到小的数字列表。完全不是随机的。在stackoverflow上看到完全错误的猜测真是太可惜了......如果有人在生产中使用它,他们就会被搞砸!
  • 不,只要您确保生成的数字在 0..(max / num_required) 范围内,这将起作用
  • 我现在看到这里的算法与我在答案中的算法相同 - 对此表示歉意。简而言之,@JoeBlow,我同意 Randy 的观点,即这是创建数字集的一种完全有效的方法。为了确保项目不会随时间平均减少,元素可以在创建后按顺序随机化。除此之外,随机性不是一个具体的概念,没有关于分布的更多信息。
【解决方案3】:

生成 10 个随机数,直到 10000 。 将它们从大到小排序:g0 到 g9

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

这将在整个范围内产生 10 个随机数,总和为 10000。

【讨论】:

  • 对不起,我不明白你的意思。
  • 这和@Joe Blow 解释得更有说服力的一样。
【解决方案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 与元素 2 有相同的机会成为数字 x,这意味着它必须偏向于大小为 Max/n 的数字。问题中没有明确说明 OP 是想要更可能地射击接近 Max 的单个元素还是想要均匀分布。 [道歉 - 从术语的角度来看,我不确定这是否会产生“均匀分布”,所以我只用外行的术语来指代它]

总而言之,说元素的“随机”列表必然均匀分布是不正确的。正如上面其他 cmets 所述,缺少的元素是所需的分布。

为了证明这一点,我提出了以下解决方案,其中包含随机分布模式的顺序随机数。如果第一个元素在 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

可能需要在创建这些元素后随机化它们的顺序,具体取决于它们的使用方式[否则,每个元素的平均大小会随着每次迭代而减小]。

【讨论】:

  • 正如 cmets 中详细解释的那样,当然,对于非数学家的绝对初学者提出的此类问题,最好不要解释“分布”。请注意,artefecto 已经这样做了,并且确实包含了指向相关 matlab 函数的链接。
【解决方案5】:

更新:@Joe Blow 给出了完美的答案。我的答案具有生成大致相同大小(或至少差异不大于(10000 / 10))的块的特殊功能,因此将其保留在适当的位置。

我想到的最简单和最快的方法是:

  • 将 10000 除以 10 并将值存储在数组中。 (价值10000的10倍)

  • 遍历 for 循环中的 10 个元素中的每一个。

  • 从每个元素中减去一个介于 (10000 / 10) 之间的随机数。

  • 将该数字添加到以下元素。

这将为您提供一些随机值,添加后将产生最终值(忽略浮点问题)。

应该很容易实现。

不过,您会在某个时候达到 PHP 的最大整数限制。不确定这可以在多大程度上用于价值接近 10 亿甚至更高的价值。

【讨论】:

  • 我想我知道你的意思,但我不确定。我会在此基础上尝试一些事情并报告。同时,我们将不胜感激任何额外的帮助。
  • @Joe Blow 好吧,这或多或少就是这些步骤的作用——它们为您提供的块的大小不会超过 (10000 / 10)。通过在调用随机化器时减少限制,可以使块的大小越来越相似。这不是 OP 要求的,所以微调这是另一天的问题
  • @JoeBlow 此答案顶部的黄色警告清楚地说明这不是最佳解决方案,因此我不会担心“有人以错误的方式使用它”并感到惊讶的情况。当你的回答是 +8 时,你的“你需要积分”这句话很搞笑 :)
  • 对我来说幸运的是,由于我的回答提供了始终小于 100 的第一块,飞机坠毁造成的伤亡人数一直保持在可接受的水平。
  • @JoeBlow 软件工程师会“冷静下来”,除非他们不是专业人士。黄色警告的哪一部分特别是错误的?当然不是那个说你的答案是最好的。也许你可以更有建设性。即使 Pekka 的解决方案与所讨论的问题不完全匹配,但它在某种程度上是相关的——并且通常会保留这样的答案——你无法预见究竟什么会对未来的读者有所帮助。
【解决方案6】:

相关:http://www.mathworks.cn/matlabcentral/newsreader/view_thread/141395

看到这个MATLAB package。它附带一个文件,其中包含实施背后的理论。

这个函数生成随机的、均匀分布的向量,x = [x1,x2,x3,...,xn]',它们有一个指定的和 s,我们有一个

这是实现(© 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

【讨论】:

  • 很简单的东西。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-14
  • 2017-07-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多