Question

I'm simulating a stochastic differential equation with a monte carlo method, which in principle is perfectly suited for openMP, as different realizations do not depend on each other. Unfortunately I'm facing some problems with my code, which produces wrong result as soon as I turn on openMP. Without it, it works perfectly fine. My 'critical' loop looks like this:

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

I would truly appreciate any help. Thank you in advance :-)

Was it helpful?

Solution 3

Ok, so based on @jmbr and @raxman answers I moved the inner loop to a separate function, and made sure that rng is now really private. Also, note the seeding trick, which turns up vital. On top of that I introduced reduction on the OptionPrice. The code below works fine.

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

Then in the big loop I go with:

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

And off you go :-)

OTHER TIPS

A common mistake is forgetting that each thread must have its own random number generator. If that's not the case, then each call to dW will be messing up with the internal state of the (shared, instead of private) random number generator.

I hope this helps.

Well one problem I see is that you have a race condition on the variable price. You should be doing a reduction

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

The same goes for your variable OptionPrice

Also it looks to me like rng is still shared, not private. You should define it in the parallel block if you want it private or declare it private (for private variables I prefer to declare them int the parallel block which automatically makes them private rather than declare them private).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top