2013-03-31 61 views
6

我最近剛剛發現了一個C++的bug /特性,我不能完全理解,並希望有人在這裏有更好的C++知識可以指向正確的方向。由於輸出的不同蒙特卡羅積分結果

下面您會發現我嘗試使用蒙特卡羅積分找出高斯曲線下的區域。配方是:

  1. 生成大量的正態分佈的隨機變量(平均值爲零,標準差爲1)。
  2. 正方形這些數字。
  3. 取所有廣場的平均值。平均值將是對曲線下面積的非常接近的估計(在高斯情況下,它是1.0)。

下面的代碼包含兩個簡單的功能:rand_uni,它返回一個隨機變量,零和一,和rand_norm之間均勻分佈的,這是一個(比較差,但「足夠好政府工作」)逼近的正態分佈隨機變量。

main貫穿循環10億次,每次調用rand_norm,將其與pow平方並添加到累加變量中。在此循環之後,累計結果僅以運行次數除以Result=<SOME NUMBER>打印到終端。

問題在於下面代碼的非常古怪的行爲:當每個生成的隨機變量打印到cout(是的,十億次),那麼最終結果是正確的,無論使用的是哪種編譯器(1.0015,這很漂亮接近,我想要的)。如果我沒有在每次循環迭代中打印隨機變量,我會在gcc下獲得inf,在clang下獲得448314。坦率地說,這只是令人難以置信的頭腦,因爲這是我與C++的第一次碰撞,我真的不知道,問題可能是什麼:pow是什麼東西? cout行爲怪異嗎?

任何提示將不勝感激!

來源

// Monte Carlo integration of the Gaussian curve 

#include <iostream> 
#include <cstdlib> 
#include <cmath> 


using namespace std; 


enum { 
    no_of_runs = 1000000 
}; 


// uniform random variable 
double rand_uni() { 
    return ((double) rand()/(RAND_MAX)); 
}; 


// approximation of a normaly distributed random variable 
double rand_norm() { 
    double result; 
    for(int i=12; i > 0; --i) { 
    result += rand_uni(); 
    } 
    return result - 6; 
}; 


int main(const int argc, 
     const char** argv) { 

    double result = 0; 
    double x; 

    for (long i=no_of_runs; i > 0; --i) { 
    x = pow(rand_norm(), 2); 
    #ifdef DO_THE_WEIRD_THING 
    cout << x << endl;  // MAGIC?! 
    #endif 
    result += x; 
    } 

    // Prints the end result 
    cout << "Result=" 
     << result/no_of_runs 
     << endl << endl; 

} 

Makefile的

CLANG=clang++ 
GCC=g++ 
OUT=normal_mc 

default: *.cpp 
    $(CLANG) -o $(OUT).clang.a *.cpp 
    $(CLANG) -o $(OUT).clang.b -DDO_THE_WEIRD_THING *.cpp 
    $(GCC) -o $(OUT).gcc.a *.cpp 
    $(GCC) -o $(OUT).gcc.b -DDO_THE_WEIRD_THING *.cpp 

回答

3

double rand_norm()result啓動+ =隨機值之前,將不會被初始化爲0。

所有cout的使用和重置堆棧內存的一部分,隨後由rand_norm的調用使用,在您執行cout時「解決」您的問題。

將第一行更改爲double result = 0.0;來修復它。

double rand_norm() { 
    double result = 0.0; 
    for(int i=12; i > 0; --i) { 
    result += rand_uni(); 
    } 
    return result - 6; 
}; 

此外,你應該種子的隨機數生成器,你總是會得到的僞隨機數完全相同的序列,沒有它,你的第一個電話前加

srand(time(NULL)); 

到蘭特()或者看一些更好的隨機數發生器,例如Boost.Random

+0

感謝您的提示和解釋! – jst

3

在你的rand_norm()函數中結果沒有被初始化,那是你的bug。以防萬一你想知道爲什麼當你打印這些值時它是有效的,因爲一個單元化的變量將具有它所具有的內存區域的值,在你的代碼中它是堆棧,所以調用cout < <改變了你的堆棧值。以下是您的功能的固定版本:

double rand_norm() { 
    double result = 0.0; 
    for(int i=12; i > 0; --i) { 
    result += rand_uni(); 
    } 
    return result - 6; 
}; 
+0

我是盲人!謝謝 :) – jst