相信只要是程序猿都會知道rand()函數是用來取隨機數的一個庫函數,但是它出的結果真的是一組隨機數嗎?我們來看看這段代碼運行的結果:
1 #include<stdio.h> 2 #include<stdlib.h> 3 int main(void) 4 { 5 int j; 6 for(j=0;j<5;j++) 7 { 8 printf("rand():%d\n",rand()); 9 } 10 }
linux下gcc每次運行結果如下:
windows vc6.0每次運行結果如下:(本人windows系統為64位機)
(由於編譯器的不同,可能顯示的結果也不同吧!)
rand()函數不是隨機的嗎?怎么每次運行的結果都是一樣的?其實計算機也不像人們想象的那么智能,它也是按照人們的思想來隨機出數的。本人在linux下查找頭文件沒有找到rand()函數的定義,上網查了一下也沒找到,說是被封裝到庫中了。若是有大牛們看到這篇文章,請幫幫小弟解決心中的疑問吧!
那么如何用rand()函數獲取你想要的取值范圍呢?其實rand()函數的取值范圍在0~RAND_MAX之間;
那么什么是RAND_MAX呢?
linux下的RAND_MAX值為2147483647(二進制32位)
windows下的RAND_MAX值為32767(二進制16位)
由此可見RAND_MAX是根據編譯器對int型分配的空間而定的;這種說法應該也是錯的,因為我在windows下的vc中打印sizeof(int)的值之后竟然顯示4,也就是說int在vc中的存儲空間應該是32位,所以我認為是vc編譯器對rand()函數的定義做了修改,使RAND_MAX的值更小,方便了開發者的取值;(下面會介紹為什么編譯器這樣做)
我們知道了rand()函數的取值范圍后,如何取得你想要的數值范圍呢?我們取0~10的值好了。正常的思路如下,10*rand()/(RAND_MAX+1)+1(用10乘以rand()取得的隨機數,然后除以RAND_MAX,再加1),應該是這樣的了。代碼如下:
1 #include<stdio.h> 2 #include<stdlib.h> 3 int main(void) 4 { 5 int i; 6 for(i=0;i<3;i++) 7 { 8 d=rand(); 9 c=1 + (10*d/(RAND_MAX)); 10 printf("1 + (10*rand()/(RAND_MAX+1)):%d\n",c); 11 } 12 13 }
運行結果如下:
好像也達到我們的效果了。但是如果把這段代碼放到linux下用gcc編譯又是什么樣的結果呢?
同樣的代碼,我們來看看結果
這是怎么回事?為什么同樣的代碼,到了另一個編譯器后就不一樣了?
還記得我們剛才分別在這兩個編譯器中求的RAND_MAX的值嗎?對,vc中是32767,而gcc中是2147483647。這時候你該問了跟這個有關系嗎?我可以十分肯定的告訴你,相當的有關系。我們來寫個小程序驗證我的猜想吧!代碼如下:
1 #include<stdio.h> 2 #include<stdlib.h> 3 int main(void) 4 { 5 int i,a,d; 6 for(i=0;i<5;i++) 7 { 8 d=rand(); 9 a=d*10; 10 printf("%d",sizeof(int)); 11 printf("rand()*10:%d\n",a); 12 } 13 }
運行結果如下:
你看出有什么不一樣了嗎?對,這就是vc為什么對rand()函數的RAND_MAX的值進行修改了。在gcc中rand()的取值范圍是0~32位的二進制數,如果拿這個隨機數乘以10的話,很可能會發生數值溢出,也就是說gcc中int的值最大就取到2147483647,如果乘以10的話,只能接着往后排列了,-2147483647、-2147483646、-2147483645········一直到取得的那個值。所以會得到一些負數。
到了這里我想你應該知道解決的辦法了吧~!沒錯,就是用一個double類型的數來接收rand()*10,我們沒辦法改變RAND_MAX的值,我們可以用更大的數來表示rand()*10。
這下應該可以了吧,我們修改一下代碼看看效果:
1 #include<stdio.h> 2 #include<stdlib.h> 3 int main(void) 4 { 5 int i,a,d; 6 for(i=0;i<5;i++) 7 { 8 printf("(int)(10.0*rand()/(RAND_MAX+1.0)):%d\n",1+(int)(10.0*d/(RAND_MAX+1.0))); 9 } 10 }
運行結果如下:
對,這就是我們想要的結果了!
PS——函數會隨着編譯器的不同而效果不同,但是它終究逃不過開發者的眼睛,注意細節。
附加:
取0-1之間的浮點型值:
1 #include <stdio.h> 2 #include<stdlib.h> 3 #include<time.h> 4 5 int main(void) 6 { 7 int i; 8 float a; 9 srand((unsigned)time(NULL)); 10 for(i=0;i<10;i++) 11 { 12 printf("%.1f\n",rand()/(RAND_MAX+0.1)); 13 } 14 }
srand()函數是設置隨機數的種子,由前面的推論可知rand()函數只是一個偽隨機函數,srand()函數就是為rand()函數設置種子;time()函數是獲取當前的時間,因此第九行代碼就是為rand()函數設置一個根據系統時間變化的隨機種子,這樣代碼在每次運行的時候的結果都不會一樣了!