【问题标题】:Modified Ackermann Function in Python Segmentation faultPython 分段错误中修改的 Ackermann 函数
【发布时间】:2014-12-03 10:42:16
【问题描述】:

所以我尝试创建一个基本 Ackermann 函数的修改版本,它使用字典来存储已经计算的值,以便下次程序遇到类似的函数调用时,它可以使用已经计算的值,并且这个安静的进程似乎加快了很多。代码如下:

import sys
sys.setrecursionlimit(100000)

resultset ={}

def ackermann(m, n):
    """Computes the Ackermann function A(m, n)

    See http://en.wikipedia.org/wiki/Ackermann_function

    n, m: non-negative integers
    """
    if (m,n) in resultset:
        return resultset[(m,n)]
    if m == 0:
        ans = n+1;
    elif n == 0:
        ans = ackermann(m-1, 1)
    else:
        ans = ackermann(m-1, ackermann(m, n-1))
    if m != 0:
        resultset[(m,n)] = ans
    return ans;

for i in range(0,10) :
    for j in range(0,10) :
        print("ackermann(%d, %d): " % (i, j) + str(ackermann(i,j)))

现在我遇到的问题是它会在很短的时间后停止执行。输出如下:

ackermann(0, 0): 1
ackermann(0, 1): 2
ackermann(0, 2): 3
ackermann(0, 3): 4
ackermann(0, 4): 5
ackermann(0, 5): 6
...
...
...
ackermann(3, 2): 29
ackermann(3, 3): 61
ackermann(3, 4): 125
ackermann(3, 5): 253
ackermann(3, 6): 509
ackermann(3, 7): 1021
ackermann(3, 8): 2045
ackermann(3, 9): 4093
ackermann(4, 0): 13
ackermann(4, 1): 65533
Segmentation fault

我的系统是带有 12 GB 内存的 core i5,这个程序在达到内存限制之前就退出了,可能是什么问题?

我还尝试使用 Shelves 代替字典,以便将数据存储在磁盘上。这是代码:

我还尝试使用书架而不是字典,以便查看磁盘上的使用情况。这是那个的代码..

import sys
sys.setrecursionlimit(100000)

import shelve
resultset = shelve.open("file.o")

def ackermann(m, n):
    """Computes the Ackermann function A(m, n)

    See http://en.wikipedia.org/wiki/Ackermann_function

    n, m: non-negative integers
    """
    if str((m,n)) in resultset:
        return resultset[str((m,n))]
    if m == 0:
        ans = n+1;
    elif n == 0:
        ans = ackermann(m-1, 1)
    else:
        ans = ackermann(m-1, ackermann(m, n-1))
    if m != 0:
        resultset[str((m,n))] = ans
    return ans;

for i in range(0,6) :
    for j in range(0,6) :
        print("ackermann(%d, %d): " % (i, j) + str(ackermann(i,j)))

输出文件正好是 6MB,python 崩溃了。有人知道为什么吗?

【问题讨论】:

    标签: python math dictionary segmentation-fault out-of-memory


    【解决方案1】:

    经过大量的试验和错误,我能够理解问题是程序由于递归而耗尽了堆栈空间。通过将堆栈大小设置为无限,我能够在 Linux 上解决此问题。不幸的是,我认为 Windows 上没有类似的解决方案。这是我所做的代码..

    import resource, sys
    resource.setrlimit(resource.RLIMIT_STACK, (resource.RLIM_INFINITY, resource.RLIM_INFINITY))
    sys.setrecursionlimit(10**8)
    
    resultset ={}
    
    def ackermann(m, n):
        """Computes the Ackermann function A(m, n)
    
        See http://en.wikipedia.org/wiki/Ackermann_function
    
        n, m: non-negative integers
        """
        if (m,n) in resultset:
            return resultset[(m,n)]
        if m == 0:
            ans = n+1;
        elif n == 0:
            ans = ackermann(m-1, 1)
        else:
            ans = ackermann(m-1, ackermann(m, n-1))
        if m != 0:
            resultset[(m,n)] = ans
        return ans;
    
    for i in range(0,6) :
        for j in range(0,6) :
            print("ackermann(%d, %d): " % (i, j) + str(ackermann(i,j)))
    

    这两行是魔法发生的地方:

    resource.setrlimit(resource.RLIMIT_STACK, (resource.RLIM_INFINITY, resource.RLIM_INFINITY)) sys.setrecursionlimit(10**8)

    无论如何感谢您的尝试。 :)

    【讨论】:

      【解决方案2】:

      Ackermann 函数变得非常大,非常快....下一步 (4, 2) 的值是 2.00352993040684646497907235156025575044782547556975141... × 10^19728。

      如果您查看 segfault,您可能会得到这样的结果:

      python[4413]: segfault at 7fff2bae5ff8 ip 000000000052185f sp 00007fff2bae6000 error 6 in python2.7[400000+2bd000]

      错误 6 表示页面写入失败。

      【讨论】:

      • 对不起,我不是python方面的专家,你说的页面写入文件到底是什么意思?真的是内存不足吗?你知道我能做些什么来解决这个问题吗?
      • 不是文件——它正在尝试写入内存并且没有剩余页面。我认为你不能轻易解决这个问题——我在运行 64 位 Linux 和 64GB RAM 的 32 核 Xeon 上测试了相同的代码,但它同时失败了。
      • 是的,即使我在具有 64Gb 内存和 20 个内核运行 64 位 linux 的 DigitalOcean VM 上尝试过,但仍然失败。问题是它没有使用所有可用的内存,我不知道为什么。如果我相信我的任务管理器,它几乎不会使用几 MB。
      猜你喜欢
      • 2020-12-29
      • 1970-01-01
      • 2010-12-27
      • 1970-01-01
      • 1970-01-01
      • 2023-03-18
      • 1970-01-01
      • 2021-08-15
      相关资源
      最近更新 更多