/*
 * C program to compute the value of pi using Monte Carlo method.
 *
 * command-line arguments:  number_of_samples, seed
 *
 * Preliminary OpenMP parallel version.  Does not work well -- results
 * are the same as sequential version, but performance is no better
 * (for reasons as discussed in class).
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>   /* has fabs() */
/* copied from not-strictly-standard part of math.h */
#define M_PI		3.14159265358979323846
#include <omp.h>

#include "timer.h"  /* has get_time() */

/* main program */

int main(int argc, char* argv[]) {

    char* usage_fmt = "usage:  %s number_of_samples seed\n";
    char* end_ptr_for_strtol;

    /* process command-line arguments */
    if (argc != 3)  {
        fprintf(stderr, usage_fmt, argv[0]);
        exit(EXIT_FAILURE);
    }
    long num_samples = strtol(argv[1], &end_ptr_for_strtol, 10);
    if (*end_ptr_for_strtol != '\0') {
        fprintf(stderr, usage_fmt, argv[0]);
        exit(EXIT_FAILURE);
    }
    long seed = strtol(argv[2], &end_ptr_for_strtol, 10);
    if (*end_ptr_for_strtol != '\0') {
        fprintf(stderr, usage_fmt, argv[0]);
        exit(EXIT_FAILURE);
    }

    int nthreads;

    /* record start time */
    double start_time = get_time();

    /* do calculation */ 
    srand((unsigned int) seed);
    long count = 0;
    double x, y;

    #pragma omp parallel
    {
        #pragma omp master
        {
            nthreads = omp_get_num_threads();
        }
        #pragma omp for private(x,y) reduction(+:count) schedule(static)
        for (long i = 0; i < num_samples; ++i) {
            /* apparently rand() is not thread-safe */
            x = (double) rand() / (double) (RAND_MAX);
            y = (double) rand() / (double) (RAND_MAX);
            if ((x*x + y*y) <= 1.0)
                ++count;
        }
    }
    double pi = 4.0 * (double) count / (double) num_samples;

    /* record end time and print results */
    double end_time = get_time();
    printf("OpenMP C program results with %d threads:\n", nthreads);
    printf("number of samples = %ld, seed = %ld\n", num_samples, seed);
    printf("estimated pi = %12.10f\n", pi);
    printf("difference between estimated pi and math.h M_PI = %12.10f\n", 
            fabs(pi - M_PI));
    printf("time to compute = %g seconds\n", end_time - start_time);

    /* clean up and return */
    return EXIT_SUCCESS;
}