3.7 欧拉函数

  欧拉函数(Euler’s totient function),也叫φ函数,入参只能是正整数。定义是从1到N这N个数里,和N互质的数的个数。欧拉函数没有通项公式,只有分段递归公式。下面是1~10的欧拉函数值:

x 1 2 3 4 5 6 7 8 9 10
φ(x) 1 1 2 2 4 2 6 4 6 4

  欧拉函数最简单的算法是循环。但是这个计算方法非常费时。高斯证明了以下一个公式:
∑ d ∣ n ϕ ( d ) = n \sum_{d|n}\phi(d)=n dnϕ(d)=n
  这里的d|n的意思是遍历n所有的约数。比如10的所有约数是1,2,5,10。这个公式没有恰当的翻译,我姑且翻译为约数欧拉函数和。所以应用上述公式有:
ϕ ( 1 ) + ϕ ( 2 ) + ϕ ( 5 ) + ϕ ( 10 ) = 10 \phi(1)+\phi(2)+\phi(5)+\phi(10)=10 ϕ(1)+ϕ(2)+ϕ(5)+ϕ(10)=10
  验证下哈,确实没错:
ϕ ( 1 ) + ϕ ( 2 ) + ϕ ( 5 ) + ϕ ( 10 ) = 1 + 1 + 4 + 4 = 10 \phi(1)+\phi(2)+\phi(5)+\phi(10)=1+1+4+4=10 ϕ(1)+ϕ(2)+ϕ(5)+ϕ(10)=1+1+4+4=10
  但是明白了这个公式后,我们就可以用一种快速的算法去计算了。但是计算过程并不能让人马上明白,所以我以刚才的φ(10)为例子。细细讲一下:
∵ ϕ ( 1 ) + ϕ ( 2 ) + ϕ ( 5 ) + ϕ ( 10 ) = 10 ∴ ϕ ( 10 ) = 10 − ϕ ( 1 ) − ϕ ( 2 ) − ϕ ( 5 ) \because \phi(1)+\phi(2)+\phi(5)+\phi(10)=10\\ \therefore \phi(10)=10-\phi(1)-\phi(2)-\phi(5)\\ ϕ(1)+ϕ(2)+ϕ(5)+ϕ(10)=10ϕ(10)=10ϕ(1)ϕ(2)ϕ(5)
  所以就是找到所有的因数。这个时候需要用到一种类似埃拉托色尼筛选法的算法。托色尼筛选法算法的本质是,我们不要去前面找所有的因数。而是去后面找所有的倍数减去我本身,与常规数组的向前遍历的算法稍有不同。我以求φ(10)为例子,讲解一下

  第一步先初始化为n

x 0 1 2 3 4 5 6 7 8 9 10
φ(x) 0 1 2 3 4 5 6 7 8 9 10

  1后面所有的数都是1的倍数,所以全部减去φ(1),所以变成:

x 0 1 2 3 4 5 6 7 8 9 10
φ(x) 0 1 1 2 3 4 5 6 7 8 9

  2后面所有2的倍数所以全部减去φ(2),所以变成:

x 0 1 2 3 4 5 6 7 8 9 10
φ(x) 0 1 1 2 2 4 4 6 6 8 8

  3后面所有3的倍数所以全部减去φ(3),所以变成:

x 0 1 2 3 4 5 6 7 8 9 10
φ(x) 0 1 1 2 2 4 2 6 6 6 8

  4后面所有4的倍数所以全部减去φ(4),所以变成:

x 0 1 2 3 4 5 6 7 8 9 10
φ(x) 0 1 1 2 2 4 2 6 4 6 8

  5后面所有5的倍数所以全部减去φ(5),所以变成:

x 0 1 2 3 4 5 6 7 8 9 10
φ(x) 0 1 1 2 2 4 2 6 4 6 4

  那么明白了算法之后,代码就容易了:

# _*_ coding:utf-8 _*_

def euler_totient(n):
    phi = [i for i in range(0, n + 1)]
    for i in range(1, n + 1):
        # 把i后面的全部减去phi[i]
        for j in range(i << 1, n + 1, i):
            phi[j] -= phi[i]
    return phi[n]


if __name__ == '__main__':
    print(euler_totient(10))

  测试结果:

4

你可能感兴趣的:(数学算法,数学)