2014-12-01 78 views
2

我是一位物理學家,編寫一個程序,涉及從高斯分佈中繪製幾個(數十億次)隨機數的程序。我正在嘗試使用C++ 11。這些隨機數的產生由一個應該花費很少時間的操作分開。我最擔心的是,如果我產生如此之多的隨機數字,這麼短的時間間隔,可能會導致次優的性能。我正在測試某些統計屬性,這些屬性在很大程度上依賴於數字隨機性的獨立性,因此,我的結果對這些問題特別敏感。我的問題是,我在代碼(我的實際代碼的簡化版本)中提到的那些數字類型,我是否明顯地(或者甚至是巧妙地)做錯了什麼?幾個隨機數C++

#include <random> 

// Several other includes, etc. 

int main() { 

    int dim_vec(400), nStats(1e8); 
    vector<double> vec1(dim_vec), vec2(dim_vec); 

    // Initialize the above vectors, which are order 1 numbers. 

    random_device rd; 
    mt19937 generator(rd()); 
    double y(0.0); 
    double l(0.0); 

    for (int i(0);i<nStats;i++) 
    { 
     for (int j(0);j<dim_vec;j++) 
     { 
      normal_distribution<double> distribution(0.0,1/sqrt(vec1[j])); 
      l=distribution(generator); 
      y+=l*vec2[j]; 
     } 
     cout << y << endl; 
     y=0.0; 
    } 
} 
+1

使用你只需要一個分配對象,按隨機號一個也沒有。 – 2014-12-01 18:11:24

+2

@ n.m。看起來每個索引都有不同的stddev,所以如果內存不是問題,它可能會更快地具有dim_vec分發對象而不是一個。 – IdeaHat 2014-12-01 18:19:10

回答

6

normal_distribution被允許有狀態。通過這種特殊的分配方式,通常會與其他呼叫成對地生成數字,在奇數呼叫中返回第二個緩存號碼。通過在每個呼叫上構建一個新的分配,您將丟棄該緩存。

幸運的,你可以「塑造」一個單一的分佈用不同normal_distribution :: param_type的呼喚:

normal_distribution<double> distribution; 
using P = normal_distribution<double>::param_type; 
for (int i(0);i<nStats;i++) 
    { 
     for (int j(0);j<dim_vec;j++) 
     { 
      l=distribution(generator, P(0.0,1/sqrt(vec1[j]))); 
      y+=l*vec2[j]; 
     } 
     cout << y << endl; 
     y=0.0; 
    } 

我不熟悉的std::normal_distribution所有實現。但是我寫了libc++。所以我可以用一定的確定性告訴你,我對代碼的輕微重寫會對性能產生積極的影響。我不確定它會對質量有什麼影響,除非說我知道它不會降低質量。低於約在分佈內的時間生成對數的合法性

更新

關於Severin Pappadeux的評論:見N1452其中這個非常技術進行討論,並使其爲:

分配有時會通過調用其運算符()的相關來源的 隨機數來存儲值。例如,用於產生正態分佈的隨機數的共同 方法是 檢索2張均勻分佈的隨機數,並計算兩個 正態分佈的隨機數了出來。爲了將 分配的隨機數緩存重置爲定義的狀態,每個 分配都有一個重置成員函數。每當關聯的引擎被交換或恢復時,應該在 分配上被調用。

+0

我理解你的論點。但是從分配中獲取其他數字不應該影響產出的質量。如果是這樣,我認爲這是一個糟糕的實施。 – user515430 2014-12-01 19:15:37

+0

@ user515430:好的。我無可否認地猜測。我會根據我所知道的事實修改我的答案。 – 2014-12-01 19:28:08

+0

'在這種特殊的分佈情況下,通常會與其他呼叫成對地生成數字,而在奇數呼叫中,返回第二個緩存號碼「您確定它是允許的嗎?在使用偶數高斯的情況下,然後保存發生器種子,退出,恢復種子並返回採樣,最後得到不同的答案,而不是一次對所有事件進行採樣的情況。 – 2014-12-01 19:50:15

1

上優良HH應答

    通過移位和規模(畝,SIGMA)從正常(0,1)產生的
  1. 正態分佈的頂部的思考:

N(畝,西格瑪)=畝+ N(0,1)*西格瑪

如果你的意思(畝)始終爲零,可以簡化和加速(用不加0。0)你的代碼做類似

normal_distribution<double> distribution; 
for (int i(0);i<nStats;i++) 
{ 
    for (int j(0);j<dim_vec;j++) 
    { 
     l = distribution(generator); 
     y += l*vec2[j]/sqrt(vec1[j]); 
    } 
    cout << y << endl; 
    y=0.0; 
} 
  • 如果速度是最重要的,我會盡量預先計算的主要10^8環外的一切我所能。是否可以預先計算sqrt(vec1 [j]),以便保存在sqrt()調用上?是否有可能將vec2 [j]/sqrt(vec1 [j])作爲單個向量來使用 ?

  • 如果無法預先計算這些向量,我會嘗試保存內存訪問。保持vec2 [j]和vec1 [j]在一起可能有助於獲取一條緩存線而不是兩條。所以申報vector<pair<double,double>> vec12(dim_vec);和採樣y+=l*vec12[j].first/sqrt(vec12[j].second)