Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
最长Collatz(或冰雹)序列优化-Python 2.7_Python_Algorithm_Caching_Optimization_Collatz - Fatal编程技术网

最长Collatz(或冰雹)序列优化-Python 2.7

最长Collatz(或冰雹)序列优化-Python 2.7,python,algorithm,caching,optimization,collatz,Python,Algorithm,Caching,Optimization,Collatz,我制作了一个程序,打印出一个数字列表,每一个数字都需要更多的步骤(根据)才能达到1,而之前的步骤是: limit = 1000000000 maximum = 0 known = {} for num in xrange(2, limit): start_num = num steps = 0 while num != 1: if num < start_num: steps += known[num]

我制作了一个程序,打印出一个数字列表,每一个数字都需要更多的步骤(根据)才能达到1,而之前的步骤是:

limit = 1000000000
maximum = 0
known = {}
for num in xrange(2, limit):
    start_num = num
    steps = 0
    while num != 1:
        if num < start_num:
            steps += known[num]
            break;
        if num & 1:
            num = (num*3)+1
            steps += 1
        steps += 1
        num //= 2
    known[start_num] = steps
    if steps > maximum:
        print start_num,"\t",steps
        maximum = steps
limit=100000000
最大值=0
已知={}
对于xrange中的num(2,限制):
start_num=num
步数=0
而num!=1:
如果num最大值:
打印开始编号“\t”,步骤
最大值=步数
我缓存我已经知道的结果以加速程序。此方法最多可工作10亿次,我的计算机内存不足(8GB)

  • 有没有更有效的方法来缓存结果
  • 有没有办法进一步优化该计划

  • 提前感谢您。

    要大幅提高Collatz程序的速度,似乎有其固有的困难;我所知道的最好的程序,在全世界数百(数千…)台PC上使用空闲周期

    在纯CPython中,您可以做一些简单的事情来稍微优化您的程序,尽管速度和空间优化常常是不一致的:

    • 速度:Python中计算量大的程序应该始终作为函数编写,而不是作为主程序编写。这是因为局部变量访问比全局变量访问快得多
    • 空间:使
      成为已知的
      列表而不是dict所需的内存大大减少。您正在为每个数字存储一些内容;dict更适合于稀疏映射
    • 空间:一个
      数组。数组
      仍然需要更少的空间-尽管比使用列表慢
    • 速度:对于奇数
      n
      3*n+1
      必然是偶数,因此您可以通过直接转到
      (3*n+1)//2==n+(n>>1)+1将两个步骤折叠为1
    • 速度:给定一个最终结果(数字和步数),你可以跳到前面,填写该数字乘以2的所有幂的结果。例如,如果
      n
      采取
      s
      步骤,那么
      2*n
      将采取
      s+1
      4*n
      将采取
      s+2
      8*n
      将采取
      s+3
      ,依此类推
    虽然我使用的是Python3(在Python2中,您至少需要将
    range
    更改为
    xrange
    ),但这里有一些代码包含所有这些建议。请注意,启动时有很长的延迟-这是用十亿个32位无符号零填充大型
    数组所需的时间

    def coll(limit):
        from array import array
        maximum = 0
        known = array("L", (0 for i in range(limit)))
        for num in range(2, limit):
            steps = known[num]
            if steps:
                if steps > maximum:
                    print(num, "\t", steps)
                    maximum = steps
            else:
                start_num = num
                steps = 0
                while num != 1:
                    if num < start_num:
                        steps += known[num]
                        break
                    while num & 1:
                        num += (num >> 1) + 1
                        steps += 2
                    while num & 1 == 0:
                        num >>= 1
                        steps += 1
                if steps > maximum:
                    print(start_num, "\t", steps)
                    maximum = steps
                while start_num < limit:
                    assert known[start_num] == 0
                    known[start_num] = steps
                    start_num <<= 1
                    steps += 1
    
    coll(1000000000)
    
    def coll(限制):
    从数组导入数组
    最大值=0
    已知=数组(“L”,(0表示范围内的i(限制)))
    对于范围内的数值(2,限制):
    步骤=已知[num]
    如果步骤:
    如果步骤>最大值:
    打印(数字“\t”,步数)
    最大值=步数
    其他:
    start_num=num
    步数=0
    而num!=1:
    如果num>1)+1
    步数+=2
    当num&1==0时:
    数值>>=1
    步数+=1
    如果步骤>最大值:
    打印(开始编号“\t”,步骤)
    最大值=步数
    当开始数量<限制时:
    断言已知[start_num]==0
    已知[开始数量]=步数
    
    start_num您只需要缓存奇数。在程序中考虑当你开始处理一个数字时会发生什么。

    如果您使用起始编号X,然后执行
    mod 4
    ,则最终会出现以下四种情况之一:

    • 0或2:重复除以2最终会得到一个小于X的奇数。您已缓存该值。因此,只需将除数除以2,将其添加到缓存值中,就可以得到序列长度
    • 1:(3x+1)/2将得到一个偶数,再除以2将得到一个小于X的数。如果结果是奇数,那么您已经有了缓存的值,因此您可以向其中添加3。如果结果为偶数,则重复除以2,直到得到奇数(已缓存),将3和除以2的数目添加到缓存的值中,即得到序列长度
    • 3:进行标准Collatz序列计算,直到得到一个小于起始数的数字。然后,要么缓存该值,要么该数字为偶数,然后重复除以2,直到得到奇数
    这可能会使您的程序慢一点,因为您还有几次除以2,但它会使您的缓存容量加倍

    只需为
    x mod 4==3
    的数字保存序列长度,就可以使缓存容量再次翻倍,但这样做的代价是处理时间更长

    这些只会使缓存空间线性增加。您真正需要的是一种整理缓存的方法,这样您就不必保存这么多结果。以一些处理时间为代价,您只需要缓存产生迄今为止发现的最长序列的数字

    考虑到当您计算27有111个步骤时,您已经保存了:

    starting value, steps
    1, 0
    2, 1
    3, 7
    6, 8
    7, 16
    9, 19
    18, 20
    25, 23
    27, 111
    
    所以当你看到28,你除以2得到14。搜索缓存时,您会看到14到1的步骤数不能超过19(因为任何小于18的步骤数都不能超过19)。所以最大可能的序列长度是20。但您已经有了最多111个。所以你可以停下来

    这可能会花费更多的处理时间,但会大大扩展缓存。到837799为止,您只有44个条目。看

    有趣的是,如果你做一个对数散点图