筛法求欧拉函数值

做project euler时遇到的欧拉函数。
Euler's Totient function, φ(n) [sometimes called the phi function], is used to determine the number of positive numbers less than or equal to n which are relatively prime to n. For example, as 1, 2, 4, 5, 7, and 8, are all less than nine and relatively prime to nine, φ(9)=6.
The number 1 is considered to be relatively prime to every positive number, so φ(1)=1.

即欧拉函数φ(n)表示≤n且与n互素的正整数的数目(其实等于仅对1而言,φ(1)=1,1被认为与任何数互素)。
编程求一个数的φ(n)显然很简单,用gcd()就可以了,但如果求一个很大范围(N)内所有数的欧拉函数值,gcd()就难以胜任了。
在网上找了一下,发现欧拉函数的一个公式:
φ(n)=n*(1-1/p1)(1-1/p2)....(1-1/pk),其中p1、p2…pk为n的所有素因子。
比如:φ(12)=12*(1-1/2)(1-1/3)=4。
利用这个就比较好求了,可以用类似求素数的筛法。
先筛出N以内的所有素数,再以素数筛每个数的φ值。
比如求10以内所有数的φ值:
设一数组phi[11],赋初值phi[1]=1,phi[2]=2...phi[10]=10;
然后从2开始循环,把2的倍数的φ值*(1-1/2),则phi[2]=2*1/2=1,phi[4]=4*1/2=2,phi[6]=6*1/2=3....;
再是3,3的倍数的φ值*(1-1/3),则phi[3]=3*2/3=2,phi[6]=3*2/3=2,phi[9]=.....;
再5,再7...因为对每个素数都进行如此操作,因此任何一个n都得到了φ(n)=n*(1-1/p1)(1-1/p2)....(1-1/pk)的运算
觉得这个“筛”还是比较好用的,以前求数的所有因子之和也是用的它。
代码如下:

 

 

 

 

 


#include
#define N 10000000
main()

{

    int *phi,i,j;
    char *prime;

    

     prime=(char*)malloc((N+1)*sizeof(char));

     prime[0]=prime[1]=0;

    for(i=2;i<=N;i++)

     {

         prime[i]=1;

     }

    for(i=2;i*i<=N;i++)

     {

        if(prime[i])

         {

            for(j=i*i;j<=N;j+=i)

             {

                 prime[j]=0;

             }

         }

     }                            //这段求出了N内的所有素数   

 

 

 

    phi=(int*)malloc((N+1)*sizeof(int));
    for(i=1;i<=N;i++)

     {

         phi[i]=i;

     }

    for(i=2;i<=N;i++)

     {

        if(prime[i])

         {

            for(j=i;j<=N;j+=i)

             {

                 phi[j]=phi[j]/i*(i-1);    //此处注意先/i再*(i-1),否则范围较大时会溢出

             }

         }

     }                            //这段求出了N内所有数的欧拉函数值

}

你可能感兴趣的:(筛法求欧拉函数值)