概述
C++ 使用rand函数生成大随机数的较佳方法
- 较佳方法
- 一些其它方法的问题:
较佳方法
Rand()函数能生成[0,32767]间的随机整数,相当于15个随机的二进制位。
若需生成更大的整数,最佳方案应该是进行两次 rand(),将两次rand()的值按二进制位拼接起来。
big_randnum = (rand()<<15) + rand();
our_number=big_random%1000000;
此处<<为二进制左移运算,末位补0。第一次rand得到前15个二进制位,第二次rand得到后15个二进制位,用加法拼接得到30个二进制位,即范围为
[
0
,
2
30
−
1
]
=
[
0
,
1073741823
]
[0,2^{30}-1]=[0,1073741823]
[0,230−1]=[0,1073741823]的大随机数。
其数学本质为:
大
随
机
数
=
第
一
次
r
a
n
d
(
)
值
×
32768
+
第
二
次
r
a
n
d
(
)
值
大随机数=第一次rand()值times32768+第二次rand()值
大随机数=第一次rand()值×32768+第二次rand()值
r
a
n
d
(
)
∈
[
0
,
32767
]
rand()in[0,32767]
rand()∈[0,32767]
∴
大
随
机
数
∈
[
0
,
1073741823
]
且
分
布
均
匀
therefore大随机数in[0,1073741823]且分布均匀
∴大随机数∈[0,1073741823]且分布均匀
然后把取得的大随机数 对 实际需要的范围 取膜、调整即可。
可以发现,比如我们实际运用中需要的范围是
[
0
,
9999
]
[0,9999]
[0,9999],而我们用rand()%10000来生成,就会导致概率不均:
r
a
n
d
(
)
∈
[
0
,
32767
]
rand()in[0,32767]
rand()∈[0,32767]
[
0
,
32767
]
=
[
0
,
9999
]
∪
[
10000
,
19999
]
∪
[
20000
,
29999
]
∪
[
30000
,
32767
]
[0,32767]=[0,9999]cup[10000,19999]cup[20000,29999]cup[30000,32767]
[0,32767]=[0,9999]∪[10000,19999]∪[20000,29999]∪[30000,32767]
∴
P
(
[
0
,
2767
]
)
>
P
(
[
2768
,
9999
]
)
therefore P([0,2767])gt P([2768,9999])
∴P([0,2767])>P([2768,9999])
令我们想要的范围为
[
0
,
N
]
[0,N]
[0,N],当N远小于RAND_MAX的时候,比如[0,233]时,这种不均可以忽略。但比如范围达到[0,10000]时,概率就很不均匀了,使用本文上述的生成大随机数的方法,用更大的随机数对想要取的范围取膜,会使分布更加均匀,提高随机数的质量。
当然另一个思路是用判断语句强行舍弃赘余的部分,若发现取得的值在赘余部分就舍弃,能保证概率绝对均匀,其实对程序速度影响也不大(常数级别)但会令强迫症极度不爽。我们拼接成大数能减少赘余部分占比,因为也能优化这种舍弃赘余的思路。
很明显,这种方法还可以无限拼接扩展:
superbig_randnum=(rand()<<30) + (rand()<<15) + rand();
veryverysuperbig_randnum=(rand()<<45) + (rand()<<30) + (rand()<<15) + rand();
// 依次类推
s
u
p
e
r
b
i
g
r
a
n
d
n
u
m
∈
[
0
,
2
45
−
1
]
=
[
0
,
35184372088831
]
superbigrandnumin[0,2^{45}-1]=[0,35184372088831]
superbigrandnum∈[0,245−1]=[0,35184372088831]
v
e
r
y
v
e
r
y
s
u
p
e
r
b
i
g
r
a
n
d
n
u
m
∈
[
0
,
2
60
−
1
]
=
[
0
,
1152921504606846975
]
veryverysuperbigrandnumin[0,2^{60}-1]=[0,1152921504606846975]
veryverysuperbigrandnum∈[0,260−1]=[0,1152921504606846975]
亦可与高精度运算技巧结合使用。
一些其它方法的问题:
(int) ((double)rand() / RAND_MAX) * 1000000;
这样能保证分布大体均匀,但[0,1000000]之间很多数会是取不到的。
RAND_MAX为C++内置常量,值为32767,表示rand()函数能取到的最大值。1000000乘1/32767约等于31,明显27、28、29这些数字是永远随机不出来的,而且能随机出来的数字都位于1000000乘32767分之N的位置,绝对不符合随机数的要求。
而且也违背了祖师爷香农的信息守恒。
#include <iostream>
#include <ctime>
#include <stdlib.h>
#include <cmath>
using namespace std;
void main(){
int num;
int totalNum;
srand((unsigned int)(time(NULL)));
for(int i = 0; i < 10; i++){
totalNum = 0;
for(int j = 0; j < 6; j++){
num = rand() % 10;
totalNum += num * pow(10, j);
}
cout << totalNum << endl;
}
}
杀鸡焉用牛刀,数字本来就是以二进制方式储存的,何苦非得用十进制运算一位一位来拼凑。除法和取余运算%的效率真的非常低,这都%了多少次10了这?看着好难受啊。
最后
以上就是柔弱铃铛为你收集整理的C++ 使用rand()函数生成大随机数最佳方法较佳方法一些其它方法的问题:的全部内容,希望文章能够帮你解决C++ 使用rand()函数生成大随机数最佳方法较佳方法一些其它方法的问题:所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复