[libmath-prime-util-perl] 06/15: Don't use MULTICALL yet -- memory leak
Partha P. Mukherjee
ppm-guest at moszumanska.debian.org
Thu May 21 18:48:46 UTC 2015
This is an automated email from the git hooks/post-receive script.
ppm-guest pushed a commit to annotated tag v0.29
in repository libmath-prime-util-perl.
commit 70ba979e592fbe95a3e2f7f79003599c22dd1ae0
Author: Dana Jacobsen <dana at acm.org>
Date: Tue May 28 20:57:57 2013 -0700
Don't use MULTICALL yet -- memory leak
---
Changes | 3 ++
XS.xs | 70 +++++++++++++++++++-------------
factor.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++-------
factor.h | 16 ++++----
t/32-iterators.t | 13 ++++++
5 files changed, 172 insertions(+), 50 deletions(-)
diff --git a/Changes b/Changes
index ba643c7..38bbf9f 100644
--- a/Changes
+++ b/Changes
@@ -4,6 +4,9 @@ Revision history for Perl extension Math::Prime::Util.
- Fix a signed vs. unsigned char issue in ranged moebius.
+ - forprimes now uses a segmented sieve. This (1) allows arbitrary 64-bit
+ ranges with good memory use, and (2) allows nesting on threaded perls.
+
- Added XS strong Lucas test, but not using Selfridge parameters.
Hence we only use it internally.
diff --git a/XS.xs b/XS.xs
index 0bbf285..2d23cd5 100644
--- a/XS.xs
+++ b/XS.xs
@@ -399,6 +399,9 @@ pminus1_factor(IN UV n, IN UV B1 = 1*1024*1024, IN UV B2 = 0)
SIMPLE_FACTOR(pminus1_factor, n, B1, B2);
int
+_XS_is_pseudoprime(IN UV n, IN UV a)
+
+int
_XS_miller_rabin(IN UV n, ...)
PREINIT:
UV bases[64];
@@ -429,6 +432,9 @@ int
_XS_is_strong_lucas_pseudoprime(IN UV n)
int
+_XS_is_frobenius_underwood_pseudoprime(IN UV n)
+
+int
_XS_is_prob_prime(IN UV n)
int
@@ -681,39 +687,49 @@ forprimes (SV* block, IN SV* svbeg, IN SV* svend = 0)
croak("Not a subroutine reference");
SAVESPTR(GvSV(PL_defgv));
svarg = newSVuv(0);
- ctx = start_segment_primes(beg, end, &segment);
- if (!CvISXSUB(cv)) {
- dMULTICALL;
- I32 gimme = G_VOID;
- PUSH_MULTICALL(cv);
- while (beg < 7) {
- beg = (beg <= 2) ? 2 : (beg <= 3) ? 3 : 5;
- { sv_setuv(svarg, beg); GvSV(PL_defgv) = svarg; MULTICALL; }
- beg += 1 + (beg > 2);
+ /* Handle early part */
+ while (beg < 7) {
+ dSP;
+ beg = (beg <= 2) ? 2 : (beg <= 3) ? 3 : 5;
+ if (beg <= end) {
+ sv_setuv(svarg, beg);
+ GvSV(PL_defgv) = svarg;
+ PUSHMARK(SP);
+ call_sv((SV*)cv, G_VOID|G_DISCARD);
}
+ beg += 1 + (beg > 2);
+ }
+ if (beg <= end) {
+ ctx = start_segment_primes(beg, end, &segment);
while (next_segment_primes(ctx, &seg_base, &seg_low, &seg_high)) {
- START_DO_FOR_EACH_SIEVE_PRIME( segment, seg_low - seg_base, seg_high - seg_base )
- { sv_setuv(svarg, seg_base + p); GvSV(PL_defgv) = svarg; MULTICALL; }
- END_DO_FOR_EACH_SIEVE_PRIME
- }
+ /* I'm getting a memory leak in the MULTICALL and I'm having no luck
+ * finding out why it is happening. Forget MULTICALL for now. */
+ if (0 && !CvISXSUB(cv)) {
+ dMULTICALL;
+ I32 gimme = G_VOID;
+ PUSH_MULTICALL(cv);
+ START_DO_FOR_EACH_SIEVE_PRIME( segment, seg_low - seg_base, seg_high - seg_base ) {
+ sv_setuv(svarg, seg_base + p);
+ GvSV(PL_defgv) = svarg;
+ MULTICALL;
+ } END_DO_FOR_EACH_SIEVE_PRIME
#ifdef PERL_HAS_BAD_MULTICALL_REFCOUNT
- if (CvDEPTH(multicall_cv) > 1)
- SvREFCNT_inc(multicall_cv);
+ if (CvDEPTH(multicall_cv) > 1)
+ SvREFCNT_inc(multicall_cv);
#endif
- POP_MULTICALL;
- } else {
- while (beg < 7) {
- beg = (beg <= 2) ? 2 : (beg <= 3) ? 3 : 5;
- { dSP; sv_setuv(svarg, beg); GvSV(PL_defgv) = svarg; PUSHMARK(SP); call_sv((SV*)cv, G_VOID|G_DISCARD); }
- beg += 1 + (beg > 2);
- }
- while (next_segment_primes(ctx, &seg_base, &seg_low, &seg_high)) {
- START_DO_FOR_EACH_SIEVE_PRIME( segment, seg_low - seg_base, seg_high - seg_base )
- { dSP; sv_setuv(svarg, seg_base + p); GvSV(PL_defgv) = svarg; PUSHMARK(SP); call_sv((SV*)cv, G_VOID|G_DISCARD); }
- END_DO_FOR_EACH_SIEVE_PRIME
+ POP_MULTICALL;
+ } else {
+ START_DO_FOR_EACH_SIEVE_PRIME( segment, seg_low - seg_base, seg_high - seg_base ) {
+ dSP;
+ sv_setuv(svarg, seg_base + p);
+ GvSV(PL_defgv) = svarg;
+ PUSHMARK(SP);
+ call_sv((SV*)cv, G_VOID|G_DISCARD);
+ } END_DO_FOR_EACH_SIEVE_PRIME
+ }
}
+ end_segment_primes(ctx);
}
- end_segment_primes(ctx);
SvREFCNT_dec(svarg);
#endif
XSRETURN_UNDEF;
diff --git a/factor.c b/factor.c
index 6533ef7..db8bfba 100644
--- a/factor.c
+++ b/factor.c
@@ -308,6 +308,25 @@ static int jacobi_iu(IV in, UV m) {
}
+/* Fermat pseudoprime */
+int _XS_is_pseudoprime(UV n, UV a)
+{
+ UV x;
+ UV const nm1 = n-1;
+
+ if (n <= 3) return 0;
+ if (a < 2) croak("Base %"UVuf" is invalid", a);
+ if (a >= n) {
+ a %= n;
+ if ( a <= 1 || a == nm1 )
+ return 1;
+ }
+
+ x = powmod(a, nm1, n); /* x = a^(n-1) mod n */
+ return (x == 1);
+}
+
+
/* Miller-Rabin probabilistic primality test
* Returns 1 if probably prime relative to the bases, 0 if composite.
* Bases must be between 2 and n-2
@@ -405,28 +424,31 @@ int _XS_is_prob_prime(UV n)
#else
-#if 0
- /* TODO: Must verify this Lucas with Feitsma database */
- if (1 && n >= UVCONST(4294967295)) {
+ /* Verified with Feitsma database. No counterexamples below 2^64.
+ * This is faster than multiple M-R routines once we're over 32-bit */
+ if (n >= UVCONST(4294967295)) {
prob_prime = _SPRP2(n) && _XS_is_strong_lucas_pseudoprime(n);
return 2*prob_prime;
}
-#endif
- /* Better bases from http://miller-rabin.appspot.com/, 23 May 2013 */
+ /* Better bases from http://miller-rabin.appspot.com/, 27 May 2013 */
+ /* Verify with:
+ * cat /local/share/spsps-below-2-to-64.txt | perl -MMath::Prime::Util=:all
+ * -nE 'chomp; next unless is_strong_pseudoprime($_, @bases); say;'
+ */
if (n < UVCONST(341531)) {
- bases[0] = UVCONST(9345883071009581737);
+ bases[0] = UVCONST( 9345883071009581737 );
nbases = 1;
- } else if (n < UVCONST(716169301)) {
- bases[0] = 15;
- bases[1] = UVCONST( 13393019396194701 );
+ } else if (n < UVCONST(885594169)) {
+ bases[0] = UVCONST( 725270293939359937 );
+ bases[1] = UVCONST( 3569819667048198375 );
nbases = 2;
- } else if (n < UVCONST(273919523041)) { /* 29+ bits */
- bases[0] = 15;
- bases[1] = UVCONST( 7363882082 );
- bases[2] = UVCONST( 992620450144556 );
+ } else if (n < UVCONST(350269456337)) {
+ bases[0] = UVCONST( 4230279247111683200 );
+ bases[1] = UVCONST( 14694767155120705706 );
+ bases[2] = UVCONST( 16641139526367750375 );
nbases = 3;
- } else if (n < UVCONST(55245642489451)) { /* 37+ bits */
+ } else if (n < UVCONST(55245642489451)) { /* 38+ bits */
bases[0] = 2;
bases[1] = UVCONST( 141889084524735 );
bases[2] = UVCONST( 1199124725622454117 );
@@ -1158,3 +1180,73 @@ int racing_squfof_factor(UV n, UV *factors, UV rounds)
factors[0] = n;
return 1;
}
+
+
+/****************************************************************************/
+
+int _XS_is_frobenius_underwood_pseudoprime(UV n)
+{
+ int bit;
+ UV x, result, multiplier, a, b, np1, len, t1, t2, na;
+ IV t;
+
+ if (n < 2) return 0;
+ if (n < 4) return 1;
+ if ((n % 2) == 0) return 0;
+ if (is_perfect_square(n,0)) return 0;
+ if (n == UV_MAX) return 0;
+
+ x = 0;
+ t = -1;
+ while ( jacobi_iu( t, n ) != -1 ) {
+ x++;
+ t = (IV)(x*x) - 4;
+ }
+ result = addmod( addmod(x, x, n), 5, n);
+ multiplier = addmod(x, 2, n);
+
+ a = 1;
+ b = 2;
+ np1 = n+1;
+ { UV v = np1; len = 1; while (v >>= 1) len++; }
+
+ if (x == 0) {
+ for (bit = len-2; bit >= 0; bit--) {
+ t2 = addmod(b, b, n);
+ na = mulmod(a, t2, n);
+ t1 = addmod(b, a, n);
+ t2 = addmod(b, n-a, n); /* subtract */
+ b = mulmod(t1, t2, n);
+ a = na;
+ if ( (np1 >> bit) & UVCONST(1) ) {
+ t1 = mulmod(a, 2, n);
+ na = addmod(t1, b, n);
+ t1 = addmod(b, b, n);
+ b = addmod(t1, n-a, n); /* subtract */
+ a = na;
+ }
+ }
+ } else {
+ for (bit = len-2; bit >= 0; bit--) {
+ t1 = mulmod(a, x, n);
+ t2 = addmod(b, b, n);
+ t1 = addmod(t1, t2, n);
+ na = mulmod(a, t1, n);
+ t1 = addmod(b, a, n);
+ t2 = addmod(b, n-a, n); /* subtract */
+ b = mulmod(t1, t2, n);
+ a = na;
+ if ( (np1 >> bit) & UVCONST(1) ) {
+ t1 = mulmod(a, multiplier, n);
+ na = addmod(t1, b, n);
+ t1 = addmod(b, b, n);
+ b = addmod(t1, n-a, n); /* subtract */
+ a = na;
+ }
+ }
+ }
+ if (_XS_get_verbose()>1) printf("%"UVuf" is %s with x = %"UVuf"\n", n, (a == 0 && b == result) ? "probably prime" : "composite", x);
+ if (a == 0 && b == result)
+ return 1;
+ return 0;
+}
diff --git a/factor.h b/factor.h
index 77608c5..29722bf 100644
--- a/factor.h
+++ b/factor.h
@@ -10,22 +10,20 @@ extern int factor(UV n, UV *factors);
extern int trial_factor(UV n, UV *factors, UV maxtrial);
extern int fermat_factor(UV n, UV *factors, UV rounds);
-
extern int holf_factor(UV n, UV *factors, UV rounds);
-
-extern int squfof_factor(UV n, UV *factors, UV rounds);
-extern int racing_squfof_factor(UV n, UV *factors, UV rounds);
-
-
extern int pbrent_factor(UV n, UV *factors, UV maxrounds, UV a);
-
extern int prho_factor(UV n, UV *factors, UV maxrounds);
-
extern int pminus1_factor(UV n, UV *factors, UV B1, UV B2);
+extern int squfof_factor(UV n, UV *factors, UV rounds);
+extern int racing_squfof_factor(UV n, UV *factors, UV rounds);
+
+extern int _XS_is_pseudoprime(UV n, UV a);
extern int _XS_miller_rabin(UV n, const UV *bases, int nbases);
+extern int _SPRP2(UV n);
extern int _XS_is_prob_prime(UV n);
-extern int _XS_is_prime_tom(UV n, int t);
+extern int _XS_is_strong_lucas_pseudoprime(UV n);
+extern int _XS_is_frobenius_underwood_pseudoprime(UV n);
extern UV _XS_divisor_sum(UV n);
diff --git a/t/32-iterators.t b/t/32-iterators.t
index bfc285b..7e4ae1e 100644
--- a/t/32-iterators.t
+++ b/t/32-iterators.t
@@ -8,6 +8,7 @@ use Math::Prime::Util qw/primes forprimes prime_iterator/;
my $use64 = Math::Prime::Util::prime_get_config->{'maxbits'} > 32;
plan tests => 8 + 5
+ + 11
+ 3 + 7
+ 2;
@@ -22,6 +23,18 @@ ok(!eval { forprimes { 1 } "abc"; }, "forprimes abc");
ok(!eval { forprimes { 1 } 2, "abc"; }, "forprimes 2, abc");
ok(!eval { forprimes { 1 } 5.6; }, "forprimes abc");
+{my @t; forprimes {push @t,$_} 1; is_deeply( [@t], [], "forprimes 1" ); }
+{my @t; forprimes {push @t,$_} 2; is_deeply( [@t], [2], "forprimes 3" ); }
+{my @t; forprimes {push @t,$_} 3; is_deeply( [@t], [2,3], "forprimes 3" ); }
+{my @t; forprimes {push @t,$_} 4; is_deeply( [@t], [2,3], "forprimes 4" ); }
+{my @t; forprimes {push @t,$_} 5; is_deeply( [@t], [2,3,5], "forprimes 5" ); }
+{my @t; forprimes {push @t,$_} 3,5; is_deeply( [@t], [3,5], "forprimes 3,5" ); }
+{my @t; forprimes {push @t,$_} 3,6; is_deeply( [@t], [3,5], "forprimes 3,6" ); }
+{my @t; forprimes {push @t,$_} 3,7; is_deeply( [@t], [3,5,7], "forprimes 3,7" ); }
+{my @t; forprimes {push @t,$_} 5,7; is_deeply( [@t], [5,7], "forprimes 5,7" ); }
+{my @t; forprimes {push @t,$_} 5,11; is_deeply( [@t], [5,7,11], "forprimes 5,11" ); }
+{my @t; forprimes {push @t,$_} 7,11; is_deeply( [@t], [7,11], "forprimes 7,11" ); }
+
{ my @t; forprimes { push @t, $_ } 50;
is_deeply( [@t], [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47], "forprimes 50" );
}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-perl/packages/libmath-prime-util-perl.git
More information about the Pkg-perl-cvs-commits
mailing list