#include<stdio.h>
#include<gmp.h>
#include<stdlib.h>

#define NT 4
#define LIMIT 500000//23140
#define DIGITS 500000//30000

void *worker1(void *ptr);
void *worker2(void *ptr);

int start_i1=1,start_i2=1,end_i1,end_i2;
int thid[NT];

pthread_mutex_t mut1,mut2;

mpz_t f1,f2;
mpq_t ratio1,ratio2; 
mpq_t total1,total2;

int main(int argc, char *argv[])
{
  int i,j;
  unsigned long int seti,setn;

  setpriority(0,0,20);

  pthread_t th[NT];  
  pthread_mutex_init(&mut1,0);
  pthread_mutex_init(&mut2,0);
  
  end_i1 = end_i2 = LIMIT/NT;

  for(i=0;i<NT;i++)
   thid[i] = i;
  for(i=0;i<NT;i++)
  {
   if(i%2 == 0)
     pthread_create(&th[i],0,worker1,&thid[i]);
   else
     pthread_create(&th[i],0,worker2,&thid[i]);	   
  }

  for(i=0;i<NT;i++)
   pthread_join(th[i],0);

  mpq_t final; 
  mpq_init(final);

 /*******Mul 16 to total1******/
  mpz_mul_ui(mpq_numref(total1),mpq_numref(total1),16);
 /************/
 /*******Mul 4 to total2******/
  mpz_mul_ui(mpq_numref(total2),mpq_numref(total2),4);
 /************/
 /*******CREATE/APPEND in a FILE*******/
 FILE *fd;
 fd = fopen("pi.txt","a");
 /***************/

 mpq_sub(final,total1,total2);
 
 mpq_canonicalize(final);
 
 mpz_t num,den,quo,rem;

 mpz_init(num);
 mpz_init(den);
 mpz_init(quo);
 mpz_init(rem);
 

 mpq_get_num(num,final);
 mpq_get_den(den,final);

 mpz_tdiv_qr(quo,rem,num,den);

 //fputc('\n',fd); 
 mpz_out_str(fd,10,quo);
 fputs(".",fd); 
 
 for(j=0;j<=DIGITS;j++)
 {
  mpz_mul_ui(num,rem,10);
  mpz_tdiv_qr(quo,rem,num,den);
  /*if(j%50 == 0)
   fputc('\n',fd); //printf("\n");
  else if(j%10 == 0)
   fputc(' ',fd);// printf(" ");
   */
  mpz_out_str(fd,10,quo);
 }

}

void *worker1(void *ptr)
{
  int i;    	
  unsigned long int seti,setn;	

  pthread_mutex_lock(&mut1);
  
  if(start_i1 == 1)
  {
    mpq_init(ratio1);
    mpz_init(f1);

    mpq_init(total1);
    mpq_set_ui(total1,1,5);
  }

  for(i=start_i1; i<=end_i1; i++)
  {
   seti = i%2 == 0 ? 1:-1;
   setn = 2*i+1;
 
   mpz_ui_pow_ui(f1,5,setn);
   mpz_mul_ui(f1,f1,setn);
 
   mpq_set_si(ratio1,seti,1);
   mpq_set_den(ratio1,f1);
   
   mpq_add(total1,total1,ratio1);
  }
   start_i1 = end_i1 + 1;
   end_i1  += end_i1;

  pthread_mutex_unlock(&mut1);
  pthread_exit(ptr);
}

void *worker2(void *ptr)
{
  int i;    	
  unsigned long int seti,setn;	

  pthread_mutex_lock(&mut2);

  if(start_i2 == 1)
  {
    mpq_init(ratio2);
    mpz_init(f2);
   
    mpq_init(total2);
    mpq_set_ui(total2,1,239);
  }

  for(i=start_i2; i<=end_i2; i++)
  {
   seti = i%2 == 0 ? 1:-1;
   setn = 2*i+1;
 
   mpz_ui_pow_ui(f2,239,setn);
   mpz_mul_ui(f2,f2,setn);
 
   mpq_set_si(ratio2,seti,1);
   mpq_set_den(ratio2,f2);
 
   mpq_add(total2,total2,ratio2);
  }
   start_i2 = end_i2 + 1;
   end_i2  += end_i2;

  pthread_mutex_unlock(&mut2);
  pthread_exit(ptr);
}