为什么这些优化似乎慢得多?

时间:2018-07-16 14:17:18

标签: python recursion optimization

我正在学习Python(我有其他语言的背景知识,尤其是C等),并且我试图编写一些简单的函数来增强我在Python教程中阅读的内容。特别是,这是我尝试确定一个是否为整数的函数的方法:

def isComposite(n):
    """Straight loop."""
    for x in range(2, int(math.sqrt(n)) + 1):
        if n % x == 0:
            return x
    return False

_PrimeList = [2]

def isCompPL(n):
    """Recursive version."""
    for x in _PrimeList:
        if n % x == 0:
            if n == x:
                return False
            return x
    for x in range(_PrimeList[-1], int(math.sqrt(n)) + 1):
        if not isCompPL(x):
            if x > _PrimeList[-1]:
                _PrimeList.append(x)
            if n % x == 0:
                return x
    return False

def isCompSR(n):
    """Serialized recursive version."""
    l = [n]
    while (math.sqrt(l[0]) > _PrimeList[-1]):
        l.insert(0, int(math.sqrt(l[0])))
    l.insert(0, _PrimeList[-1] + 1)
    while (len(l) > 2):
        q = l.pop([0])
        for x in range(q, l[0]):
            for y in _PrimeList:
                if x % y == 0:
                    break
            else:
                _PrimeList.append(x)
    return isCompPL(n)
isComposite(n)isCompPL(n)开始时,

isCompSR(n)_PrimeList[2]快几个数量级。当_PrimeList包含所有素数到n的平方根时,则isCompPL(n)isCompSR(n)都会赶上,并且可能比isComposite(n)快,但不是明显地如此。更令我惊讶的是,如果我呼叫isCompSR(511111111111),则后续呼叫isCompSR(1111111111111)仍然比呼叫isComposite(1111111111111)慢得多,而在第一次呼叫{{1 }}。

Python的列表操作中是否存在隐藏的东西,这些东西使得这些尝试在优化方面不成功,还是仅仅是我添加了很多额外的主要测试,而我需要以某种方式减少这一部分?

1 个答案:

答案 0 :(得分:0)

两个主要评论者(@ alexis,@ juanpa.arrivillaga)都对我编写的代码进行了正确的评估(评估了太多数字,以低效的方式使用列表数据类型),并且在两方面都有改进,更新后的“序列化递归”功能总体上要快得多,并且比_PrimeList初始化后的“直线循环”版本要快得多。 isCompSR(n)的当前版本如下:

def isCompSR(n):
    """Serialized recursive version."""
    for x in _PrimeList:
        if n % x == 0:
            return x
    l = [n]
    while (math.sqrt(l[-1]) > _PrimeList[-1]):
        l.append(int(math.sqrt(l[-1])))
    l.append(_PrimeList[-1] + 1)
    while (len(l) > 2):
        q = l.pop()
        for x in range(q, l[-1]):
            if n % x == 0:
                return x
            for y in _PrimeList:
                if x % y == 0:
                    break
            else:
                _PrimeList.append(x)
    return False

请注意,此代码现在将在除n的第一个质数处“删除”,而不是像以前一样继续处理直到math.sqrt(n)的所有数字。另外,现在可以通过调用l.append而不是在开头插入和弹出来更适当地使用列表.pop()