/*CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
C                                                                             C
C  COMPUTE MERTENS FUNCTION (local maxima using Deleglise & Rivat algorithm)  C
C  10/31/15 (DKC)							      C
C                                                                             C
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC*/
#include <stdio.h>
#include <math.h>
#include "table3.h"
extern char *malloc();
int newmobl(unsigned long long a, unsigned long long b, int *out, unsigned int *table);
int newrivl(unsigned long long x, unsigned int u, char *mobb, int *M);
unsigned long long Msize=3000000000;   // for 16 GB of RAM, 64-bit OS
//
unsigned int incnt=73;
unsigned int in[73*2]={
 0x00000007, 48, 
 0x0000000e, 60, 
 0x00000015, 64, 
 0x0000001c, 72, 
 0x0000002a, 80, 
 0x00000038, 84, 
 0x00000046, 90, 
 0x0000004d, 96, 
 0x0000007e, 100, 
 0x0000008c, 108, 
 0x0000009a, 120, 
 0x000000e7, 128, 
 0x00000134, 144, 
 0x000001ce, 160, 
 0x00000268, 168, 
 0x00000302, 180, 
 0x0000039c, 192, 
 0x0000056a, 200, 
 0x00000604, 216, 
 0x00000738, 224, 
 0x000007d2, 240, 
 0x00000bbb, 256, 
 0x00000fa4, 288, 
 0x00001776, 320, 
 0x00001f48, 336, 
 0x0000271a, 360, 
 0x00002eec, 384, 
 0x00004662, 400, 
 0x00004e34, 432, 
 0x00005dd8, 448, 
 0x0000754e, 480, 
 0x00009c68, 504, 
 0x0000bbb0, 512, 
 0x0000ea9c, 576, 
 0x00015fea, 600, 
 0x00018ed6, 640, 
 0x0001d538, 672, 
 0x000298ba, 720, 
 0x00031dac, 768, 
 0x0004ac82, 800, 
 0x00053174, 864, 
 0x00063b58, 896, 
 0x0007ca2e, 960, 
 0x000a62e8, 1008, 
 0x000c76b0, 1024, 
 0x000f945c, 1152, 
 0x00175e8a, 1200, 
 0x001d99e2, 1280, 
 0x001f28b8, 1344, 
 0x002ebd14, 1440, 
 0x003b33c4, 1536, 
 0x0058cda6, 1600, 
 0x005d7a28, 1680, 
 0x0062ab9c, 1728, 
 0x00766788, 1792, 
 0x0094016a, 1920, 
 0x00c55738, 2016, 
 0x00eccf10, 2048, 
 0x012802d4, 2304, 
 0x01bc043e, 2400, 
 0x025005a8, 2688, 
 0x0378087c, 2880, 
 0x04a00b50, 3072, 
 0x06f010f8, 3360, 
 0x081813cc, 3456, 
 0x0aa34d38, 3584, 
 0x0c241db2, 3600, 
 0x0d4c2086, 3840, 
 0x10302798, 4032, 
 0x15469a70, 4096, 
 0x18483b64, 4320, 
 0x1a98410c, 4608, 
 0x27e46192, 4800};
//
void main() {
unsigned long long *oldtmp,*newtmp;
int *temp;
int *M;
char *m;
unsigned int p,tindex,prind,delta,joff,newind,count,total,h,k,u,pritab[1000];
unsigned int MAXN,g;
unsigned long long index,ta,tb,i,j,N,ut,pz,tz;
int savet,t;
double sum,f1,f2;
FILE *Outfp;
Outfp = fopen("out1ar.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)>Msize) {
   printf("not enough memory \n");
   goto zskip;
   }
temp=(int*) malloc(4004);
if (temp==NULL) {
   printf("not enough memory \n");
   return;
   }
oldtmp=(long long*) malloc(64000);
if (oldtmp==NULL) {
   printf("not enough memory \n");
   return;
   }
newtmp=(long long *) malloc(64000);
if (newtmp==NULL) {
   printf("not enough memory \n");
   return;
   }
M=(int*) malloc((Msize+1)*4);
if (M==NULL) {
   printf("not enough memory \n");
   return;
   }
m=(char*) malloc(Msize+1);
if (m==NULL) {
   printf("not enough memory \n");
   return;
   }
printf("computing Mobius function \n");
index=0;
ta=1;
tb=1001;
for (i=0; i<(Msize/1000); i++) {
   t=newmobl(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<=Msize; i++) {
   m[i]=(char)M[i];
   M[i]=M[i-1]+M[i];
   }
//
printf("finding maxima \n");
for (g=0; g<incnt; g++) {
//
// factor N
//
   N=(unsigned long long)in[2*g]*360;
   ut=N;
   prind=0;
   tindex=0;
   total=1;
   h=(unsigned int)(sqrt((double)ut)+0.01);  // for p>2, the difference between
   for (i=0; i<41538; i++) {		     // successive primes is greater
      p=table[i];			     // than 1, so adding 0.01 is okay
      if (p>h)
	 goto fskip;
      count=0;
      while (ut==(ut/p)*p) {
	 if (count==0)
	    oldtmp[tindex]=p;
	 else
	    oldtmp[tindex]=oldtmp[tindex-1]*p;
	 tindex=tindex+1;
	 if (tindex>7999) {
	    printf("divisor table not big enough: N=%d \n",N);
	    goto zskip;
	    }
	 ut=ut/p;
	 count=count+1;
	 }
      if (count!=0) {
	 total=total*(count+1);
	 pritab[prind]=count;
	 prind=prind+1;
	 if (prind>1000) {
	    printf("prime table not big enough: N=%d \n",N);
	    goto zskip;
	    }
	 }
      if (ut==1)
	 goto askip;
      }
   printf("error: prime look-up table not big enough \n");
   goto zskip;
//
//  compute combinations of factors
//
fskip:
   oldtmp[tindex]=ut;
   tindex=tindex+1;
   if (tindex>7999) {
      printf("divisor table not big enough: N=%d \n",N);
      goto zskip;
      }
   count=1;
   total=total*(count+1);
   pritab[prind]=count;
   prind=prind+1;
   if (prind>1000) {
       printf("prime table not big enough: N=%d \n",N);
       goto zskip;
       }
askip:
   if (total!=in[2*g+1]) {
      printf("error: total=%d %d \n",total,in[2*g+1]);
      goto zskip;
      }
   if (prind==1) {
      newind=tindex;
      goto cskip;
      }
   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]=oldtmp[j+joff];
	 newind=newind+1;
	 }
      for (j=0; j<pritab[2*i+1]; j++) {
	 newtmp[newind]=oldtmp[j+joff+count];
	 newind=newind+1;
	 }
      for (j=0; j<count; j++) {
	 tz=oldtmp[j+joff];
	 for (k=0; k<pritab[2*i+1]; k++) {
	    pz=tz*oldtmp[k+count+joff];
	    newtmp[newind]=pz;
	    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++)
      oldtmp[i]=newtmp[i];
   pritab[delta]=0;
   pritab[delta+1]=0;
   prind=delta;
   if (delta>1)
      goto bskip;
//
// compute j(x)
//
cskip:
   if ((newind+1)!=in[2*g+1]) {
      printf("error: newind=%d %d \n",newind,in[2*g+1]);
      goto zskip;
      }
   sum=1.0;
   for (i=0; i<newind; i++) {
      tz=oldtmp[i];
      if (tz>Msize) {
	 t=newrivl(tz,u,m,M);
	 if (tz==N)
	    savet=t;
	 printf("x=%I64x, t=%d \n",tz,t);
	 }
      else {
	 t=M[tz-1];
	 if (tz==N)
	    savet=t;
	 }
      sum=sum+(double)t*(double)t;
      }
   printf(" %d %I64x %d %I64x %d %d \n",N,N,(unsigned int)sum,(unsigned long long)sum,newind+1,savet);
   fprintf(Outfp," %I64x, %I64x, %d, %d, \n",N,(unsigned long long)sum,newind+1,savet);
   }
zskip:
fclose(Outfp);
return;
}