[libmath-prime-util-perl] 03/14: New internal macro to loop a..b using primary sieve
Partha P. Mukherjee
ppm-guest at moszumanska.debian.org
Thu May 21 18:47:52 UTC 2015
This is an automated email from the git hooks/post-receive script.
ppm-guest pushed a commit to annotated tag v0.25
in repository libmath-prime-util-perl.
commit 718c44d785f1557512e786e4c235957a9f9203cb
Author: Dana Jacobsen <dana at acm.org>
Date: Mon Mar 11 18:31:36 2013 -0700
New internal macro to loop a..b using primary sieve
---
Changes | 3 +++
TODO | 7 -------
XS.xs | 16 +++-------------
factor.c | 41 +++++++++++++++++++----------------------
lehmer.c | 15 ++++-----------
sieve.h | 35 +++++++++++++++++++++++++++++++++++
util.c | 61 ++++++++++++++-----------------------------------------------
7 files changed, 78 insertions(+), 100 deletions(-)
diff --git a/Changes b/Changes
index 71c04c9..fdc9b74 100644
--- a/Changes
+++ b/Changes
@@ -5,6 +5,9 @@ Revision history for Perl extension Math::Prime::Util.
- Speed up p-1 stage 2 factoring. This makes factor() about 20% faster
for 19 digit semiprimes.
+ - New internal macro to loop over primary sieve starting at 2. Simplifies
+ code in quite a few places.
+
0.24 10 March 2013
- Fix compilation with old pre-C99 strict compilers (decl after statement).
diff --git a/TODO b/TODO
index dc0ddd7..a75cc17 100644
--- a/TODO
+++ b/TODO
@@ -41,11 +41,4 @@
- More efficient totient segment. Do we really need primes to n/2?
-- Add a more complex system for allowing something like:
- FOREACH_PRIME(low, high) {
- ....
- } END_FOREACH_PRIME
- that (1) handles any low / high, and (2) segments. Take segment_primes
- from XS.xs to do this.
-
- Implement S2 calculation for LMO prime count.
diff --git a/XS.xs b/XS.xs
index 5f2f42d..ff46ecc 100644
--- a/XS.xs
+++ b/XS.xs
@@ -102,19 +102,9 @@ sieve_primes(IN UV low, IN UV high)
AV* av = newAV();
CODE:
if (low <= high) {
- if (get_prime_cache(high, &sieve) < high) {
- release_prime_cache(sieve);
- croak("Could not generate sieve for %"UVuf, high);
- } else {
- if ((low <= 2) && (high >= 2)) { av_push(av, newSVuv( 2 )); }
- if ((low <= 3) && (high >= 3)) { av_push(av, newSVuv( 3 )); }
- if ((low <= 5) && (high >= 5)) { av_push(av, newSVuv( 5 )); }
- if (low < 7) { low = 7; }
- START_DO_FOR_EACH_SIEVE_PRIME( sieve, low, high ) {
- av_push(av,newSVuv(p));
- } END_DO_FOR_EACH_SIEVE_PRIME
- release_prime_cache(sieve);
- }
+ START_DO_FOR_EACH_PRIME(low, high) {
+ av_push(av,newSVuv(p));
+ } END_DO_FOR_EACH_PRIME
}
RETVAL = newRV_noinc( (SV*) av );
OUTPUT:
diff --git a/factor.c b/factor.c
index 75e496b..26622cf 100644
--- a/factor.c
+++ b/factor.c
@@ -66,7 +66,7 @@ int factor(UV n, UV *factors)
}
/* This p-1 gets about 2/3 of what makes it through the above */
if (!split_success) {
- split_success = pminus1_factor(n, tofac_stack+ntofac, 4000, 80000)-1;
+ split_success = pminus1_factor(n, tofac_stack+ntofac, 5000, 80000)-1;
if (verbose) printf("pminus1 %d\n", split_success);
}
/* Some rounds of HOLF, good for close to perfect squares */
@@ -632,19 +632,21 @@ int pminus1_factor(UV n, UV *factors, UV B1, UV B2)
UV sqrtB1 = isqrt(B1);
MPUassert( (n >= 3) && ((n%2) != 0) , "bad n in pminus1_factor");
- for (q = 2; q <= sqrtB1; q = _XS_next_prime(q)) {
- UV k = q*q;
- UV kmin = B1/q;
+ START_DO_FOR_EACH_PRIME(2, sqrtB1) {
+ UV k = p*p;
+ UV kmin = B1/p;
while (k <= kmin)
- k *= q;
+ k *= p;
a = powmod(a, k, n);
- }
+ q = p;
+ } END_DO_FOR_EACH_PRIME
if (a == 0) { factors[0] = n; return 1; }
f = gcd_ui(a-1, n);
if (f == 1) {
savea = a;
saveq = q;
- for (; q <= B1; q = _XS_next_prime(q)) {
+ START_DO_FOR_EACH_PRIME(q+1, B1) {
+ q = p;
a = powmod(a, q, n);
if ( (j++ % 32) == 0) {
if (a == 0 || gcd_ui(a-1, n) != 1)
@@ -652,23 +654,24 @@ int pminus1_factor(UV n, UV *factors, UV B1, UV B2)
savea = a;
saveq = q;
}
- }
+ } END_DO_FOR_EACH_PRIME
if (a == 0) { factors[0] = n; return 1; }
f = gcd_ui(a-1, n);
}
/* If we found more than one factor in stage 1, backup and single step */
if (f == n) {
a = savea;
- for (q = saveq; q <= B1; q = _XS_next_prime(q)) {
- UV k = q;
- UV kmin = B1/q;
+ START_DO_FOR_EACH_PRIME(saveq, B1) {
+ UV k = p;
+ UV kmin = B1/p;
while (k <= kmin)
- k *= q;
+ k *= p;
a = powmod(a, k, n);
f = gcd_ui(a-1, n);
+ q = p;
if (f != 1)
break;
- }
+ } END_DO_FOR_EACH_PRIME
/* If f == n again, we could do:
* for (savea = 3; f == n && savea < 100; savea = _XS_next_prime(savea)) {
* a = savea;
@@ -681,8 +684,7 @@ int pminus1_factor(UV n, UV *factors, UV B1, UV B2)
}
/* STAGE 2 */
- if (f == 1 && B2 > B1 && q >= 5) {
- const unsigned char* sieve;
+ if (f == 1 && B2 > B1) {
UV bm = a;
UV b = 1;
UV bmdiff;
@@ -699,11 +701,7 @@ int pminus1_factor(UV n, UV *factors, UV B1, UV B2)
a = powmod(a, q, n);
j = 1;
- if (get_prime_cache(B2, &sieve) < B2) {
- release_prime_cache(sieve);
- croak("Could not generate sieve for %"UVuf, B2);
- }
- START_DO_FOR_EACH_SIEVE_PRIME( sieve, q+1, B2 ) {
+ START_DO_FOR_EACH_PRIME( q+1, B2 ) {
UV lastq = q;
UV qdiff;
q = p;
@@ -729,8 +727,7 @@ int pminus1_factor(UV n, UV *factors, UV B1, UV B2)
if (f != 1)
break;
}
- } END_DO_FOR_EACH_SIEVE_PRIME
- release_prime_cache(sieve);
+ } END_DO_FOR_EACH_PRIME
f = gcd_ui(b, n);
}
if ( (f != 1) && (f != n) ) {
diff --git a/lehmer.c b/lehmer.c
index 267787b..1417e2e 100644
--- a/lehmer.c
+++ b/lehmer.c
@@ -183,9 +183,8 @@ static UV* generate_small_primes(UV n)
* Remember to free when done. */
static UV* generate_small_primes(UV n)
{
- const unsigned char* sieve;
UV* primes;
- UV i;
+ UV i = 0;
double fn = (double)n;
double flogn = log(fn);
double flog2n = log(flogn);
@@ -195,20 +194,14 @@ static UV* generate_small_primes(UV n)
(n >= 18) ? (UV) ceil(fn*(flogn+flog2n-1.0+((flog2n+0.30)/flogn)))
: 59;
- if (get_prime_cache(nth_prime, &sieve) < nth_prime) {
- release_prime_cache(sieve);
- croak("Could not generate sieve for %"UVuf, nth_prime);
- }
New(0, primes, n+1, UV);
if (primes == 0)
croak("Can not allocate small primes\n");
- primes[0] = 0; primes[1] = 2; primes[2] = 3; primes[3] = 5;
- i = 3;
- START_DO_FOR_EACH_SIEVE_PRIME( sieve, 7, nth_prime ) {
+ primes[0] = 0;
+ START_DO_FOR_EACH_PRIME(2, nth_prime) {
if (i >= n) break;
primes[++i] = p;
- } END_DO_FOR_EACH_SIEVE_PRIME
- release_prime_cache(sieve);
+ } END_DO_FOR_EACH_PRIME
if (i < n)
croak("Did not generate enough small primes.\n");
if (verbose > 1) printf("generated %lu small primes, from 2 to %lu\n", i, primes[i]);
diff --git a/sieve.h b/sieve.h
index 8e1f3f9..6dca024 100644
--- a/sieve.h
+++ b/sieve.h
@@ -81,5 +81,40 @@ static UV prev_prime_in_sieve(const unsigned char* sieve, UV p) {
} \
}
+#define START_DO_FOR_EACH_PRIME(a, b) \
+ { \
+ const unsigned char* sieve_; \
+ UV d_ = 0; \
+ UV m_ = 7; \
+ UV p = a; \
+ UV l_ = b; \
+ if (get_prime_cache(l_, &sieve_) < l_) { \
+ release_prime_cache(sieve_); \
+ croak("Could not generate sieve for %"UVuf, l_); \
+ } \
+ if (p <= 5) { \
+ p = (p <= 2) ? 2 : (p <= 3) ? 3 : 5; \
+ } else { \
+ d_ = p/30; \
+ m_ = p-d_*30; \
+ m_ += distancewheel30[m_]; \
+ p = d_*30 + m_; \
+ } \
+ while ( p <= l_ ) { \
+ if (p < 7 || !(sieve_[d_] & masktab30[m_]))
+
+#define RETURN_FROM_EACH_PRIME(x) \
+ do { release_prime_cache(sieve_); return(x); } while (0)
+
+#define END_DO_FOR_EACH_PRIME \
+ if (p < 7) { \
+ p += 1 + (p > 2); \
+ } else { \
+ m_ = nextwheel30[m_]; if (m_ == 1) { d_++; } \
+ p = d_*30+m_; \
+ } \
+ } \
+ release_prime_cache(sieve_); \
+ }
#endif
diff --git a/util.c b/util.c
index 3eb4929..c7c3505 100644
--- a/util.c
+++ b/util.c
@@ -769,7 +769,7 @@ UV _XS_nth_prime(UV n)
char* _moebius_range(UV lo, UV hi)
{
char* mu;
- UV i, p;
+ UV i;
UV sqrtn = isqrt(hi);
#if 1
IV* A;
@@ -786,14 +786,13 @@ char* _moebius_range(UV lo, UV hi)
croak("Could not get memory for %"UVuf" moebius results\n", hi-lo+1);
for (i = lo; i <= hi; i++)
A[i-lo] = 1;
- prime_precalc(sqrtn);
- for (p = 2; p <= sqrtn; p = _XS_next_prime(p)) {
+ START_DO_FOR_EACH_PRIME(2, sqrtn) {
UV p2 = p*p;
for (i = PGTLO(p2, lo); i <= hi; i += p2)
A[i-lo] = 0;
for (i = PGTLO(p, lo); i <= hi; i += p)
A[i-lo] *= -(IV)p;
- }
+ } END_DO_FOR_EACH_PRIME
New(0, mu, hi-lo+1, char);
if (mu == 0)
croak("Could not get memory for %"UVuf" moebius results\n", hi-lo+1);
@@ -807,6 +806,7 @@ char* _moebius_range(UV lo, UV hi)
Safefree(A);
#endif
#if 0
+ UV p;
/* Simple char method, Needs way too many primes */
New(0, mu, hi-lo+1, char);
if (mu == 0)
@@ -827,6 +827,7 @@ char* _moebius_range(UV lo, UV hi)
* (1) I'm using the log function, which should be fixed (easy).
* (2) it doesn't work. try 64-101 vs. 64 vs. 100.
*/
+ UV p;
unsigned char* A;
New(0, A, hi-lo+1, unsigned char);
if (A == 0)
@@ -862,7 +863,6 @@ char* _moebius_range(UV lo, UV hi)
UV* _totient_range(UV lo, UV hi) {
UV* totients;
- const unsigned char* sieve;
UV i, sievehi;
if (hi < lo) croak("_totient_range error hi %lu < lo %lu\n", hi, lo);
New(0, totients, hi-lo+1, UV);
@@ -872,18 +872,10 @@ UV* _totient_range(UV lo, UV hi) {
totients[i-lo] = i;
sievehi = hi/2;
for (i=P2GTLO(2*2,2,lo); i <= hi; i += 2) totients[i-lo] -= totients[i-lo]/2;
- for (i=P2GTLO(2*3,3,lo); i <= hi; i += 3) totients[i-lo] -= totients[i-lo]/3;
- for (i=P2GTLO(2*5,5,lo); i <= hi; i += 5) totients[i-lo] -= totients[i-lo]/5;
- if (get_prime_cache(sievehi, &sieve) < sievehi) {
- release_prime_cache(sieve);
- croak("Could not generate sieve for %"UVuf, sievehi);
- } else {
- START_DO_FOR_EACH_SIEVE_PRIME( sieve, 7, sievehi ) {
- for (i = P2GTLO(2*p,p,lo); i <= hi; i += p)
- totients[i-lo] -= totients[i-lo]/p;
- } END_DO_FOR_EACH_SIEVE_PRIME
- release_prime_cache(sieve);
- }
+ START_DO_FOR_EACH_PRIME(3, sievehi) {
+ for (i = P2GTLO(2*p,p,lo); i <= hi; i += p)
+ totients[i-lo] -= totients[i-lo]/p;
+ } END_DO_FOR_EACH_PRIME
for (i = lo; i <= hi; i++)
if (totients[i-lo] == i)
totients[i-lo] = i-1;
@@ -951,49 +943,24 @@ IV _XS_mertens(UV n) {
double _XS_chebyshev_theta(UV n)
{
- const unsigned char* sieve;
KAHAN_INIT(sum);
-
- if (n >= 2) KAHAN_SUM(sum, 0.6931471805599453094172321214581765680755L);
- if (n >= 3) KAHAN_SUM(sum, 1.0986122886681096913952452369225257046475L);
- if (n >= 5) KAHAN_SUM(sum, 1.6094379124341003746007593332261876395256L);
- if (n < 7) return (double) sum;
-
- if (get_prime_cache(n, &sieve) < n) {
- release_prime_cache(sieve);
- croak("Could not generate sieve for %"UVuf, n);
- }
- START_DO_FOR_EACH_SIEVE_PRIME(sieve, 7, n) {
+ START_DO_FOR_EACH_PRIME(2, n) {
KAHAN_SUM(sum, logl(p));
- } END_DO_FOR_EACH_SIEVE_PRIME
- release_prime_cache(sieve);
+ } END_DO_FOR_EACH_PRIME
return (double) sum;
}
double _XS_chebyshev_psi(UV n)
{
- const unsigned char* sieve;
- UV prime, mults_are_one;
+ UV mults_are_one = 0;
long double logn, logp;
KAHAN_INIT(sum);
logn = logl(n);
- for (prime = 2; prime <= 5 && prime <= n; prime += prime-1) {
- logp = logl(prime);
- KAHAN_SUM(sum, logp * floorl(logn/logp + 1e-15));
- }
- if (n < 7) return (double) sum;
-
- if (get_prime_cache(n, &sieve) < n) {
- release_prime_cache(sieve);
- croak("Could not generate sieve for %"UVuf, n);
- }
- mults_are_one = 0;
- START_DO_FOR_EACH_SIEVE_PRIME(sieve, 7, n) {
+ START_DO_FOR_EACH_PRIME(2, n) {
logp = logl(p);
if (!mults_are_one && p > (n/p)) mults_are_one = 1;
KAHAN_SUM(sum, (mults_are_one) ? logp : logp * floorl(logn/logp + 1e-15));
- } END_DO_FOR_EACH_SIEVE_PRIME
- release_prime_cache(sieve);
+ } END_DO_FOR_EACH_PRIME
return (double) sum;
}
--
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