/******************************************************************************
* Filename:  07minimum.c
* Author:  Nabil Lehlou
* Modified by Amy Apon
*
* get the the min of an array using parallelism (3 different methods)
******************************************************************************/
#include <omp.h>
#include <stdio.h>
#include <stdlib.h>

#define LIMIT1 39916800 //divisible by 2,3,4,5,6,7,8,9,10,11,12  
#define LIMIT 403200 // divisible by 2, 3, 4, 5, 6, 7, 8, 10 
#define ITERS 1

int main (int argc, char *argv[]) 
{
	int i, k, tid, min, nthreads, mymin, mylimit;
	int a[LIMIT];
	double times[4][ITERS], stop, start;
	FILE *outFile = stdout;

	nthreads = omp_get_num_threads();
	for(i=0; i<LIMIT; i++)
	{
		a[i] = rand()%1000;
	}

	//Method 1 is one threads only, sequential
	start = omp_get_wtime();
        min = a[0];
        for(i=0; i<LIMIT; i++)
        {
                if(min > a[i])
                        min = a[i];
        }
        stop = omp_get_wtime();
        times[0][0] = stop-start; 

	//Method 2 uses a parallel for, has a race condition?
        start = omp_get_wtime();
        min = a[0];
        # pragma omp parallel for
        for(i=0; i<LIMIT; i++)
        {
                if(min > a[i])
                        min = a[i];
        }
        stop = omp_get_wtime();
        times[1][0] = stop-start; 

	//Method 3 
        start = omp_get_wtime();
        min = a[0];
        #pragma omp parallel shared(min)  private(mylimit, mymin, tid, nthreads)
        {
                nthreads = omp_get_num_threads();
                tid = omp_get_thread_num();
                mylimit = LIMIT/nthreads;
                mymin = a[mylimit*tid];
                for(i=mylimit*tid; i<mylimit*(tid+1); i++)
                {
                        if(mymin > a[i])
                                mymin = a[i];
                }
                #pragma omp critical
                {
                        if(min > mymin)
                                min = mymin;
                }
        }
        stop = omp_get_wtime();
        times[2][0] = stop-start; 

	fprintf(outFile, "Method 1 (Sequential)    time:  %lf seconds.\n", times[0][0] );
	fprintf(outFile, "Method 2 (Parallel for)  time:  %lf seconds.\n", times[1][0] );
	fprintf(outFile, "Method 3 (Data parallel) time:  %lf seconds.\n", times[2][0] );
}

