#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <limits.h>

int primes[] =
{
    2, 3, 5, 7, 11, 13, 17, 19,
    23, 29, 31, 37, 41, 43, 47, 53,
    59, 61, 67, 71, 73, 79, 83, 89,
    97, 101, 103, 107, 109, 113, 127, 131,
    137, 139, 149, 151, 157, 163, 167, 173,
    179, 181, 191, 193, 197, 199, 211, 223,
    227, 229, 233, 239, 241, 251, 257, 263,
    269, 271, 277, 281, 283, 293, 307, 311,INT_MAX
};
#define PI 3.1415926535897932384626433832795

// 计算x以内y光滑数的个数
// 参考文献
// 1. 《On integers free of large prime factors》 by A.Hildebrand and G.Tenenbaum. .
// 2. 《A Fast Algorithm for Approximately Counting Smooth Numbers》 by Jonathan P. Sorenson

/*
  用到的几个函数
  1. zeta(s,y)
   // prod= (1- p1^(-s))(1- p2^(-s))...(1- pi^(-s)), pi<=y
   // return 1/prod
  2. phi1(s,y)= sum(log(p)/( p^s-1)), p<=y
  3. phi2(s,y)= sum(p^s*(log p)^2/( p^s-1)^2), p<=y
  4. 函数 alpha(s,c,v),表示方程v - phi1(s,c) =0 的解s
  5. 函数 HT(x,y,s)= (x^s * zeta(s,y))/(s * sqrt(pi * phi2(s,y))
  */

  //1. zeta(s, y)
  // prod= (1- p1^(-s))(1- p2^(-s))...(1- pi^(-s)), pi<=y
  // return 1/prod
double zeta(double s, int y)
{
    double prod = 1.0;
    for (int i = 0; primes[i] <= y; i++)
    {
        double p = (double)primes[i];
        double item = 1.0 - pow(p, -s);
        prod *= item;
    }
    return 1.0 / prod;
}

// 2. phi1(s, y) = sum( log(p)/(p^s - 1) ) for p<=y
double phi1(double s, int y)
{
    double sum = 0.0;
    for (int i = 0; primes[i] <= y; i++)
    {
        double p = (double)primes[i];
        double item = log(p) / (pow(p, s) - 1.0);
        sum += item;
    }
    return sum;
}

//3. phi2(s, y) = sum( p^s * (log p)^2 / (p^s - 1)^2 ) for p <= y
double phi2(double s, int y)
{
    double sum = 0.0;
    for (int i = 0; primes[i] <= y; i++)
    {
        double p = (double)primes[i];
 double ps1= pow(p,s)-1;
        double item = pow(p,s)*log(p)*log(p)/(ps1*ps1);
        sum += item;
    }
    return sum;
}

typedef struct alpha_iter_st
{
    double a0;
    double v0;
    double a1;
    double v1;
    double v; // target value
}ALPHA_ST;


/*
 函数 phi1(x,c),x为自变量,c是常数,
 v0=phi1(x0,c),v1=phi1(x1,c),
 求 方程 v - phi1(x, c) = 0 的解x
 假定函数 phi1(x,c)在区间[x0,x1],近似为一次函数, 则
  斜率 k=(v1-v0)/(x1-x0)
=> (x-x1)=k/(v-v1)
=> x= x1+(x-x1)
=> x= x1+(v-v0)/k
*/

// 计算函数 phi1(s,y)的近似值s0,
// s0= log(1 + y/v)/log(y), 这里y是素数
inline double get_s0_v1(double v, int y)
{
    return log(1.0 + (double)y/v)/log((double)y);
}

/*
   首先用牛顿迭代法求 函数4.
   方法。
   1.计算 初值 r0
   2.使用牛顿迭代法求r1,
   3.若r1-r0<1e-12, 结束计算,返回r1
      否则 r0=r1, 继续重复步骤2
*/

//inline double alpha_core(ALPHA_ST* p)
// return max(p),p是素数,p<=y,
int correct(int y)
{
    if (y < 2)
        return -1;
    
    int i = 0;
    while (primes[i] <= y)
        i++;
    return primes[i - 1];
}

double get_x1(int y, double v, double x0, double v0, double* pv)
{
    double v1;
    double x1 = x0;

    if (v0 < v) // x0 is bigger than the true value
    {
        do
        {
            x1 *= 0.9;
            v1 = phi1(x1, y);
            //printf("x1=%.16lf, t=%.16lf\n", x1, v1);
        } while (v1 < v);
        *pv = v1;
        return x1;
    }

    // now x0 is smaller than the true value
    do
    {
        x1 *= 1.1;
        v1 = phi1(x1, y);
        //printf("x1=%.16lf, t=%.16lf\n", x1, v1);
    } while (v1 > v);

    *pv = v1;
    return x1;
}
//5. 函数 alpha(v,y) 表示方程 phi1(s,y) - v=0 的解s
double alpha(double v, int y)
{
    assert(y <= 311);

    ALPHA_ST c;
    int i;
    double k, a2;

    y = correct(y);
    c.v = v;
    //printf("v=%.16lf\n", v);

    c.a0 = get_s0_v1(v, y);
    c.v0 = phi1(c.a0, y);

    //printf("a0=%.16lf,v0=%.16f\n", c.a0, c.v0);

    c.a1 = get_x1(y, v, c.a0, c.v0, &(c.v1));
    //printf("a1=%.16lf, v1=%.16lf\n", c.a1, c.v1);

    i = 2;
    while (true)
    {
        k = (c.v1 - c.v0) / (c.a1 - c.a0);
        a2 = c.a1 + (c.v - c.v1) / k;

        c.a0 = c.a1;
        c.v0 = c.v1;
        c.a1 = a2;
        c.v1 = phi1(c.a1, y);
        //printf("\n a[%d]= %.16lf, v[%d]=%.16lf\n", i, c.a1, i, c.v1);
        if (fabs(c.a1 - c.a0) < c.a0 * 1e-9)
            break;
        i++;
    }

    k = (c.v1 - c.v0) / (c.a1 - c.a0);
    a2 = c.a1 + (c.v - c.v1) / k;
    //printf("\n phi1(%.16lf,%d)=%.16lf\n", a2, y, phi1(a2, y));
    return a2;
}

double sm_count(double x, int y)
{
    double s, z, u;
    double r;

    y = correct(y);
    s = alpha(log(x), y);
    z = zeta(s, y);
    u = phi2(s, y);
    r = pow(x, s) * z / (s * sqrt(2*PI * u));
    return r;
}

double sm_count_logx(double logx, int y)
{
    double s, z, u;
    double r;

    y = correct(y);
    s = alpha(logx, y);
    z = zeta(s, y);
    u = phi2(s, y);
    r = s*logx + log(z) - log(s*sqrt(2*PI*u));
    return r;
}

void test()
{
    double x, s, logx;
    int n, y;

    n = 48;
    y = primes[n - 1];
    x = pow(2.0, 64);
    logx = log(x);
    s = alpha(log(x),y);
}

void test2()
{
    double x = pow(2.0, 64.0);
    double r;
    int y;
    for (int i = 4; i <= 48; i += 4)
    {
        y = primes[i - 1];
        r = sm_count(x, y);
        printf("sm_count( 2^64,%d)= %.16lf\n", y,r);
    }
}

void test3()
{
  int y;
  int pow2;
  int n;
  int step;
  for (int j=0;j<2;j++)
  {
     if (j==0)
     {	pow2=64; n=12; step=4;}
     else
     { pow2=4096; n=2; step=4;}
     printf("\n----------------------------------\n");
     for (int i=1;i<=n;i++)
     {
        int y=primes[i*step-1];
   double logx = pow2*log(2.0);
    double logsm= sm_count_logx(logx,y);
    //printf("log(sm_count(2^%d,%d))=%.16lf\n",pow2,y,logsm);
    double r= exp(logsm);
    printf("sm_count(2^%d,%d)=%.16lf\n",pow2,y,r);
     }
  }
}
int main()
{
    test2();
    test3();
    return 0;
}

/* test2 输出结果
sm_count( 2^64,7)= 87145.0247772681177594
sm_count( 2^64,19)= 11286548.3023795727640390
sm_count( 2^64,37)= 211967017.2076353728771210
sm_count( 2^64,53)= 1599684387.4000642299652100
sm_count( 2^64,71)= 7107020116.2066755294799805
sm_count( 2^64,89)= 22998573481.4820442199707031
sm_count( 2^64,107)= 58913795304.6139526367187500
sm_count( 2^64,131)= 129415464204.2234191894531250
sm_count( 2^64,151)= 250108239713.3505859375000000
sm_count( 2^64,173)= 441507555760.2599487304687500
sm_count( 2^64,193)= 726098055915.4711914062500000
sm_count( 2^64,223)= 1128020024926.1152343750000000
*/


/* test3 输出结果
----------------------------------
sm_count(2^64,7)=87145.0247772680886555
sm_count(2^64,19)=11286548.3023795988410711
sm_count(2^64,37)=211967017.2076350152492523
sm_count(2^64,53)=1599684387.4000587463378906
sm_count(2^64,71)=7107020116.2067070007324219
sm_count(2^64,89)=22998573481.4820785522460938
sm_count(2^64,107)=58913795304.6140899658203125
sm_count(2^64,131)=129415464204.2231750488281250
sm_count(2^64,151)=250108239713.3501892089843750
sm_count(2^64,173)=441507555760.2587890625000000
sm_count(2^64,193)=726098055915.4709472656250000
sm_count(2^64,223)=1128020024926.1152343750000000
----------------------------------
sm_count(2^4096,7)=1163396154613.0056152343750000
sm_count(2^4096,19)=884405629135495102464.0000000000000000
*/

 
/* 
n | 真实值 | 计算值  
4; | 85,348 | 87,145.
8; | 11,169,655 | 11,286,548.
12; | 210,499,995 | 211,967,017.
16; | 1,591,363,196 | 1,599,684,387.
20; | 7,077,350,886 | 7,107,020,116.
24; | 22,918,160,232 | 22,998,573,481.
28; | 58,735,924,658 | 58,913,795,304
32; | 129,070,232,683 | 129,415,464,204.
36; | 249,507,947,485 | 250,108,239,713.
40; | 440,539,214,034 | 441,507,555,760.
44; | 724,624,467,775 | 726,098,055,915.
48; | 1,125,880,419,418 | 1,128,020,024,926.
*/