我正在使用蒙特卡罗方法模拟随机微分方程,这种方法原则上非常适合openMP,因为不同的实现不相互依赖。不幸的是,我的代码遇到了一些问题,一旦打开openMP就会产生错误的结果。没有它,它的工作原理非常好。我的'关键'循环看起来像这样:
double price = 0.0
#pragma omp parallel for private(VOld, VNew)
for (long i = 0; i < NSim; ++i){
VOld = S_0;
for (long index = 0; index < Nt; ++index){
VNew = VOld + (dt * r * VOld) + (sqrdt * sig * VOld * dW());
VOld = VNew;
}
double tmp = myOption.PayOff(VNew);
price += (tmp)/double(NSim);
}
我真的很感激任何帮助。提前谢谢: - )
答案 0 :(得分:2)
一个常见的错误是忘记每个线程必须有自己的随机数生成器。如果不是这样,那么每次调用dW都会搞乱(共享的,而不是私有的)随机数生成器的内部状态。
我希望这会有所帮助。
答案 1 :(得分:2)
我看到的一个问题是变量price
上存在竞争条件。你应该做一个减少
#pragma omp parallel for private(VOld, VNew) reduction(+:price)
您的变量OptionPrice
在我看来,rng仍然是共享的,而非私有的。你应该在并行块中定义它,如果你想要它是私有的或者声明它是私有的(对于私有变量,我更喜欢在并行块中声明它们自动使它们成为私有而不是声明它们是私有的。)
答案 2 :(得分:1)
好的,基于@jmbr和@raxman的答案我将内循环移动到一个单独的函数,并确保rng
现在真的是私有的。另外,请注意播种技巧,这一点至关重要。最重要的是,我在reduction
上介绍了OptionPrice
。下面的代码工作正常。
double SimulateStockPrice(const double InitialPrize, const double dt, const long Nt, const double r, const double sig, boost::mt19937 *rng){
static unsigned long seed = 0;
boost::mt19937 *rng = new boost::mt19937();
rng -> seed((++seed) + time(NULL));
boost::normal_distribution<> nd(0.0, 1.0);
boost::variate_generator< boost::mt19937, boost::normal_distribution<> > dW(*rng, nd);
double sqrdt = sqrt(dt);
double PriceNew(0.0), PriceOld(InitialPrize);
for (long index = 0; index < Nt; ++index){
PriceNew = PriceOld + (dt * r * PriceOld) + (sqrdt * sig * PriceOld * dW());
PriceOld = PriceNew;
}
delete rng;
return PriceNew;
}
然后在大循环中我选择:
#pragma omp parallel for default(none) shared(dt, NSim, Nt, S_0, myOption) reduction(+:OptionPrice)
for (long i = 0; i < NSim; ++i){
double StockPrice = SimulateStockPrice(S_0, dt, Nt, myOption.r, myOption.sig, rng);
double PayOff = myOption.myPayOffFunction(StockPrice);
OptionPrice += PayOff;
}
然后你走了: - )