使用randn
实现randm
的通用方法
分以下两种情况:
一、n > m
对于n > m的情况,可以直接截断,即不断使用randn
生成随机数,直到该随机数小于等于m的倍数为止(该倍数要小于等于n)。
比如rand5
实现rand2
,因为rand5
生成的随机数范围为{1,2,3,4,5},如果随机到了5,那就重新生成,直至为1或2或3或4为止,然后模2,并加1 ,即可得到1或2,且生成1 2 的概率都相同,实现了rand2
。
#include <cstdio>
#include <cstdlib>
#include <ctime>
using namespace std;
int rand5() {
return rand() % 5 + 1;
}
int rand2() {
int res;
do{
res = rand5();
} while(res > 4);
return res % 2 + 1;
}
int main() {
srand(time(0)); // 设置随机种子,使随机结果不固定
printf("rand5的随机结果:\n");
for (int i = 0; i < 10; i++) {
printf("%d ", rand5());
}
printf("\n\nrand2的随机结果:\n");
for(int i = 0; i < 10; i++) {
printf("%d ", rand2());
}
return 0;
}
二、 n < m
考虑以下两种情形:
1. rand5
生成rand7
rand5
的范围比rand7
小,无法使用前面直接截断的方法。
考虑到:
rand5
的取值范围为{1,2,3,4,5}
rand5 - 1
的范围为{0,1,2,3,4}
(rand5 - 1) * 5
的范围为{0,5,10,15,20}
那么,rand5 + (rand5 - 1) * 5
的范围为{1,2,3,4,5,6,7,8,9,10,…, 25},即1~25出现概率均为1/25,截断大于21的部分,然后模7并加1,即为rand7
。
#include <cstdio>
#include <cstdlib>
#include <ctime>
using namespace std;
int rand5() {
return rand() % 5 + 1;
}
int rand7() {
int res;
do{
res = rand5() + (rand5() - 1) * 5;
} while(res > 21);
return res % 7 + 1;
}
int main() {
srand(time(0)); // 设置随机种子,使随机结果不固定
printf("rand5的随机结果:\n");
for (int i = 0; i < 10; i++) {
printf("%d ", rand5());
}
printf("\n\nrand7的随机结果:\n");
for(int i = 0; i < 10; i++) {
printf("%d ", rand7());
}
return 0;
}
2. rand5
生成rand70
现在考虑rand5
生成rand70
,用上述方法只能得到1~25的数,但是70大于25该怎么办?
(rand5 - 1) * 25
的取值范围为{0,25,50,75,100},与1~25的数相加,可以得到1~125的随机整数,且每个数的出现概率相同,再截断大于70的部分,即为rand70
。
#include <cstdio>
#include <cstdlib>
#include <ctime>
using namespace std;
int rand5() {
return rand() % 5 + 1;
}
int rand70() {
int res;
do{
res = rand5() + (rand5() - 1) * 5 + (rand5() - 1) * 25;
} while(res > 70);
return res;
}
int main() {
srand(time(0)); // 设置随机种子,使随机结果不固定
printf("rand5的随机结果:\n");
for (int i = 0; i < 10; i++) {
printf("%d ", rand5());
}
printf("\n\nrand70的随机结果:\n");
for(int i = 0; i < 10; i++) {
printf("%d ", rand70());
}
return 0;
}
总结:
r a n d n + ( r a n d n − 1 ) ∗ n randn + (randn - 1) * n randn+(randn−1)∗n 可以生成 1 ~ n 2 1~n^2 1~n2的随机整数
r a n d n + ( r a n d n − 1 ) ∗ n + ( r a n d n − 1 ) ∗ n 2 randn + (randn - 1) * n + (randn - 1) * n^2 randn+(randn−1)∗n+(randn−1)∗n2 可以生成 1 ~ n 3 1~n^3 1~n3的随机整数
⋯ \cdots ⋯
r a n d n + ( r a n d n − 1 ) ∗ n + ⋯ + ( r a n d n − 1 ) ∗ n i randn + (randn - 1)*n + \cdots + (randn - 1) * n ^i randn+(randn−1)∗n+⋯+(randn−1)∗ni 可以生成 1 ~ n i + 1 1~n^{i+1} 1~ni+1的随机整数
因此对于n < m的情况,可以使用 r a n d n randn randn不断的加上 ( r a n d n − 1 ) ∗ n i ( i = 1 , 2 , 3 , . . . ) (randn - 1) * n^i(i = 1, 2, 3, ...) (randn−1)∗ni(i=1,2,3,...),直至 n i + 1 ≥ m n^{i+1} ≥ m ni+1≥m,然后截断大于m的最大倍数的部分(该倍数要小于等于 n i + 1 n^{i+1} ni+1),最后模m并加1即可得到 r a n d m randm randm。