[libmath-prime-util-perl] 54/181: Huge speedup for znprimroot with non-cyclic input
Partha P. Mukherjee
ppm-guest at moszumanska.debian.org
Thu May 21 18:51:06 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 7033eec7f3f75bca50658ce6846e7ce18ee31828
Author: Dana Jacobsen <dana at acm.org>
Date: Sat Dec 28 12:16:53 2013 -0800
Huge speedup for znprimroot with non-cyclic input
---
lib/Math/Prime/Util.pm | 25 +++++++++++++++++++------
t/19-moebius.t | 5 ++++-
util.c | 10 +++++++---
3 files changed, 30 insertions(+), 10 deletions(-)
diff --git a/lib/Math/Prime/Util.pm b/lib/Math/Prime/Util.pm
index e3d9468..64de45b 100644
--- a/lib/Math/Prime/Util.pm
+++ b/lib/Math/Prime/Util.pm
@@ -1830,8 +1830,8 @@ sub _generic_kronecker {
my($a, $b) = @_;
croak "Parameter must be defined" if !defined $a;
croak "Parameter must be defined" if !defined $b;
- croak "Parameter '$a' must be an integer" unless $a =~ /^-?\d+/;
- croak "Parameter '$b' must be an integer" unless $b =~ /^-?\d+/;
+ croak "Parameter '$a' must be an integer" unless $a =~ /^[-+]?\d+/;
+ croak "Parameter '$b' must be an integer" unless $b =~ /^[-+]?\d+/;
return Math::BigInt->new(''.Math::Prime::Util::GMP::kronecker($a,$b))
if $_HAVE_GMP && defined &Math::Prime::Util::GMP::kronecker;
@@ -3860,9 +3860,6 @@ the primitive root exists, while L<OEIS A046145|http://oeis.org/A046145>
is a list of the smallest primitive roots, which is what this function
produces.
-This will always produce the smallest primitive root. Pari does not
-necessarily produce the smallest result for composites.
-
=head2 random_prime
@@ -4556,6 +4553,17 @@ Compute L<OEIS A054903|http://oeis.org/A054903> just like CRG4's Pari example:
say if divisor_sum($_)+6 == divisor_sum($_+6)
} 9,1e7;
+Construct the table shown in L<OEIS A046147|http://oeis.org/A046147>:
+
+ use Math::Prime::Util qw/znorder euler_phi/;
+ foreach my $n (1..100) {
+ my $phi = euler_phi($n);
+ my @r = grep { Math::BigInt::bgcd($_,$n) == 1
+ && znorder($_,$n) == $phi
+ } 1..$n-1;
+ say "$n ", join(" ", @r);
+ }
+
=head1 PRIMALITY TESTING NOTES
Above C<2^64>, L</is_prob_prime> performs an extra-strong
@@ -4853,7 +4861,12 @@ Math::Pari.
=item C<kronecker>, C<znorder>, C<znprimroot>
-Similar to MPU's L</kronecker>, L</znorder>, and L</znprimroot>.
+Similar to MPU's L</kronecker>, L</znorder>, and L</znprimroot>. Pari's
+C<znprimroot> only returns the smallest root for prime powers. The
+behavior is undefined when the group is not cyclic (sometimes it throws
+an exception, sometimes it returns an incorrect answer).
+MPU's L</znprimroot> will always return the smallest root if it exists,
+and C<undef> otherwise.
=item C<sigma>
diff --git a/t/19-moebius.t b/t/19-moebius.t
index 1423ccb..328846f 100644
--- a/t/19-moebius.t
+++ b/t/19-moebius.t
@@ -214,6 +214,7 @@ my %primroots = (
1407827621 => 2,
1520874431 => 17,
1685283601 => 164,
+ 100000001 => undef,
);
if ($use64) {
$primroots{2232881419280027} = 6;
@@ -253,7 +254,7 @@ plan tests => 0 + 1
+ 7 + scalar(keys %totients)
+ 1 # Small Carmichael Lambda
+ scalar(@mult_orders)
- + scalar(keys %primroots)
+ + scalar(keys %primroots) + 2
+ scalar(keys %jordan_totients)
+ 2 # Dedekind psi calculated two ways
+ 2 # Calculate J5 two different ways
@@ -404,6 +405,8 @@ foreach my $moarg (@mult_orders) {
while (my($n, $root) = each (%primroots)) {
is( znprimroot($n), $root, "znprimroot($n) == " . ((defined $root) ? $root : "<undef>") );
}
+is( znprimroot("-100000898"), 31, "znprimroot(\"-100000898\") == 31" );
+is( znprimroot("+100000898"), 31, "znprimroot(\"+100000898\") == 31" );
###### liouville
foreach my $i (@liouville_pos) {
is( liouville($i), 1, "liouville($i) = 1" );
diff --git a/util.c b/util.c
index d2c18e7..336a333 100644
--- a/util.c
+++ b/util.c
@@ -1015,17 +1015,21 @@ UV znprimroot(UV n) {
UV a, phi;
int i, nfactors;
if (n <= 4) return (n == 0) ? 0 : n-1;
+ if (n % 4 == 0) return 0;
phi = totient(n);
+ /* Check if a primitive root exists. */
+ if (!_XS_is_prob_prime(n) && phi != carmichael_lambda(n)) return 0;
nfactors = factor_exp(phi, fac, exp);
for (i = 0; i < nfactors; i++)
exp[i] = phi / fac[i]; /* exp[i] = phi(n) / i-th-factor-of-phi(n) */
for (a = 2; a < n; a++) {
if (kronecker_uu(a, n) == 0) continue;
- for (i = 0; i < nfactors; i++) {
- if (powmod(a, exp[i], n) == 1) break;
- }
+ for (i = 0; i < nfactors; i++)
+ if (powmod(a, exp[i], n) == 1)
+ break;
if (i == nfactors) return a;
}
+ return 0;
}
--
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