/*CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
C                                                                             C
C  COMPUTE MERTENS FUNCTION (local maxima using Deleglise & Rivat algorithm)  C
C  10/18/15 (DKC)							      C
C                                                                             C
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC*/
#include <stdio.h>
#include <math.h>
#include "table2.h"
extern char *malloc();
int newmob(unsigned int a, unsigned int b, int *out, unsigned int *table);
int newriv(unsigned int x1, unsigned int x2, unsigned int u, char *mobb, int *M);
int fastriv(unsigned int x1, unsigned int u, char *mobb, int *M);
void mul64_32(unsigned int a0, unsigned int a2, unsigned int m0,
	      unsigned int *product);
//
unsigned int incnt=62;
unsigned int in[62*2]={
 14, 60, 
 21, 64, 
 28, 72, 
 42, 80, 
 56, 84, 
 70, 90, 
 77, 96, 
 126, 100, 
 140, 108, 
 154, 120, 
 231, 128, 
 308, 144, 
 462, 160, 
 616, 168, 
 770, 180, 
 924, 192, 
 1386, 200, 
 1540, 216, 
 1848, 224, 
 2002, 240, 
 3003, 256, 
 4004, 288, 
 6006, 320, 
 8008, 336, 
 10010, 360, 
 12012, 384, 
 18018, 400, 
 20020, 432, 
 24024, 448, 
 30030, 480, 
 40040, 504, 
 48048, 512, 
 60060, 576, 
 90090, 600, 
 102102, 640, 
 120120, 672, 
 170170, 720, 
 204204, 768, 
 306306, 800, 
 340340, 864, 
 408408, 896, 
 510510, 960, 
 680680, 1008, 
 816816, 1024, 
 1021020, 1152, 
 1531530, 1200, 
 1939938, 1280, 
 2042040, 1344, 
 3063060, 1440, 
 3879876, 1536, 
 5819814, 1600, 
 6126120, 1680, 
 6466460, 1728, 
 7759752, 1792, 
 9699690, 1920, 
 12932920, 2016, 
 15519504, 2048, 
 19399380, 2304, 
 29099070, 2400, 
 38798760, 2688, 
 58198140, 2880, 
 77597520, 3072};
//
void main() {
int t,*temp,*newtmp;
int *M;
char *m;
unsigned int MAXN,P[3],T[2],U[2],g,i,j,k,count,u,index,ta,tb;
unsigned int flag2,flag3,flag5,ut,total,tindex,p;
unsigned int pritab[100],prind,delta,joff,newind;
double sum,f1,f2;
FILE *Outfp;
Outfp = fopen("out1ah.dat","w");
MAXN=in[2*incnt-2];
f1=log(log((double)MAXN)+log(360.0));
f1=f1*f1;
f1=exp(1.0/3.0*log(f1));
f2=exp(1.0/3.0*(log((double)MAXN)+log(360.0)));
u=(unsigned int)(f1*f2);
printf("x/u=%d, u=%d \n",(MAXN/u)*360,u);
if (((MAXN/u)*360)>400000000) {
   printf("not enough memory \n");
   goto zskip;
   }
//
temp=(int*) malloc(32000);
if (temp==NULL) {
   printf("not enough memory \n");
   return;
   }
newtmp=(int*) malloc(32000);
if (newtmp==NULL) {
   printf("not enough memory \n");
   return;
   }
M=(int*) malloc(1600000004);
if (M==NULL) {
   printf("not enough memory \n");
   return;
   }
m=(char*) malloc(400000001);
if (m==NULL) {
   printf("not enough memory \n");
   return;
   }
printf("computing Mobius function \n");
index=0;
ta=1;
tb=1001;
for (i=0; i<400000; i++) {
   t=newmob(ta,tb,temp,table);
   if (t!=1) {
      printf("error \n");
      goto zskip;
      }
   ta=tb;
   tb=tb+1000;
   for (j=0; j<1000; j++)
      M[j+index]=temp[j];
   index=index+1000;
   }
//
// compute Mertens function
//
printf("computing Mertens function \n");
m[0]=(char)M[0];
for (i=1; i<=400000000; i++) {
   m[i]=(char)M[i];
   M[i]=M[i-1]+M[i];
   }
mul64_32(0,MAXN,360,P);
printf("computing sum: MAXN=%#010x %#010x \n",P[1],P[2]);
//
// factor N
//
for (g=0; g<incnt; g++) {
   ut=in[2*g];
   prind=0;
   total=0;
   flag2=3;
   temp[0]=2;
   temp[1]=4;
   temp[2]=8;
   tindex=3;
   count=0;
   while ((ut&1)==0) {
      temp[tindex]=temp[tindex-1]*2;
      tindex=tindex+1;
      count=count+1;
      ut=ut>>1;
      }
   flag2=flag2+count;
   pritab[prind]=flag2;
   prind=prind+1;
   flag3=2;
   temp[tindex]=3;
   temp[tindex+1]=9;
   tindex=tindex+2;
   count=0;
   while (ut==(ut/3)*3) {
      temp[tindex]=temp[tindex-1]*3;
      tindex=tindex+1;
      count=count+1;
      ut=ut/3;
      }
   flag3=flag3+count;
   pritab[prind]=flag3;
   prind=prind+1;
   flag5=1;
   temp[tindex]=5;
   tindex=tindex+1;
   count=0;
   while (ut==(ut/5)*5) {
      temp[tindex]=temp[tindex-1]*5;
      tindex=tindex+1;
      if (tindex>3999) {
	 printf("divisor table not big enough \n");
	 goto zskip;
	 }
      count=count+1;
      ut=ut/5;
      }
   flag5=flag5+count;
   pritab[prind]=flag5;
   prind=prind+1;
   total=(flag2+1)*(flag3+1)*(flag5+1);
   if (ut==1)
      goto askip;
   for (i=3; i<17983; i++) {
      p=table[i];
      count=0;
      while (ut==(ut/p)*p) {
	 if (count==0)
	    temp[tindex]=p;
	 else
	    temp[tindex]=temp[tindex-1]*p;
	 tindex=tindex+1;
	 if (tindex>3999) {
	    printf("divisor table not big enough \n");
	    goto zskip;
	    }
	 ut=ut/p;
	 count=count+1;
	 }
      if (count!=0) {
	 total=total*(count+1);
	 pritab[prind]=count;
	 prind=prind+1;
	 if (prind>49) {
	    printf("prime table not big enough \n");
	    goto zskip;
	    }
	 }
      if (ut==1)
	 goto askip;
      }
   printf("error: prime look-up table not big enough \n");
   goto zskip;
//
//  compute combinations of factors
//
askip:
   if (total!=in[2*g+1]) {
      printf("error: total=%d %d \n",total,in[2*g+1]);
      goto zskip;
      }
   for (i=(tindex-1); i>0; i--) {
      temp[2*i+1]=temp[i];
      temp[2*i]=0;
      }
   temp[1]=temp[0];
   temp[0]=0;
   delta=0;
   pritab[prind]=0;
   pritab[prind+1]=0;
bskip:
   joff=0;
   delta=0;
   newind=0;
   for (i=0; i<(prind+1)/2; i++) {
      count=pritab[2*i];
      for (j=0; j<count; j++) {
	 newtmp[newind*2]=temp[2*(j+joff)];
	 newtmp[newind*2+1]=temp[2*(j+joff)+1];
	 newind=newind+1;
	 }
      for (j=0; j<pritab[2*i+1]; j++) {
	 newtmp[newind*2]=temp[2*(j+joff+count)];
	 newtmp[newind*2+1]=temp[2*(j+joff+count)+1];
	 newind=newind+1;
	 }
      for (j=0; j<count; j++) {
	 T[0]=temp[2*(j+joff)];
	 T[1]=temp[2*(j+joff)+1];
	 for (k=0; k<pritab[2*i+1]; k++) {
	    U[0]=temp[2*(k+count+joff)];
	    U[1]=temp[2*(k+count+joff)+1];
	    if (T[0]==0)
	       mul64_32(U[0],U[1],T[1],P);
	    else
	       mul64_32(T[0],T[1],U[1],P);
	    newtmp[newind*2]=P[1];
	    newtmp[newind*2+1]=P[2];
	    newind=newind+1;
	    if (newind>3999) {
	       printf("divisor table not big enough \n");
	       goto zskip;
	       }
	    }
	 }
      joff=joff+pritab[2*i]+pritab[2*i+1];
      pritab[delta]=pritab[2*i]*pritab[2*i+1]+pritab[2*i]+pritab[2*i+1];
      delta=delta+1;
      }
   for (i=0; i<newind; i++) {
      temp[i*2]=newtmp[i*2];
      temp[i*2+1]=newtmp[i*2+1];
      }
   pritab[delta]=0;
   pritab[delta+1]=0;
   prind=delta;
   if (delta>1)
      goto bskip;
   if ((newind+1)!=in[2*g+1]) {
      printf("error: total=%d %d \n",newind,in[2*g+1]);
      goto zskip;
      }
//
// compute j(x)
//
   sum=1.0;
   for (i=0; i<newind; i++) {
      T[0]=temp[i*2];
      T[1]=temp[i*2+1];
      if (T[0]!=0) {
	 t=newriv(T[0],T[1],u,m,M);
	 printf("x=%#010x %#010x, t=%d \n",T[0],T[1],t);
	 }
      else {
	 if (T[1]>400000000) {
	    t=fastriv(T[1],u,m,M);
	    printf("x=%#010x, t=%d \n",T[1],t);
	    }
	 else
	    t=M[T[1]-1];
	 }
      sum=sum+(double)t*(double)t;
      }
   mul64_32(0,in[2*g],360,P);
   printf(" %#010x %#010x %d %d \n",P[1],P[2],(unsigned int)sum,newind+1);
   fprintf(Outfp," %#010x, %#010x, %d, %d, \n",P[1],P[2],(unsigned int)sum,newind+1);
   }
zskip:
fclose(Outfp);
return;
}