#include<stdio.h>
#include<stdlib.h>
#include<gmp.h>
#include<pthread.h>
#include<sys/time.h>
#include<sys/resource.h>
#define NT 4
#define BASE 10
#define N_DIGITS 1000000

mpq_t e1,e2,e3,e4;
int thid[NT];
void rationaltodecimal(mpq_t m,int n)
{
   mpz_t numr,denomr,m_q,m_r;
   int i;
   FILE *fp;

   mpz_init(numr);
   mpz_init(denomr);
   mpz_init(m_q);
   mpz_init(m_r);

   mpq_get_num(numr,m);
   mpq_get_den(denomr,m);
   mpz_tdiv_qr(m_q,m_r,numr,denomr);
   fp = fopen("pi.txt","a");
   mpz_out_str(fp,BASE,m_q);
   fprintf(fp,"\n\n");
   for(i =0; i < n; i++){
     mpz_mul_ui(numr,m_r, BASE);     
     mpz_tdiv_qr(m_q,m_r, numr, denomr);
     mpz_out_str(fp, BASE, m_q);
     if((i+1) % 10 == 0)
       fputs(" ",fp);
     if((i+1) % 50 == 0)
       fputs("\n",fp);
     if((i+1) % 1000 == 0)
       fprintf(fp,"\n\n\n");

   }
   fprintf(fp,"\n");
   mpz_clear(numr);
   mpz_clear(denomr);
   mpz_clear(m_q);
   mpz_clear(m_r);
}

void *worker1(void *ptr)
{
  unsigned long long int i,sum =1,tmp = 2401;
  mpq_t t;
  mpz_t p,dr;
  mpz_init(p);
  mpq_init(t);
  mpz_init(dr);
  mpq_set_ui(t,1,49);
  mpq_set(e1,t);
  mpz_set_ui(p,49);
 
  for(i = 1;i<70000;i++)
  {
      sum+=2;
      mpz_mul_ui(p,p,tmp);
      mpz_mul_ui(dr,p,sum);
      mpq_set_den(t,dr);
      if(i%2 == 0)
       mpq_add(e1,e1,t);
      else
       mpq_sub(e1,e1,t);
   }
  mpq_clear(t);
  mpz_clear(dr);
  mpz_clear(p);
  pthread_exit(ptr);
}
void *worker2(void *ptr)
{
  unsigned long long int i,sum =1,tmp = 3249;
  mpq_t t;
  mpz_t p,dr;
  mpz_init(p);
  mpq_init(t);
  mpz_init(dr);
  mpq_set_ui(t,1,57);
  mpq_set(e2,t);
  mpz_set_ui(p,57);
 
  for(i = 1;i<60000;i++)
  {
      sum+=2;
      mpz_mul_ui(p,p,tmp);
      mpz_mul_ui(dr,p,sum);
      mpq_set_den(t,dr);
      if(i%2 == 0)
       mpq_add(e2,e2,t);
      else
       mpq_sub(e2,e2,t);
   }
  mpq_clear(t);
  mpz_clear(dr);
  mpz_clear(p);
  pthread_exit(ptr);
}
void *worker3(void *ptr)
{
  unsigned long long int i,sum =1,tmp = 57121;
  mpq_t t;
  mpz_t p,dr;
  mpz_init(p);
  mpq_init(t);
  mpz_init(dr);
  mpq_set_ui(t,1,239);
  mpq_set(e3,t);
  mpz_set_ui(p,239);
 
  for(i = 1;i<50000;i++)
  {
      sum+=2;
      mpz_mul_ui(p,p,tmp);
      mpz_mul_ui(dr,p,sum);
      mpq_set_den(t,dr);
      if(i%2 == 0)
       mpq_add(e3,e3,t);
      else
       mpq_sub(e3,e3,t);
   }
  mpq_clear(t);
  mpz_clear(dr);
  mpz_clear(p);
  pthread_exit(ptr);
}
void *worker4(void *ptr)
{
  unsigned long long int i,sum =1,tmp = 12197656249;
  mpq_t t;
  mpz_t p,dr;
  mpz_init(p);
  mpq_init(t);
  mpz_init(dr);
  mpq_set_ui(t,1,110443);
  mpq_set(e4,t);
  mpz_set_ui(p,110443);
 
  for(i = 1;i<10000;i++)
  {
      sum+=2;
      mpz_mul_ui(p,p,tmp);
      mpz_mul_ui(dr,p,sum);
      mpq_set_den(t,dr);
      if(i%2 == 0)
       mpq_add(e4,e4,t);
      else
       mpq_sub(e4,e4,t);
   }
  mpq_clear(t);
  mpz_clear(dr);
  mpz_clear(p);
  pthread_exit(ptr);
}

int main(int args,char *argv[])
{
  setpriority(0,0,20);
  pthread_t th[NT];
  int i;
  mpq_init(e1);
  mpq_init(e2);
  mpq_init(e3);
  mpq_init(e4);

  mpq_set_ui(e1,1,49);
  mpq_set_ui(e2,1,57);
  mpq_set_ui(e3,1,239);
  mpq_set_ui(e4,1,110443);


  for(i=0;i<NT;i++)
    thid[i] = i;

  pthread_create(&th[0], 0, worker1,&thid[0]);
  pthread_create(&th[1], 0, worker2,&thid[1]);
  pthread_create(&th[2], 0, worker3,&thid[2]);
  pthread_create(&th[3], 0, worker4,&thid[3]);

  for(i = 0;i<NT;i++)
    pthread_join(th[i],0);
 
  mpz_mul_ui(mpq_numref(e1),mpq_numref(e1),48);
  mpz_mul_ui(mpq_numref(e2),mpq_numref(e2),128);
  mpz_mul_ui(mpq_numref(e3),mpq_numref(e3),20);
  mpz_mul_ui(mpq_numref(e4),mpq_numref(e4),48);

  mpq_sub(e2,e2,e3);
  mpq_add(e1,e1,e2);
  mpq_add(e1,e1,e4);

  rationaltodecimal(e1,N_DIGITS);
  mpq_clear(e1);
  mpq_clear(e2);
  mpq_clear(e3);
  mpq_clear(e4);

}