偽隨機數
首先我們必須要明確的是,計算機里頭產生的“隨機數”不是真正意義上的隨機數,它是計算機中的隨機函數按照某種特定算法模擬產生的,可以說我們按照這個算法而算出來的結果都是確定的。如何去理解這段話呢?就像簡單的1+1算式,我們按照規定的加法算法算出來了結果2,這個結果完全是確定的,出現這個結果的概率是1,這就不再是隨機事件,而是必然事件了。真正意義上的隨機數在現實中是隨機產生的,不能被預知,是隨機事件,這點需要與計算機的“隨機數”進行區別,因此我們也把計算機的“隨機數”稱作偽隨機數,偽隨機數只是計算機對現實隨機數的一種模擬結果。
生成過程
直接調用
用C/C++生成偽隨機數十分簡單,只需要使用一個能夠生成偽隨機數的函數rand()
即可,使用rand()
時需要在源代碼頭部加上預編譯指令#include <stdlib.h>
或者#include <cstdlib>
,否則會編譯不通過。這兩條指令的區別是,前者適用于C語言,后者則適用于C++。簡易的代碼如下:
#include <cstdio>
#include <cstdlib>
int main()
{
printf("%d\n",rand()); //直接調用rand()函數輸出即可
return 0;
}
在這里,我們發現了個問題,使用這段代碼輸出的偽隨機數不論程序運行幾次都是不變的,生成的值都是固定的……知道為什么叫偽隨機數了吧,畢竟都是按照特定算法算出來的,只是直接調用并不能用來模擬隨機的過程!那我們該怎么辦呢?
時間初始化
要想用C/C++模擬出隨機數,除了用到rand()
函數,還需要用到srand()
與time()
這兩種函數。那么,我們先來認識一下這三種函數:
-
rand()
:能夠產生偽隨機數的隨機函數,產生的值在0~RAND_MAX之間,一般來說RAND_MAX的大小由系統決定。直接調用該函數將返回的模擬的偽隨機數,類型為整數(可以是int,也可以是long long,只要是整數即可) -
srand()
:偽隨機數發生器的初始化函數,原型void srand(unsigned int seed)
,rand()
可以通過srand()
的seed參數值(種子值)產生一系列偽隨機數。 -
time()
:該函數可以返回自UNIX紀元起至當前時刻的秒數,使用time(NULL)
或time(0)
來獲取當前系統時間,函數原型time_t time(time_t *t)
。
現在,我們可以很好的解釋為什么直接調用rand()
產生的數值都是固定不變的,因為srand()
的初始化種子值都是固定不變的。為什么呢?如果沒有事先設置srand()
,會默認種子值為1,即unsigned int seed = 1
,從而導致rand()
根據其產生的偽隨機數都是不變的數值。
我們需要引入一場變化,通過什么呢?當然是時間!時間始終在變化著,需要用到time(NULL)
來引入變化的時間,將其作為初始化函數的參數!使用time()
函數需要加上預編譯指令#include <time.h>
或者#include <ctime>
。生成偽隨機數的代碼如下:
#include <cstdio>
#include <cstdlib>
#include <ctime>
int main()
{
srand(time(NULL)); //初始化函數引入變化的時間種子參數
printf("%d\n",rand());
return 0;
}
如果使用C++,運用流輸入輸出可能是更加簡便,毋須指明相應的格式符,只要加上#include <iostream>
就可以直接使用std::cin
與std::cout
,不過相比于scanf()
與printf()
速度要慢得多,在算法競賽里不推薦使用。
使用方法
特定范圍的偽隨機數
我們往往需要產生的是某一特定范圍的隨機數,那我們應該如何編寫代碼呢?其實道理很簡單,只需對rand()
取余即可,代碼如下:
#include <cstdio>
#include <cstdlib>
#include <ctime>
int main()
{
srand(time(NULL));
int n;
int a;
scanf("%d",&n);
scanf("%d",&a);
printf("%d\n",a+rand()%n); //產生[a,n+a)范圍內的偽隨機數
return 0;
}
偽隨機小數
如果我們需要產生[0,1]的小數,該如何編寫代碼呢?這里有個簡單的方法,如果需要2位小數,就將rand()
對101取余,再除以100.0即可得到滿足要求的偽隨機小數。同理,需要3位小數,就對1001取余再除以1000.0。代碼如下:
#include <cstdio>
#include <cstdlib>
#include <ctime>
int main()
{
srand(time(NULL));
printf("%.2f\n",(rand()%101)/100.0); //獲得[0,1]之內的2位隨機小數
return 0;
}