我們在編程實現算法的過程中,往往需要使用到隨機數。由於計算機是一台以邏輯為基礎的機器,沒法做到真正的隨機(大概量子計算機可以?)。所以計算機生成的是偽隨機數,供我們使用。
我們使用C語言的rand函數,生成的也是偽隨機數。
一個簡單的示范如下:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <time.h> 4 5 int 6 main(int argc, char** argv) 7 { 8 // 以機器當前的時間來構造生成偽隨機數的"種子" 。 9 srand((unsigned int)time(NULL)); 10 int i; 11 // 打印10個偽隨機數 12 for (i = 0; i < 10; i++) { 13 14 printf("%d ", rand()); 15 } 16 printf("\n"); 17 18 system("pause"); 19 return 0; 20 }
很顯然,如果不使用第九行的srand函數,那么我們的程序每次打印的10個偽隨機數序列是一樣的,在本機上始終是41, 18467, 6334, ......。這是由於C語言是利用linear congruential generator作為生成器來生成偽隨機數,但是這個生成器生成偽隨機數,需要一個“種子”來進行運算。而如果我們僅僅調用rand函數,那么我們始終使用的是C語言自己設置的固定的“種子”來生成偽隨機數,所以生成的偽隨機數的序列肯定是一模一樣的咯。
當我們使用srand,以時間為參數,為rand提供一個不一樣的“種子”,那么由於每次的“種子”都不一樣,當然每次的偽隨機數的序列都不一樣。
但是從代碼實現中,我們不能清楚地看出來srand函數提供的“種子”如何就被rand函數用上了。
從ISO C99標准(ISO/IEC 9899:1999(E))當中的偽隨機數一節(7.20.2 Pseudo-random sequence generation functions),我們可以看到一個簡明的可移植的實現樣例:
1 static unsigned long int next = 1; 2 3 int rand(void) // RAND_MAX assumed to be 32767 4 { 5 next = next * 1103515245 + 12345; 6 return (unsigned int)(next/65536) % 32768; 7 } 8 9 void srand(unsigned int seed) 10 { 11 next = seed; 12 }
在這個樣例中,“種子”為靜態內部變量next,初始值為1。如果我們不使用srand來更新next,很顯然我們每次調用程序生成的偽隨機數都是一樣的(next從1開始)。如果我們在程序中用srand來更新next,那么我們每次運行程序,就給next初始化以不同的值,於是就能夠得到不一樣的偽隨機數序列。
但是,rand函數和srand函數的實現真如樣例這般簡單嗎?
放到下篇再寫吧。