算法-使用randn()实现randm()的套路

这篇博客探讨了如何通过数学方法将rand3()函数转换为rand7(),确保每个位置的概率相等。核心步骤包括调整rand3()的范围、扩大间隙和求余操作。该方法同样适用于更复杂的随机数转换,如从rand5()到rand7()。通过不断试错和概率分析,作者提供了一个通用的解决策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如何利用一个randn()【表示得到从1到n的随机数】改造为一个randm()的函数?

rand()函数要求的是每个位置出现等概率。

首先会想到使用 乘 + if判断的解法,以rand3实现rand7为例:

while(true) {
    int s = rand3() * 3 - 2; //因为原数至少为2,所以不满足条件,需要减掉2
    return s;
}

乍一看,确实只会返回1到7的整数,

但是假设原来rand3()获取每个位置的概率是1/3,这现在获取1的概率必须要三次都取得1,即(1/3)^3

而要取得4【即三个整数和为6】,可以是2 2 2,也可以是1 2 3的任何一种排列(共6种),即取得4的概率是取得1概率的7倍,这显然不符合每个位置取得概率相同的定义。

解题方法

(1)将srand = rand3() - 1,使得变成0, 1, 2随机取;

(2)将srand 扩大到刚好容纳一个rand3() - 1的程度,即扩大三倍

(3)将srand * 3 + rand3() - 1

(4)筛选结果,若在0 ~ 6中, + 1返回;否则再来一次

public int rand3_To_rand7() {
        while (true) {
            int srand = (rand3() - 1) * 3;
            int sum = srand + rand3() - 1;
            if (sum >= 7) { //模板:保證每個7都出現相同的概率,即8,9的存在會使得1,2概率上升。
                continue;
            } else {
                return sum + 1; //對七取余会导致得不到7,需要整体右移一位
            }
        }
    }

分析:

将srand扩大三倍,会随机生成0 3 6这三个数,每个未知的空位刚好为3(空位需要带上自己)

对其随机加上0 1 2,就会使得出现res: 0 1 2 3 4 5 6 7 8的概率相等

当res >= 7时,说明超过了0 ~ 6 七个数的范围,剔除。

返回res + 1


对于其他复杂一点的情况,只需适当求余即可,如rand5()实现rand7():

 public int rand5_To_rand7(){
        while (true) {
            int srand = rand5() - 1;
            int s = srand * 5;
            int sum = s + rand5() - 1;
            if (sum >= 21) {
                continue;
            } else {
                return sum % 7 + 1;
            }
        }
    }

总结:

关键步骤是扩大间隙,要扩大到刚好可以装得下n - 1个数的位置即可。

在返回时,确定范围必须满足所求随机数的最大值的整数倍,使得取得每个位置概率相等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值