有時候,我們需要隨機產生一個在某范圍的數,C/C++提供了一個庫函數rand()來產生隨機數。
函數原型:int rand(void);
功能:返回一個[0,RAND_MAX]間的隨機整數。其中RAND_MAX是定義在stdlib.h頭文件中的一個常量。
注意: rand()函數包含在頭文件stdlib.h中,要使用它必須用#include<stdlib.h>引入該頭文件;
計算機實際上並沒有真正做到產生一個隨機數,只是在一串預先定義好的數據中選擇一個返回給函數。
那么,如何得到一個在a到b的整數呢?有兩種方法:
法一:
公式:a+rand()%(b-a+1)
示例:
n=1000+rand()%9000;//隨機生成一個四位數返回給n。a+rand()%(b-a+1),四位數即1000-9999,此時a=1000,b=9999
法二:
公式:a+rand()*(b-a+1)/RAND_MAX
示例:
n=1000+rand()*9000/RAND_MAX;//隨機生成一個四位數返回給n。a+rand()*(b-a+1)/RAND_MAX,四位數即1000-9999,此時a=1000,b=9999
當要產生多個隨機數時,rand()會重復調用產生相同的數字序列。如果想要每次執行產生的隨機數不同,就需要進行隨機初始化。因此引入srand()函數。
函數原型:void srand(unsigned seed);
功能:根據隨機數生成器的種子seed的值初始化隨機數。
我們當然可以用數組和循環來設置種子的值,那么有沒有什么我們可以直接利用的一直變化的值呢?
當然有,時間就是。我們可以借助time.h頭文件中的time(NULL)返回機器當前的時間。
函數原型:time_t time(time_t *t)
功能:返回自紀元 Epoch(1970-01-01 00:00:00 UTC)起經過的時間。當參數為空指針NULL時,返回到當前機器時間的秒數,精度為長整型ld。
注意:要使用time()函數,先要通過#include<time.h>引入time.h頭文件。
示例:
#include <stdio.h> #include <time.h> int main () { time_t seconds; seconds = time(NULL); printf("自 1970-01-01 起的小時數 = %ld\n", seconds/3600); return(0); }
現在,將time(NULL)作為srand()函數的隨機數產生器種子,即srand(time(NULL))就可以通過不斷變化的系統時間得到不同的隨機數。
示例:
問題描述:
隨機產生一個四位數,同時給出各位數字和。
#include<stdio.h> #include<stdlib.h> #include<time.h> int main() { while(1) { int n,a,b,c,d,s; srand(time(NULL)); // n=1000+rand()%9000;//a+rand()%(b-a+1),四位數1000-9999,a=1000,b=9999 n=1000+rand()*9000/RAND_MAX; a=n/1000; b=n%1000/100; c=n%100/10; d=n%10; s=a+b+c+d; printf("%d\n",n); printf("s=%d\n",s); getchar(); } return 0; }
運行結果:
可以看出,我們成功得到了隨機的四位數。
拓展問題:
1.為什么還會產生連續的相同的隨機數?
答:鍵盤按太快了,函數讀取系統時間有一定的延遲,是以秒為單位的,在1秒內按下的多個輸入均視為相同時間,隨機種子數不變,所以產生了相同的數。
2.1970年到現在已經過去了n秒,n是一個很大的數,是不是比rand()函數參數取的最大值RAND_MAX還大?會不會因為溢出而產生錯誤?
答:不會。在VC6中,RAND_MAX值是0x7fff,n確實比RAND_MAX大的多,即使n小於RAND_MAX,在未來也必然會有超過RAND_MAX的時刻。此時的隨機種子數seed=n mod RAND_MAX,即按RAND_MAX長度為一個周期,取余數賦值給隨機種子數seed。