私は最近、完全に理解できない C++ のバグ/機能に出くわしました。ここで C++ の知識が豊富な人が私を正しい方向に向けてくれることを望んでいました。
以下に、モンテカルロ積分を使用してガウス曲線の下の領域を見つけようとする私の試みを示します。レシピは次のとおりです。
- 多数の正規分布確率変数 (平均が 0、標準偏差が 1) を生成します。
- これらの数を二乗します。
- すべての正方形の平均を取ります。平均は、曲線の下の領域の非常に近い推定値になります (ガウスの場合は 1.0)。
以下のコードは、2 つの単純な関数で構成されています。rand_uni
は、0 と 1 の間で一様に分布する確率変数を返しますrand_norm
。 は、正規分布する確率変数の近似 (やや貧弱ですが、「政府の仕事には十分」) です。
main
ループを 10 億回実行し、そのたびに呼び出しrand_norm
、それを 2 乗pow
し、累積変数に追加します。このループの後、累積された結果が実行回数で除算され、ターミナルに として出力されResult=<SOME NUMBER>
ます。
問題は、以下のコードの非常に風変わりな動作にあります: 生成された各確率変数が出力されるとcout
(そうです、10 億回)、最終結果は、使用するコンパイラに関係なく正しいものになります (1.0015、これは私が欲しいです)。ループの反復ごとに確率変数を出力しないと、と 448314 を下回ってしまいinf
ます。gcc
clang
率直に言って、これは頭がおかしくなり、C++ との最初の (-ish) 遭遇であるため、何が問題なのかよくわかりません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;
}
メイクファイル
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