So I wanted to calculate a sum from a particular projecteuler question using gp. Here's the, admittedly unreadable, code:
{
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)
}
This code takes two minutes or three to output the answer on my fairly modest machine but it does it without going over the default parisize = 8000000
(around 8 MB of memory).
Now, I read somewhere that gp2c
which compiles gp
scripts into c
code can improve performance.
So I just made a program.gp
file:
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)}
And run it with gp2c-run program.gp
.
In the interactive prompt that comes up, I just executed calculate()
. However, to my surprise, I got a stack overflow with it asking me to increase the stack size even when I changed parisizemax
to almost 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
Why does the same program, when compiled to c
need so much extra memory?
For reference, the same program with n = 1000 instead of 10000 only shows the answer after increasing the stack size to 256000000
(250 MB) whereas it just needs the default 8 MB when just using gp
. Something doesn't add up.
By default, neither gp2c
nor gp2c-run
generate code to handle the PARI stack, meaning you will get stack overflows quickly. Use gp2c-run -g program.gp
: the -g
flag will cause gp2c
to clean up the stack as the computation progresses. There is such an example in the gp2c tutorial.