Я бы вообще смотрел на C код после компиляции и искал в нём причины замедления. Типа повторных вычислений, лишних вызовов функций, лишних присваиваний больших данных.
Именно. Более того, я скормил код GP (до компиляции) в LLM (Qwen) и оно дало неплохие советы.
Ещё надо бы разобраться как писать так, чтобы заведомо небольшие числа транслировались бы в long.
Вот об этом:
(Оффтоп)
Declaring the types of variables allow gp2c to perform some optimisations. For example, the following piece of GP code
rho(n)=
{
local(x,y);
x=2; y=5;
while(gcd(y-x,n)==1,
x=(x^2+1)%n;
y=(y^2+1)%n; y=(y^2+1)%n
);
gcd(n,y-x)
}
generate the following output.
GEN rho(GEN n)
{
GEN x;
GEN y;
x = gdeux;
y = stoi(5);
while (gegalgs(ggcd(gsub(y, x), n), 1))
{
x = gmod(gaddgs(gsqr(x), 1), n);
y = gmod(gaddgs(gsqr(y), 1), n);
y = gmod(gaddgs(gsqr(y), 1), n);
}
return ggcd(n, gsub(y, x));
}
The function gsqr, gaddgs, gmod, ggcd, are generic PARI functions that handle gen objects. Since we only want to factor integers with this method, we can declare n, x y as int:
rho(n:int)=
{
local(x:int,y:int);
x=2; y=5;
while(gcd(y-x,n)==1,
x=(x^2+1)%n;
y=(y^2+1)%n; y=(y^2+1)%n
);
gcd(n,y-x)
}
The new C code output by gp2c is:
GEN rho(GEN n) /* int */
{
GEN x; /* int */
GEN y; /* int */
x = gdeux;
y = stoi(5);
while (cmpis(gcdii(subii(y, x), n), 1) == 0)
{
x = modii(addis(sqri(x), 1), n);
y = modii(addis(sqri(y), 1), n);
y = modii(addis(sqri(y), 1), n);
}
return gcdii(n, subii(y, x));
}
Now, the code now uses the more specific functions sqri, addis, modii, and gcdii.
The most efficient way to use typing is to declare some variables as small. This way this variable will be implemented by C long variables, which are faster than PARI integers and do not require garbage collecting. However, you will not be protected from integers overflow. For that reason, gp2c will automatically declare some loop indices as small when the range cannot cause overflow. However gp2c can be too conservative but you can force a loop index to be small with the syntax for(i:small=a,b,...).
-- 13.11.2025, 18:30 --Dmitriy40Например
Берём такие функции и кладём в файл types.gp
Код:
f_small(st:small,en:small)=my(c:small);for(i:small=st,en,c++);return(c)
g_norm(a,b)=my(c=0);for(i=a,b,c++);return(c)
Запускаем в интерпретаторе:
Код:
? f_small(1,10^8)
cpu time = 9,140 ms, real time = 9,143 ms.
%1 = 100000000
? g_norm(1,10^8)
cpu time = 9,858 ms, real time = 9,858 ms.
%2 = 100000000
Одинаково. Ну ок.
Компилируем и запускаем:
Код:
? g_norm(1,10^8)
cpu time = 2,782 ms, real time = 2,786 ms.
%2 = 100000000
? f_small(1,10^8)
%3 = 100000000
? ##
*** last result: cpu time 0 ms, real time 0 ms.
Ноль! Ну я не знаю, может там компилятор шибко умный и просто подставляет вход на выход...
Код обоих в С (опция трансляции -g, т.е. со сборкой мусора со стека)
(Оффтоп)
Код:
/*-*- compile-command: "cc -c -o types.gp.o -g -O3 -Wall -fomit-frame-pointer -fno-strict-aliasing -fPIC -I\"/usr/include/x86_64-linux-gnu\" types.gp.c && cc -o types.gp.so -shared -g -O3 -Wall -fomit-frame-pointer -fno-strict-aliasing -fPIC -Wl,-shared -Wl,-z,relro types.gp.o -lc -lm -L/usr/lib/x86_64-linux-gnu -lpari"; -*-*/
#include <pari/pari.h>
/*
GP;install("init_types","v","init_types","./types.gp.so");
GP;install("f_small","lLL","f_small","./types.gp.so");
GP;install("g_norm","D0,G,D0,G,","g_norm","./types.gp.so");
*/
void init_types(void);
long f_small(long st, long en);
GEN g_norm(GEN a, GEN b);
/*End of prototype*/
void
init_types(void) /* void */
{
pari_sp ltop = avma;
avma = ltop;
return;
}
long
f_small(long st, long en)
{
pari_sp ltop = avma;
long c;
{
pari_sp btop = avma;
long i;
for (i = st; i <= en; ++i)
{
++c;
avma = btop;
}
}
avma = ltop;
return c;
}
GEN
g_norm(GEN a, GEN b)
{
pari_sp ltop = avma;
GEN c = gen_0;
{
pari_sp btop = avma;
GEN i = gen_0;
for (i = gcopy(a); gcmp(i, b) <= 0; i = gaddgs(i, 1))
{
c = gaddgs(c, 1);
if (gc_needed(btop, 1))
gerepileall(btop, 2, &c, &i);
}
}
c = gerepilecopy(ltop, c);
return c;
}
Хорошо видно, что
c++ транслируется в
С как
c = gaddgs(c, 1); в общем случае
++c в случае long
Ускорение примерно бесконечное
