6

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

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

  1. 生成大量正态分布的随机变量(均值为 0,标准差为 1)。
  2. 平方这些数字。
  3. 取所有正方形的平均值。平均值将是曲线下面积的非常接近的估计值(在高斯的情况下,它是 1.0)。

下面的代码由两个简单的函数组成:rand_uni,它返回一个随机变量,均匀分布在 0 和 1 之间,以及rand_norm,它是正态分布随机变量的一个(相当差,但“足够好”)近似值。

main循环运行十亿次,rand_norm每次调用,将其平方pow并添加到累积变量中。在此循环之后,累积的结果仅除以运行次数并打印到终端作为Result=<SOME NUMBER>.

问题在于下面代码的非常古怪的行为:当每个生成的随机变量被打印到cout(是的,十亿次)时,无论使用什么编译器,最终结果都是正确的(1.0015,非常接近,我想)。如果我不在每次循环迭代中打印随机变量,我会得到inf448314gccclang.

坦率地说,这只是令人难以置信,因为这是我第一次(-ish)遇到 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;

}

生成文件

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
4

2 回答 2

3

在开始 += 随机值之前, in 未初始化为0 resultdouble rand_norm()

所有 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

于 2013-03-31T09:12:58.270 回答
3

在您的 rand_norm() 函数中,结果未初始化,这是您的错误。以防万一您想知道为什么在打印值时它会起作用,这是因为一个未初始化的变量将具有它所拥有的内存区域的值,在您的代码中它是堆栈,因此调用 cout<< 会更改您的堆栈值。这是您的功能的固定版本:

double rand_norm() {
  double result = 0.0;
  for(int i=12; i > 0; --i) {
    result += rand_uni();
  }
  return result - 6;
};
于 2013-03-31T09:14:17.883 回答