# OpenMP Monte Carlo $$\pi$$¶

Let’s parallelize our Monte Carlo example of computing pi.

We now want each thread to have independent random numbers. We do this by creating a random number generator separately on each thread. To future ensure that they are independent, we create a different seed on each thread.

Then this calculation can proceed in a trivially parallel fashion. The only thing we need to do is mark the sum for a reduction at the end of the parallel region.

Listing 104 pi.cpp
#include <iostream>
#include <iomanip>

#include <random>
#include <cmath>

#ifdef _OPENMP
#include <omp.h>
#endif

const int N = 1000000;

int main() {

#ifdef _OPENMP
auto start = omp_get_wtime();
#endif

int N_circle{0};

#pragma omp parallel reduction(+:N_circle)
{

// each thread will have its own random number
// engine

std::random_device rd;
#ifdef _OPENMP
#else
std::seed_seq seed{static_cast<int>(rd())};
#endif
std::mt19937 generator(seed);
std::uniform_real_distribution<double> uniform(0.0, 1.0);

#pragma omp for
for (int n = 0; n < N; ++n) {

double x = uniform(generator);
double y = uniform(generator);

double r2 = std::pow(x - 0.5, 2) + std::pow(y - 0.5, 2);

if (r2 <= 0.25) {
N_circle++;
}

}

}

std::cout << "pi = " << std::setprecision(10) << 4 * static_cast<double>(N_circle) / N << std::endl;

#ifdef _OPENMP
std::cout << "time = " << omp_get_wtime() - start << std::endl;
#endif

}


Tip

There is one further trick here – all of the OpenMP stuff is wrapped in #ifdef _OPENMP – the _OPENMP preprocessor variable is defined by the standard if we are building with OpenMP. By wrapping those features, this allows the code to be compiled without OpenMP if we desire.