【问题标题】:Ackermann's function segfaults on gcc阿克曼在 gcc 上的函数段错误
【发布时间】:2013-04-24 08:29:53
【问题描述】:

很明显,我不是一个称职的 C 作家,但想知道,与这个问题有关 Ackermann very inefficient with Haskell/GHC(这可能使我不合理地激怒了我)为什么作者的程序要计算 Wilhelm Ackermann 的著名函数:

int ack(int m, int n) {
  if (m == 0) return n+1;
  if (n == 0) return ack(m-1, 1);
  return ack(m-1, ack(m, n-1));
}

int main() {
  printf("%d\n", ack(4,1));
  return 0;
}

工作正常,但是当给出明显的优化(这在其他地方有帮助)并给出论点 (4,2) 时——这在算法上当然是残酷的——以 Segmentation fault: 11 结尾:

int ack(int m, int n) {
  if (m == 0) return n+1;
  if (m == 1) return n+2;
  if (n == 0) return ack(m-1, 1);
  return ack(m-1, ack(m, n-1));
}

int main() {
  printf("%d\n", ack(4,2));
  return 0;
}

如果我注释掉“优化”行if (m == 1) return n+2;,程序会像在其他语言中一样继续运行,但不会产生相同的效果——至少在运行 5 分钟后不会。 [更正,似乎确实如此——在 8 分 41 秒之后](我应该注意,我使用的是 os x 附带的 gcc,但似乎也发生了同样的情况,例如 ideone.com 上的 gcc-4.7.2。)

我同意该程序甚至不值得编译,但想知道为什么分段错误(通常被视为恐怖并且在我熟悉的其他语言中被视为语言缺陷或编译器错误)是适当的响应对于 gcc

【问题讨论】:

  • 阿克曼应该这样做。
  • Hot Licks,嗯,这就是我的观点,但其他人似乎有不同的想法——规定只有特定的编译器响应是合理的。

标签: c gcc


【解决方案1】:

两个程序都用完了堆栈,而您的改进做得更快。请注意,所需的堆栈与参数“n”成正比,并且“n”增长很快。所以没有错误,只是一台有限的机器。

让我从我的存档中添加一些代码,只是为了好玩和更快。它还显示了 'n' 随着 'm' 的每一个增量的增长速度。

typedef unsigned long long N;
N acker (N m, N n)
{
        while (1)
        switch (m)
        {
        case 0: return n+1U;
        case 1: return n+2U;
        case 2: return 2U*(n+1U)+1U;
        case 3: return (1LLU<<(n+3U))-3U;
        default:
                if (n == 0U)
                        n = 1U;
                else
                        n = acker(m, n-1U);
                m--;
                break;
        }
        return n+1U;
}

【讨论】:

  • 嗯,这肯定是惊人的快!我知道我所谓的优化在这种情况下会使事情变得更糟,如果只是通过模糊 gcc 对此事的看法(尽管您似乎能够立即看到它)。我将对此进行更多研究。
猜你喜欢
  • 2010-11-28
  • 1970-01-01
  • 1970-01-01
  • 2012-01-31
  • 2015-07-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-27
相关资源
最近更新 更多