python - 求约数 质数法

博客探讨了使用质数法优化求约数算法的过程,包括单次开方增强、质数库的引入及其影响。作者通过实验比较不同优化方案在小数量级和大数量级的性能,发现质数库在某些情况下反而降低效率,但大数量级时表现更好。最终决定优化元组搜索算法,以提高整体效率。
摘要由CSDN通过智能技术生成

置顶成品:在这里面,我一直是思考的,如果有特殊情况,会怎样,于是按着特殊情况去优化提升效率,结果却是整体效率下降,于是两个思路:
1、保证特殊情况的优化,去忍受整体效率
2、保证整体效率,忍受特殊情况
好累,上午就得出的这个结果,因为如果再去做特殊情况的优化的话,因为复杂度问题,可能会产生众多的bug,这是最头疼的一件事。
所以懒惰的我选择… 搞一搞其他问题吧!把质数库加入到目前最通用的算法中!说实话,不想放弃!虽然耗了好长时间在这个上面了,比上一次的浮点数优化层次太深了!

我刚才搜了下判断一个数是否是素数的算法,涉及到了太多高等数学的知识,我放弃思考了。就这样吧!

简单单次开方法:

def 约数(n):
    if n==1:return 1
    y=[1,n]
    if (m:=n**0.5)%1==0:
        m=int(m)
        y.append(m)
    else:m=int(m+1)
    for i in range(2,m):
        if n/i%1==0:
            y.append(i)
            y.append(int(n/i))
    y.sort()
    return y

单次开方增强:从小到的寻找质数,同时生成对应约数组,循环生成直至新的目标数不再包含该质数。寻找更大的质数。思路虽然简单,但是期间遇上更多的问题,各种debug和优化后,看代码没那么容易理解思路,而我刚才尝试841,居然没有之前的一个算法快,虽然841是一种特例吧!看来还是需要更加优化

def Factor(n):
    if n==1:return [1]
    y=[]
    s=2
    while 1:
        yf=[]
        for i in range(s,int(t:=n**0.5)):
            if n/i%1==0:
                z=i
                break
        else:
            if t%1==0:
                z=int(t)
            elif n/(t//1)%1==0:
                z=int(t//1)
                for i in y:
                    yf.append(i*z)
                y+=yf+[z]
                yf=[]
                z=int(n/(t//1))
                for i in y:
                    yf.append(i*z)
                y+=yf+[z]
                y.sort()
                return y
            else:z=int(n)
        yf.append(z)
        n=n/z
        for i in y:
            yf.append(i*z)
        y+=yf
        while 1:
            if (t:=n/z)%1==0:
                n=t
                yt=[]
                for i in yf:
                    yt.append(i*z)
                y+=yt
                yf=yt[:]
            elif n==1:
                y.append(1)
                y.sort()
                return y
            else:break
        s=z+1
%%timeit
def Factor(n):
    if n==1:return [1]
    y=[]
    t=n
    while 1:
        if (t:=t**0.5)%1!=0:
            tm=int(t)
            t=int(t**2+0.1)
            break
    s=2
    while 1:
        yf=[]
        for i in range(s,int(tm:=t**0.5)):
            if n/i%1==0:
                z=i
                break
        else:
            if t%1==0:
                z=int(t)
            elif n/(t//1)%1==0:
                z=int(t//1)
                for i in y:
                    yf.append(i*z)
                y+=yf+[z]
                yf=[]
                z=int(n/(t//1))
                for i in y:
                    yf.append(i*z)
                y+=yf+[z]
                y.sort()
                return y
            else:z=int(n)
        yf.append(z)
        n=n/z
        for i in y:
            yf.append(i*z)
        y+=yf
        while 1:
            if (t:=n/z)%1==0:
                n=t
                yt=[]
                for i in yf:
                    yt.append(i*z)
                y+=yt
                yf=yt[:]
            elif n==1:
                y.append(1)
                y.sort()
                return y
            else:break
        s=z+1
for i in range(800,900):
    Factor(i)
if (o:=n%10)==1 or o==3 or o==7 or o==9:
    while 1:
        if (t:=t**0.5)%1!=0:
            tm=int(t)
            t=int(t**2+0.1)
            break

这个加进去之后,会涉及到更多的问题,一时很难解决,更适合最初的一个质数组合法。

for i in range(800,900):
简单版:505 µs ± 3.61 µs
加强版:552 µs ± 10.7 µs
循环加强版:535 µs ± 13.8 µs
之前的质数库版:737 µs ± 10.4 µs
之前的无质数库:762 µs ± 10.8 µs

10800,10900:
1.43 ms ± 12.4 µs
874 µs ± 34.5 µs
945 µs ± 16.1 µs
1.06 ms ± 15.8 µs
1.38 ms ± 32.7 µs
虽然看到小数量级时,仍未压过简单版,但是差距不大
但是大数量级时,是目前最快的了

    t=n
    while 1:
        if (t:=t**0.5)%1!=0:
            tm=int(t)
            t=int(t**2+0.1)
            break
    s=2
    while 1:
        yf=[]
        for i in range(s,int(tm:=t**0.5)):

修改版我是把之前的多次开方搬到了这里,目的是更加的减少无端的消耗,主要是当目标数是个质数时!在小数量级时,这个功能负优化,但是在大的数量级时,能减少目标数是质数时,一个指数级的运算时长!明天继续改!将三个方法的步骤完全模块化列出,各个优点整合起来!

我卸载blink上了,结果PC端无法看,坑!
我尝试使用:

来判断目标数是否应该开方,结果很无语,先上结果!
for i in range(10600,10900):
Factor(i)
未添加:2.59 ms
添加if个位数判断:2.31 ms
完全不做开方:2.13 ms
也就是说完全不做总的来说效率更高!只能说纯质数与if之间的比例。
另外如果把if加入到每次循环结果的目标数上,耗时更长,虽然这个点子单纯的好,但是加进去就不好了。
带入997:很遗憾,第一次不做任何处理,效率最高,因为内部同时做了个处理。
但如果带入994009:未经预先开放处理的123 µs ,开放处理的6.05 µs,所以还是有必要预先处理的,顶多是个取舍的问题,至于内部的每次循环,例如2*61*61=7442,这个是需要内部多次开方提升效率的。
但经过几次范围测试,总之这些都是特例,特例到多做一次处理,整体耗时都会增加!
而这里面最核心最有用的就是一次开方
------------------------------历史------------------------------
这个历史比较坑,自以为是的用不断开放法找到无法再开方的目标,再找到质数因子,再组合成约数组,以及引进了质数库。质数库这个我将尝试加入到上面的方法中,求约数仍在继续!

如果使用一个质数库去优化当前算法,那么第一个问题,选择多大的质数库,假设选择1000以内的质数,那么他的适用范围就是1000**2,即1000000 100W。

测试:
1000000的元组,内存占用8000024字节,程序占用43516K,写入文件的话,7.52MB,记事本打开很耗时。那么生成库的大小将以记事本打开速度衡量。
当生成1W的元组,记事本大小在60KB,大概60K个字符时,是秒开的。
但我们其实也根本用不到这个大的元组也未曾可知。而1W时,内存占用是常规状态,并没有显示出多么的大。那么从元组的对比效率上看呢。例如10元素的元组和多少个元素的元组,效率是差不多的。

等等,我创建了各种组合

a=tuple(range(1000000))
b=tuple(range(1000))
c=(999,)
l=list(range(1000))
s=set(range(1000))

999 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值