使用 gp2c 时堆栈溢出,但在同一程序中直接使用 gp 时不会出现堆栈溢出 (PARI/GP)

Posted

技术标签:

【中文标题】使用 gp2c 时堆栈溢出,但在同一程序中直接使用 gp 时不会出现堆栈溢出 (PARI/GP)【英文标题】:Stack Overflow when using gp2c but not when using gp directly with the same program (PARI/GP) 【发布时间】:2021-08-03 23:24:24 【问题描述】:

所以我想使用 gp 计算一个特定投影仪问题的总和。这是不可理解的代码:


n = 10000;
m=100;
sum(k=1,n,eulerphi(k),0.) - (sum(k=1,n,eulerphi(k)*(k * binomial(n-k,m-1) + sum(p = max(m + k - n - 1,1), k-1, (k-p)*binomial(n+p-k-1,m-2),0.)), 0.))/binomial(n,m)

这段代码需要两三分钟才能在我相当普通的机器上输出答案,但它不会超出默认的parisize = 8000000(大约 8 MB 内存)。

现在,我在某处读到 gp2cgp 脚本编译成 c 代码可以提高性能。

所以我刚刚制作了一个program.gp 文件:

calculate() = n = 10000; m=100; sum(k=1,n,eulerphi(k),0.) - (sum(k=1,n,eulerphi(k)*(k * binomial(n-k,m-1) + sum(p = max(m + k - n - 1,1), k-1, (k-p)*binomial(n+p-k-1,m-2),0.)), 0.))/binomial(n,m)

然后使用gp2c-run program.gp 运行它。

在出现的交互式提示中,我刚刚执行了calculate()。然而,令我惊讶的是,即使我将 parisizemax 更改为近 2 GB,我也遇到了堆栈溢出,要求我增加堆栈大小。

? default(parisizemax, 2000000000)
  ***   Warning: new maximum stack size = 2000003072 (1907.352 Mbytes).
? calculate()
  *** calculate: Warning: increasing stack size to 16000000.
  *** calculate: Warning: increasing stack size to 32000000.
  *** calculate: Warning: increasing stack size to 64000000.
  *** calculate: Warning: increasing stack size to 128000000.
  *** calculate: Warning: increasing stack size to 256000000.
  *** calculate: Warning: increasing stack size to 512000000.
  *** calculate: Warning: increasing stack size to 1024000000.
  *** calculate: Warning: increasing stack size to 2000003072.
  ***   at top-level: calculate()
  ***                 ^-----------
  *** calculate: the PARI stack overflows !
  current stack size: 2000003072 (1907.352 Mbytes)
  [hint] you can increase 'parisizemax' using default()

  ***   Break loop: type 'break' to go back to GP prompt

为什么同一个程序在编译到c 时需要这么多额外的内存? 作为参考,n = 1000 而不是 10000 的同一程序仅在将堆栈大小增加到 256000000 (250 MB) 后才显示答案,而仅使用 gp 时只需要默认的 8 MB。有些东西没有加起来。

【问题讨论】:

这确实是一个 [pari] 问题,而不是 [pari-gp]。它看起来像一些内存泄漏问题(因为你只有几个循环)。我建议您浪费时间尝试使用 gp2-c 提高性能。 (没有理由它应该更快)。建议1:去掉0.,用纯整数进行计算。建议 2:内部求和 'sum(p, (k-p)*binomial(n+p-k-1,m-2)' 可能可以在数学上简化以去除总和。 谢谢安德鲁!我会记住你的建议。 【参考方案1】:

默认情况下,gp2cgp2c-run 都不会生成处理 PARI 堆栈的代码,这意味着您将很快得到堆栈溢出。使用gp2c-run -g program.gp-g 标志将导致gp2c 随着计算的进行清理堆栈。 the gp2c tutorial中有这样一个例子。

【讨论】:

是否有充分的理由使用不带 -g 的 gp2c? 三个小问题:没有 GC 语句研究代码核心更简单,您可能希望稍后在(通常很少)真正需要它们的地方手工制作它们,代码可能最终会变成没有 GC 会快一点。但对于快速测试或您不打算查看 C 代码时,-g 应该是您的默认设置。

以上是关于使用 gp2c 时堆栈溢出,但在同一程序中直接使用 gp 时不会出现堆栈溢出 (PARI/GP)的主要内容,如果未能解决你的问题,请参考以下文章

Clojure 在函数中减少溢出,但在直接传递给 REPL 时不会溢出

为啥这个 BigInteger 值会导致堆栈溢出异常? C#

使用 JWT 身份验证登录时堆栈溢出 [关闭]

什么是堆栈溢出?

怎么解决 LINUX 堆栈溢出内存的问题

为啥在某些机器上堆栈溢出,但在另一台机器上出现分段错误?