
#include <stdio.h>
#include <math.h>

#include <mpi.h>

double f(double a)
{
    return (4.0 / (1.0 + a*a));
}


// Max Task = 4

void main(int argc, char *argv[])
{
    int done = 0, n, myPid, numprocs, i;
    long double PI25DT = 3.141592653589793238462643;
    long double myPi, pi, h, sum, x;

	// startzeit
    long double startwtime, endwtime;

    int  namelen;
    char processor_name[MPI_MAX_PROCESSOR_NAME];
	

    MPI_Init(&argc,&argv);

	   // Anzahl der Prozesse
    MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
    
	   // meine eigene ID
	MPI_Comm_rank(MPI_COMM_WORLD,&myPid);
    
	   // Prozessename
	MPI_Get_processor_name(processor_name,&namelen);
	
    fprintf(stderr,"Process %d on %s\n",  myPid, processor_name);
	fflush(stderr);
	
    n = 0;

	startwtime = MPI_Wtime();
	// einlesen aus Datei
	n=10000;
    MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD);

        if (n > 0)  {
			//puts("Master und Client rechnen");
            //printf("Pid %d rechnet \n", myPid);
            h   = n;  // Schrittweite
            h   = 1.0 / h;  // Schrittweite
            sum = 0.0;  // lokale Summe pro Client
			  // Beachte die Incrementierung    i += numprocs
            for (i = myPid + 1; i <= n; i += numprocs)
			{
                x = h * ( (long double)i - 0.5);  // mittelpunkt genauer
                sum += f(x);
            }
            myPi = h * sum*4.0;
			// myPi = myid+1;
			
			  // Akkumulationsoperation
			/*
				int MPI_Reduce(
					void  *sendbuf,			// sendepuffer			&myPi
					void *recvbuf,									&pi
					int count,										jeder ein double
					MPI_Datatype datatype,							Doubletyp Typ
					MPI_Op op,										Reduce-Op = Summe
					int root,				// Sender				Master ist Sender
					MPI_Comm comm			// Bereichsname			An Alle
				);	
			*/
            
			MPI_Reduce(&myPi, &pi, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);

			
            if (myPid == 0)
			{    
				  // nur Master gibt aus
                printf("Master: pi is approximately %.16f, Error is %.16f\n", pi, fabs(pi - PI25DT));
		        endwtime = MPI_Wtime();
		        printf("wall clock time = %f\n", endwtime-startwtime);	       
			}
			else {
              printf("Client: %d myPi is approximately %.16f, Error is %.16f\n", myPid, myPi, fabs(myPi - PI25DT));
			}

		
		}
    MPI_Finalize();
}

//1000:	   Master: pi is approximately 3.1415927369231254, Error is 0.0000000833333322
//1000000: Master: pi is approximately 3.1415926535899197, Error is 0.0000000000001266
