歐拉函數

  歐拉函數φ(x)表示小於等於x的正整數中與x互質的數的個數。好比φ(4)=2,由於4與1,3互質。編程

推導證實

  下面說明歐拉函數的性質,再經過性質得出歐拉函數的公式。函數

 

命題1:φ(1)=1spa

證實:無code

 

命題2:對於任意素數p,φ(p)=p-1blog

證實:每一個素數的因子只有1和自身,故1,2,...,p中有1,2,...,p-1與p互質。it

 

命題3:歐拉函數是積性函數,即對任意互質的正整數n,m,有φ(nm)=φ(n)φ(m)。class

證實:咱們將1~nm之間的正整數以矩陣形式展開:im

$$ \left[\begin{matrix} 1 & 2 &\cdots & m-1 & m\\ m+1 & m+2 &\cdots & 2m-1 & 2m\\ \vdots &\vdots &\ddots &\vdots &\vdots\\ \left(n-2\right)m+1 &\left(n-2\right)m+2 &\cdots &\left(n-1\right)m-1 &\left(n-1\right)m\\ \left(n-1\right)m+1 &\left(n-1\right)m+1 &\cdots & nm-1 & nm \end{matrix}\right] $$集合

對於rm+c,其中1<=r<=n,1<=c<=m,若是c與m互質,那麼rm+c則與m互質(同餘定理),故咱們能夠找到φ(m)個數c1,c2,...,cφ(m),而其他1~m中的正整數因爲與m有公約數,故與mn也必然有公約數,即不可能與mn互質。咱們將除了c1,c2,...,cφ(m)外的其他列所有從矩陣中移除。di

而對於c,m+c,...,(n-1)m+c,考慮到m與n互質,所以這裏列出的n個數在模n剩餘類環中均不一樣。事實上im+c=jm+c(mod n),有(i-j)m=0(mod n),而m與n互質,故i-j=kn,這裏的i,j取值範圍爲0~(n-1),故i=j,所以這n個數在模n的意義下兩兩不一樣。而考慮到模n剩餘類環的大小爲n,所以這n個數剛好組成了整個環,即集合爲{1,2,...,n-1}。考慮與n互質的φ(n)個數,r1,r2,...,rφ(n),咱們發現每一列中都有且只有φ(n)個數與n互質。咱們將每一列不能與n互質的數移去,這樣總共留下了φ(n)φ(m)個數。

按照上面的說明咱們得知最多隻有φ(n)φ(m)個數與mn互質,而咱們還須要保證矩陣中留下的φ(n)φ(m)個數都能與mn互質。考慮與mn非互質的數x,則mn與x有公約數p,即p|mn,考慮到m與n互質,所以或者p|m或者p|n,即x與m或n非互質。考慮到咱們上面的過程將全部與m或n非互質的數所有移除掉了,所以矩陣中留下的數全都與mn互質。

 

命題4:對於任意素數p,φ(p^n)=(p^n)*(1-1/p)。

證實:在p^n中,能與p非互質的數爲p,2p,...,p^n,共p^(n-1)個。所以咱們獲得φ(p^n)=p^n-p^(n-1)=(p^n)*(1-1/p)。

 

結合上面四條命題,對於任意一個數n,咱們能夠將其分解爲素因子的冪的乘積$ n=p_1^{c_1}\cdots p_k^{c_k} $(算術基本定理),以後利用命題4與3推出:

$$ \varphi\left(n\right)=\varphi\left(p_1^{c_1}\right)\cdots\varphi\left(p_k^{c_k}\right)=p_1^{c_1}\left(1-1/p_1\right)\cdots p_k^{c_k}\left(1-1/p_k\right)=n\prod_{i=1}^k{\left(1-\frac{1}{p_i}\right)} $$

編程實現

  計算歐拉函數有兩種方式,一種是先預處理出全部素數,以後利用O(√n)的時間複雜度計算出歐拉函數φ(n)。第二種方式是利用歐拉篩在O(N)的時間和空間複雜度內計算1~N之間的全部歐拉函數。前者消耗的空間較少,且時間複雜度在只須要計算少許值的歐拉函數值時有利,然後者則適用於須要計算大批量歐拉函數值且N較小。

  方式1:

phi(n)
    res = n
    for prime p in [1, sqrt(n)]
        if n % p != 0
            continue
        res = res / p * (p - 1)
        while n % p == 0
            n = n / p
    if n > 1 //此時n餘下一個素數
        res = res / n * (n  - 1)
    return res

  方式2:

init(limit)
    isPrime = empty-array
    phi = empty-array
    primes = empty-list    
    
    for(i = 1; i < limit; i++)
        isPrime[i] = true
    
    phi[1] = 1
    for(i = 2; i < limit; i++)
        if(isPrime[i]){
            phi[i] = i - 1
            primes.add(i)
        }
        for p in primes
            isPrime[i * p] = false
            if(i % p == 0)
                phi[i * p] = phi[i] * p
                break
            else
                phi[i * p] = phi[i] * phi[p]
    return phi
相關文章
相關標籤/搜索