百日算法 - 随机数的玩法
在计算机中,由于表示小数的变量是有范围的,所以小数是有限的,并不像数学中小数可以无限的抽象循序下去,而且计算机中,随机数出现的概率是相同的。
处于对 C++ 的青睐,所以后续的算法更多都是通过 C++语言进行编写的。
可以使用cstdlib头文件中的rand()函数来获得随机整数;
这个函数返回0~RAND_MAX之间的随机整数;
rand()函数生成的是伪随机数。即每次在同一个系统上执行这个函数的时候,rand()函数生成同一序列的数。
rand()函数的算法使用一个叫种子的值来控制生成数字。默认情况下,种子的值是1,。如果改变种子为不同值,随机数也会不同。(只要随机数种子不变,其生成的随机数序列就不会改变。)
可以使用cstdlib头文件中的srand(seed)函数来改变种子的值。为确保程序中每一次种子的值不同,可以使用time(0)作为种子,即srand(time(0))
对于 C++ 的随机数,在 《C++程序设计》一书中 有以上的解释
好清楚的基本的语法特性,我们就开始验证第一个理论。
在计算机中的随机数的出现的概率都是相同的
先定义一个获取随机数的方法,该方法中未进行种子的初始化
#include <iostream>
#include "RandomNumber.h"
using namespace std;
/**
* 获取范围是 0~1 随机数
* rand() 方法获取的随机数是 0 ~ 7FFF
* @return
*/
double RandomNumber::getMyRumber() {
return (double )rand()/RAND_MAX;
}
获取统计的数据结果
/**
* @author peggy
* @data 2023/2/15 15:32
*/
//
// Created by peggy on 2023/2/15.
//
#include <ctime>
#include <cstdlib>
#include "countRandom.h"
using namespace std;
double countRandom::getProbability(double limit) {
RandomNumber randomNumber;
//设置种子数
srand(time(0));
//统计符合提交出现的次数
double counts = 0;
for (int i = 0; i < RAND_MAX; ++i) {
if (randomNumber.getMyRumber() < limit)
counts++;
}
//出现的次数占总可能的大小
return (double) (counts / RAND_MAX);
}
测试
#include <iostream>
#include "random/countRandom.h"
using namespace std;
int main() {
countRandom Random;
double limit = 0.5;
double proBability = Random.getProbability(limit);
cout << "小于 "<<limit<<" 出现的概率" << proBability << endl;
}
小于 0.3 出现的概率0.306284
小于 0.5 出现的概率 0.501358
小于 0.9 出现的概率0.899564
小于 1 出现的概率0.999939
所以通过上面的分析可以得出,每个随机数的分布的概率都是等比例的
从上面也可以看出,其实哈,我们的随机数出现的概率是一条 y=x 直线,那么如果我们要讲概率改变为 y=x^2 变为一个曲线,那么我们该怎么处理呢?
首先分析一下 ,由于我们知道,产生的随机数,出现的概率都是相同的,我们要让出现的概率翻倍。
也就是说假设,我们要从篮子里取出一堆有编号的球(编号从1~10),而这些球的编号都是唯一的,那么取出的球的概率也是相同的。现在有两个相同规格的篮子与球,我们先划定一个界限为小于等于 8,那么随机拿出一个球,在同一个篮子中的概率就是 4/5。
现在规则改变,分别从1 号篮子与 2 号篮子摸一个球,并且要球是大于 5 的那么,1号篮子的概率是 1/2 ,2 号篮子的概率也是 1/2 。那么取这两个球中的最大一个球的编号,然后与 5 进行比较,此时获取到的编号大于 5 的概率是多少呢?
这个相当于你抽奖,抽了两次,但是你两次对比的界限是没有改变的。
所以两次抽奖或者两次摸球的事件是完全独立的,但是你中奖的几率却由原来的概率进行了翻倍,对于上面的案例来说,你摸了两次,那么摸中大于 5 的概率,就有原先独立事件的 1/2 改变,变为了 (1/2)^2 = 1/4 ,相比如摸中大于 8 的概率 (1/5)^2=1/25。
所以根据上述的结论,编写代码即可得到符合 F(x)=x^2 的随机数
#include <iostream>
#include "random/countRandom.h"
#include "random/RandomNumberToFunction.h"
using namespace std;
int main() {
countRandom Random;
double limit = 0.9;
double proBability2 = Random.getProbabilityTo2(limit);
cout << "小于 " << limit << " 出现的概率 " << proBability2 << endl;
cout << "计算的概率 " << limit * limit << endl;
}
/**
* @author peggy
* @data 2023/2/15 15:32
*/
//
// Created by peggy on 2023/2/15.
//
#include <ctime>
#include <cstdlib>
#include "countRandom.h"
#include "RandomNumberToFunction.h"
using namespace std;
struct RandomNumberToFunction randomNumberToFunction;
double countRandom::getProbabilityTo2(double limit) {
double counts = 0;
for (int i = 0; i < RAND_MAX; ++i) {
double num = randomNumberToFunction.getMAXRandom();
if (num < limit)
counts++;
}
return (double) (counts / RAND_MAX);
}
/**
* @author peggy
* @data 2023/2/15 20:23
*/
//
// Created by peggy on 2023/2/15.
//
#include "RandomNumberToFunction.h"
#include "DataUtils.h"
/**
* 将获取的随机数转化为 y=x^2
* @return
*/
struct RandomNumber randomNumber;
struct DataUtils dataUtils;
double RandomNumberToFunction::toRandomFunction() {
return this->getMAXRandom();
}
double RandomNumberToFunction::getMAXRandom() {
return dataUtils.getMAX(randomNumber.getMyRumber(),randomNumber.getMyRumber());
}
/**
* @author peggy
* @data 2023/2/15 15:13
*/
//
// Created by peggy on 2023/2/15.
//
#include <iostream>
#include "RandomNumber.h"
using namespace std;
/**
* 获取范围是 0~1 随机数
* rand() 方法获取的随机数是 0 ~ 7FFF
* @return
*/
double RandomNumber::getMyRumber() {
return (double )rand()/RAND_MAX;
}
最终运行结果
大于 0.9 出现的概率 0.808496 计算的概率 0.81
Process finished with exit code 0
当然通过上面的的案例,所以很容易的可以得出,如果要让其概率变为原来的 X^3 , 那么只需要进行三次的 getMAX(randomNumber.getMyRumber(),getMAX(randomNumber.getMyRumber(),randomNumber.getMyRumber()));即可,这里就不在赘述演示了。
那么有没有好奇过,这里如果不是 getMAX(),获取的最大值而是最小值 getMIN() 呢?那么获取的概率代表的什么呢?
其实这个也是比较好推导的,首先 getMIN() 获取的一定是最小值,那么对于 ( 0 ,X ] 而言,如果 getMIN()获取的值比 X 还要大,那么肯定是可以保证 ,另一个随机数也是比 X 还要大的,所以就是数必定是落在了 [ X , 1 ),那么这个获取的最终概率就是 [ X , 1 ) 的概率也就是 (1-X)^2,那么对于 ( 0,X ] 的概率就变成了 1-(1-X)^2
为了验证这个结论猜想,我们只需修改两点,代码修改如下。
#include <iostream>
#include "random/countRandom.h"
#include "random/RandomNumberToFunction.h"
using namespace std;
int main() {
countRandom Random;
double limit = 0.3;
double proBability2 = Random.getProbabilityTo2(limit);
cout << "小于 " << limit << " 出现的概率 " << proBability2 << endl;
cout << "计算的概率 " << 1 - (1 - limit) * (1 - limit) << endl;
}
/**
* @author peggy
* @data 2023/2/15 20:23
*/
//
// Created by peggy on 2023/2/15.
//
#include "RandomNumberToFunction.h"
#include "DataUtils.h"
/**
* 将获取的随机数转化为 y=x^2
* @return
*/
struct RandomNumber randomNumber;
struct DataUtils dataUtils;
double RandomNumberToFunction::toRandomFunction() {
return this->getMAXRandom();
}
double RandomNumberToFunction::getMAXRandom() {
return dataUtils.getMIX(randomNumber.getMyRumber(),randomNumber.getMyRumber());
}
/**
* @author peggy
* @data 2023/2/15 20:19
*/
//
// Created by peggy on 2023/2/15.
//
#include "DataUtils.h"
double DataUtils::getMAX(double num1, double num2) {
return num1 > num2 ? num1 : num2;
}
double DataUtils::getMIX(double num1, double num2) {
return num1 < num2 ? num1 : num2;
}
输出结果:
小于 0.3 出现的概率 0.505234 计算的概率 0.51
Process finished with exit code 0
小于 0.8 出现的概率 0.959685 计算的概率 0.96
Process finished with exit code 0
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 4 天