Rand7生成Rand10

·1774·4 分钟·
AI摘要: 本文介绍了如何使用数学原理和C++代码生成等概率的随机数。首先,通过数学公式$(randX() - 1) * Y + randY()$可以生成等概率的$[1, X * Y]$范围内的随机数。证明过程基于$randX()$和$randY()$分别生成$[1, X]$和$[1, Y]$之间的等概率随机数。联合概率表展示了如何从这些随机数中采样得到均匀分布的$[1, XY]$之间的随机数。接着,文章提供了使用C++编写的代码示例,演示了如何通过构造特定表达式来生成在指定范围内的均匀随机数。然而,这种方法效率较低,因为只有当采样到$[1, 10]$之间时才会停止,而$[11, 49]$之间的数会被丢弃。为了提高效率,文章提出了一种优化方法,通过模除操作将范围缩小到$[1, 10]$,并进一步优化为只采样$[41, 49]$之间的数,从而提高了效率。最后,文章还探讨了从进制的角度解决问题的方法,指出如果给定$rand1()$只能生成$[0, 1]$之间的均匀随机数,那么可以通过二进制编码的方式生成$[a, b]$之间的均匀随机数。

数学原理

数学定律:(randX()1)Y+randY()(randX() - 1) * Y + randY() 可以生成等概率的[1,XY][1, X * Y]范围内的随机数

证明:由于randX()randX()可以生成[1,X][1, X]之间的等概率随机数, randY()randY()可以生成[1,Y][1, Y]之间的等概率随机数

那么(randX()1)Y(randX() - 1)*Y可以在 [0,Y,2Y,3Y,...,(X1)Y][0, Y, 2Y, 3Y, ..., (X - 1)Y] 中随机采样 ,

因此(randX()1)Y+randY()(randX() - 1) * Y + randY()所构成的联合概率表为:

0Y2Y3Y...(X1)Y11Y+12Y+13Y+1...(X1)Y+122Y+22Y+23Y+2...(X1)Y+233Y+32Y+33Y+3...(X1)Y+3.....................YY2Y3Y4Y...XY \begin{matrix} & 0 & Y & 2Y & 3Y & ... & (X - 1)Y\\ 1 & 1 & Y+1 & 2Y+1 & 3Y+1 &...& (X- 1)Y + 1\\ 2 & 2 & Y+2 & 2Y+2 & 3Y+2 & ... & (X - 1)Y +2\\ 3 & 3 & Y+3 & 2Y+3 & 3Y+3 & ... & (X - 1)Y +3\\ ...& ...&...&...&...&...&...\\ Y & Y & 2Y & 3Y & 4Y & ... & XY\\ \end{matrix}

所以,从表中可以看到,能够均匀采样出[1,XY][1, XY]之间的随机数

代码

根据上面公式,如果想通过rand7rand7生成rand10rand10, 可以先构造出(rand71)7+rand7(rand7 - 1) * 7 + rand7, 这样就做到了在[1,49][1, 49]之间均匀随机采样

代码如下:




using namespace std;



int main() {

    while(1) {

        int rand_value = (rand7() - 1) * 7 + rand7();

        if(rand_value >= 1 && rand_value <= 10){

            cout << rand_value<< endl;

            break;

        }

    }

    return 0;

}

但是这种方法的效率偏低,因为只有采样到[1,10][1, 10]之间才结束,而[11,49][11, 49]之间的数都会被抛弃

进一步优化,[1,40][1, 40]之间都能够进行均匀随机采样,使用模除可以放缩到[1,10][1, 10]




using namespace std;



int main() {

    while(1) {

        int rand_value = (rand7() - 1) * 7 + rand7();

        if(rand_value >= 1 && rand_value <= 40){

            cout << rand_value % 10 << endl;

            break;

        }

    }

}

这样就只有[41,49][41, 49]之间的数被抛弃,效率会教上者更高

进制解法

上面的解法在于数学公式的证明和实用,另外一种解法是从进制的角度来思考

首先来看,如果给定rand1()rand1(), 只能生成 [0,1][0, 1]之间的均匀随机数,如何构造[a,b][a, b]的均匀随机数 ,这种情况就无法直接套上面的公式。

如果从二进制的角度来看,可以很容易生成[0,ba][0, b - a]之间的均匀随机数,因为可以对二进制的每一位采用rand1()rand1()随机函数。那么就可以很容易生成[a,b][a, b]之间的均匀随机数

现在将题目改成给定rand7()rand7(), 希望生成[1,10][1, 10]的均匀随机数,那么这就是用7进制来随机生成[0,10][0, 10]之间的数

Kaggle学习赛初探