[libmath-prime-util-perl] 11/20: 10x speedup for divisor_sum
Partha P. Mukherjee
ppm-guest at moszumanska.debian.org
Thu May 21 18:47:31 UTC 2015
This is an automated email from the git hooks/post-receive script.
ppm-guest pushed a commit to annotated tag v0.23
in repository libmath-prime-util-perl.
commit 8aea368b9e763da2630463f2fa5812ea21485d76
Author: Dana Jacobsen <dana at acm.org>
Date: Sat Mar 2 01:16:33 2013 -0800
10x speedup for divisor_sum
---
Changes | 2 ++
XS.xs | 3 +++
factor.c | 24 ++++++++++++++++++++++++
factor.h | 2 ++
lib/Math/Prime/Util.pm | 37 +++++++++++++++++++++++++++++++------
5 files changed, 62 insertions(+), 6 deletions(-)
diff --git a/Changes b/Changes
index e52cf01..4d3c052 100644
--- a/Changes
+++ b/Changes
@@ -20,6 +20,8 @@ Revision history for Perl extension Math::Prime::Util.
- Add the first and second Chebyshev functions (theta and psi).
+ - Divisor sum with no sub is ~10x faster.
+
0.22 26 February 2013
- Move main factor loop out of xs and into factor.c.
diff --git a/XS.xs b/XS.xs
index 83fc0ce..490b880 100644
--- a/XS.xs
+++ b/XS.xs
@@ -469,3 +469,6 @@ _XS_chebyshev_theta(IN UV n)
double
_XS_chebyshev_psi(IN UV n)
+
+UV
+_XS_divisor_sum(IN UV n)
diff --git a/factor.c b/factor.c
index b86b02b..8bc1357 100644
--- a/factor.c
+++ b/factor.c
@@ -424,6 +424,30 @@ int _XS_is_prob_prime(UV n)
}
+UV _XS_divisor_sum(UV n)
+{
+ UV factors[MPU_MAX_FACTORS+1];
+ int nfac, i;
+ UV product = 1;
+
+ if (n <= 1) return n;
+ nfac = factor(n, factors);
+ for (i = 0; i < nfac; i++) {
+ if (i+1 < nfac && factors[i] == factors[i+1]) {
+ UV fmult = factors[i]*factors[i];
+ do {
+ fmult *= factors[i++];
+ } while (i+1 < nfac && factors[i] == factors[i+1]);
+ product *= (fmult-1) / (factors[i]-1);
+ } else {
+ product *= factors[i]+1;
+ }
+ }
+ return product;
+}
+
+
+
/* Knuth volume 2, algorithm C.
* Very fast for small numbers, grows rapidly.
diff --git a/factor.h b/factor.h
index b5cf735..a13b52e 100644
--- a/factor.h
+++ b/factor.h
@@ -25,6 +25,8 @@ extern int pminus1_factor(UV n, UV *factors, UV B1, UV B2);
extern int _XS_miller_rabin(UV n, const UV *bases, int nbases);
extern int _XS_is_prob_prime(UV n);
+extern UV _XS_divisor_sum(UV n);
+
static UV gcd_ui(UV x, UV y) {
UV t;
if (y < x) { t = x; x = y; y = t; }
diff --git a/lib/Math/Prime/Util.pm b/lib/Math/Prime/Util.pm
index cc7129e..e491903 100644
--- a/lib/Math/Prime/Util.pm
+++ b/lib/Math/Prime/Util.pm
@@ -1289,16 +1289,26 @@ sub jordan_totient {
# Mathematica and Pari both have functions like this.
sub divisor_sum {
my($n, $sub) = @_;
- return 0 if defined $n && $n < 1;
+ # I really need to get cracking on an XS validator.
+ #return _XS_divisor_sum($n) if !defined $sub && defined $n && $n <= $_XS_MAXVAL && $_Config{'nobigint'};
+ return (0,1)[$n] if defined $n && $n <= 1;
_validate_positive_integer($n);
if (!defined $sub) {
- return $n if $n == 1;
- my $sum = 1 + $n;
- foreach my $f ( all_factors($n) ) {
- $sum += $f;
+ return _XS_divisor_sum($n) if $n <= $_XS_MAXVAL;
+ my $product = 1;
+ my @factors = factor($n);
+ while (@factors) {
+ if (@factors > 1 && $factors[0] == $factors[1]) {
+ my $fmult = $factors[0] * $factors[0];
+ $fmult *= shift @factors while @factors > 1 && $factors[0] == $factors[1];
+ $product *= ($fmult -1) / ($factors[0] - 1);
+ } else {
+ $product *= $factors[0]+1;
+ }
+ shift @factors;
}
- return $sum;
+ return $product;
}
croak "Second argument must be a code ref" unless ref($sub) eq 'CODE';
@@ -3191,6 +3201,21 @@ Print some primes above 64-bit range:
# Similar code using Pari:
# perl -MMath::Pari=:int,PARI,nextprime -E 'my $start = PARI "100000000000000000000"; my $end = $start+1000; my $p=nextprime($start); while ($p <= $end) { say $p; $p = nextprime($p+1); }'
+Examining the η3(x) function of Planat and Solé (2011):
+
+ sub nu3 {
+ my $n = shift;
+ my $phix = chebyshev_psi($n);
+ my $nu3 = 0;
+ foreach my $nu (1..3) {
+ $nu3 += (moebius($nu)/$nu)*LogarithmicIntegral($phix**(1/$nu));
+ }
+ return $nu3;
+ }
+ say prime_count(1000000);
+ say prime_count_approx(1000000);
+ say nu3(1000000);
+
Project Euler, problem 3 (Largest prime factor):
use Math::Prime::Util qw/factor/;
--
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