在python中进行大计算时出现分段错误

问题描述

我想为一些非常大的数字计算 collat​​z 序列,但我猜 python 无法处理这么大的数字,我不知道如何处理。

这是我的程序:

def collatz(n):
    if (n == -1 or n == 1 or n == -17 or n == -17 -2**4096):
        print('break found',n)
        return
    if str(n)[-1] in ['1','3','5','7','9']:
        #print(n)
        return collatz(3*n + 1)
    else:
        return collatz(n//2)

我想使用 n = 2**4096 范围的数字。我通过 sys.setrecursionlimit 函数增加了递归限制。但现在我面临分段错误错误。

>>> sys.setrecursionlimit(10**9)
>>> collatz(2**1000 + 1)
break found: 1
>>> collatz(2**4000 + 1)
Segmentation fault (core dumped)

请给我一些关于我需要修改什么以获得大输入支持的建议..

解决方法

使其非递归,太深的递归会溢出堆栈,堆栈通常只有几兆字节。堆栈溢出后,您的程序会因分段错误而崩溃。

您的代码修改为非递归(不会崩溃):

Try it online!

def collatz(n):
    while True:
        if (n == -1 or n == 1 or n == -17 or n == -17 -2**4096):
            print('break found',n)
            return
        if str(n)[-1] in ['1','3','5','7','9']:
            #print(n)
            n = 3 * n + 1
        else:
            n = n // 2


collatz(2**4000 + 1)

输出:

break found 1

顺便说一句,经典的 Collat​​z 问题可以用更短、更快的代码解决,例如:

Try it online!

def collatz(n):
    for i in range(1 << 50):
        if n == 1:
            return i
        n = 3 * n + 1 if n & 1 else n >> 1

print('Collatz chain length:',collatz(2**4000 + 1))

输出:

Collatz chain length: 29400

另外,我想提一下基于著名的基于 C 的 GMPY2 的 Python 库 GMP。它具有非常优化的长整数算术代码,如果您确实需要速度,可以用来提升您的代码。

在 Windows 上 gmpy2 可以通过下载 from here 并通过 pip install gmpy2‑2.0.8‑cp39‑cp39‑win_amd64.whl 安装来安装。在 Linux 上,它可以通过 sudo apt install python3-gmpy2 安装。

安装后,您可以以非常简单的方式使用 gmpy2,如下面的函数 collatz_gmpy()

Try it online!

def collatz_py(n):
    for i in range(1 << 50):
        if n == 1:
            return i
        n = 3 * n + 1 if n & 1 else n >> 1

def collatz_gmpy(n):
    from gmpy2 import mpz
    n = mpz(n)
    for i in range(1 << 50):
        if n == 1:
            return i
        n = 3 * n + 1 if n & 1 else n >> 1

def test():
    import timeit
    n = 2 ** 100000 + 1
    for i,f in enumerate([collatz_py,collatz_gmpy]):
        print(f.__name__,round(timeit.timeit(lambda: f(n),number = 1),3),'secs')

test()

输出:

collatz_py 7.477 secs
collatz_gmpy 2.916 secs

正如我们所见,与常规 Python 的变体相比,GMPY2 变体提供了 2.56x 倍的加速。

,

我会这样写:

def collatz(n):
    tmp = -17 - 2**4096            # precompute constant value outside loop
    while 1:                       # in general,iteration is better than recursion in Python for these kinds of functions
        if n in (-1,1,-17,tmp): # less typing than lots of or clauses
            return n               # return values rather than printing them
        elif n % 2 == 1:           # faster than converting to string and checking last digit
            n = 3*n + 1
        else:
            n //= 2

用例如:

print(collatz(2**4000 + 1))

性能:在我的 PC 上,使用上述代码 collatz(2**5000-1) 需要 0.069 秒。将代码更改为 elif str(n)[-1] in '13579': 需要 1.606 秒,即慢 23 倍。

collatz(2**40000-1) 上,上面的代码使用了 3.822 秒。改变

elif n % 2 == 1:

到任一

elif n % 2:

elif n & 1:

将时间减少到 1.988 秒(即没有区别)。

n //= 2 更改为 n >>= 1 将时间进一步缩短至 1.506 秒。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...