New code for primality testing
Marco Bodrato
bodrato at mail.dm.unipi.it
Fri Nov 16 19:03:55 UTC 2018
Dear developers,
in the last ten day or so, I pushed some new code for primality testing
to our repository. The code is used by mpz_probab_prime_p() and
mpz_nextprime().
The library, before, tested primality by "some trial divisions, then
<reps> Miller-Rabin probabilistic primality tests". With a suggested
range for <reps> "between 15 and 50" [see
https://gmplib.org/manual/Number-Theoretic-Functions.html ].
mpz_nextprime() uses <reps> = 25.
The main idea of the new code is to replace the first few Miller-Rabin
tests with the BPSW test. I.e. a Miller-Rabin test with the fixed base
2, and a strong Lucas' test with the parameters suggested by the BPSW
test. I decided to replace the first 24 MR tests... but it's easy to
change this!
I pushed two implementations of the test.
- One for mini-gmp, https://gmplib.org/repo/gmp/rev/1dd99c5d0bf6 .
- Another one for the main library:
+ from https://gmplib.org/repo/gmp/rev/81976c309e55 ...
+ to https://gmplib.org/repo/gmp/rev/d417bcef18e6
They both choose the parameter D in the sequence 5, -7, 9, -11, ... such
that (D/n)=-1, then compute the Lucas' sequence with P=1 and Q=(1-D)/4.
But the formulas used to compute the sequence are different.
mini-gmp uses the simplest:
U_{2k} <- U_k * V_k
V_{2k} <- V_k^2 - 2Q^k
Q^{2k} = (Q^k)^2
(1 multiplication, 2 squares, 3 modular reductions per step)
GMP uses another one (adapted from "Elementary Number Theory" by Peter
Hackman, as suggested by Niels)
U_{2k} = U_{k+1}^2 - |U_{k+1} - U_k|^2
U_{2k+1} = U_{k+1}^2 - Q*U_k^2
(3 squares, 2 modular reductions per step)
... when D=5, i.e. the U sequence is Fibonacci's sequence, a special
function is used already ported to the mpn layer [see
https://gmplib.org/repo/gmp/rev/81976c309e55 ]. I optimised this
because:
- it was not too difficult to do (ideas inherited from the existing
fib2 code);
- it's worth doing (I expect, to see this used half of the times, for
random inputs; line 80 in
https://gmplib.org/devel/lcov/shell/gmp/mpz/stronglucas.c.gcov.html
seems to confirm this).
Maybe the functions are not easy to follow. I focused on writing helper
functions for the BPSW test, the functions are not "general". Moreover,
they sometimes play with the signs, because we have to detect
zero/non-zero, we always compute squares, so we don't really need to
keep track of the correct "sign".
By the way, I wrote some comments in the code. If anyone is interested
in reading the implementation, I'll be happy to read any comment.
The implementation can be improved in many ways.
Should also mpz_lucas_mod be ported to the mpn layer? Should it return
V_n^2 instead of V_n ? testing can be improved ... and so on...
But the main point that SHOULD be improved is the repeated use of
mpz_tdiv_r () or mpn_tdiv_qr () to reduce the many intermediate results,
always by the same modulus...
I would also be curious to explore the possible implementation of some
tests for numbers with some special form. E.g. Proth's theorem, once we
have found a number D such that (D/n)=-1, if n is a Proth number, using
a Lucas' test is a waste of time...
Ĝis baldaŭ,
m
--
http://bodrato.it/papers/
More information about the gmp-devel
mailing list