rand函數的實現原理
rand函數的實現原理
rand函數產生的是偽隨機數,也就是說它不是一個真實的隨機數。
那么偽隨機數是怎么實現的呢?原理大概如下:
如果約定:a1=f(seed),an+1=f(an)那你可以行到一個序列:a1,a2,a3...an,那么要制作一個偽隨機函數rand,只需要讓它每調用一次就返回序列的下一個元素就行。
就相當于第1次調用rand返回a1,第2次返回a2,…,第n次返回an,這樣每次調rand都能拿到一個不同的數,只要整個序列的規律不明顯,整個函數看起來就是隨機的。
現在計算機上的rand函數都是用這樣的原理實現的,這里的seed被稱為“隨機數種子”。
但這里有一個問題,如果seed不變,那我們每次調用rand函數獲取的序列都是相同的。這就會造成有的程序跑一遍退出后,再重新跑一遍,兩次的輸出結果是相同的。所以我們還需要一個接口去設置seed值,這個接口就是srand函數。
linux下的rand是用類似下面的代碼實現的:
static unsigned long next = 1;/ RAND_MAX assumed to be 32767 / int myrand(void) { next = next * 1103515245 + 12345; return((unsigned)(next/65536) % 32768); }
void mysrand(unsigned seed) { next = seed; }</pre>
myrand、mysrand分別對應rand和srand,但實際的rand實現會復雜一些。
使用rand函數的一個問題
有些人使用rand函數時,因為初始化時沒有調用srand會造成程序每次運行輸出結果都相同:http://ask.csdn.net/questions/174871
如果你沒有調用srand設置隨機數種子,seed的默認值會是0,而seed為0時所決定的序列是固定的,而第一次調用rand()就是返回這個固定序列里的第1個元素,那它的值也是固定的,自然你的程序每次輸出都一樣了。
所以正確的寫法應該是程序初始化時用srand設置不同的隨機數種子(只需要設置一次),例如srand(time(NULL)),但要注意,time(NULL)的值是隔1秒才改變一次的,必要情況下可以考慮使用精度更高的時間函數,如gettimeofday。
下面這段程序,只要你不是在同一秒內執行兩次,每次輸出結果都是不一樣的:
#include <stdio.h>include <stdlib.h>
include <time.h>
int main() { srand(time(NULL)); // 設置隨機數種子 for (int i = 0; i < 10; i++) { printf("%u\n", rand()); } getchar(); return 0; }</pre>