C自定义随机数函数随机数分布及应用场景
生成随机数的功能在某些类型的程序中非常有用,特别是在游戏、统计建模程序和需要对随机事件建模的科学模拟中。以游戏为例,如果没有随机事件,怪物总是以同样的方式攻击你,你总是会找到同样的宝藏,地牢的布局永远不会改变,等等……这不会成为一个很好的游戏。1 自定义简单的伪随机数函数
基本思路是通过设置种子数、组合乘法、加法和迭代,再通过循环求余便可以得出一些简单的随机数。#include #include unsigned int PRNG() { static unsigned int seed = 5323; // 利用静态变量在每次调用时都会更新其值 seed = 8253729 * seed + 2396403; return seed % 32768; } int* rnd(int rng,int size) { int *arr = (int*)malloc(sizeof(int)*size); for (int i=0; i < size; ++i) { arr[i] = PRNG()*rng/32768; } return arr; } void arrPrint(int *arr,int size) { for (int i=0; i < size; ++i) { printf("%d ",arr[i]); if ((i+1) % 5 == 0) printf(" "); } } int main() { int *arr = rnd(10,20);// 0-10,不包括10的随机数 arrPrint(arr,20); getchar(); return 0; } /* 7 8 6 3 8 3 9 6 6 0 8 1 1 8 4 8 3 8 6 7 */2 标准库中的随机数函数
标准库中有两个函数用于产生随机数:srand(int); //设置起始种子值 rand(); // 产生随机数
头文件中的time_t time(time_t *seconds) 返回自纪元 Epoch(1970-01-01 00:00:00 UTC)起经过的时间,以秒为单位。如果 seconds 不为空,则返回值也存储在变量 seconds 中。可以以这个秒数作为随机数的种子值。#include #include // for std::rand() and std::srand() #include // for std::time() int main() { srand(time(0)); for (int count=1; count <= 20; ++count) { printf("%d ",rand()%10); if (count % 5 == 0) printf(" "); } getchar(); return 0; } /* 9 0 6 6 9 6 3 6 1 4 5 1 6 3 4 6 7 6 2 3 */3 在两个任意值之间生成概率较为均等的随机数#include #include #include // Generate a random number between min and max (inclusive) // Assumes srand() has already been called // Assumes max - min <= RAND_MAX int getRandomNumber(int min, int max) // include min and max { double fraction = 1.0 / (RAND_MAX + 1.0); return min + (max - min + 1) * (rand() * fraction); } int main() { srand(time(0)); for(int i=1; i<=20; i++) { printf("%d ",getRandomNumber(0,9)); if(i%5==0) printf(" "); } getchar(); return 0; } /* 2 7 5 4 5 9 8 3 6 8 1 2 2 6 9 7 0 1 6 3 */
为什么我们在上面的函数中使用除法而不是模。简而言之,模方法倾向于偏向于低数值。对于随机数,有一个概率分布问题,如正态分布,随机均匀分布。4 避免同一时间种子产生相同的随机序列#include //包含伪随机数生成函数 #include //包含取系统时间的函数 #include using namespace std; #define kSum 1000 // 均匀分布随机函数均匀化 double _uniform(double min, double max, long int *seed) { double t = 0; *seed = 2045 * (*seed) + 1; *seed = *seed - (*seed / 1048576) * 1048576; t = (*seed) / 1048576.0; t = min + (max - min) * t; return t; } // 均匀分布随机函数产生随机数 long int Uniform(double min, double max) { long int s = 0; double r = 0; //srand((unsigned int)time(NULL)); /*同一个时间种子可能会从产生相同的随机数列*/ s = rand(); r = _uniform(min, max, &s); return ((long int)r); } //算法二 double AverageRandom(double min, double max) { int minInteger = (int)(min * 10000); int maxInteger = (int)(max * 10000); int randInteger = rand() * rand(); int diffInteger = maxInteger - minInteger; int resultInteger = randInteger % diffInteger + minInteger; return (resultInteger/10000.0); } int main() { int num1, num2, op, result1, result2; //num1,num2:操作数,op:运算符,result1,result2: 结果 while(1) { srand(time(NULL)); //随机数种子初始化 //num1=rand() * 10 / (RAND_MAX + 1); // 生成运算数 //num2=rand() * 10 / (RAND_MAX + 1); // 生成运算数 //op=rand() * 4 / (RAND_MAX + 1); // 生成运算符 0--+, 1-- -, 2--*,3-- / num1 = Uniform(0,100); num2 = Uniform(0,100); op = Uniform(0,4); switch (op) { case 0: cout << num1 << "+" << num2 << "= ?" ; cin >> result1; if (num1 + num2 == result1) cout << "you are right "; else cout << "you are wrong "; break; case 1: cout << num1 << "-" << num2 << "= ?" ; cin >> result1; if (num1 - num2 == result1) cout << "you are right "; else cout << "you are wrong "; break; case 2: cout << num1 << "*" << num2 << "= ?" ; cin >> result1; if (num1 * num2 == result1) cout << "you are right "; else cout << "you are wrong "; break; case 3: cout << num1 << "/" << num2 << "= ?" ; cin >> result1; cout << "余数为 = ?"; cin >> result2; if ((num1 / num2 == result1) && (num1 % num2 == result2)) cout << "you are right "; else cout << "you are wrong "; break; } } return 0; }6 随机数应用场景之纸牌游戏之发牌#include #include #include void initial(int* p) //初始化一付牌 { int i; for(i=0; i<52; i++) //额外增加一个百位来模拟花色 p[i]=(i/13+3)*100+i%13+1; //301~313,401~413,501~513,601~613 } void shuffle(int *p) //洗牌 { int i,x,y; int t; srand((int)time(0)); for(i=0;i<200;i++) //洗200次 { x=rand()%52; y=rand()%52; if(x!=y) { t=p[x]; p[x]=p[y]; p[y]=t; } } } void dealCard(int* p,int* p1,int* p2,int* p3,int* p4) //发牌 { int i; for(i=0; i<13; i++) // 发13轮,每轮每家一张 { p1[i]=p[4*i]; p2[i]=p[4*i+1]; p3[i]=p[4*i+2]; p4[i]=p[4*i+3]; } } void sort(int* p) //排序 { int i,j; int t; for(i=0; i<13; i++) for(j=0; j<13-i-1; j++) { //if(p[j]>p[j+1]) if(p[j]%100>p[j+1]%100) { t=p[j]; p[j]=p[j+1]; p[j+1]=t; } } } void display(int *p) { int i; int f,d; for(i=0; i<13; i++) { f=p[i]/100;//301~313,401~413,501~513,601~613 d=p[i]%100;//1~13 if(d<10&&d>1) { printf("%2c", (d+"0")); } else if(d==1) printf(" A"); else if(d==11) printf(" J"); else if(d==12) printf(" Q"); else if(d==13) printf(" K"); else if(d==10) printf("10"); switch(f) { case 3: printf("%c ",6); // spades 黑桃 break; case 4: printf("%c ",3); // hearts 红桃 break; case 5: printf("%c ",5); // clubs 梅花 break; case 6: printf("%c ",4); // diams 方块 break; } } printf(" "); } int main() { int pai[52],player1[13],player2[13],player3[13],player4[13]; initial(pai); shuffle(pai); dealCard(pai,player1,player2,player3,player4); sort(player1); sort(player2); sort(player3); sort(player4); printf("黑桃 红桃 梅花 方块 "); printf("spades hearts clubs diams "); printf("随机发牌开始…… "); printf("East: "); display(player1); printf("South: "); display(player2); printf("West: "); display(player3); printf("North: "); display(player4); while(1); return 0; } /* 黑桃 红桃 梅花 方块 spades hearts clubs diams 随机发牌开始…… East: 2 2 2 3 3 5 6 6 9 10 10 J Q South: A A 3 5 6 7 8 8 9 10 10 J K West: A 3 4 5 6 7 8 9 J Q Q Q K North: A 2 4 4 4 5 7 7 8 9 J K K */
附,产生n个指定范围内的等概率随机数#include #include using namespace std; // m个指定范围内的等概率随机数 // 从0....n-1中随机等概率的输出m个不重复的数。这里我们假设n远大于m void knuth(int n, int m) { srand((unsigned int)time(0)); for (int i = 0; i < n; i++) if (rand()%(n-i)