2013-08-19 39 views
2

我想從沒有更換的相對較大的人口中提取n個樣本。所以,我得出的隨機數並跟蹤我以前的選擇,這樣我就可以重新取樣時,我畫了一個數量的兩倍:從大量的隨機樣本運行到無限循環

boost::mt19937 generator; 
boost::uniform_int<> distribution(0, 1669 - 1); 
boost::variate_generator<boost::mt19937, boost::uniform_int<> > 
     gen(generator, distribution); 
int n = 100; 

std::vector<int> idxs; 
while(static_cast<int>(idxs.size()) < n) 
{ 
    // get random samples 
    std::generate_n(std::back_inserter(idxs), n - idxs.size(), 
        gen); 
    // remove duplicates 
    // keep everything that's not duplicates to save time 
    std::sort(idxs.begin(), idxs.end()); 
    std::vector<int>::iterator it = std::unique(idxs.begin(), idxs.end()); 
    idxs.resize(std::distance(idxs.begin(), it)); 
} 

不幸的是,我遇到了上面使用的常量的無限循環。

我添加了一些輸出(即顯示,它不斷拾取相同數量)和10次嘗試之後,停止爲示出了此問題:

boost::mt19937 generator; 
boost::uniform_int<> distribution(0, 1669 - 1); 
boost::variate_generator<boost::mt19937, boost::uniform_int<> > 
     gen(generator, distribution); 
int n = 100; 

int repeat = 0; 
std::vector<int> idxs; 
while(static_cast<int>(idxs.size()) < n) 
{ 
    if(repeat++ > 10) break; 
    cout << "repeat " << repeat << 
      ", " << idxs.size() << " elements" << endl; 
    std::generate_n(std::back_inserter(idxs), n - idxs.size(), 
        gen); 
    cout << "last " << idxs.back() << endl; 
    std::sort(idxs.begin(), idxs.end()); 
    std::vector<int>::iterator it = std::unique(idxs.begin(), idxs.end()); 
    idxs.resize(std::distance(idxs.begin(), it)); 
} 

的代碼打印

repeat 1, 0 elements 
last 1347 
repeat 2, 99 elements 
last 1359 
repeat 3, 99 elements 
last 1359 

等,如果我不殺死程序,這似乎永遠循環。這不應該發生,對吧?我只是不幸運?或者我做錯了什麼?

短解 感謝@jxh!使用參考幫助:

boost::variate_generator<boost::mt19937&, boost::uniform_int<> > 
     gen(generator, distribution); 
+4

也許我誤解了你的代碼。但是,使用範圍(0..1668)對容器進行混洗並取第一個(n)指數更容易嗎? – hetepeperfan

+0

@hetepeperfan,對於1668年,我同意,是的。對於2e9來說更是如此。它適用於非常大的人羣,但這是失敗案例。 – chuck

回答

1

的問題是,generate_n創建gen您創建的生成的副本。因此,在撥打generate_n結束時,gen的狀態不變。因此,每次重新循環時,都會再次生成相同的序列。解決這個問題

的一種方法是在你的variate_generator使用引用到你的隨機數生成器對象:*

boost::variate_generator<boost::mt19937&, boost::uniform_int<> > 
     gen(generator, distribution); 

*由於我與升壓有限的經驗,我原來的建議是相當笨拙。我在這個答案中採用了提問者實施的解決方案。

+0

你說得對,這解決了問題。謝謝!我期望生成器需要參考,所以副本並不重要。 – chuck

+0

非常歡迎。 – jxh