分多次累计随机出某指定整数(多次随机整数,其和固定)的方法

本文探讨了一种通过多次随机生成整数,并确保这些整数的累计和等于预设特定值的方法。这种方法涉及到随机数生成、概率论和算法设计,对于编程中的各种随机场景具有实用价值。
摘要由CSDN通过智能技术生成
分多次累计随机出某指定整数(多次随机整数,其和固定)的方法
Spads
Shane Loo Li

本文分为 5 个部分
---------- ---------- ---------- ----------
1、提出问题
2、解法程序
3、测试结果
4、测试程序
5、公式证明


【提出问题】
---------- ---------- ---------- ----------
有 n 次机会,每次随机一个整数。希望这 n 个整数之和是 m ;该怎么随机呢?

对于编程语言,惯例是提供了随机函数 r() ,得到 [0, 1) 之间的一个随机浮点数。所以从编程角度来说,随机一个整数,最常见的方式就是通过对 L * r() 向下取整来获取某一个范围内的整数。以上问题就转变成为了,如何获得合适的 L ,来满足 n 次随机的整数之和为 m 。

传统的做法,就是用 2 * m / n 来做这个 L 。问题是因为取整这个操作,让这种算法会产生比较大的误差。具体误差有多大,下边测试结果一栏会详细描述。


【解法程序】 —— 以 Java 程序为例

---------- ---------- ---------- ----------

/**
 * <b>获取总量固定多次随机的倍率</b><br/>
 * 当程序需要通过一定次数随机,每次随机一个整数,最终获取总和一定的值,
 * 可通过此方法获得随机倍率。<br/>
 * 在获取此倍率 <code>randomLimit</code> 之后,每次随机时通过
 * <code>(int) (new Random().nextDouble() * randomLimit)</code> 获得随机
 * 结果。<br/><br/>
 * 本方法的核心算法,基于证明了如下二个关系式:
 * <pre>
 * (int) (2 * totalNum / chanceCount) + 1 < randomLimit
 * (int) (2 * totalNum / chanceCount) + 2 > randomLimit
 * </pre>
 * 具体推算方法,请见 Spads 的 Shane Loo Li 发表的日志。<br/>
 * http://blog.csdn.net/shanelooli/article/details/10831811
 * @param	totalNum	最终希望各随机值相加后的总量
 * @param	chanceCount	随机次数
 * @return	每次随机,[0, 1) 标准随机值应该乘以的倍率
 */
static public double getRandomLimit(int totalNum, int chanceCount)
{
	double calculateBase = 2.0 * totalNum / chanceCount;
	int calculateBaseInt = (int) calculateBase;
	double randomLimit = (calculateBaseInt + 2) * (calculateBaseInt + 1)
			/ (2 * calculateBaseInt - calculateBase + 2);
	return randomLimit;
}


【测试结果】
---------- ---------- ---------- ----------
目标总和为 5000000

随机次数 20000
简易方法: 实际随机数的总和 = 4993051, 误差 = 0.1389%
Spads Shane的新方法: 实际随机数的总和 = 4997315, 误差 = 0.0537%

随机次数 50000
简易方法: 实际随机数的总和 = 4946686, 误差 = 1.10661%
Spads Shane的新方法:
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值