C++ 随机数实现
一、随机数函数
rand() 函数
在 C++ 中可以用 rand() 函数来产生一个 0~RAND_MAX 之间的'伪随机数'。
需要导入一个库:
#include <cstdlib>
- 什么是 RAND_MAX:
它一般是个定值,且大小不可修改,它的大小取决于你的编译器和操作系统,如 Linux 最大可到 2147483647 而 Windows 可能只有 32767 这么小。
可以用如下语句查看:
cout << RAND_MAX << endl;
- 为什么是'伪随机数'呢?
原因是真正的'真随机数'在计算机中是不存在的,随机数算法也是数学公式写的(具体原理可参考相关资料)。
所以这就会导致一个问题:
当在同一个编译器中执行 rand() 语句时都会得到同一套随机数。
为了避免这种情况,可以使用 srand() 初始化随机数种子。
srand() 函数
需要先导入:#include <ctime>
需要随机数的程序一般都需要在最开始执行一次 srand((unsigned)time(NULL)), (time(NULL) 返回自 UTC 时间 1970 年 1 月 1 日 0 点以来的秒数),它的作用是初始化随机数种子,当这种种子不一样时就能产生不同的一套随机数。
要注意,srand() 函数只需要在主函数调用一次,否则可能会生成同一套随机数。
二、算法实现
1、生成 0~n 之间的随机数(包括 0 和 n):
可以用 rand()%(n+1) 来实现
int randint(int n){ return (rand()%(n+1)); }
但是这一方法有个漏洞,那就是如果当 n 大于 RAND_MAX 时,就不能得到期望的结果,在 windows 中尤为明显。
通过 rand()%n 获得区间 [0,n-1] 的随机数有很大局限性,要保证 n 小于 RAND_MAX
2、生成 0~n 之间的随机数(包括 n 和 0):
为了解决上面的问题,可以先执行 rand() 后再除以 RAND_MAX,获得 01 之间的随机实数(因为 RAND_MAX 永远大于 rand() 的返回值),然后扩大 n 倍后四舍五入,获得 [0n] 之间的均匀整数。(虽然在 n 很大时精度不好,但对于普通的应用已经足够了)
long long randint_no_max(long long n){//产生 0~n 之间的随机数(包括 n 和 0),n 可大于 RAND_MAX
double base=((double)rand())/RAND_MAX;//产生 0~1 之间的随机实数;
long long res=((double)n*base+0.5);//再把上面的实数扩大 n 倍并四舍五入
return res;
}
另外,如果想要更高的精度,可以采取多次随机的方法。
可以通过 rand()/RAND_MAX 获得 [0,n] 间的随机实数后再乘 n 获得 [0~n] 间的均匀整数
3、生成 n~m 之间的随机数(包括 n 和 m):
解决的思路其实很简单,先生成 0~m-n 之间的随机数然后再加上 n 即可:
int randint_range(int n,int m){//产生 n~m 间的随机数(包括 m 和 n)
double base=((double)rand())/RAND_MAX;
int res=n+(base*(double)(m-n+1));
return res;
}
最终总结一下:(a,b 均小于等于 RAND_MAX)
(a,b) = (rand()%(b-a+1))+a-1
[a,b) = (rand()%(b-a))+a
(a,b] = (rand()%(b-a))+a+1
[a,b] = (rand()%(b-a+1))+a
三、程序实例
#include<iostream>
#include<cstdlib>
#include<ctime>
const int MAXN=214748364;
using namespace std;
int a[MAXN];
void fill_randint(int a[],int cnt){//插入 cnt 个随机数到数组 a
for(int i=1;i<=cnt;i++){
a[i]=rand();
}
}
int randint(int n){//产生 0~n 之间的随机数 (包括 n 和 0),注意 n<=RAND_MAX 才有意义
return (rand()%(n+1));
}
long long randint_no_max(long long n){//产生 0~n 之间的随机数(包括 n 和 0),n 可大于 RAND_MAX
double base=((double)rand())/RAND_MAX;//产生 0~1 之间的随机实数;
long long res=((double)n*base+0.5);//再把上面的实数扩大 n 倍并四舍五入
return res;
}
int randint_range(int n,int m){//产生 n~m 间的随机数(包括 m 和 n)
double base=((double)rand())/RAND_MAX;
int res=n+(base*(double)(m-n+1));
return res;
}
int main(){
//初始化随机数种子
srand((unsigned)time(NULL));
//每个编译器或系统可能有不同的 RAND_MAX:
cout<<"RAND_MAX: "<<RAND_MAX<<endl;
fill_randint(a,100000);
cout<<a[100]<<' '<<a[101]<<endl;
cout<<"0~n(n<=RAND_MAX): "<<randint(10)<<endl;
cout<<"0~n(n can be any integer): "<<randint_no_max(2147483647)<<endl;
cout<<"n~m(include n and m): "<<randint_range(32767,100000)<<endl;
return 0;
}
