摘要:隨機數在軟件開發和程序設計中應用較為廣泛,該文從分析隨機數的一般原理入手,指出它們的缺陷,然后從NS(network simulator)中提取一種新的產生隨機數的方法,并驗證它的可行性。
關鍵詞:偽隨機數;隨機數;種子
中圖分類號:TP311 文獻標識碼:A 文章編號:1009-3044(2009)05-1138-03
A New Approach to Generate Random Numbers Extracted from the NS(Network Simulator)
DUAN Min1,QIAN Guang-ming2,XIAO Min3
(College of Mathematics and Computer Science of Hunan Normal University, Changsha 410081, China)
Abstract: Random number is widely used in the software development andprogramming. This article analyses the general principles of the random numbers ,points out their shortcomings and puts forward a new approach to generate random numbers extracted from the NS(network simulator).Then we verifyits feasibility.
Key words: Pseudo-random number; Random Numbers; Seed
1 引言
在用計算機編制程序時,經常需要用到隨機數,我們也知道隨機數在實際運用中非常之多,如游戲設計,信號處理,網絡仿真領域。特別在網絡仿真等領域,對隨機數的產生提出了較高的要求,僅使用C++語言類庫中的隨機函數可能會很難完成相應的工作。本文簡單的介紹我們從NS中所提取的這種隨機數的原理,并對其進行了測試,希望以后可以應用到我們需要的領域中去。
2 隨機數
2.1 偽隨機數
隨機數是計算機隨機產生的一個任意數字,但是計算機不會產生一個絕對隨機的隨機數,我們希望計算機產生一個絕對的隨機數,這是一種理想的隨機數,然而計算機產生的只能是相對的隨機數,即偽隨機數。
偽隨機數并不是假隨機數,這里的“偽”是有規律的意思,就是計算機產生的偽隨機數既是隨機的又是有規律的。怎樣理解呢?產生的偽隨機數有時遵守一定的規律,有時不遵守任何規律;偽隨機數有一部分遵守一定的規律;另一部分不遵守任何規律。比如“世上沒有兩片形狀完全相同的樹葉”,這正是點到了事物的特性,即隨機性,但是每種樹的葉子都有近似的形狀,這正是事物的共性,即規律性。從這個角度講,計算機只能產生偽隨機數而不能產生絕對隨機的隨機數。
2.2 種子(seed)
種子(seed)是用來產生隨機數的一個初始值,可以是我們自己給定的,也可以通過一定的運算而得到的,也可能是通過獲取當前系統的時間而得到的。獲取種子的值不同,那么其后面產生的一系列化的隨機數也不同,如果每次給定的種子是一樣的,那很有可能其后產生的一系列化的隨機數是相同的。所以我們要產生隨機數時,要避免給一個固定的初始值,種子通常是一個無符號的整形數。
3 VC++中隨機數的實現
在VC的環境下,我們可以用庫函數random()來產生一個隨機數,它返回的是–32768 到32767中的任意一個數。在VC6.0環境下是這樣定義的:random(數字)。數字是我們自己給予賦值的,注意的是random(1)產生的是數字0,而不是1,因為random()產生的是由0到數字減一的效果。例如random(10)產生的實際上是0~9的數字。
在VC中還可能用另外一個隨機函數rand()來產生隨機數,包含在頭文件
#define RAND_MAX 0x7fff(32767)
它是一個short 型數據的最大值,如果要產生一個浮點型的隨機數,可以將rand()/1000.0這樣就得到一個0~32.767之間平均分布的隨機浮點數,我們也可以自己去定義這個最大數。
我們寫一個小程序,來產生一個隨機數。
#include
#include
int main()
{int k;
k = rand();
printf(\"%d\\", k);
return 0;
}
這個程序是產生了隨機數,但是我們同時也發現它產生的隨機數是不變的。我們就需要講到VC中另一個函數srand()函數進行隨機化, srand()函數也包含在頭文件
#include
#include
void main(void)
{ int i;
srand( (unsigned)time( NULL ) );
for( i = 0; i<10; i++)
printf(\"%6d\\", rand());
}
這樣所產生的數便是隨機數,因為它所得到的種子(seed) 是根據系統時間所獲取的,因為系統的時間是在不斷變化的,所以種子(seed)也變化,那么rand()所產生的這樣產生的隨機數也就不一樣了。
4 NS中隨機數程序抽取
在網絡仿真中,對隨機數的要求特別的高,要產生一系列的隨機數,僅僅利用VC中為我們提供的庫函數還是不行的,這樣得到的隨機數的范圍小,精度不夠高,達不到我們的目的。現在我們就來介紹NS 中抽取的一種經典的隨機數算法。
在程序中我們定義了三種類型的種子,一種是RAW_SEED_SOURCE的種子,當我們接受到這種類型的種子時,不做任何操作,第二種是PREDEF_SEED_SOURCE的種子,我們通過先前定義的數組predef_seeds[N_SEEDS_]對種子(seed)進行一個初始的賦值,這個值根據seed傳來的參數不同,所得的初始種子的值也會不同,但是這樣以后產生的種子是可以預見的,也就是說這樣產生的一系列化的數不帶有隨機性。當我們接受的種子類型是HEURISTIC_SEED_SOURCE(啟發式種子類型)時,我們調用了函數gettimeofday(struct timeval *p, struct timezone *z)獲取系統的目前時間,它返回數組的元素包括秒(sec)和百萬分之一秒/微秒(usec),然后通過一個運算操作,獲得種子(seed)的初值。然后由這個初始化的種子(seed)值去產生一系列化的隨機數。由于時間都在不斷的變化,所以種子(seed)也就在相應產生著變化,以至于以后每次產生的數都不同的。其中gettimeofday(struct timeval *p, struct timezone *z)的函數定義為:
Inline int gettimeofday(struct timeval *p,struct timezone *z) //獲取時間的函數
{ struct timeb tb; //定義一個時間結構體,用來傳遞時間
ftime(tb); //時間函數
p->tv_sec = tb.time; //把當前所得到的時間傳給結構體p,單位是秒
p->tv_usec = tb.millitm;//
return 0;
}
gettimeofday()會把目前的時間用p所指的結構返回,當地時區的信息則放到z所指的結構中。
timeval結構定義為:
struct timeval{
long tv_sec; /*秒*/
long tv_usec; /*微秒*/
};
timezone 結構定義為:
struct timezone{
int tz_minuteswest;
int tz_dsttime; };
我們就是利用這個函數來獲是時間,并用它來對種子賦初值,并且在后面調用了next()函數來產生下一組隨機數。每次產生的隨機數都是和第一次的種子相關的,我們把它產生的隨機數與由PREDEF_SEED_SOURCE類型所產生的隨機數相比。每運行一次,PREDEF_SEED_SOURCE類型所產生的隨機數是相同的,而由HEURISTIC_SEED_SOURCE(啟發式種子類型)類型的種子產生的隨機數卻在不斷變化。
5 隨機數的測試
雖然我們已經提取了隨機數,但是還需要進一步的驗證和測試,函數RngTest()就是為了驗證所產生的數是否是真正的隨機數。首先它實例化了一個對象RNG rng(RNG::RAW_SEED_SOURCE, 1L),對seed(種子)進行了一次初始化,然后通過一系列的調用來確定以后產生的種子符合哪一種類型的種子。因為如果是HEURISTIC_SEED_SOURCE(啟發式種子類型),其后的調用過程和測試時調用的過程是一致的,并且通過后面數值的比較,我們發現所得到的隨機數的是屬于哪一種類型的。其調用過程如圖1所示。
通過這種測試和驗證,我們從NS中提取的這種隨機數方法具有可行性,它產生的隨機數是真正的隨機數,并且精度高。
6 結束語
隨機數應用十分廣泛,隨機現象也隨處可見,偽隨機數作為系統仿真中首要問題之一,對它的研究來提高系統工程仿真有著重要的意義。本文提供的這種隨機數,具有一定的實用價值,其具體應用可以根據實際的情況要求進行選擇。
參考文獻:
[1] 徐雷鳴,龐博,趙耀. NS與網絡模擬[M]. 北京:人民郵電出版社,2003.
[2] 西蒙. Visual C++ 6編程寶典[M]. 北京: 電子工業出版社,2005.
[3] 梁田貴,張鵬. 算法分析與設計[M]. 冶金工業出版社,2004.
[4] http://nsnam.cvs.sourceforge.net/nsnam/ns-2.