生成一定范围内的 N 个随机数,其总和为常数

2024-07-01

我想生成从 [a,b] 之间的特定分布(例如均匀随机)抽取的 N 个随机数,其总和为常数 C。我尝试了一些我自己能想到的解决方案,以及在类似线程上提出的一些解决方案,但是他们中的大多数要么适用于有限形式的问题,要么我无法证明结果仍然遵循所需的分布。

我尝试过的: 生成 N 个随机数,将它们全部除以它们的总和,然后乘以所需的常数。这似乎有效,但结果不遵循数字应在 [a:b] 范围内的规则。

生成 N-1 个随机数加上 0 和所需的常数 C 并对它们进行排序。然后计算每两个连续数字之间的差,差值就是结果。这再次求和为 C,但与上一个方法有相同的问题(范围可能大于 [a:b]。

我还尝试生成随机数,并始终以保留所需总和和范围的方式跟踪最小值和最大值,并得出以下代码:

bool generate(function<int(int, int)> randomGenerator,
              int min, int max, int len, int sum,
              std::vector<int> &output) {
    /**
     * Not possible to produce such a sequence
     */
    if (min * len > sum)
        return false;
    if (max * len < sum)
        return false;

    int curSum = 0;
    int left = sum - curSum;
    int leftIndexes = len - 1;
    int curMax = left - leftIndexes*min;
    int curMin = left - leftIndexes*max;

    for (int i = 0; i < len; i++) {
        int num = randomGenerator((curMin < min) ? min : curMin,
                                  (curMax > max) ? max : curMax);
        output.push_back(num);
        curSum += num;
        left = sum - curSum;
        leftIndexes--;
        curMax = left - leftIndexes * min;
        curMin = left - leftIndexes * max;
    }

    return true;
}

这似乎有效,但结果有时非常倾斜,我认为它不遵循原始分布(例如均匀分布)。例如:

//10 numbers within [1:10] which sum to 50:
generate(uniform, 1, 10, 10, 50, output);
//result:
2,7,2,5,2,10,5,8,4,5 => sum=50
//This looks reasonable for uniform, but let's change to 
//10 numbers within [1:25] which sum to 50:
generate(uniform, 1, 25, 10, 50, output);
//result:
24,12,6,2,1,1,1,1,1,1 => sum= 50

注意输出中存在多少个。这听起来可能很合理,因为范围更大。但它们看起来确实不像均匀分布。 我不确定即使有可能实现我想要的目标,也许限制使问题无法解决。


如果您希望样本遵循均匀分布,则问题可以简化为生成总和 = 1 的 N 个随机数。这又是狄利克雷分布的特殊情况,但也可以使用指数分布更轻松地计算。具体方法如下:

  1. Take a uniform sample v1 … vN with all vi between 0 and 1.
  2. For all i, 1<=i<=N, define ui := -ln vi (notice that ui > 0).
  3. Normalize the ui as pi := ui/s where s is the sum u1+...+uN.

The p1..pN are uniformly distributed (in the simplex of dim N-1) and their sum is 1.

You can now multiply these pi by the constant C you want and translate them by summing some other constant A like this

qi := A + pi*C.

EDIT 3

为了解决评论中提出的一些问题,让我补充以下内容:

  • To ensure that the final random sequence falls in the interval [a,b] choose the constants A and C above as A := a and C := b-a, i.e., take qi = a + pi*(b-a). Since pi is in the range (0,1) all qi will be in the range [a,b].
  • One cannot take the (negative) logarithm -ln(vi) if vi happens to be 0 because ln() is not defined at 0. The probability of such an event is extremely low. However, in order to ensure that no error is signaled the generation of v1 ... vN in item 1 above must treat any occurrence of 0 in a special way: consider -ln(0) as +infinity (remember: ln(x) -> -infinity when x->0). Thus the sum s = +infinity, which means that pi = 1 and all other pj = 0. Without this convention the sequence (0...1...0) would never be generated (many thanks to @Severin Pappadeux for this interesting remark.)
  • 正如中所解释的问题附带的第四条评论作者:@Neil Slater 从逻辑上讲,不可能满足原始框架的所有要求。因此,任何解决方案都必须放宽对原始解决方案的适当子集的约束。 @Behrooz 的其他评论似乎证实在这种情况下这就足够了。

EDIT 2

评论中又提出了一个问题:

为什么重新调整统一样本是不够的?

换句话说,我为什么要费心去取负对数呢?

原因是,如果我们只是重新缩放,那么生成的样本将不会均匀分布在段 (0,1)(或最终样本的 [a,b])上。

To visualize this let's think 2D, i.e., let's consider the case N=2. A uniform sample (v1,v2) corresponds to a random point in the square with origin (0,0) and corner (1,1). Now, when we normalize such a point dividing it by the sum s=v1+v2 what we are doing is projecting the point onto the diagonal as shown in the picture (keep in mind that the diagonal is the line x + y = 1):

但考虑到绿色线(更接近从 (0,0) 到 (1,1) 的主对角线)比橙色线(更接近 x 轴和 y 轴)长,因此投影往往会在投影线的中心(蓝色),缩放后的样本所在的位置。这表明简单的缩放不会在所描绘的对角线上产生均匀的样本。另一方面,可以从数学上证明负对数确实会产生所需的均匀性。因此,我不会复制粘贴数学证明,而是邀请每个人都实现这两种算法,并检查生成的图是否如该答案所描述的那样。

(Note: here http://www.caesarsystems.com/blog/capabilities/probabilistic-splits/#.VQ7HCVwayJU是关于这个有趣主题的博客文章以及在石油和天然气行业的应用)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

生成一定范围内的 N 个随机数,其总和为常数 的相关文章

随机推荐

  • 使用硬件键盘时 Android TabHost 选项卡会窃取焦点

    我目前有一个TabHost包含 4 个选项卡 在一些片段上我们有一些EditText布局内的视图 我们注意到 当您尝试输入任何内容时EditText使用硬件键盘的视图 焦点被窃取EditText并赋予当前活动选项卡TabHost 这只发生在
  • 如何生成唯一的DICOM UID?

    我正在研究 DICOM 门控 PET 数据 我想人为地创建一个包含门控数据的 DICOM 图像系列 我正在查询 SOPInstanceUID 的增量值 它标记每个阶段或门中的每个图像切片 这些对于门中的每个切片都有不同的值 并且在门之间递增
  • 谷歌地图如何将图像添加到InfoWindow中

    您好 我正在尝试将图像添加到谷歌地图信息窗口中 我的代码就像这样的脚本 var ContactUs function return main function to initiate the module init function var
  • 如何在 WinRT 中从 C++ 获取堆栈跟踪?

    我需要从 C 应用程序获取堆栈跟踪 并将其序列化为字符串 以便稍后解析 我在 Windows 上听说过的唯一 API 是 StackWalk64 它似乎不受支持 如何在 Windows 应用商店应用程序中从 C 获取堆栈跟踪 我能够调试复杂
  • 为什么 (false || null) 返回 null,而 (null || false) 返回 false?

    为什么false null返回与以下不同的结果null false 我可以安全地依靠吗return myVar false如果 myVar 是其中之一 则返回 falsenull or false but true否则 所有组合 false
  • 如何在Azure函数应用程序中调用函数后动态更改内容

    我正在使用 Visual Studio 2019 使用 Azure function v3 0 开发 Azure function 应用程序 我实现了一个时间触发的功能 我想更改内容 时间表 function json function j
  • 与选择顶部相反

    Transact SQL 有一个方便的SELECT TOP 4 whatever FROM 我想做一个 SELECT 查询 返回表中的最后 n 个条目 而不是第一个条目 这是我用来返回在表中输入的前四个项目的查询 使用 SELECT TOP
  • 不可能的? HTML 鼠标悬停边框颜色随边框折叠而变化?

    我希望有一个表格 其中所有边框 内部 外部 的宽度都是单个像素 我通过设置来实现这一点border collapse桌子上的风格 那么我希望onmouseover每个 TD 单元 改变border color为不同的颜色 如果表格边框尚未折
  • 无法获得正确的程序集过滤器来使用 TeamCity 8 和 dotCover 代码覆盖率

    我已经配置了一个 Nunit 测试运行程序构建步骤 该步骤成功运行我的测试套件 指向我的 Net 解决方案的测试子项目 例如 解决方案 Solution Test bin debug Solution Test dll 我的解决方案结构如下
  • 如何通过 CLI/Ruby 系统调用捆绑安装?

    是否可以通过 ruby 系统调用运行捆绑安装 我正在尝试安装 gems 并在另一个路径下运行项目测试 例如命令是 cd some other project bundle install gem list rspec spec 理想情况下
  • 如何获取与 PostgreSQL 中的视图或表关联的触发器

    我有一个要求 即我必须获取与给定表 视图关联的触发器列表 谁能帮我找到 PostgreSQL 中表的触发器 这将返回您想知道的所有详细信息 select from information schema triggers 或者如果您想对特定表
  • java.io.IOException:服务发现失败

    我正在开发一个 Android 应用程序 在两部配对的智能手机之间使用蓝牙连接 蓝牙逻辑基于著名的BluetoothChat SDK示例 管理服务器线程的 服务 类accept 一个客户端线程connect 和一个用于在套接字上读 写的线程
  • 如何在 Google 地图 v3 中的每个标记上添加编号?

    我想问大家如何使用 JavaScript 在 Google 地图 v3 中的每个标记上动态添加数字 例如 第一个标记是 1 第二个标记是 2 等等 在这种情况下 我的位置数据如下 new google maps LatLng 1 3667
  • 使用 ThreadCount TestNG 限制并行测试的数量

    我在这里很头疼 我不知道如何处理这个问题 我有几个通过 xml 运行的测试类 约90个测试班 每个班约10 Test进入其中 我配置了一个硒网格 带有maxSession 5因此 单个节点上最多可以并行运行 5 个并行浏览器实例 这是我不明
  • 重新编译asp.net网站时如何重新启动IIS站点

    添加到 Asp net 项目的构建 编译脚本中以启动 IIS 在 DLL 重建上重新启动网站而不是对网站的第一个请求的最佳方法是什么 当前流程 编译工程 Wait 点击 ASPX 页面 IIS 开始重新加载 Wait 页面加载 理想流程 编
  • 在 Bootstrap 中的悬停中打开折叠选项卡

    我在 Bootstrap 中有折叠面板 单击选项卡标题即可打开该面板 我试图弄清楚如何使用鼠标悬停在选项卡的总宽度上来打开 但我没有得到它 下面是默认关闭的单个选项卡的代码 div class panel panel default sty
  • 关于ListView中ViewHolder模式实现优化

    因此 众所周知的 ViewHolder 模式通常看起来像 ListAdapter Override public View getView final int position View convertView final ViewGrou
  • Android 三星 S I9000 屏幕尺寸和密度问题

    我在 Samsung S I9000 上使用应用程序时遇到问题 我的应用程序上的按钮比应有的大得多 此外 系统选择 res values small 作为值的来源 总而言之 它的表现就好像该设备有一个非常小的屏幕 尽管它应该是 800x48
  • Bootstrap 样式不适用于 Angular2 组件

    Bootstrap 样式不适用于 Angular2 组件 在以下 Angular2 组件中 它不能作为 ui 中的引导流体容器工作 如果我在带有 div 元素的组件内使用 container fluid 则会在作品中出现 例如 不工作 Co
  • 生成一定范围内的 N 个随机数,其总和为常数

    我想生成从 a b 之间的特定分布 例如均匀随机 抽取的 N 个随机数 其总和为常数 C 我尝试了一些我自己能想到的解决方案 以及在类似线程上提出的一些解决方案 但是他们中的大多数要么适用于有限形式的问题 要么我无法证明结果仍然遵循所需的分