输出导致蒙特卡罗积分的不同结果

时间:2013-03-31 09:04:09

标签: c++ gcc clang cout montecarlo

我最近偶然发现了一个C ++错误/功能,我无法完全理解,希望有更好的C ++知识的人能指出我正确的方向。

下面你会发现我尝试使用蒙特卡罗积分找出高斯曲线下的区域。食谱是:

  1. 生成大量正态分布的随机变量(平均值为零,标准差为1)。
  2. 对这些数字进行平方。
  3. 取所有方块的平均值。平均值将是对曲线下面积的非常接近的估计(在高斯的情况下,它是1.0)。
  4. 下面的代码包含两个简单的函数:rand_uni,它返回一个随机变量,均匀分布在0和1之间,rand_norm,它是一个(相当差,但是'足够好'政府工作')近似正态分布的随机变量。

    main遍历循环十亿次,每次调用rand_norm,将其与pow进行平方并添加到累加变量。在此循环之后,累计结果将除以运行次数并以Result=<SOME NUMBER>打印到终端。

    问题在于下面代码的非常古怪的行为:当每个生成的随机变量打印到cout(是,十亿次)时,无论使用何种编译器,最终结果都是正确的(1.0015,这是非常接近,我想要的)。如果我不在每次循环迭代中打印随机变量,我会在inf下获得gcc,在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
    

2 个答案:

答案 0 :(得分:3)

result中的double rand_norm()在启动+ =随机值之前未初始化为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));

在您第一次调用rand()之前,或者查看一些更好的随机数生成器,例如Boost.Random

答案 1 :(得分:3)

在你的rand_norm()函数中,结果未初始化,那就是你的错误。为了防止在打印值时它为什么会起作用,因为单位化变量将具有它所具有的内存区域的值,在代码中它是堆栈,因此调用cout&lt;&lt;改变了你的堆栈值。以下是您的功能的固定版本:

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