2

我正在用蒙特卡罗方法模拟一个随机微分方程,它原则上非常适合 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);
}

我真的很感激任何帮助。先感谢您 :-)

4

3 回答 3

2

一个常见的错误是忘记每个线程必须有自己的随机数生成器。如果不是这样,那么每次调用 dW 都会弄乱(共享,而不是私有)随机数生成器的内部状态。

我希望这有帮助。

于 2013-05-24T23:08:58.160 回答
2

好吧,我看到的一个问题是您对变量有竞争条件price。你应该做减法

#pragma omp parallel for private(VOld, VNew) reduction(+:price)

你的变量也是如此OptionPrice

在我看来,rng 仍然是共享的,而不是私有的。如果你想要它私有或声明它私有,你应该在并行块中定义它(对于私有变量,我更喜欢将它们声明在并行块中,这会自动使它们成为私有而不是声明它们私有)。

于 2013-05-25T13:58:56.357 回答
1

好的,所以基于@jmbr 和@raxman 的答案,我将内部循环移到了一个单独的函数中,并确保它rng现在真的是私有的。另外,请注意播种技巧,这变得至关重要。最重要的是,我reductionOptionPrice. 下面的代码工作正常。

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;
}

你走了:-)

于 2013-05-25T13:28:21.530 回答