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

#ifdef HAVE_PTHREAD
#include <pthread.h>
#define WITH_THREADS
typedef pthread_t thread_t;
#else
typedef int thread_t;
#undef WITH_THREADS
#endif

struct ThreadArgs
{
	int step;
	long int nrruns;
	int offset;
	double result;
	thread_t tid;
};

#define DEFNRRUNS 2000000000L

static void* calc_taylor (void *arg)
{
struct ThreadArgs *ta=arg;
long int i,max;
int step,offset;
double ret;

	ret=0;step=ta->step;offset=ta->offset;
	max=ta->nrruns/ta->step;
	for (i=0;i<max;i+=1)
	{
		ret+=1.0/(2*(offset+i*step)+1);
	}
	ta->result=ret;
	return ta;
}

static uint64_t parselarge (const char* s, uint64_t defvalue, int factor)
{
uint64_t res;
char *endptr;

	res=strtoull (s, &endptr, 10);
	if (endptr==s) return defvalue;
	if (*endptr==0) return res;
	switch (*endptr)
	{
		case 't':
		case 'T':
			res*=factor;
		case 'g':
		case 'G':
			res*=factor;
		case 'm':
		case 'M':
			res*=factor;
		case 'k':
		case 'K':
			res*=factor;
			break;
		default:
			break;
	}
	return res;
}

int main (int argc, char **argv)
{
double result;
struct ThreadArgs *ta;
int i;
int nrthreads;
uint64_t nrruns;

#ifdef WITH_THREADS
	nrthreads=2;
#else
	nrthreads=1;
#endif
	nrruns=DEFNRRUNS;
	for (i=1;i<argc;i++)
	{
		if (argv[i][0]=='-')
		{
			switch (argv[i][1])
			{
				case 'n':
					if (i+1>=argc)
					{
						fprintf (stderr,"-%c requires a parameter.\n",argv[i][1]);
						return -1;
					}
					nrthreads=atoi(argv[++i]);
#ifndef WITH_THREADS
					if (nrthreads>1)
						fprintf (stderr,"Thread support not compiled in, "
								"using one single thread.\n");
					nrthreads=1;
#endif
					break;
				case 'r':
					if (i+1>=argc)
					{
						fprintf (stderr,"-%c requires a parameter.\n",argv[i][1]);
						return -1;
					}
					nrruns=parselarge(argv[++i], DEFNRRUNS, 1000);
					break;
				default:
					fprintf (stderr,"unknown option -%c\n",argv[i][1]);
					return -1;
			}
		} else
		{
			fprintf (stderr,"unknown parameter \"%s\"\n",argv[i]);
			return -1;
		}
	}
	ta=malloc(sizeof(struct ThreadArgs)*nrthreads);
	if (nrthreads==1)
	{
		ta[0].offset=0;ta[0].step=2;ta[0].nrruns=nrruns;
		calc_taylor (ta);
		result=ta[0].result;
		ta[0].offset=1;
		calc_taylor (ta);
		result-=ta[0].result;
	} else
	{
#ifdef WITH_THREADS
		for (i=0;i<nrthreads;i++)
		{
			ta[i].offset=i;
			ta[i].step=nrthreads;
			ta[i].nrruns=nrruns;
			pthread_create (&ta[i].tid,NULL,calc_taylor,ta+i);
			if (i%2==0) result+=ta[i].result; else result-=ta[i].result;
		}
		result=0.0;
		for (i=0;i<nrthreads;i++)
		{
			pthread_join (ta[i].tid,NULL);
			if (i%2==0) result+=ta[i].result; else result-=ta[i].result;
		}
#endif
	}
	fprintf (stdout, "PI: %.12f\n",4*result);
	free (ta);
	return 0;
}

