question on PARI/GP t_INTMOD exponentiation optimization for multiple similar size big exponents with same base
[email protected] Mon, 16 Feb 2026 15:49:51 +0100
| Newsgroups | gmane.comp.mathematics.pari.user |
|---|---|
| Message-ID | <[email protected]> |
It all started with me trying to play with J. Brillhart, D. H. Lehmer
and J. L. Selfridge 1975 paper theorem 1:
https://t5k.org/prove/prove3_1.html
While theorem 1 does not require the same a_i for different prime
divisors p_i of N-1 to be used, I learned that a primitive root allows
to be used for all prime divisors of N-1.
I played with prime Euclid numbers https://oeis.org/A014545, for which
the factorization of N-1 is trivial. A simple sequential replacement of
znprimroot() is much faster because znprimroot() has to factor N-1
first, and prime 457th Euclid number is smallest example where GP has to
spend much time on the factorization:
hermann@7950x:~$ gp -q seq.gp
? #
timer = 1 (on)
? euclid_prime_find_root(457)
cpu time = 8,368 ms, real time = 8,370 ms.
31
? lift(znprimroot(prime(457)#+1))
cpu time = 1min, 34,734 ms, real time = 1min, 34,744 ms.
31
? #digits(prime(457)#+1)
1368
?
I created a parallel version of my gist which is much faster than
sequential:
https://gist.github.com/Hermann-SW/a14dc268d533b96afbd52b2a9d3c92e8
hermann@7950x:~$ gp -q par2.gp
? #
timer = 1 (on)
? euclid_prime_find_root(457)
cpu time = 14,400 ms, real time = 1,216 ms.
31
?
Next I wanted to speedup the parallel computation in passing
Mod(g,N)^((N-1)/prime(n)) to check function as a base where the slightly
bigger Mod(g,N)^((N-1)/prime(i)) can be computed from quickly for
1<=i<n. This is the small diff:
hermann@7950x:~$ diff par2.gp par3.gp
1,2c1,2
< check(En, n, phi, g, i)={
< parfor(i=1, n, lift(Mod(g, En)^(phi / prime(i))) == 1, r, if(r,
return(0)));
---
> check(En, n, phi, g, base, i)={
> parfor(i=1, n, lift(base * Mod(g, En)^(phi / prime(i) - phi /
> prime(n))) == 1, r, if(r, return(0)));
11c11,12
< if(check(En, n, phi, g, i), return(g));
---
> base=Mod(g, En)^(phi / prime(n));
> if(check(En, n, phi, g, base, i), return(g));
hermann@7950x:~$
I did let run seq.gp over night and hat to abort execution for prime
2673th Euclid number (with 10,387 decimal digits) after 12.5h. Parallel
versions completed in 20 minutes (on 16C/32T AMD 7950X CPU), but to my
surprise the runtime gets worse by my "improvement". First runtime for
par2.gp, then for par3.gp:
? euclid_prime_find_root(2673)
%5 = 139
? ##
*** last result: cpu time 4h, 45min, 45,149 ms, real time 19min,
46,915 ms.
?
? euclid_prime_find_root(2673)
%4 = 139
? ##
*** last result: cpu time 4h, 48min, 3,278 ms, real time 22min,
14,287 ms.
?
It seems that GP does optimize muliple modular exponentiation with same
base better than how I tried to do it.
1) What optimization is happening in GP for par2.gp exponentiation?
2) Where in the code base do I have to look for that optimization?
Regards,
Hermann.