2012-07-06 56 views
2

我有一個小型測試程序,它嘗試使用boost :: random保存和恢復隨機數生成器的狀態,但它不像文檔表示。從升壓文檔:在boost :: random中正確保存/恢復RNG狀態意外行爲

類哪個型號的僞隨機數生成器也應效法可流傳送的概念,即實現operator < <和運營商>>。如果是這樣,運營商< <將僞隨機數發生器的所有當前狀態寫入給定的ostream,以便操作員>>可以在稍後恢復狀態。國家應以與平臺無關的方式編寫,但假定用於寫入和讀取的語言環境相同。具有恢復狀態的僞隨機數發生器和處於剛剛寫入狀態的原始數據發生器應該是等效的。

據我所知,如果一個RNG狀態被保存,然後一個數字被拉出來,狀態應該改變。如果狀態稍後恢復,則應該允許在發生器回滾時生成完全相同的數字。我制定了一個測試程序來檢查這個問題,但乍看之下,似乎狀態並未恢復。考慮代碼:

unsigned int s = static_cast<unsigned int>(std::time(0)); 

//typedef boost::minstd_rand base_generator_type; 
typedef boost::mt19937 base_generator_type; 
base_generator_type randgen(s); 
boost::uniform_01<base_generator_type> getrand(randgen); 
//boost::normal_distribution<float> noise(0,1); 
//boost::variate_generator<base_generator_type, 
//boost::normal_distribution<float> > getrand(randgen, noise); 

double numsbefore[2], numsrightafter[2], numsnew[4]; 

//generate a short sequence, save it, and display 
numsbefore[0] = getrand(); 
numsbefore[1] = getrand(); 

cout << "First Sequence, before save: " 
    << numsbefore[0] << " " 
    << numsbefore[1] << endl; 

//save the current RNG state to a file using the stream interface 
std::ofstream rngfileout("test_rngfile.txt"); 
rngfileout << randgen; 
rngfileout.close(); 

//generate the next two numbers and display 
numsrightafter[0] = getrand(); 
numsrightafter[1] = getrand(); 
cout << "Next, right after save: " 
    << numsrightafter[0] << " " 
    << numsrightafter[1] << endl; 

//read in the RNG state that was saved, back into the RNG, restoring the state 
//to be such as it was prior to the most recent two calls to randgen() 
std::ifstream rngfilein("test_rngfile.txt", ifstream::in); 

if(!rngfilein.good()) 
{ 
    cout << "Couldn't read from file\n"; 
    return 0; 
} 
rngfilein >> randgen; 
rngfilein.close(); 

//declare and initialize a new variate generator to the newly-restored generator 
boost::uniform_01<base_generator_type> getrand2(randgen); 
// boost::variate_generator<base_generator_type, 
//  boost::normal_distribution<float> > getrand2(randgen, noise); 

//copy the new variate function into the old one, to allow us to use 
//the old one on the restored generator 
getrand = getrand2; 

//generate the next sequence 
//The first two should be the same as the most recent two called 
//The next two should be new random numbers 
numsnew[0] = getrand(); 
numsnew[1] = getrand(); 
numsnew[2] = getrand(); 
numsnew[3] = getrand(); 

cout << "Restored, Next: " 
    << numsnew[0] << " " 
    << numsnew[1] << " " 
    << numsnew[2] << " " 
    << numsnew[3] << endl; 

在給定時間種子的輸出是:

第一個序列,前保存:0.970021 0.266862
接着,保存後右:0.110485 0.267466
恢復,接着:0.970021 0.266862 0.110485 0.267466


該代碼的評論說明了我認爲應該發生的事情。此外,某些行還包含使用不同的生成器和不同的分發版進行相同測試的註釋代碼。其中任何一個都會出現同樣的問題:狀態恢復後從生成器randgen獲取的下兩個值與保存後立即生成的兩個值不同,因爲它們應該是這樣。

經過仔細檢查(調試)後,似乎對variate generator getrand()的調用完全不會改變生成器randgen的狀態,無論我調用getrand()多少次,所以當我保存它,就像它剛剛創建時一樣,因此,當我在恢復後再次從中恢復時,它只是從一開始就開始。

不應該每次調用生成器都會導致狀態前進嗎?如果RNG狀態永不改變,我甚至會得到不是相同數字的序列?我正在查看/保存的發電機不是「真正的」發電機嗎?

另外,getrand = getrand2的賦值操作可能看起來很粗略,但是爲這些定義了=運算符,並且用getrand2()代替了最後4個調用沒有什麼區別。

回答

1

是我正在查看/保存的發電機不是「真正的」,或什麼?

確實如此。您正在使用的構造函數uniform_01實際上使提供的引擎的副本,而不是參考。

如果你正在使用Boost 1.39或更高版本,你可以使用它像這個:

boost::uniform_01<> getrand; 
getrand(randgen); 

如果你被困在一個較舊的升壓和你不需要getrand是可複製,改變uniform_01的類型參數base_generator_typebase_generator_type&也應該有效。