Python 优化Totient函数

Python 优化Totient函数,python,function,Python,Function,我试图最大化Python上的Euler ToClient函数,因为它可以使用大量的任意数字。问题是程序在一段时间后被终止,因此它没有达到所需的比率。我曾想过将起始数字增加到一个更大的数字,但我认为这样做并不明智。我试图得到一个数字,当除以总数值大于10时。本质上,我试图找到一个符合这个标准的零散的数字 这是我的φ函数: def phi(n): amount = 0 for k in range(1, n + 1): if fractions.gcd(n, k)

我试图最大化Python上的Euler ToClient函数,因为它可以使用大量的任意数字。问题是程序在一段时间后被终止,因此它没有达到所需的比率。我曾想过将起始数字增加到一个更大的数字,但我认为这样做并不明智。我试图得到一个数字,当除以总数值大于10时。本质上,我试图找到一个符合这个标准的零散的数字

这是我的φ函数:

def phi(n):
    amount = 0

    for k in range(1, n + 1):
        if fractions.gcd(n, k) == 1:
            amount += 1

    return amount

我有一个部分的解决方案给你,但是结果看起来不太好。。(这个解决方案可能不会给你现代计算机硬件的答案(目前ram的数量是有限的))我从pcg挑战中得到了一个答案,并对其进行了修改,以将n/phi(n)的比率提高到一个特定的n

import numba as nb
import numpy as np
import time

n = int(2**31)

@nb.njit("i4[:](i4[:])", locals=dict(
    n=nb.int32, i=nb.int32, j=nb.int32, q=nb.int32, f=nb.int32))

def summarum(phi):
    #calculate phi(i) for i: 1 - n
    #taken from <a>https://codegolf.stackexchange.com/a/26753/42652</a>
    phi[1] = 1
    i = 2
    while i < n:
        if phi[i] == 0:
            phi[i] = i - 1
            j = 2
            while j * i < n:
                if phi[j] != 0:
                    q = j
                    f = i - 1
                    while q % i == 0:
                        f *= i
                        q //= i
                    phi[i * j] = f * phi[q]
                j += 1
        i += 1
    #divide each by n to get ratio n/phi(n)
    i = 1
    while i < n: #jit compiled while loop is faster than: for i in range(): blah blah blah
        phi[i] = i//phi[i]
        i += 1
    return phi

if __name__ == "__main__":
    s1 = time.time()
    a = summarum(np.zeros(n, np.int32))
    locations = np.where(a >= 10)
    print(len(locations))
将numba作为nb导入
将numpy作为np导入
导入时间
n=int(2**31)
@注:njit(“i4[:](i4[:]),locals=dict(
n=nb.int32,i=nb.int32,j=nb.int32,q=nb.int32,f=nb.int32)
def总和(phi):
#计算i:1-n的φ(i)
#取自https://codegolf.stackexchange.com/a/26753/42652
φ[1]=1
i=2
而i=10)
打印(透镜(位置))
我的工作电脑上只有足够的内存。试验约
0
,最大比值约为6。虽然10^8已经花了几秒钟的时间(不确定开销是多少……spyder最近表现得很奇怪)

p55#是一个满足所需条件的零碎数字

此外,由于pn#/phi(pn#)是一个严格递增的序列,因此所有后续的基本数也是:

p1#/phi(p1#)是2,这是正的。对于n>1,pn#/phi(pn#)等于pn-1#pn/phi(pn-1#pn),因为pn和pn-1是互质,所以等于(pn-1#/phi(pn-1#))*(pn/phi(pn))。我们知道所有n的pn>phi(pn)>0,所以pn/phi(pn)>1。所以我们得到序列pn#/phi(pn#)是严格递增的

我不相信这些是唯一满足您要求的零散数字,但我没有一种有效的方法来生成脑海中出现的其他数字。相比之下,生成primorial相当于生成前n个primer并将列表相乘(无论是使用functools.reduce()、3.8+中的math.prod()还是ye old for循环)

至于写一个φ(n)函数的一般问题,我可能会先找到n的素因子,然后用欧拉乘积公式求φ(n)。另外,请确保不要使用浮点除法。即使通过尝试除法找到n的素因子,也应该比计算gcd n次要好,但是当使用大n时,用一个有效的素因子分解算法来代替它将带来好处。除非你想要一个好十字架,否则不要自己写。我知道有一个问题存在于sympy,考虑到这个问题的普遍性,可能还有很多其他问题。需要的时间


说到时间安排,如果这对你(或未来的读者)来说仍然有足够的相关性,你会想要时间安排。。。当然也要把前面的答案放在一起。

N/phi(N)的高比率最有可能是素数的乘积。如果你只是寻找一个比率大于10的数字,那么你可以生成素数,并且只检查素数的乘积,直到你得到想要的比率为止

def totientRatio(maxN,ratio=10):
    primes    = []
    primeProd = 1
    isPrime   = [1]*(maxN+1)
    p         = 2
    while p*p<=maxN:
        if isPrime[p]:
            isPrime[p*p::p] = [0]*len(range(p*p,maxN+1,p))
            primes.append(p)
            primeProd *= p
            tot = primeProd
            for f in primes:
                tot -= tot//f
            if primeProd/tot >= ratio:
                return primeProd,primeProd/tot,len(primes)
        p += 1 + (p&1)
这将为您提供具有该比率的最小数字。该数字的倍数将具有相同的比率

n = 16516447045902521732188973253623425320896207954043566485360902980990824644545340710198976591011245999110

n*2/totient(n*2) = 10.00371973209101

n*11*13/totient(n*11*13) = 10.00371973209101
在达到下一个素数乘积(即,该数字乘以下一个素数)之前,没有任何数字具有更高的比率

从产品中移除素数会影响比例(1-1/p)。
例如,如果m=n/109,那么m/phi(m)=n/phi(n)*(1-1/109)

这将允许您高效地浏览比率,并找到满足您需要的数字

例如,要获得比率>=10但更接近10的数字,可以转到下一个素数乘积并删除一个或多个较小的素数以降低比率。这可以使用组合(来自itertools)完成,并允许您找到非常具体的比率:

m = n*263/241

m/totient(m) = 10.000234225865265

m = n*(263...839) / (7 * 61 * 109 * 137)  # 839 is 146th prime 

m/totient(m) = 10.000000079805726

我的第一个想法是使用“if
gcd(m,n)=1
然后
φ(mn)=φ(m)φ(n)
”的乘法性质,并尝试通过回归进行对数分解。不要只对
n
的所有数字使用
循环,对于大的
n
,这可能会变得相当缓慢。取而代之的是,1)获取所有小于等于
n
(或
sqrt(n)
?不确定)的素数;2) 使用这些来获得
n
,3)使用这些来获得ToClient。更多的工作,但应该更快。它的可能重复不是重复,只是找到Totient和找到said Totient在大数上的比率是不同的。找到一个使比率更进一步的数字有点困难,而且你不能保证简单地找到这样的比率。嗨,沃克,你能补充一些细节/解释一下为什么会这样吗?
n*263/totient(n*263) = 10.041901868473037
(n//109) / totient(n//109)    = 9.91194248684247

10.00371973209101 * (1-1/109) = 9.91194248684247
m = n*263/241

m/totient(m) = 10.000234225865265

m = n*(263...839) / (7 * 61 * 109 * 137)  # 839 is 146th prime 

m/totient(m) = 10.000000079805726