Algorithm 将数字表示为0..maxSummand中N个数字的均匀随机和

Algorithm 将数字表示为0..maxSummand中N个数字的均匀随机和,algorithm,random,Algorithm,Random,可以有无限种方式将正数表示为numberofsummandpositive summand的总和,每个总和不超过maxSummand。我需要一种方法来为给定的sum、numberOfSummands和maxSummand大致统一地生成其中一种表示,即,任何可能的N个summands列表都可以以大致相等的概率返回(只要双浮点精度允许) 例如: asSummands(sum = 41.0, numberOfSummands = 3, maxSummand = 22.0, prng = somePRN

可以有无限种方式将正数表示为
numberofsummand
positive summand的总和,每个总和不超过
maxSummand
。我需要一种方法来为给定的
sum
numberOfSummands
maxSummand
大致统一地生成其中一种表示,即,任何可能的N个summands列表都可以以大致相等的概率返回(只要双浮点精度允许)

例如:

asSummands(sum = 41.0, numberOfSummands = 3, maxSummand = 22.0, prng = somePRNG())
可以返回:

[18.3, 5.8, 16.9]
(在实际生成的列表中,点后面肯定会有更多的数字。)

我可以忽略这样一个事实,即不可能使用某些求和函数达到某个求和函数(例如,如果
maxSummand
为2.0,则无法使用4个求和函数达到10.0的求和函数),假设从未使用此类参数调用算法

我还假设PRNG统一生成数字

我只能想出一个远非统一的解决方案:


将总和切分为
numberOfSummands
equal summands,挑选其中的几对,并为每一对,将一个随机数从一个对元素转移到另一个元素,这样总的总和就不会改变,然后将总和洗牌。它适用于偶数个求和数,我可以修改它以适用于奇数个求和数,但解决方案感觉相当愚蠢,我觉得可能有一种更自然的方法。

好的,您可能可以使用Dirichlet分布,link。在最简单的形式中,当所有<代码> a <代码>设置为1时,它将生成一致的席,使得它们在0…1中都是一致的,并且所有的

S X_i = 1
基本上,您只需通过
41
重新缩放示例,您就在这里

但是!你有附加条件,使得任何席的数量小于某个阈值(22/41,在你的情况下约0.54)


最有可能的情况是,如果总和中没有很多项,您可以在Dirichlet采样的基础上应用接受/拒绝:对点集进行采样,如果任何点小于阈值,则接受该点集。

更新以包括
maxSummand
限制

对于需要求和为x的
n
数字的一般情况:

  • 生成介于0和1之间的
    n
    数字
  • 把它们加起来
  • 将每个数字除以总和。您现在拥有的
    n
    数字总和为1.0
  • 将每个数字乘以
    x
  • 如果对最大和有限制,可以修改算法,如下所示:

  • 生成介于0和maxSummand之间的
    n
    数字
  • 求和,给出
    Sum
  • x
    (您的目标总和)除以
    sum
    ,得到
    比例
  • 将生成的每个数字乘以
    比例

  • 您现在拥有的
    n
    数字总和为
    x
    ,并且没有任何数字超过
    maxSummand

    (请注意其他潜在的投票人:关于生成一个特定数字的总和有很多问题,但我看到的那些问题在总和上没有上界,这使得问题变得不同和困难。)你如何定义“一致随机”呢这里?还有,你是专门说任意实数作为分裂,还是仅仅是整数,或者仅仅是达到固定精度水平的实数?@templatetypedef除了求和数和PRNG之外的每个参数都是实数。通过“一致随机”我的意思是,所有可能的结果都应该具有相同的概率。这不是这个问题所涉及的,它所描述的问题不同于“得到n个和x之和的随机数”@Suseika:事实上,这是一个额外的限制,即任何数字都不能超过
    maxSummand
    。我将修改我的答案以包含该限制。它不会在0..maxSummand中生成数字,而是在0..maxSummand*scale中生成随机数@苏塞卡:没错。我这方面的假设很愚蠢。我得好好考虑一下。