【C】揭秘rand()函數;


  相信只要是程序猿都會知道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()函數設置一個根據系統時間變化的隨機種子,這樣代碼在每次運行的時候的結果都不會一樣了!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM