// Program to calculate bounds on f_k that guarantee system of APs does not cover. // See https://arxiv.org/abs/1811.03547, particularly Table 1. // // Portability: we need "int" to be at least 32-bit and "long long" to be at least 64-bit. #include #include #include #define llong long long // Need this to be at least 64-bits . #define EPS 1e-15 // Error margin to guard against fp arithmetic errors. #define Max ((llong)1e12) // Bound on largest prime considered. // The following is a list of k for which f_k will be printed. // Must be in increasing order, and last term should be > Max for safety. llong disp[]={2,3,4,5,6,7,8,9,10,21,100,1000,10000,51000,100000,1000000, (llong)1e7,(llong)1e8,(llong)1e9,(llong)1e10,Max+1}; // Speed of program largely limited by the speed at which one can generate primes. // The following is a modified Sieve of Eratothenes. // Due to memory constraints, we sieve in blocks of length 30*M, stored in sv[]. // Each block is divided into shorter sub-blocks of length 30, each stored in one "int". // Thus, if bit i of sv[j] is set then sp+30*j+i is *not* prime. // When a prime is sieved, only multiples that are relatively prime to 30=2*3*5 are sieved, // thus speeding the process up by a factor 30/8. // Only primes in pr[] are sieved (initialized by primesetup()), // thus the largest of these should be > sqrt(Max). #define M ((llong)1000000) // Sieve block size is 30*M int sv[M]; // Sieve array, "int" must be at least 32-bit llong sp; // Sieve array base offset, multiple of 30*M, -30*M indicates empty llong pr[M]; // List of small primes // msk is a bit mask containing those numbers mod 30 relatively prime to 30 const msk=(1<<1)|(1<<7)|(1<<11)|(1<<13)|(1<<17)|(1<<19)|(1<<23)|(1<<29); // add[n mod 30] is the amount needed to be added to n so that it is relatively prime to 30 int add[]={1,6,5,4,3,2,1,4,3,2,1,2,1,4,3,2,1,2,1,4,3,2,1,6,5,4,3,2,1,2}; // Return first prime number >p (64-bit) // llong nextp(llong p){ llong i,j,l,m,r; if(p<5){ // deal with small numbers if(p<2)return 2; if(p<3)return 3; return 5; } p+=add[p%30]; // next number relatively prime to 30 while(1){ r=p%30;m=(p-r-sp)/30; // m = offset in array sv[], r = p mod 30 // sv[m]|((1<=r // sv[m]==-1 indicates all bits set if(m>=0 && m=0&&m=0, so i+sp first multiple of pr[]>=sp if(i+sp=m*m for(j=0;j<30;j++){ // loop of next 30 muliples of pr[m] if((msk&(1<<(i%30)))!=0){ // if these are relatively prime to 30 for(l=i/30;l2 // until either the condition f_k < (\log k+\log\log k-3)^2 k holds // or we reach a stage where it is unlikely ever to hold. // If successful, the f_k values can be used to bound g_k // in Table 1 of https://arxiv.org/abs/1811.03547 // void try(double f2){ llong i,p,k; double a,b,d,f; time_t start,now; printf("\nTry f_2=%.12f\n",f2); f=f2; i=0; // index of next f_k to print in disp[] k=2;p=3; // start at prime p_2=3 time(&start); printf(" k p_k f_k time"); printf(" ln k+lnln k-(f_k/k)^.5\n"); // this number >3 yields success while(p<=Max){ if(k==disp[i]){ time(&now); printf("%13lld %13lld %18.12g %6d ",k,p,f,(int)(now-start)); printf("%f\n",log(k)+log(log(k))-sqrt(f/k)); i++; } if(k%1000==0){ // we do this test rarely as it is slow a=log(k)+log(log(k))-3; a-=a*EPS; // ensure we have an under-estimate if(f(a+1)*(a+1)*k && k>1000){ printf("Will prrobably fail for some k>%lld, p>%lld\n",k,p); break; } } p=nextp(p); k++; a=(3.*p-1)/((double)(p-1)*(p-1)); b=f/((double)(p-1)*(p-1)); // this is "4b_k*f_{k-1}" in the paper if(b>=1){ printf("Failed at k=%lld, p=%lld\n",k,p); break; } d=(1+a)/(1+sqrt(1+4*a*(1+a)/b)); // the optimal value of \delta_k f*=(1+EPS)*(1+a/(1-d))/(1-b/(4*d*(1-d))); } if(p>Max)printf("Not able to verify f_2 small enough\n"); time(&now); printf("%d seconds\n",(int)(now-start)); } main(){ if(primesetup()){ printf("Need to increase M or make M even\n"); return; } try(1.260997); // fast, but gives slightly worse bounds try(1.260997375); // slower, gives the bounds listed in Table 1 }