[libmath-prime-util-perl] 84/181: Move factor_exp and divisors to XS->Perl, merge with factor
Partha P. Mukherjee
ppm-guest at moszumanska.debian.org
Thu May 21 18:51:09 UTC 2015
This is an automated email from the git hooks/post-receive script.
ppm-guest pushed a commit to annotated tag v0.36
in repository libmath-prime-util-perl.
commit 4a10314df4a3133659515da23ca42baf0187290b
Author: Dana Jacobsen <dana at acm.org>
Date: Tue Dec 31 16:24:33 2013 -0800
Move factor_exp and divisors to XS->Perl, merge with factor
---
XS.xs | 89 +++++++++++++++++++++-------------------
factor.c | 25 ++++++++----
lib/Math/Prime/Util.pm | 109 +++++++++++++++++--------------------------------
3 files changed, 100 insertions(+), 123 deletions(-)
diff --git a/XS.xs b/XS.xs
index 4c29062..23a5fe2 100644
--- a/XS.xs
+++ b/XS.xs
@@ -278,41 +278,6 @@ sieve_primes(IN UV low, IN UV high)
RETVAL
void
-_XS_factor_exp(IN UV n)
- PREINIT:
- UV factors[MPU_MAX_FACTORS+1];
- UV exponents[MPU_MAX_FACTORS+1];
- int i, nfactors;
- PPCODE:
- nfactors = factor_exp(n, factors, exponents);
- if (GIMME_V == G_SCALAR) {
- PUSHs(sv_2mortal(newSVuv(nfactors)));
- } else {
- /* Return ( [p1,e1], [p2,e2], [p3,e3], ... ) */
- if (n == 1) XSRETURN_EMPTY;
- EXTEND(SP, nfactors);
- for (i = 0; i < nfactors; i++) {
- AV* av = newAV();
- av_push(av, newSVuv(factors[i]));
- av_push(av, newSVuv(exponents[i]));
- PUSHs( sv_2mortal(newRV_noinc( (SV*) av )) );
- }
- }
-
-void
-_XS_divisors(IN UV n)
- PPCODE:
- if (GIMME_V == G_SCALAR) {
- PUSHs(sv_2mortal(newSVuv( divisor_sum(n, 0) )));
- } else {
- UV i, ndivisors;
- UV* divs = _divisor_list(n, &ndivisors);
- for (i = 0; i < ndivisors; i++)
- XPUSHs(sv_2mortal(newSVuv(divs[i])));
- Safefree(divs);
- }
-
-void
trial_factor(IN UV n, ...)
ALIAS:
fermat_factor = 1
@@ -478,26 +443,64 @@ next_prime(IN SV* svn)
void
factor(IN SV* svn)
+ ALIAS:
+ factor_exp = 1
+ divisors = 2
+ PREINIT:
+ U32 gimme_v;
+ int status, i, nfactors;
PPCODE:
- U32 gimme_v = GIMME_V;
- int status = _validate_int(aTHX_ svn, 0);
+ gimme_v = GIMME_V;
+ status = _validate_int(aTHX_ svn, 0);
if (status == 1) {
UV factors[MPU_MAX_FACTORS+1];
+ UV exponents[MPU_MAX_FACTORS+1];
UV n = my_svuv(svn);
- int i, nfactors = factor(n, factors);
if (gimme_v == G_SCALAR) {
- PUSHs(sv_2mortal(newSVuv(nfactors)));
+ switch (ix) {
+ case 0: nfactors = factor(n, factors); break;
+ case 1: nfactors = factor_exp(n, factors, 0); break;
+ default: nfactors = divisor_sum(n, 0); break;
+ }
+ PUSHs(sv_2mortal(newSVuv( nfactors )));
} else if (gimme_v == G_ARRAY) {
- EXTEND(SP, nfactors);
- for (i = 0; i < nfactors; i++) {
- PUSHs(sv_2mortal(newSVuv( factors[i] )));
+ switch (ix) {
+ case 0: nfactors = factor(n, factors);
+ EXTEND(SP, nfactors);
+ for (i = 0; i < nfactors; i++)
+ PUSHs(sv_2mortal(newSVuv( factors[i] )));
+ break;
+ case 1: nfactors = factor_exp(n, factors, exponents);
+ /* if (n == 1) XSRETURN_EMPTY; */
+ EXTEND(SP, nfactors);
+ for (i = 0; i < nfactors; i++) {
+ AV* av = newAV();
+ av_push(av, newSVuv(factors[i]));
+ av_push(av, newSVuv(exponents[i]));
+ PUSHs( sv_2mortal(newRV_noinc( (SV*) av )) );
+ }
+ break;
+ default: {
+ UV ndivisors;
+ UV* divs = _divisor_list(n, &ndivisors);
+ EXTEND(SP, ndivisors);
+ for (i = 0; i < ndivisors; i++)
+ PUSHs(sv_2mortal(newSVuv( divs[i] )));
+ Safefree(divs);
+ }
+ break;
}
}
} else {
- _vcallsubn(aTHX_ gimme_v, "_generic_factor", 1);
+ switch (ix) {
+ case 0: _vcallsubn(aTHX_ gimme_v, "_generic_factor", 1); break;
+ case 1: _vcallsubn(aTHX_ gimme_v, "_generic_factor_exp", 1); break;
+ default: _vcallsubn(aTHX_ gimme_v, "_generic_divisors", 1); break;
+ }
return; /* skip implicit PUTBACK */
}
+
void
divisor_sum(IN SV* svn, ...)
PPCODE:
diff --git a/factor.c b/factor.c
index 9a671c6..4b0f976 100644
--- a/factor.c
+++ b/factor.c
@@ -134,16 +134,25 @@ int factor(UV n, UV *factors)
int factor_exp(UV n, UV *factors, UV* exponents)
{
- int i, j, nfactors = factor(n, factors);
+ int i, j, nfactors;
if (n == 1) return 0;
- exponents[0] = 1;
- for (i = 1, j = 1; i < nfactors; i++) {
- if (factors[i] != factors[i-1]) {
- exponents[j] = 1;
- factors[j++] = factors[i];
- } else {
- exponents[j-1]++;
+ /* MPUassert(factors != 0, "factors array is null"); */
+ nfactors = factor(n, factors);
+
+ if (exponents == 0) {
+ for (i = 1, j = 1; i < nfactors; i++)
+ if (factors[i] != factors[i-1])
+ factors[j++] = factors[i];
+ } else {
+ exponents[0] = 1;
+ for (i = 1, j = 1; i < nfactors; i++) {
+ if (factors[i] != factors[i-1]) {
+ exponents[j] = 1;
+ factors[j++] = factors[i];
+ } else {
+ exponents[j-1]++;
+ }
}
}
return j;
diff --git a/lib/Math/Prime/Util.pm b/lib/Math/Prime/Util.pm
index fd63fc0..de9155f 100644
--- a/lib/Math/Prime/Util.pm
+++ b/lib/Math/Prime/Util.pm
@@ -60,8 +60,6 @@ sub import {
sub _import_nobigint {
$_Config{'nobigint'} = 1;
return unless $_Config{'xs'};
- undef *factor_exp; *factor_exp = \&_XS_factor_exp;
- undef *divisors; *divisors = \&_XS_divisors;
#undef *prime_count; *prime_count = \&_XS_prime_count;
undef *nth_prime; *nth_prime = \&_XS_nth_prime;
undef *is_pseudoprime; *is_pseudoprime = \&_XS_is_pseudoprime;
@@ -110,6 +108,8 @@ BEGIN {
*znorder = \&Math::Prime::Util::_generic_znorder;
*znprimroot = \&Math::Prime::Util::_generic_znprimroot;
*factor = \&Math::Prime::Util::_generic_factor;
+ *factor_exp = \&Math::Prime::Util::_generic_factor_exp;
+ *divisors = \&Math::Prime::Util::_generic_divisors;
*forprimes = sub (&$;$) { _generic_forprimes(@_); }; ## no critic qw(ProhibitSubroutinePrototypes)
*fordivisors = sub (&$) { _generic_fordivisors(@_); }; ## no critic qw(ProhibitSubroutinePrototypes)
*forcomposites = sub (&$) { _generic_forcomposites(@_); }; ## no critic qw(ProhibitSubroutinePrototypes)
@@ -130,6 +130,10 @@ BEGIN {
*pplus1_factor = \&Math::Prime::Util::PP::pminus1_factor; # TODO: implement PP p+1.
};
+ # aliases for deprecated names. Will eventually be removed.
+ *all_factors = \&divisors;
+ *miller_rabin = \&is_strong_pseudoprime;
+
$_Config{'nobigint'} = 0;
$_Config{'gmp'} = 0;
# See if they have the GMP module and haven't requested it not to be used.
@@ -1231,37 +1235,6 @@ sub consecutive_integer_lcm {
return $pn;
}
-sub divisors {
- my $n = shift;
-
- _validate_num($n) || _validate_positive_integer($n);
-
- return _XS_divisors($n) if $n <= $_XS_MAXVAL;
-
- # In scalar context, returns sigma_0(n). Very fast.
- return divisor_sum($n,0) unless wantarray;
- return ($n == 0) ? (0,1) : (1) if $n <= 1;
-
- my %all_factors;
- foreach my $f1 (factor($n)) {
- next if $f1 >= $n;
- my $big_f1 = Math::BigInt->new("$f1");
- my @to_add = map { ($_ <= ~0) ? int($_->bstr) : $_ }
- grep { $_ < $n }
- map { $big_f1 * $_ }
- keys %all_factors;
- undef @all_factors{ $f1, @to_add };
- }
- # Add 1 and n
- undef $all_factors{1};
- undef $all_factors{$n};
- my @divisors = sort {$a<=>$b} keys %all_factors;
- return @divisors;
-}
-
-# alias the old "all_factors" to the new name: divisors
-*all_factors = \&divisors;
-
# A008683 Moebius function mu(n)
# A030059, A013929, A030229, A002321, A005117, A013929 all relate.
sub _generic_moebius {
@@ -1326,7 +1299,7 @@ sub jordan_totient {
_validate_num($n) || _validate_positive_integer($n);
return 1 if $n <= 1;
- my @pe = ($n <= $_XS_MAXVAL) ? _XS_factor_exp($n) : factor_exp($n);
+ my @pe = factor_exp($n);
my $totient = $n - $n + 1;
@@ -1394,7 +1367,7 @@ sub _generic_forcomposites(&$;$) { ## no critic qw(ProhibitSubroutinePrototypes)
sub _generic_fordivisors (&$) { ## no critic qw(ProhibitSubroutinePrototypes)
my($sub, $n) = @_;
_validate_num($n) || _validate_positive_integer($n);
- my @divisors = ($n <= $_XS_MAXVAL) ? _XS_divisors($n) : divisors($n);
+ my @divisors = divisors($n);
{
my $pp;
local *_ = \$pp;
@@ -1436,7 +1409,7 @@ sub _generic_exp_mangoldt {
return 2 if ($n & ($n-1)) == 0; # n power of 2
return 1 unless $n & 1; # even n can't be p^m
- my @pe = ($n <= $_XS_MAXVAL) ? _XS_factor_exp($n) : factor_exp($n);
+ my @pe = factor_exp($n);
return 1 if scalar @pe > 1;
return $pe[0]->[0];
}
@@ -1510,7 +1483,7 @@ sub _generic_carmichael_lambda {
# lambda(n) = phi(n)/2 for powers of two greater than 4
return euler_phi($n)/2 if ($n & ($n-1)) == 0;
- my @pe = ($n <= $_XS_MAXVAL) ? _XS_factor_exp($n) : factor_exp($n);
+ my @pe = factor_exp($n);
$pe[0]->[1]-- if $pe[0]->[0] == 2 && $pe[0]->[1] > 2;
my $lcm = Math::BigInt::blcm(
@@ -1539,7 +1512,7 @@ sub _generic_znorder {
# This is easy and usually fast, but can bog down with too many divisors.
if ($lambda <= $_XS_MAXVAL) {
- foreach my $k (_XS_divisors($lambda)) {
+ foreach my $k (divisors($lambda)) {
return $k if $a->copy->bmodpow("$k", $n)->is_one;
}
return;
@@ -1738,8 +1711,6 @@ sub _generic_factor {
my($n) = @_;
_validate_num($n) || _validate_positive_integer($n);
- return _XS_factor($n) if $n <= $_XS_MAXVAL;
-
if ($_HAVE_GMP) {
my @factors;
if ($n != 1) {
@@ -1754,42 +1725,41 @@ sub _generic_factor {
return Math::Prime::Util::PP::factor($n);
}
-sub factor_exp {
+sub _generic_factor_exp {
my($n) = @_;
_validate_num($n) || _validate_positive_integer($n);
- return _XS_factor_exp($n) if ref($n) ne 'Math::BigInt' && $n <= $_XS_MAXVAL;
-
my %exponents;
my @factors = grep { !$exponents{$_}++ } factor($n);
return scalar @factors unless wantarray;
return (map { [$_, $exponents{$_}] } @factors);
}
-#sub trial_factor {
-# my($n, $limit) = @_;
-# _validate_num($n) || _validate_positive_integer($n);
-# $limit = 2147483647 unless defined $limit;
-# _validate_num($limit) || _validate_positive_integer($limit);
-# return _XS_trial_factor($n, $limit) if $n <= $_XS_MAXVAL;
-# if ($_HAVE_GMP) {
-# my @factors;
-# while (1) {
-# last if $n <= 1 || is_prob_prime($n);
-# my @f = sort { $a <=> $b }
-# Math::Prime::Util::GMP::trial_factor($n, $limit);
-# pop(@f); # Remove remainder
-# last unless scalar @f > 0;
-# foreach my $f (@f) {
-# push @factors, $f;
-# $n /= $f;
-# }
-# }
-# push @factors, $n if $n > 1;
-# return @factors;
-# }
-# return Math::Prime::Util::PP::trial_factor($n, $limit);
-#}
+sub _generic_divisors {
+ my($n) = @_;
+ _validate_num($n) || _validate_positive_integer($n);
+
+ # In scalar context, returns sigma_0(n). Very fast.
+ return divisor_sum($n,0) unless wantarray;
+ return ($n == 0) ? (0,1) : (1) if $n <= 1;
+
+ my %all_factors;
+ foreach my $f1 (factor($n)) {
+ next if $f1 >= $n;
+ my $big_f1 = Math::BigInt->new("$f1");
+ my @to_add = map { ($_ <= ~0) ? int($_->bstr) : $_ }
+ grep { $_ < $n }
+ map { $big_f1 * $_ }
+ keys %all_factors;
+ undef @all_factors{ $f1, @to_add };
+ }
+ # Add 1 and n
+ undef $all_factors{1};
+ undef $all_factors{$n};
+ my @divisors = sort {$a<=>$b} keys %all_factors;
+ return @divisors;
+}
+
sub is_pseudoprime {
my($n, $a) = @_;
@@ -1871,11 +1841,6 @@ sub is_frobenius_underwood_pseudoprime {
return Math::Prime::Util::PP::is_frobenius_underwood_pseudoprime($n);
}
-sub miller_rabin {
- #warn "miller_rabin() is deprecated. Use is_strong_pseudoprime instead.";
- return is_strong_pseudoprime(@_);
-}
-
sub lucas_sequence {
my($n, $P, $Q, $k) = @_;
_validate_num($n) || _validate_positive_integer($n);
--
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