[libmath-prime-util-perl] 05/13: Improvements for PP prime_count
Partha P. Mukherjee
ppm-guest at moszumanska.debian.org
Thu May 21 18:47:41 UTC 2015
This is an automated email from the git hooks/post-receive script.
ppm-guest pushed a commit to annotated tag v0.24
in repository libmath-prime-util-perl.
commit adbc62bd73b14370a5e296f2cf87c4092e4106d9
Author: Dana Jacobsen <dana at acm.org>
Date: Thu Mar 7 14:14:26 2013 -0800
Improvements for PP prime_count
---
Changes | 5 +++-
lib/Math/Prime/Util/PP.pm | 59 ++++++++++++++++++++++++++---------------------
2 files changed, 37 insertions(+), 27 deletions(-)
diff --git a/Changes b/Changes
index 564a113..3261b2a 100644
--- a/Changes
+++ b/Changes
@@ -6,7 +6,10 @@ Revision history for Perl extension Math::Prime::Util.
- Fix compilation with old pre-C99 strict compilers (decl after statement).
- - Some more prime count improvements to speed and space.
+ - More XS prime count improvements to speed and space.
+
+ - PP prime count for 10^9 and larger is ~2x faster and uses much less
+ memory. Similar impact for nth_prime 10^8 or larger.
0.23 5 March 2013
diff --git a/lib/Math/Prime/Util/PP.pm b/lib/Math/Prime/Util/PP.pm
index 21e7679..5d68b16 100644
--- a/lib/Math/Prime/Util/PP.pm
+++ b/lib/Math/Prime/Util/PP.pm
@@ -421,21 +421,21 @@ sub _legendre_phi {
my $primea = $primes->[$a-1];
my %newvals;
while (my($v,$c) = each %vals) {
- next if $c == 0;
- # next if $v < $primea;
- $newvals{$v} += $c;
my $sval = int($v / $primea);
- if ($sval >= $primea) {
- $newvals{$sval} -= $c;
- } else {
+ if ($sval < $primea) {
$sum -= $c;
+ } else {
+ $newvals{$sval} -= $c;
}
}
- %vals = %newvals;
+ # merge newvals into vals
+ while (my($v,$c) = each %newvals) {
+ $vals{$v} += $c;
+ delete $vals{$v} if $vals{$v} == 0;
+ }
$a--;
}
while (my($v,$c) = each %vals) {
- next if $c == 0;
$sum += $c * _mapes($v, $a);
}
return $sum;
@@ -452,17 +452,22 @@ sub _sieve_prime_count {
}
sub _count_with_sieve {
- my ($sref, $high) = @_;
- return (0,0,1,2,2,3,3)[$high] if $high < 7;
+ my ($sref, $low, $high) = @_;
+ ($low, $high) = (2, $low) if !defined $high;
+ my $count = 0;
+ if ($low < 3) { $low = 3; $count++; }
+ else { $low |= 1; }
$high-- if ($high % 2) == 0; # Make high go to odd number.
- my $send = ($high >> 1) + 1;
+ return $count if $low > $high;
+ my $sbeg = $low >> 1;
+ my $send = $high >> 1;
- if ( !defined $sref || $send > length($$sref) ) {
- # We could take the full count of $sref, then segment sieve to high.
- $sref = _sieve_erat($high);
- return 1 + $$sref =~ tr/0//;
+ if ( !defined $sref || $send >= length($$sref) ) {
+ # outside our range, so call the segment siever.
+ my $seg_ref = _sieve_segment($low, $high);
+ return $count + $$seg_ref =~ tr/0//;
}
- return 1 + substr($$sref, 0, $send) =~ tr/0//;
+ return $count + substr($$sref, $sbeg, $send-$sbeg+1) =~ tr/0//;
}
sub _lehmer_pi {
@@ -480,18 +485,20 @@ sub _lehmer_pi {
my $sum = int(($b + $a - 2) * ($b - $a + 1) / 2);
$sum += _legendre_phi($x, $a, $primes);
- # Get a big sieve for our primecounts. The C code uses b*16 as a compromise,
- # as that cuts out all the inner loop sieves and about half the outer loop.
- # It also takes good advantage of segment sieving for the big outer counts.
- # We'll just go ahead and sieve everything we need now. This is really much
- # more than we should use, but it saves a _huge_ amount of time given we're
- # not using a segment sieve for the outer loop.
- #my $sref = _sieve_erat($b * 16);
- my $sref = _sieve_erat( int($x / $primes->[$a]) );
+ # Get a big sieve for our primecounts. The C code compromises with either
+ # b*10 or x^3/5, as that cuts out all the inner loop sieves and about half
+ # of the big outer loop counts.
+ # Our sieve count isn't nearly as optimized here, so error on the side of
+ # more primes. This uses a lot more memory but saves a lot of time.
+ my $sref = _sieve_erat( int($x / $primes->[$a] / 5) );
- foreach my $i ($a+1 .. $b) {
+ my ($lastw, $lastwpc) = (0,0);
+ foreach my $i (reverse $a+1 .. $b) {
my $w = int($x / $primes->[$i-1]);
- $sum = $sum - _count_with_sieve($sref,$w);
+ $lastwpc += _count_with_sieve($sref,$lastw+1, $w);
+ $lastw = $w;
+ $sum -= $lastwpc;
+ #$sum -= _count_with_sieve($sref,$w);
if ($i <= $c) {
my $bi = _count_with_sieve($sref,int(sqrt($w)+0.5));
foreach my $j ($i .. $bi) {
--
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