| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Math::Prime::Util::PP; | 
| 2 | 40 |  |  | 40 |  | 1256442 | use strict; | 
|  | 40 |  |  |  |  | 98 |  | 
|  | 40 |  |  |  |  | 1406 |  | 
| 3 | 40 |  |  | 40 |  | 224 | use warnings; | 
|  | 40 |  |  |  |  | 95 |  | 
|  | 40 |  |  |  |  | 1451 |  | 
| 4 | 40 |  |  | 40 |  | 223 | use Carp qw/carp croak confess/; | 
|  | 40 |  |  |  |  | 84 |  | 
|  | 40 |  |  |  |  | 3608 |  | 
| 5 |  |  |  |  |  |  |  | 
| 6 |  |  |  |  |  |  | BEGIN { | 
| 7 | 40 |  |  | 40 |  | 185 | $Math::Prime::Util::PP::AUTHORITY = 'cpan:DANAJ'; | 
| 8 | 40 |  |  |  |  | 2088 | $Math::Prime::Util::PP::VERSION = '0.73'; | 
| 9 |  |  |  |  |  |  | } | 
| 10 |  |  |  |  |  |  |  | 
| 11 |  |  |  |  |  |  | BEGIN { | 
| 12 | 40 | 100 |  | 40 |  | 669 | do { require Math::BigInt;  Math::BigInt->import(try=>"GMP,Pari"); } | 
|  | 28 |  |  |  |  | 31244 |  | 
|  | 28 |  |  |  |  | 708043 |  | 
| 13 |  |  |  |  |  |  | unless defined $Math::BigInt::VERSION; | 
| 14 |  |  |  |  |  |  | } | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  | # The Pure Perl versions of all the Math::Prime::Util routines. | 
| 17 |  |  |  |  |  |  | # | 
| 18 |  |  |  |  |  |  | # Some of these will be relatively similar in performance, some will be | 
| 19 |  |  |  |  |  |  | # very slow in comparison. | 
| 20 |  |  |  |  |  |  | # | 
| 21 |  |  |  |  |  |  | # Most of these are pretty simple.  Also, you really should look at the C | 
| 22 |  |  |  |  |  |  | # code for more detailed comments, including references to papers. | 
| 23 |  |  |  |  |  |  |  | 
| 24 | 0 |  |  |  |  | 0 | BEGIN { | 
| 25 | 40 |  |  | 40 |  | 715535 | use constant OLD_PERL_VERSION=> $] < 5.008; | 
|  | 40 |  |  |  |  | 106 |  | 
|  | 40 |  |  |  |  | 3114 |  | 
| 26 | 40 |  |  | 40 |  | 262 | use constant MPU_MAXBITS     => (~0 == 4294967295) ? 32 : 64; | 
|  | 40 |  |  |  |  | 87 |  | 
|  | 40 |  |  |  |  | 2091 |  | 
| 27 | 40 |  |  | 40 |  | 248 | use constant MPU_64BIT       => MPU_MAXBITS == 64; | 
|  | 40 |  |  |  |  | 94 |  | 
|  | 40 |  |  |  |  | 2024 |  | 
| 28 | 40 |  |  | 40 |  | 241 | use constant MPU_32BIT       => MPU_MAXBITS == 32; | 
|  | 40 |  |  |  |  | 98 |  | 
|  | 40 |  |  |  |  | 1921 |  | 
| 29 |  |  |  |  |  |  | #use constant MPU_MAXPARAM    => MPU_32BIT ? 4294967295 : 18446744073709551615; | 
| 30 |  |  |  |  |  |  | #use constant MPU_MAXDIGITS   => MPU_32BIT ? 10 : 20; | 
| 31 | 40 |  |  | 40 |  | 255 | use constant MPU_MAXPRIME    => MPU_32BIT ? 4294967291 : 18446744073709551557; | 
|  | 40 |  |  |  |  | 96 |  | 
|  | 40 |  |  |  |  | 1918 |  | 
| 32 | 40 |  |  | 40 |  | 255 | use constant MPU_MAXPRIMEIDX => MPU_32BIT ?  203280221 :  425656284035217743; | 
|  | 40 |  |  |  |  | 79 |  | 
|  | 40 |  |  |  |  | 1971 |  | 
| 33 | 40 |  |  | 40 |  | 250 | use constant MPU_HALFWORD    => MPU_32BIT ? 65536 : OLD_PERL_VERSION ? 33554432 : 4294967296; | 
|  | 40 |  |  |  |  | 119 |  | 
|  | 40 |  |  |  |  | 2176 |  | 
| 34 | 40 |  |  | 40 |  | 285 | use constant UVPACKLET       => MPU_32BIT ? 'L' : 'Q'; | 
|  | 40 |  |  |  |  | 98 |  | 
|  | 40 |  |  |  |  | 2729 |  | 
| 35 | 40 |  |  | 40 |  | 256 | use constant MPU_INFINITY    => (65535 > 0+'inf') ? 20**20**20 : 0+'inf'; | 
|  | 40 |  |  |  |  | 91 |  | 
|  | 40 |  |  |  |  | 2216 |  | 
| 36 | 40 |  |  | 40 |  | 250 | use constant BZERO           => Math::BigInt->bzero; | 
|  | 40 |  |  |  |  | 88 |  | 
|  | 40 |  |  |  |  | 347 |  | 
| 37 | 40 |  |  | 40 |  | 6953 | use constant BONE            => Math::BigInt->bone; | 
|  | 40 |  |  |  |  | 146 |  | 
|  | 40 |  |  |  |  | 334 |  | 
| 38 | 40 |  |  | 40 |  | 4740 | use constant BTWO            => Math::BigInt->new(2); | 
|  | 40 |  |  |  |  | 182 |  | 
|  | 40 |  |  |  |  | 412 |  | 
| 39 | 40 |  |  | 40 |  | 5232 | use constant INTMAX          => (!OLD_PERL_VERSION || MPU_32BIT) ? ~0 : 562949953421312; | 
|  | 40 |  |  |  |  | 269 |  | 
|  | 40 |  |  |  |  | 2659 |  | 
| 40 | 40 |  |  | 40 |  | 706 | use constant BMAX            => Math::BigInt->new('' . INTMAX); | 
|  | 40 |  |  |  |  | 190 |  | 
|  | 40 |  |  |  |  | 313 |  | 
| 41 | 40 |  |  | 40 |  | 5232 | use constant B_PRIM767       => Math::BigInt->new("261944051702675568529303"); | 
|  | 40 |  |  |  |  | 94 |  | 
|  | 40 |  |  |  |  | 205 |  | 
| 42 | 40 |  |  | 40 |  | 4622 | use constant B_PRIM235       => Math::BigInt->new("30"); | 
|  | 40 |  |  |  |  | 85 |  | 
|  | 40 |  |  |  |  | 169 |  | 
| 43 | 40 |  |  | 40 |  | 3929 | use constant PI_TIMES_8      => 25.13274122871834590770114707; | 
|  | 40 |  |  | 0 |  | 105 |  | 
|  | 40 |  |  |  |  | 772863 |  | 
| 44 |  |  |  |  |  |  | } | 
| 45 |  |  |  |  |  |  |  | 
| 46 |  |  |  |  |  |  | my $_precalc_size = 0; | 
| 47 |  |  |  |  |  |  | sub prime_precalc { | 
| 48 | 0 |  |  | 0 | 0 | 0 | my($n) = @_; | 
| 49 | 0 | 0 |  |  |  | 0 | croak "Parameter '$n' must be a positive integer" unless _is_positive_int($n); | 
| 50 | 0 | 0 |  |  |  | 0 | $_precalc_size = $n if $n > $_precalc_size; | 
| 51 |  |  |  |  |  |  | } | 
| 52 |  |  |  |  |  |  | sub prime_memfree { | 
| 53 | 10 |  |  | 10 | 0 | 45 | $_precalc_size = 0; | 
| 54 | 10 | 50 | 33 |  |  | 54 | eval { Math::Prime::Util::GMP::_GMP_memfree(); } | 
|  | 0 |  |  |  |  | 0 |  | 
| 55 |  |  |  |  |  |  | if defined $Math::Prime::Util::GMP::VERSION && $Math::Prime::Util::GMP::VERSION >= 0.49; | 
| 56 |  |  |  |  |  |  | } | 
| 57 | 5 |  |  | 5 |  | 17 | sub _get_prime_cache_size { $_precalc_size } | 
| 58 | 0 |  |  | 0 |  | 0 | sub _prime_memfreeall { prime_memfree; } | 
| 59 |  |  |  |  |  |  |  | 
| 60 |  |  |  |  |  |  |  | 
| 61 |  |  |  |  |  |  | sub _is_positive_int { | 
| 62 | 0 | 0 | 0 | 0 |  | 0 | ((defined $_[0]) && $_[0] ne '' && ($_[0] !~ tr/0123456789//c)); | 
| 63 |  |  |  |  |  |  | } | 
| 64 |  |  |  |  |  |  |  | 
| 65 |  |  |  |  |  |  | sub _bigint_to_int { | 
| 66 |  |  |  |  |  |  | #if (OLD_PERL_VERSION) { | 
| 67 |  |  |  |  |  |  | #  my $pack = ($_[0] < 0) ? lc(UVPACKLET) : UVPACKLET; | 
| 68 |  |  |  |  |  |  | #  return unpack($pack,pack($pack,"$_[0]")); | 
| 69 |  |  |  |  |  |  | #} | 
| 70 | 16602 |  |  | 16602 |  | 1388287 | int("$_[0]"); | 
| 71 |  |  |  |  |  |  | } | 
| 72 |  |  |  |  |  |  |  | 
| 73 |  |  |  |  |  |  | sub _upgrade_to_float { | 
| 74 | 1012 | 100 |  | 1012 |  | 5147 | do { require Math::BigFloat; Math::BigFloat->import(); } | 
|  | 1 |  |  |  |  | 1011 |  | 
|  | 1 |  |  |  |  | 23737 |  | 
| 75 |  |  |  |  |  |  | if !defined $Math::BigFloat::VERSION; | 
| 76 | 1012 |  |  |  |  | 4871 | Math::BigFloat->new(@_); | 
| 77 |  |  |  |  |  |  | } | 
| 78 |  |  |  |  |  |  |  | 
| 79 |  |  |  |  |  |  | # Get the accuracy of variable x, or the max default from BigInt/BigFloat | 
| 80 |  |  |  |  |  |  | # One might think to use ref($x)->accuracy() but numbers get upgraded and | 
| 81 |  |  |  |  |  |  | # downgraded willy-nilly, and it will do the wrong thing from the user's | 
| 82 |  |  |  |  |  |  | # perspective. | 
| 83 |  |  |  |  |  |  | sub _find_big_acc { | 
| 84 | 34 |  |  | 34 |  | 95 | my($x) = @_; | 
| 85 | 34 |  |  |  |  | 67 | my $b; | 
| 86 |  |  |  |  |  |  |  | 
| 87 | 34 | 50 |  |  |  | 219 | $b = $x->accuracy() if ref($x) =~ /^Math::Big/; | 
| 88 | 34 | 100 |  |  |  | 415 | return $b if defined $b; | 
| 89 |  |  |  |  |  |  |  | 
| 90 | 15 |  |  |  |  | 75 | my ($i,$f) = (Math::BigInt->accuracy(), Math::BigFloat->accuracy()); | 
| 91 | 15 | 0 | 33 |  |  | 356 | return (($i > $f) ? $i : $f)   if defined $i && defined $f; | 
|  |  | 50 |  |  |  |  |  | 
| 92 | 15 | 50 |  |  |  | 62 | return $i if defined $i; | 
| 93 | 15 | 50 |  |  |  | 53 | return $f if defined $f; | 
| 94 |  |  |  |  |  |  |  | 
| 95 | 15 |  |  |  |  | 79 | ($i,$f) = (Math::BigInt->div_scale(), Math::BigFloat->div_scale()); | 
| 96 | 15 | 50 | 33 |  |  | 460 | return (($i > $f) ? $i : $f)   if defined $i && defined $f; | 
|  |  | 50 |  |  |  |  |  | 
| 97 | 15 | 0 |  |  |  | 0 | return $i if defined $i; | 
| 98 | 15 | 0 |  |  |  | 0 | return $f if defined $f; | 
| 99 | 15 |  |  |  |  | 0 | return 18; | 
| 100 |  |  |  |  |  |  | } | 
| 101 |  |  |  |  |  |  |  | 
| 102 |  |  |  |  |  |  | sub _bfdigits { | 
| 103 | 0 |  |  | 0 |  | 0 | my($wantbf, $xdigits) = (0, 17); | 
| 104 | 0 | 0 | 0 |  |  | 0 | if (defined $bignum::VERSION || ref($_[0]) =~ /^Math::Big/) { | 
| 105 | 0 | 0 |  |  |  | 0 | do { require Math::BigFloat; Math::BigFloat->import(); } | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 106 |  |  |  |  |  |  | if !defined $Math::BigFloat::VERSION; | 
| 107 | 0 | 0 |  |  |  | 0 | if (ref($_[0]) eq 'Math::BigInt') { | 
| 108 | 0 |  |  |  |  | 0 | my $xacc = ($_[0])->accuracy(); | 
| 109 | 0 |  |  |  |  | 0 | $_[0] = Math::BigFloat->new($_[0]); | 
| 110 | 0 | 0 |  |  |  | 0 | ($_[0])->accuracy($xacc) if $xacc; | 
| 111 |  |  |  |  |  |  | } | 
| 112 | 0 | 0 |  |  |  | 0 | $_[0] = Math::BigFloat->new("$_[0]") if ref($_[0]) ne 'Math::BigFloat'; | 
| 113 | 0 |  |  |  |  | 0 | $wantbf = _find_big_acc($_[0]); | 
| 114 | 0 |  |  |  |  | 0 | $xdigits = $wantbf; | 
| 115 |  |  |  |  |  |  | } | 
| 116 | 0 |  |  |  |  | 0 | ($wantbf, $xdigits); | 
| 117 |  |  |  |  |  |  | } | 
| 118 |  |  |  |  |  |  |  | 
| 119 |  |  |  |  |  |  |  | 
| 120 |  |  |  |  |  |  | sub _validate_num { | 
| 121 | 269 |  |  | 269 |  | 725 | my($n, $min, $max) = @_; | 
| 122 | 269 | 50 |  |  |  | 890 | croak "Parameter must be defined" if !defined $n; | 
| 123 | 269 | 100 |  |  |  | 886 | return 0 if ref($n); | 
| 124 | 236 | 50 | 33 |  |  | 1227 | croak "Parameter '$n' must be a positive integer" | 
|  |  |  | 33 |  |  |  |  | 
| 125 |  |  |  |  |  |  | if $n eq '' || ($n =~ tr/0123456789//c && $n !~ /^\+\d+$/); | 
| 126 | 236 | 50 | 33 |  |  | 864 | croak "Parameter '$n' must be >= $min" if defined $min && $n < $min; | 
| 127 | 236 | 50 | 33 |  |  | 654 | croak "Parameter '$n' must be <= $max" if defined $max && $n > $max; | 
| 128 | 236 | 50 |  |  |  | 769 | substr($_[0],0,1,'') if substr($n,0,1) eq '+'; | 
| 129 | 236 | 100 | 66 |  |  | 819 | return 0 unless $n < ~0 || int($n) eq ''.~0; | 
| 130 | 232 |  |  |  |  | 598 | 1; | 
| 131 |  |  |  |  |  |  | } | 
| 132 |  |  |  |  |  |  |  | 
| 133 |  |  |  |  |  |  | sub _validate_positive_integer { | 
| 134 | 16409 |  |  | 16409 |  | 28525 | my($n, $min, $max) = @_; | 
| 135 | 16409 | 50 |  |  |  | 32271 | croak "Parameter must be defined" if !defined $n; | 
| 136 | 16409 | 50 |  |  |  | 32541 | if (ref($n) eq 'CODE') { | 
| 137 | 0 |  |  |  |  | 0 | $_[0] = $_[0]->(); | 
| 138 | 0 |  |  |  |  | 0 | $n = $_[0]; | 
| 139 |  |  |  |  |  |  | } | 
| 140 | 16409 | 100 |  |  |  | 38008 | if (ref($n) eq 'Math::BigInt') { | 
|  |  | 50 |  |  |  |  |  | 
| 141 | 727 | 50 | 33 |  |  | 2675 | croak "Parameter '$n' must be a positive integer" | 
| 142 |  |  |  |  |  |  | if $n->sign() ne '+' || !$n->is_int(); | 
| 143 | 727 | 100 |  |  |  | 13838 | $_[0] = _bigint_to_int($_[0]) if $n <= BMAX; | 
| 144 |  |  |  |  |  |  | } elsif (ref($n) eq 'Math::GMPz') { | 
| 145 | 0 | 0 |  |  |  | 0 | croak "Parameter '$n' must be a positive integer" if Math::GMPz::Rmpz_sgn($n) < 0; | 
| 146 | 0 | 0 |  |  |  | 0 | $_[0] = _bigint_to_int($_[0]) if $n <= INTMAX; | 
| 147 |  |  |  |  |  |  | } else { | 
| 148 | 15682 |  |  |  |  | 26454 | my $strn = "$n"; | 
| 149 | 15682 | 50 |  |  |  | 28925 | if ($strn eq '-0') { $_[0] = 0; $strn = '0'; } | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 150 | 15682 | 100 | 66 |  |  | 50020 | croak "Parameter '$strn' must be a positive integer" | 
|  |  |  | 66 |  |  |  |  | 
| 151 |  |  |  |  |  |  | if $strn eq '' || ($strn =~ tr/0123456789//c && $strn !~ /^\+?\d+$/); | 
| 152 | 15681 | 100 |  |  |  | 30124 | if ($n <= INTMAX) { | 
| 153 | 15547 | 50 |  |  |  | 30846 | $_[0] = $strn if ref($n); | 
| 154 |  |  |  |  |  |  | } else { | 
| 155 | 134 |  |  |  |  | 589 | $_[0] = Math::BigInt->new($strn) | 
| 156 |  |  |  |  |  |  | } | 
| 157 |  |  |  |  |  |  | } | 
| 158 | 16408 | 50 | 66 |  |  | 72447 | $_[0]->upgrade(undef) if ref($_[0]) eq 'Math::BigInt' && $_[0]->upgrade(); | 
| 159 | 16408 | 50 | 66 |  |  | 42134 | croak "Parameter '$_[0]' must be >= $min" if defined $min && $_[0] < $min; | 
| 160 | 16408 | 50 | 33 |  |  | 31728 | croak "Parameter '$_[0]' must be <= $max" if defined $max && $_[0] > $max; | 
| 161 | 16408 |  |  |  |  | 23009 | 1; | 
| 162 |  |  |  |  |  |  | } | 
| 163 |  |  |  |  |  |  |  | 
| 164 |  |  |  |  |  |  | sub _validate_integer { | 
| 165 | 1215 |  |  | 1215 |  | 2333 | my($n) = @_; | 
| 166 | 1215 | 50 |  |  |  | 2583 | croak "Parameter must be defined" if !defined $n; | 
| 167 | 1215 | 50 |  |  |  | 2990 | if (ref($n) eq 'CODE') { | 
| 168 | 0 |  |  |  |  | 0 | $_[0] = $_[0]->(); | 
| 169 | 0 |  |  |  |  | 0 | $n = $_[0]; | 
| 170 |  |  |  |  |  |  | } | 
| 171 | 1215 |  |  |  |  | 2244 | my $poscmp = OLD_PERL_VERSION ?  562949953421312 : ''.~0; | 
| 172 | 1215 |  |  |  |  | 1771 | my $negcmp = OLD_PERL_VERSION ? -562949953421312 : -(~0 >> 1); | 
| 173 | 1215 | 100 |  |  |  | 2872 | if (ref($n) eq 'Math::BigInt') { | 
| 174 | 1185 | 50 |  |  |  | 3288 | croak "Parameter '$n' must be an integer" if !$n->is_int(); | 
| 175 | 1185 | 100 | 100 |  |  | 10189 | $_[0] = _bigint_to_int($_[0]) if $n <= $poscmp && $n >= $negcmp; | 
| 176 |  |  |  |  |  |  | } else { | 
| 177 | 30 |  |  |  |  | 61 | my $strn = "$n"; | 
| 178 | 30 | 50 |  |  |  | 72 | if ($strn eq '-0') { $_[0] = 0; $strn = '0'; } | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 179 | 30 | 50 | 33 |  |  | 150 | croak "Parameter '$strn' must be an integer" | 
|  |  |  | 33 |  |  |  |  | 
| 180 |  |  |  |  |  |  | if $strn eq '' || ($strn =~ tr/-0123456789//c && $strn !~ /^[-+]?\d+$/); | 
| 181 | 30 | 100 | 100 |  |  | 146 | if ($n <= $poscmp && $n >= $negcmp) { | 
| 182 | 27 | 50 |  |  |  | 73 | $_[0] = $strn if ref($n); | 
| 183 |  |  |  |  |  |  | } else { | 
| 184 | 3 |  |  |  |  | 19 | $_[0] = Math::BigInt->new($strn) | 
| 185 |  |  |  |  |  |  | } | 
| 186 |  |  |  |  |  |  | } | 
| 187 | 1215 | 50 | 66 |  |  | 131299 | $_[0]->upgrade(undef) if ref($_[0]) && $_[0]->upgrade(); | 
| 188 | 1215 |  |  |  |  | 9156 | 1; | 
| 189 |  |  |  |  |  |  | } | 
| 190 |  |  |  |  |  |  |  | 
| 191 |  |  |  |  |  |  | sub _binary_search { | 
| 192 | 0 |  |  | 0 |  | 0 | my($n, $lo, $hi, $sub, $exitsub) = @_; | 
| 193 | 0 |  |  |  |  | 0 | while ($lo < $hi) { | 
| 194 | 0 |  |  |  |  | 0 | my $mid = $lo + int(($hi-$lo) >> 1); | 
| 195 | 0 | 0 | 0 |  |  | 0 | return $mid if defined $exitsub && $exitsub->($n,$lo,$hi); | 
| 196 | 0 | 0 |  |  |  | 0 | if ($sub->($mid) < $n) { $lo = $mid+1; } | 
|  | 0 |  |  |  |  | 0 |  | 
| 197 | 0 |  |  |  |  | 0 | else                   { $hi = $mid;   } | 
| 198 |  |  |  |  |  |  | } | 
| 199 | 0 |  |  |  |  | 0 | return $lo-1; | 
| 200 |  |  |  |  |  |  | } | 
| 201 |  |  |  |  |  |  |  | 
| 202 |  |  |  |  |  |  | my @_primes_small = (0,2); | 
| 203 |  |  |  |  |  |  | { | 
| 204 |  |  |  |  |  |  | my($n, $s, $sieveref) = (7-2, 3, _sieve_erat_string(5003)); | 
| 205 |  |  |  |  |  |  | push @_primes_small, 2*pos($$sieveref)-1 while $$sieveref =~ m/0/g; | 
| 206 |  |  |  |  |  |  | } | 
| 207 |  |  |  |  |  |  | my @_prime_next_small = ( | 
| 208 |  |  |  |  |  |  | 2,2,3,5,5,7,7,11,11,11,11,13,13,17,17,17,17,19,19,23,23,23,23, | 
| 209 |  |  |  |  |  |  | 29,29,29,29,29,29,31,31,37,37,37,37,37,37,41,41,41,41,43,43,47, | 
| 210 |  |  |  |  |  |  | 47,47,47,53,53,53,53,53,53,59,59,59,59,59,59,61,61,67,67,67,67,67,67,71); | 
| 211 |  |  |  |  |  |  |  | 
| 212 |  |  |  |  |  |  | # For wheel-30 | 
| 213 |  |  |  |  |  |  | my @_prime_indices = (1, 7, 11, 13, 17, 19, 23, 29); | 
| 214 |  |  |  |  |  |  | my @_nextwheel30 = (1,7,7,7,7,7,7,11,11,11,11,13,13,17,17,17,17,19,19,23,23,23,23,29,29,29,29,29,29,1); | 
| 215 |  |  |  |  |  |  | my @_prevwheel30 = (29,29,1,1,1,1,1,1,7,7,7,7,11,11,13,13,13,13,17,17,19,19,19,19,23,23,23,23,23,23); | 
| 216 |  |  |  |  |  |  | my @_wheeladvance30 = (1,6,5,4,3,2,1,4,3,2,1,2,1,4,3,2,1,2,1,4,3,2,1,6,5,4,3,2,1,2); | 
| 217 |  |  |  |  |  |  | my @_wheelretreat30 = (1,2,1,2,3,4,5,6,1,2,3,4,1,2,1,2,3,4,1,2,1,2,3,4,1,2,3,4,5,6); | 
| 218 |  |  |  |  |  |  |  | 
| 219 |  |  |  |  |  |  | sub _tiny_prime_count { | 
| 220 | 2 |  |  | 2 |  | 4 | my($n) = @_; | 
| 221 | 2 | 50 |  |  |  | 6 | return if $n >= $_primes_small[-1]; | 
| 222 | 2 |  |  |  |  | 6 | my $j = $#_primes_small; | 
| 223 | 2 |  |  |  |  | 5 | my $i = 1 + ($n >> 4); | 
| 224 | 2 |  |  |  |  | 8 | while ($i < $j) { | 
| 225 | 18 |  |  |  |  | 25 | my $mid = ($i+$j)>>1; | 
| 226 | 18 | 100 |  |  |  | 34 | if ($_primes_small[$mid] <= $n) { $i = $mid+1; } | 
|  | 8 |  |  |  |  | 16 |  | 
| 227 | 10 |  |  |  |  | 18 | else                            { $j = $mid;   } | 
| 228 |  |  |  |  |  |  | } | 
| 229 | 2 |  |  |  |  | 10 | return $i-1; | 
| 230 |  |  |  |  |  |  | } | 
| 231 |  |  |  |  |  |  |  | 
| 232 |  |  |  |  |  |  | sub _is_prime7 {  # n must not be divisible by 2, 3, or 5 | 
| 233 | 9711 |  |  | 9711 |  | 21787 | my($n) = @_; | 
| 234 |  |  |  |  |  |  |  | 
| 235 | 9711 | 50 | 66 |  |  | 21073 | $n = _bigint_to_int($n) if ref($n) eq 'Math::BigInt' && $n <= BMAX; | 
| 236 | 9711 | 100 |  |  |  | 26925 | if (ref($n) eq 'Math::BigInt') { | 
| 237 | 280 | 100 |  |  |  | 1047 | return 0 unless Math::BigInt::bgcd($n, B_PRIM767)->is_one; | 
| 238 | 217 | 100 |  |  |  | 793228 | return 0 unless _miller_rabin_2($n); | 
| 239 | 103 |  |  |  |  | 5123 | my $is_esl_prime = is_extra_strong_lucas_pseudoprime($n); | 
| 240 | 103 | 50 |  |  |  | 22582 | return ($is_esl_prime)  ?  (($n <= "18446744073709551615") ? 2 : 1)  :  0; | 
|  |  | 100 |  |  |  |  |  | 
| 241 |  |  |  |  |  |  | } | 
| 242 |  |  |  |  |  |  |  | 
| 243 | 9431 | 100 |  |  |  | 16979 | if ($n < 61*61) { | 
| 244 | 3295 |  |  |  |  | 6145 | foreach my $i (qw/7 11 13 17 19 23 29 31 37 41 43 47 53 59/) { | 
| 245 | 19679 | 100 |  |  |  | 35253 | return 2 if $i*$i > $n; | 
| 246 | 17757 | 100 |  |  |  | 32670 | return 0 if !($n % $i); | 
| 247 |  |  |  |  |  |  | } | 
| 248 | 111 |  |  |  |  | 431 | return 2; | 
| 249 |  |  |  |  |  |  | } | 
| 250 |  |  |  |  |  |  |  | 
| 251 | 6136 | 100 | 100 |  |  | 74794 | return 0 if !($n %  7) || !($n % 11) || !($n % 13) || !($n % 17) || | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
| 252 |  |  |  |  |  |  | !($n % 19) || !($n % 23) || !($n % 29) || !($n % 31) || | 
| 253 |  |  |  |  |  |  | !($n % 37) || !($n % 41) || !($n % 43) || !($n % 47) || | 
| 254 |  |  |  |  |  |  | !($n % 53) || !($n % 59); | 
| 255 |  |  |  |  |  |  |  | 
| 256 |  |  |  |  |  |  | # We could do: | 
| 257 |  |  |  |  |  |  | #   return is_strong_pseudoprime($n, (2,299417)) if $n < 19471033; | 
| 258 |  |  |  |  |  |  | # or: | 
| 259 |  |  |  |  |  |  | #   foreach my $p (@_primes_small[18..168]) { | 
| 260 |  |  |  |  |  |  | #     last if $p > $limit; | 
| 261 |  |  |  |  |  |  | #     return 0 unless $n % $p; | 
| 262 |  |  |  |  |  |  | #   } | 
| 263 |  |  |  |  |  |  | #   return 2; | 
| 264 |  |  |  |  |  |  |  | 
| 265 | 3683 | 100 |  |  |  | 7249 | if ($n <= 1_500_000) { | 
| 266 | 373 |  |  |  |  | 859 | my $limit = int(sqrt($n)); | 
| 267 | 373 |  |  |  |  | 522 | my $i = 61; | 
| 268 | 373 |  |  |  |  | 886 | while (($i+30) <= $limit) { | 
| 269 | 667 | 100 | 100 |  |  | 4798 | return 0 unless ($n% $i    ) && ($n%($i+ 6)) && | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
| 270 |  |  |  |  |  |  | ($n%($i+10)) && ($n%($i+12)) && | 
| 271 |  |  |  |  |  |  | ($n%($i+16)) && ($n%($i+18)) && | 
| 272 |  |  |  |  |  |  | ($n%($i+22)) && ($n%($i+28)); | 
| 273 | 624 |  |  |  |  | 914 | $i += 30; | 
| 274 |  |  |  |  |  |  | } | 
| 275 | 330 |  |  |  |  | 655 | for my $inc (6,4,2,4,2,4,6,2) { | 
| 276 | 921 | 100 |  |  |  | 1728 | last if $i > $limit; | 
| 277 | 629 | 100 |  |  |  | 1189 | return 0 if !($n % $i); | 
| 278 | 596 |  |  |  |  | 857 | $i += $inc; | 
| 279 |  |  |  |  |  |  | } | 
| 280 | 297 |  |  |  |  | 1037 | return 2; | 
| 281 |  |  |  |  |  |  | } | 
| 282 |  |  |  |  |  |  |  | 
| 283 | 3310 | 100 |  |  |  | 5966 | if ($n < 47636622961201) {   # BPSW seems to be faster after this | 
| 284 |  |  |  |  |  |  | # Deterministic set of Miller-Rabin tests.  If the MR routines can handle | 
| 285 |  |  |  |  |  |  | # bases greater than n, then this can be simplified. | 
| 286 | 3255 |  |  |  |  | 4172 | my @bases; | 
| 287 |  |  |  |  |  |  | # n > 1_000_000 because of the previous block. | 
| 288 | 3255 | 100 |  |  |  | 5635 | if    ($n <         19471033) { @bases = ( 2,  299417); } | 
|  | 3169 | 100 |  |  |  | 5159 |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 289 | 4 |  |  |  |  | 6 | elsif ($n <         38010307) { @bases = ( 2,  9332593); } | 
| 290 | 12 |  |  |  |  | 24 | elsif ($n <        316349281) { @bases = ( 11000544, 31481107); } | 
| 291 | 29 |  |  |  |  | 54 | elsif ($n <       4759123141) { @bases = ( 2, 7, 61); } | 
| 292 | 40 |  |  |  |  | 120 | elsif ($n <     154639673381) { @bases = ( 15, 176006322, 4221622697); } | 
| 293 | 1 |  |  |  |  | 4 | elsif ($n <   47636622961201) { @bases = ( 2, 2570940, 211991001, 3749873356); } | 
| 294 | 0 |  |  |  |  | 0 | elsif ($n < 3770579582154547) { @bases = ( 2, 2570940, 880937, 610386380, 4130785767); } | 
| 295 | 0 |  |  |  |  | 0 | else                          { @bases = ( 2, 325, 9375, 28178, 450775, 9780504, 1795265022); } | 
| 296 | 3255 | 100 |  |  |  | 5869 | return is_strong_pseudoprime($n, @bases)  ?  2  :  0; | 
| 297 |  |  |  |  |  |  | } | 
| 298 |  |  |  |  |  |  |  | 
| 299 |  |  |  |  |  |  | # Inlined BPSW | 
| 300 | 55 | 100 |  |  |  | 234 | return 0 unless _miller_rabin_2($n); | 
| 301 | 46 | 100 |  |  |  | 257 | return is_almost_extra_strong_lucas_pseudoprime($n) ? 2 : 0; | 
| 302 |  |  |  |  |  |  | } | 
| 303 |  |  |  |  |  |  |  | 
| 304 |  |  |  |  |  |  | sub is_prime { | 
| 305 | 6808 |  |  | 6808 | 0 | 65488 | my($n) = @_; | 
| 306 | 6808 | 50 | 33 |  |  | 22428 | return 0 if defined($n) && int($n) < 0; | 
| 307 | 6808 |  |  |  |  | 77349 | _validate_positive_integer($n); | 
| 308 |  |  |  |  |  |  |  | 
| 309 | 6808 | 100 |  |  |  | 11319 | if (ref($n) eq 'Math::BigInt') { | 
| 310 | 323 | 100 |  |  |  | 1081 | return 0 unless Math::BigInt::bgcd($n, B_PRIM235)->is_one; | 
| 311 |  |  |  |  |  |  | } else { | 
| 312 | 6485 | 100 | 100 |  |  | 10769 | if ($n < 7) { return ($n == 2) || ($n == 3) || ($n == 5) ? 2 : 0; } | 
|  | 68 | 100 |  |  |  | 264 |  | 
| 313 | 6417 | 100 | 100 |  |  | 28299 | return 0 if !($n % 2) || !($n % 3) || !($n % 5); | 
|  |  |  | 100 |  |  |  |  | 
| 314 |  |  |  |  |  |  | } | 
| 315 | 3338 |  |  |  |  | 55289 | return _is_prime7($n); | 
| 316 |  |  |  |  |  |  | } | 
| 317 |  |  |  |  |  |  |  | 
| 318 |  |  |  |  |  |  | # is_prob_prime is the same thing for us. | 
| 319 |  |  |  |  |  |  | *is_prob_prime = \&is_prime; | 
| 320 |  |  |  |  |  |  |  | 
| 321 |  |  |  |  |  |  | # BPSW probable prime.  No composites are known to have passed this test | 
| 322 |  |  |  |  |  |  | # since it was published in 1980, though we know infinitely many exist. | 
| 323 |  |  |  |  |  |  | # It has also been verified that no 64-bit composite will return true. | 
| 324 |  |  |  |  |  |  | # Slow since it's all in PP and uses bigints. | 
| 325 |  |  |  |  |  |  | sub is_bpsw_prime { | 
| 326 | 32 |  |  | 32 | 0 | 106 | my($n) = @_; | 
| 327 | 32 | 50 | 33 |  |  | 179 | return 0 if defined($n) && int($n) < 0; | 
| 328 | 32 |  |  |  |  | 7354 | _validate_positive_integer($n); | 
| 329 | 32 | 100 |  |  |  | 110 | return 0 unless _miller_rabin_2($n); | 
| 330 | 7 | 50 |  |  |  | 368 | if ($n <= 18446744073709551615) { | 
| 331 | 0 | 0 |  |  |  | 0 | return is_almost_extra_strong_lucas_pseudoprime($n) ? 2 : 0; | 
| 332 |  |  |  |  |  |  | } | 
| 333 | 7 | 100 |  |  |  | 1256 | return is_extra_strong_lucas_pseudoprime($n) ? 1 : 0; | 
| 334 |  |  |  |  |  |  | } | 
| 335 |  |  |  |  |  |  |  | 
| 336 |  |  |  |  |  |  | sub is_provable_prime { | 
| 337 | 5 |  |  | 5 | 0 | 119 | my($n) = @_; | 
| 338 | 5 | 50 | 33 |  |  | 62 | return 0 if defined $n && $n < 2; | 
| 339 | 5 |  |  |  |  | 57 | _validate_positive_integer($n); | 
| 340 | 5 | 50 |  |  |  | 34 | if ($n <= 18446744073709551615) { | 
| 341 | 0 | 0 |  |  |  | 0 | return 0 unless _miller_rabin_2($n); | 
| 342 | 0 | 0 |  |  |  | 0 | return 0 unless is_almost_extra_strong_lucas_pseudoprime($n); | 
| 343 | 0 |  |  |  |  | 0 | return 2; | 
| 344 |  |  |  |  |  |  | } | 
| 345 | 5 |  |  |  |  | 687 | my($is_prime, $cert) = Math::Prime::Util::is_provable_prime_with_cert($n); | 
| 346 | 5 |  |  |  |  | 65 | $is_prime; | 
| 347 |  |  |  |  |  |  | } | 
| 348 |  |  |  |  |  |  |  | 
| 349 |  |  |  |  |  |  | # Possible sieve storage: | 
| 350 |  |  |  |  |  |  | #   1) vec with mod-30 wheel:   8 bits  / 30 | 
| 351 |  |  |  |  |  |  | #   2) vec with mod-2 wheel :  15 bits  / 30 | 
| 352 |  |  |  |  |  |  | #   3) str with mod-30 wheel:   8 bytes / 30 | 
| 353 |  |  |  |  |  |  | #   4) str with mod-2 wheel :  15 bytes / 30 | 
| 354 |  |  |  |  |  |  | # | 
| 355 |  |  |  |  |  |  | # It looks like using vecs is about 2x slower than strs, and the strings also | 
| 356 |  |  |  |  |  |  | # let us do some fast operations on the results.  E.g. | 
| 357 |  |  |  |  |  |  | #   Count all primes: | 
| 358 |  |  |  |  |  |  | #      $count += $$sieveref =~ tr/0//; | 
| 359 |  |  |  |  |  |  | #   Loop over primes: | 
| 360 |  |  |  |  |  |  | #      foreach my $s (split("0", $$sieveref, -1)) { | 
| 361 |  |  |  |  |  |  | #        $n += 2 + 2 * length($s); | 
| 362 |  |  |  |  |  |  | #        .. do something with the prime $n | 
| 363 |  |  |  |  |  |  | #      } | 
| 364 |  |  |  |  |  |  | # | 
| 365 |  |  |  |  |  |  | # We're using method 4, though sadly it is memory intensive relative to the | 
| 366 |  |  |  |  |  |  | # other methods.  I will point out that it is 30-60x less memory than sieves | 
| 367 |  |  |  |  |  |  | # using an array, and the performance of this function is over 10x that | 
| 368 |  |  |  |  |  |  | # of naive sieves. | 
| 369 |  |  |  |  |  |  |  | 
| 370 |  |  |  |  |  |  | sub _sieve_erat_string { | 
| 371 | 56 |  |  | 56 |  | 181 | my($end) = @_; | 
| 372 | 56 | 100 |  |  |  | 300 | $end-- if ($end & 1) == 0; | 
| 373 | 56 |  |  |  |  | 155 | my $s_end = $end >> 1; | 
| 374 |  |  |  |  |  |  |  | 
| 375 | 56 |  |  |  |  | 286 | my $whole = int( $s_end / 15);   # Prefill with 3 and 5 already marked. | 
| 376 | 56 | 50 |  |  |  | 220 | croak "Sieve too large" if $whole > 1_145_324_612;  # ~32 GB string | 
| 377 | 56 |  |  |  |  | 4823 | my $sieve = '100010010010110' . '011010010010110' x $whole; | 
| 378 | 56 |  |  |  |  | 258 | substr($sieve, $s_end+1) = '';   # Ensure we don't make too many entries | 
| 379 | 56 |  |  |  |  | 220 | my ($n, $limit) = ( 7, int(sqrt($end)) ); | 
| 380 | 56 |  |  |  |  | 294 | while ( $n <= $limit ) { | 
| 381 | 1622 |  |  |  |  | 3250 | for (my $s = ($n*$n) >> 1; $s <= $s_end; $s += $n) { | 
| 382 | 2487327 |  |  |  |  | 3994527 | substr($sieve, $s, 1) = '1'; | 
| 383 |  |  |  |  |  |  | } | 
| 384 | 1622 |  |  |  |  | 2197 | do { $n += 2 } while substr($sieve, $n>>1, 1); | 
|  | 3912 |  |  |  |  | 7689 |  | 
| 385 |  |  |  |  |  |  | } | 
| 386 | 56 |  |  |  |  | 2067 | return \$sieve; | 
| 387 |  |  |  |  |  |  | } | 
| 388 |  |  |  |  |  |  |  | 
| 389 |  |  |  |  |  |  | # TODO: this should be plugged into precalc, memfree, etc. just like the C code | 
| 390 |  |  |  |  |  |  | { | 
| 391 |  |  |  |  |  |  | my $primary_size_limit = 15000; | 
| 392 |  |  |  |  |  |  | my $primary_sieve_size = 0; | 
| 393 |  |  |  |  |  |  | my $primary_sieve_ref; | 
| 394 |  |  |  |  |  |  | sub _sieve_erat { | 
| 395 | 620 |  |  | 620 |  | 1035 | my($end) = @_; | 
| 396 |  |  |  |  |  |  |  | 
| 397 | 620 | 100 |  |  |  | 1190 | return _sieve_erat_string($end) if $end > $primary_size_limit; | 
| 398 |  |  |  |  |  |  |  | 
| 399 | 606 | 100 |  |  |  | 1209 | if ($primary_sieve_size == 0) { | 
| 400 | 2 |  |  |  |  | 4 | $primary_sieve_size = $primary_size_limit; | 
| 401 | 2 |  |  |  |  | 6 | $primary_sieve_ref = _sieve_erat_string($primary_sieve_size); | 
| 402 |  |  |  |  |  |  | } | 
| 403 | 606 |  |  |  |  | 1426 | my $sieve = substr($$primary_sieve_ref, 0, ($end+1)>>1); | 
| 404 | 606 |  |  |  |  | 1398 | return \$sieve; | 
| 405 |  |  |  |  |  |  | } | 
| 406 |  |  |  |  |  |  | } | 
| 407 |  |  |  |  |  |  |  | 
| 408 |  |  |  |  |  |  |  | 
| 409 |  |  |  |  |  |  | sub _sieve_segment { | 
| 410 | 547 |  |  | 547 |  | 1051 | my($beg,$end,$limit) = @_; | 
| 411 | 547 | 50 | 33 |  |  | 1129 | ($beg, $end) = map { _bigint_to_int($_) } ($beg, $end) | 
|  | 0 |  |  |  |  | 0 |  | 
| 412 |  |  |  |  |  |  | if ref($end) && $end <= BMAX; | 
| 413 | 547 | 50 |  |  |  | 1174 | croak "Internal error: segment beg is even" if ($beg % 2) == 0; | 
| 414 | 547 | 50 |  |  |  | 1013 | croak "Internal error: segment end is even" if ($end % 2) == 0; | 
| 415 | 547 | 50 |  |  |  | 944 | croak "Internal error: segment end < beg" if $end < $beg; | 
| 416 | 547 | 50 |  |  |  | 914 | croak "Internal error: segment beg should be >= 3" if $beg < 3; | 
| 417 | 547 |  |  |  |  | 1086 | my $range = int( ($end - $beg) / 2 ) + 1; | 
| 418 |  |  |  |  |  |  |  | 
| 419 |  |  |  |  |  |  | # Prefill with 3 and 5 already marked, and offset to the segment start. | 
| 420 | 547 |  |  |  |  | 895 | my $whole = int( ($range+14) / 15); | 
| 421 | 547 |  |  |  |  | 908 | my $startp = ($beg % 30) >> 1; | 
| 422 | 547 |  |  |  |  | 3306 | my $sieve = substr('011010010010110', $startp) . '011010010010110' x $whole; | 
| 423 |  |  |  |  |  |  | # Set 3 and 5 to prime if we're sieving them. | 
| 424 | 547 | 100 |  |  |  | 1181 | substr($sieve,0,2) = '00' if $beg == 3; | 
| 425 | 547 | 100 |  |  |  | 916 | substr($sieve,0,1) = '0'  if $beg == 5; | 
| 426 |  |  |  |  |  |  | # Get rid of any extra we added. | 
| 427 | 547 |  |  |  |  | 1015 | substr($sieve, $range) = ''; | 
| 428 |  |  |  |  |  |  |  | 
| 429 |  |  |  |  |  |  | # If the end value is below 7^2, then the pre-sieve is all we needed. | 
| 430 | 547 | 100 |  |  |  | 971 | return \$sieve if $end < 49; | 
| 431 |  |  |  |  |  |  |  | 
| 432 | 536 | 50 |  |  |  | 1149 | my $sqlimit = ref($end) ? $end->copy->bsqrt() : int(sqrt($end)+0.0000001); | 
| 433 | 536 | 50 | 33 |  |  | 1204 | $limit = $sqlimit if !defined $limit || $sqlimit < $limit; | 
| 434 |  |  |  |  |  |  | # For large value of end, it's a huge win to just walk primes. | 
| 435 |  |  |  |  |  |  |  | 
| 436 | 536 |  |  |  |  | 1084 | my($p, $s, $primesieveref) = (7-2, 3, _sieve_erat($limit)); | 
| 437 | 536 |  |  |  |  | 1469 | while ( (my $nexts = 1 + index($$primesieveref, '0', $s)) > 0 ) { | 
| 438 | 40025 |  |  |  |  | 51445 | $p += 2 * ($nexts - $s); | 
| 439 | 40025 |  |  |  |  | 46200 | $s = $nexts; | 
| 440 | 40025 |  |  |  |  | 48583 | my $p2 = $p*$p; | 
| 441 | 40025 | 100 |  |  |  | 58545 | if ($p2 < $beg) { | 
| 442 | 39327 |  |  |  |  | 56036 | my $f = 1+int(($beg-1)/$p); | 
| 443 | 39327 | 100 |  |  |  | 62634 | $f++ unless $f % 2; | 
| 444 | 39327 |  |  |  |  | 47810 | $p2 = $p * $f; | 
| 445 |  |  |  |  |  |  | } | 
| 446 |  |  |  |  |  |  | # With large bases and small segments, it's common to find we don't hit | 
| 447 |  |  |  |  |  |  | # the segment at all.  Skip all the setup if we find this now. | 
| 448 | 40025 | 100 |  |  |  | 71722 | if ($p2 <= $end) { | 
| 449 |  |  |  |  |  |  | # Inner loop marking multiples of p | 
| 450 |  |  |  |  |  |  | # (everything is divided by 2 to keep inner loop simpler) | 
| 451 | 20147 |  |  |  |  | 25950 | my $filter_end = ($end - $beg) >> 1; | 
| 452 | 20147 |  |  |  |  | 26352 | my $filter_p2  = ($p2  - $beg) >> 1; | 
| 453 | 20147 |  |  |  |  | 31573 | while ($filter_p2 <= $filter_end) { | 
| 454 | 726651 |  |  |  |  | 895908 | substr($sieve, $filter_p2, 1) = "1"; | 
| 455 | 726651 |  |  |  |  | 1129642 | $filter_p2 += $p; | 
| 456 |  |  |  |  |  |  | } | 
| 457 |  |  |  |  |  |  | } | 
| 458 |  |  |  |  |  |  | } | 
| 459 | 536 |  |  |  |  | 1668 | \$sieve; | 
| 460 |  |  |  |  |  |  | } | 
| 461 |  |  |  |  |  |  |  | 
| 462 |  |  |  |  |  |  | sub trial_primes { | 
| 463 | 2 |  |  | 2 | 0 | 2158 | my($low,$high) = @_; | 
| 464 | 2 | 100 |  |  |  | 8 | if (!defined $high) { | 
| 465 | 1 |  |  |  |  | 2 | $high = $low; | 
| 466 | 1 |  |  |  |  | 1 | $low = 2; | 
| 467 |  |  |  |  |  |  | } | 
| 468 | 2 |  |  |  |  | 8 | _validate_positive_integer($low); | 
| 469 | 2 |  |  |  |  | 6 | _validate_positive_integer($high); | 
| 470 | 2 | 50 |  |  |  | 6 | return if $low > $high; | 
| 471 | 2 |  |  |  |  | 46 | my @primes; | 
| 472 |  |  |  |  |  |  |  | 
| 473 |  |  |  |  |  |  | # For a tiny range, just use next_prime calls | 
| 474 | 2 | 50 |  |  |  | 9 | if (($high-$low) < 1000) { | 
| 475 | 2 | 50 |  |  |  | 330 | $low-- if $low >= 2; | 
| 476 | 2 |  |  |  |  | 191 | my $curprime = next_prime($low); | 
| 477 | 2 |  |  |  |  | 19 | while ($curprime <= $high) { | 
| 478 | 24 |  |  |  |  | 130 | push @primes, $curprime; | 
| 479 | 24 |  |  |  |  | 33 | $curprime = next_prime($curprime); | 
| 480 |  |  |  |  |  |  | } | 
| 481 | 2 |  |  |  |  | 79 | return \@primes; | 
| 482 |  |  |  |  |  |  | } | 
| 483 |  |  |  |  |  |  |  | 
| 484 |  |  |  |  |  |  | # Sieve to 10k then BPSW test | 
| 485 | 0 | 0 | 0 |  |  | 0 | push @primes, 2  if ($low <= 2) && ($high >= 2); | 
| 486 | 0 | 0 | 0 |  |  | 0 | push @primes, 3  if ($low <= 3) && ($high >= 3); | 
| 487 | 0 | 0 | 0 |  |  | 0 | push @primes, 5  if ($low <= 5) && ($high >= 5); | 
| 488 | 0 | 0 |  |  |  | 0 | $low = 7 if $low < 7; | 
| 489 | 0 | 0 |  |  |  | 0 | $low++ if ($low % 2) == 0; | 
| 490 | 0 | 0 |  |  |  | 0 | $high-- if ($high % 2) == 0; | 
| 491 | 0 |  |  |  |  | 0 | my $sieveref = _sieve_segment($low, $high, 10000); | 
| 492 | 0 |  |  |  |  | 0 | my $n = $low-2; | 
| 493 | 0 |  |  |  |  | 0 | while ($$sieveref =~ m/0/g) { | 
| 494 | 0 |  |  |  |  | 0 | my $p = $n+2*pos($$sieveref); | 
| 495 | 0 | 0 | 0 |  |  | 0 | push @primes, $p if _miller_rabin_2($p) && is_extra_strong_lucas_pseudoprime($p); | 
| 496 |  |  |  |  |  |  | } | 
| 497 | 0 |  |  |  |  | 0 | return \@primes; | 
| 498 |  |  |  |  |  |  | } | 
| 499 |  |  |  |  |  |  |  | 
| 500 |  |  |  |  |  |  | sub primes { | 
| 501 | 169 |  |  | 169 | 0 | 16026 | my($low,$high) = @_; | 
| 502 | 169 | 100 |  |  |  | 503 | if (scalar @_ > 1) { | 
| 503 | 65 |  |  |  |  | 224 | _validate_positive_integer($low); | 
| 504 | 65 |  |  |  |  | 235 | _validate_positive_integer($high); | 
| 505 | 65 | 100 |  |  |  | 203 | $low = 2 if $low < 2; | 
| 506 |  |  |  |  |  |  | } else { | 
| 507 | 104 |  |  |  |  | 224 | ($low,$high) = (2, $low); | 
| 508 | 104 |  |  |  |  | 260 | _validate_positive_integer($high); | 
| 509 |  |  |  |  |  |  | } | 
| 510 | 169 |  |  |  |  | 453 | my $sref = []; | 
| 511 | 169 | 100 | 66 |  |  | 771 | return $sref if ($low > $high) || ($high < 2); | 
| 512 | 163 | 100 |  |  |  | 1302 | return [grep { $_ >= $low && $_ <= $high } @_primes_small] | 
|  | 270187 | 100 |  |  |  | 650791 |  | 
| 513 |  |  |  |  |  |  | if $high <= $_primes_small[-1]; | 
| 514 |  |  |  |  |  |  |  | 
| 515 |  |  |  |  |  |  | return [ Math::Prime::Util::GMP::sieve_primes($low, $high, 0) ] | 
| 516 | 13 | 50 | 33 |  |  | 173 | if $Math::Prime::Util::_GMPfunc{"sieve_primes"} && $Math::Prime::Util::GMP::VERSION >= 0.34; | 
| 517 |  |  |  |  |  |  |  | 
| 518 |  |  |  |  |  |  | # At some point even the pretty-fast pure perl sieve is going to be a | 
| 519 |  |  |  |  |  |  | # dog, and we should move to trials.  This is typical with a small range | 
| 520 |  |  |  |  |  |  | # on a large base.  More thought on the switchover should be done. | 
| 521 | 13 | 50 | 66 |  |  | 120 | return trial_primes($low, $high) if ref($low)  eq 'Math::BigInt' | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
| 522 |  |  |  |  |  |  | || ref($high) eq 'Math::BigInt' | 
| 523 |  |  |  |  |  |  | || ($low > 1_000_000_000_000 && ($high-$low) < int($low/1_000_000)); | 
| 524 |  |  |  |  |  |  |  | 
| 525 | 12 | 100 | 66 |  |  | 92 | push @$sref, 2  if ($low <= 2) && ($high >= 2); | 
| 526 | 12 | 100 | 66 |  |  | 62 | push @$sref, 3  if ($low <= 3) && ($high >= 3); | 
| 527 | 12 | 100 | 66 |  |  | 53 | push @$sref, 5  if ($low <= 5) && ($high >= 5); | 
| 528 | 12 | 100 |  |  |  | 36 | $low = 7 if $low < 7; | 
| 529 | 12 | 100 |  |  |  | 46 | $low++ if ($low % 2) == 0; | 
| 530 | 12 | 100 |  |  |  | 39 | $high-- if ($high % 2) == 0; | 
| 531 | 12 | 50 |  |  |  | 39 | return $sref if $low > $high; | 
| 532 |  |  |  |  |  |  |  | 
| 533 | 12 |  |  |  |  | 25 | my($n,$sieveref); | 
| 534 | 12 | 100 |  |  |  | 35 | if ($low == 7) { | 
| 535 | 5 |  |  |  |  | 10 | $n = 0; | 
| 536 | 5 |  |  |  |  | 21 | $sieveref = _sieve_erat($high); | 
| 537 | 5 |  |  |  |  | 42 | substr($$sieveref,0,3,'111'); | 
| 538 |  |  |  |  |  |  | } else { | 
| 539 | 7 |  |  |  |  | 10 | $n = $low-1; | 
| 540 | 7 |  |  |  |  | 23 | $sieveref = _sieve_segment($low,$high); | 
| 541 |  |  |  |  |  |  | } | 
| 542 | 12 |  |  |  |  | 34551 | push @$sref, $n+2*pos($$sieveref)-1 while $$sieveref =~ m/0/g; | 
| 543 | 12 |  |  |  |  | 2899 | $sref; | 
| 544 |  |  |  |  |  |  | } | 
| 545 |  |  |  |  |  |  |  | 
| 546 |  |  |  |  |  |  | sub sieve_range { | 
| 547 | 0 |  |  | 0 | 0 | 0 | my($n, $width, $depth) = @_; | 
| 548 | 0 |  |  |  |  | 0 | _validate_positive_integer($n); | 
| 549 | 0 |  |  |  |  | 0 | _validate_positive_integer($width); | 
| 550 | 0 |  |  |  |  | 0 | _validate_positive_integer($depth); | 
| 551 |  |  |  |  |  |  |  | 
| 552 | 0 |  |  |  |  | 0 | my @candidates; | 
| 553 | 0 |  |  |  |  | 0 | my $start = $n; | 
| 554 |  |  |  |  |  |  |  | 
| 555 | 0 | 0 |  |  |  | 0 | if ($n < 5) { | 
| 556 | 0 | 0 | 0 |  |  | 0 | push @candidates, (2-$n) if $n <= 2 && $n+$width-1 >= 2; | 
| 557 | 0 | 0 | 0 |  |  | 0 | push @candidates, (3-$n) if $n <= 3 && $n+$width-1 >= 3; | 
| 558 | 0 | 0 | 0 |  |  | 0 | push @candidates, (4-$n) if $n <= 4 && $n+$width-1 >= 4 && $depth < 2; | 
|  |  |  | 0 |  |  |  |  | 
| 559 | 0 |  |  |  |  | 0 | $start = 5; | 
| 560 | 0 |  |  |  |  | 0 | $width -= ($start - $n); | 
| 561 |  |  |  |  |  |  | } | 
| 562 |  |  |  |  |  |  |  | 
| 563 | 0 | 0 |  |  |  | 0 | return @candidates, map {$start+$_-$n } 0 .. $width-1 if $depth < 2; | 
|  | 0 |  |  |  |  | 0 |  | 
| 564 | 0 |  |  |  |  | 0 | return @candidates, map { $_ - $n } | 
| 565 | 0 | 0 | 0 |  |  | 0 | grep { ($_ & 1) && ($depth < 3 || ($_ % 3)) } | 
| 566 | 0 | 0 |  |  |  | 0 | map { $start+$_ } | 
|  | 0 |  |  |  |  | 0 |  | 
| 567 |  |  |  |  |  |  | 0 .. $width-1                     if $depth < 5; | 
| 568 |  |  |  |  |  |  |  | 
| 569 | 0 | 0 |  |  |  | 0 | if (!($start & 1)) { $start++; $width--; } | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 570 | 0 | 0 |  |  |  | 0 | $width-- if !($width&1); | 
| 571 | 0 | 0 |  |  |  | 0 | return @candidates if $width < 1; | 
| 572 |  |  |  |  |  |  |  | 
| 573 | 0 |  |  |  |  | 0 | my $sieveref = _sieve_segment($start, $start+$width-1, $depth); | 
| 574 | 0 |  |  |  |  | 0 | my $offset = $start - $n - 2; | 
| 575 | 0 |  |  |  |  | 0 | while ($$sieveref =~ m/0/g) { | 
| 576 | 0 |  |  |  |  | 0 | push @candidates, $offset + (pos($$sieveref) << 1); | 
| 577 |  |  |  |  |  |  | } | 
| 578 | 0 |  |  |  |  | 0 | return @candidates; | 
| 579 |  |  |  |  |  |  | } | 
| 580 |  |  |  |  |  |  |  | 
| 581 |  |  |  |  |  |  | sub sieve_prime_cluster { | 
| 582 | 12 |  |  | 12 | 0 | 8097 | my($lo,$hi,@cl) = @_; | 
| 583 | 12 |  |  |  |  | 67 | my $_verbose = Math::Prime::Util::prime_get_config()->{'verbose'}; | 
| 584 | 12 |  |  |  |  | 67 | _validate_positive_integer($lo); | 
| 585 | 12 |  |  |  |  | 35 | _validate_positive_integer($hi); | 
| 586 |  |  |  |  |  |  |  | 
| 587 | 12 | 50 |  |  |  | 54 | if ($Math::Prime::Util::_GMPfunc{"sieve_prime_cluster"}) { | 
| 588 | 0 | 0 |  |  |  | 0 | return map { ($_ > ''.~0) ? Math::BigInt->new(''.$_) : $_ } | 
|  | 0 |  |  |  |  | 0 |  | 
| 589 |  |  |  |  |  |  | Math::Prime::Util::GMP::sieve_prime_cluster($lo,$hi,@cl); | 
| 590 |  |  |  |  |  |  | } | 
| 591 |  |  |  |  |  |  |  | 
| 592 | 12 | 50 |  |  |  | 38 | return @{primes($lo,$hi)} if scalar(@cl) == 0; | 
|  | 0 |  |  |  |  | 0 |  | 
| 593 |  |  |  |  |  |  |  | 
| 594 | 12 |  |  |  |  | 36 | unshift @cl, 0; | 
| 595 | 12 |  |  |  |  | 47 | for my $i (1 .. $#cl) { | 
| 596 | 36 |  |  |  |  | 77 | _validate_positive_integer($cl[$i]); | 
| 597 | 36 | 50 |  |  |  | 94 | croak "sieve_prime_cluster: values must be even" if $cl[$i] & 1; | 
| 598 | 36 | 50 |  |  |  | 110 | croak "sieve_prime_cluster: values must be increasing" if $cl[$i] <= $cl[$i-1]; | 
| 599 |  |  |  |  |  |  | } | 
| 600 | 12 |  |  |  |  | 39 | my($p,$sievelim,@p) = (17, 2000); | 
| 601 | 12 | 50 |  |  |  | 42 | $p = 13 if ($hi-$lo) < 50_000_000; | 
| 602 | 12 | 50 |  |  |  | 2636 | $p = 11 if ($hi-$lo) <  1_000_000; | 
| 603 | 12 | 100 | 100 |  |  | 2173 | $p =  7 if ($hi-$lo) <     20_000 && $lo < INTMAX; | 
| 604 |  |  |  |  |  |  |  | 
| 605 |  |  |  |  |  |  | # Add any cases under our sieving point. | 
| 606 | 12 | 100 |  |  |  | 3320 | if ($lo <= $sievelim) { | 
| 607 | 2 | 50 |  |  |  | 6 | $sievelim = $hi if $sievelim > $hi; | 
| 608 | 2 |  |  |  |  | 24 | for my $n (@{primes($lo,$sievelim)}) { | 
|  | 2 |  |  |  |  | 9 |  | 
| 609 | 606 |  |  |  |  | 791 | my $ac = 1; | 
| 610 | 606 |  |  |  |  | 1014 | for my $ci (1 .. $#cl) { | 
| 611 | 606 | 100 |  |  |  | 1048 | if (!is_prime($n+$cl[$ci])) { $ac = 0; last; } | 
|  | 484 |  |  |  |  | 681 |  | 
|  | 484 |  |  |  |  | 636 |  | 
| 612 |  |  |  |  |  |  | } | 
| 613 | 606 | 100 |  |  |  | 1180 | push @p, $n if $ac; | 
| 614 |  |  |  |  |  |  | } | 
| 615 | 2 |  |  |  |  | 32 | $lo = next_prime($sievelim); | 
| 616 |  |  |  |  |  |  | } | 
| 617 | 12 | 50 |  |  |  | 940 | return @p if $lo > $hi; | 
| 618 |  |  |  |  |  |  |  | 
| 619 |  |  |  |  |  |  | # Compute acceptable residues. | 
| 620 | 12 |  |  |  |  | 450 | my $pr = primorial($p); | 
| 621 | 12 |  |  |  |  | 55 | my $startpr = _bigint_to_int($lo % $pr); | 
| 622 |  |  |  |  |  |  |  | 
| 623 | 12 | 100 |  |  |  | 714 | my @acc = grep { ($_ & 1) && $_%3 }  ($startpr .. $startpr + $pr - 1); | 
|  | 25620 |  |  |  |  | 41818 |  | 
| 624 | 12 |  |  |  |  | 415 | for my $c (@cl) { | 
| 625 | 48 | 50 |  |  |  | 90 | if ($p >= 7) { | 
| 626 | 48 | 100 | 100 |  |  | 94 | @acc = grep { (($_+$c)%3) && (($_+$c)%5) && (($_+$c)%7) } @acc; | 
|  | 16618 |  |  |  |  | 39272 |  | 
| 627 |  |  |  |  |  |  | } else { | 
| 628 | 0 | 0 |  |  |  | 0 | @acc = grep { (($_+$c)%3)  && (($_+$c)%5) } @acc; | 
|  | 0 |  |  |  |  | 0 |  | 
| 629 |  |  |  |  |  |  | } | 
| 630 |  |  |  |  |  |  | } | 
| 631 | 12 |  |  |  |  | 37 | for my $c (@cl) { | 
| 632 | 48 |  |  |  |  | 71 | @acc = grep { Math::Prime::Util::gcd($_+$c,$pr) == 1 } @acc; | 
|  | 1912 |  |  |  |  | 3750 |  | 
| 633 |  |  |  |  |  |  | } | 
| 634 | 12 |  |  |  |  | 31 | @acc = map { $_-$startpr } @acc; | 
|  | 606 |  |  |  |  | 717 |  | 
| 635 |  |  |  |  |  |  |  | 
| 636 | 12 | 50 |  |  |  | 49 | print "cluster sieve using ",scalar(@acc)," residues mod $pr\n" if $_verbose; | 
| 637 | 12 | 50 |  |  |  | 35 | return @p if scalar(@acc) == 0; | 
| 638 |  |  |  |  |  |  |  | 
| 639 |  |  |  |  |  |  | # Prepare table for more sieving. | 
| 640 | 12 |  |  |  |  | 19 | my @mprimes = @{primes( $p+1, $sievelim)}; | 
|  | 12 |  |  |  |  | 34 |  | 
| 641 | 12 |  |  |  |  | 95 | my @vprem; | 
| 642 | 12 |  |  |  |  | 39 | for my $p (@mprimes) { | 
| 643 | 3577 |  |  |  |  | 4798 | for my $c (@cl) { | 
| 644 | 14306 |  |  |  |  | 35209 | $vprem[$p]->[ ($p-($c%$p)) % $p ] = 1; | 
| 645 |  |  |  |  |  |  | } | 
| 646 |  |  |  |  |  |  | } | 
| 647 |  |  |  |  |  |  |  | 
| 648 |  |  |  |  |  |  | # Walk the range in primorial chunks, doing primality tests. | 
| 649 | 12 |  |  |  |  | 36 | my($nummr, $numlucas) = (0,0); | 
| 650 | 12 |  |  |  |  | 81 | while ($lo <= $hi) { | 
| 651 |  |  |  |  |  |  |  | 
| 652 | 70 |  |  |  |  | 7142 | my @racc = @acc; | 
| 653 |  |  |  |  |  |  |  | 
| 654 |  |  |  |  |  |  | # Make sure we don't do anything past the limit | 
| 655 | 70 | 100 |  |  |  | 191 | if (($lo+$acc[-1]) > $hi) { | 
| 656 | 12 |  |  |  |  | 1783 | my $max = _bigint_to_int($hi-$lo); | 
| 657 | 12 |  |  |  |  | 271 | @racc = grep { $_ <= $max } @racc; | 
|  | 606 |  |  |  |  | 846 |  | 
| 658 |  |  |  |  |  |  | } | 
| 659 |  |  |  |  |  |  |  | 
| 660 |  |  |  |  |  |  | # Sieve more values using native math | 
| 661 | 70 |  |  |  |  | 6673 | foreach my $p (@mprimes) { | 
| 662 | 12500 |  |  |  |  | 20373 | my $rem = _bigint_to_int( $lo % $p ); | 
| 663 | 12500 |  |  |  |  | 105067 | @racc = grep { !$vprem[$p]->[ ($rem+$_) % $p ] } @racc; | 
|  | 191619 |  |  |  |  | 327084 |  | 
| 664 | 12500 | 100 |  |  |  | 26400 | last unless scalar(@racc); | 
| 665 |  |  |  |  |  |  | } | 
| 666 |  |  |  |  |  |  |  | 
| 667 |  |  |  |  |  |  | # Do final primality tests. | 
| 668 | 70 | 100 |  |  |  | 195 | if ($lo < 1e13) { | 
| 669 | 24 |  |  |  |  | 45 | for my $r (@racc) { | 
| 670 | 442 |  |  |  |  | 677 | my($good, $p) = (1, $lo + $r); | 
| 671 | 442 |  |  |  |  | 605 | for my $c (@cl) { | 
| 672 | 884 |  |  |  |  | 1067 | $nummr++; | 
| 673 | 884 | 50 |  |  |  | 2064 | if (!Math::Prime::Util::is_prime($p+$c)) { $good = 0; last; } | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 674 |  |  |  |  |  |  | } | 
| 675 | 442 | 50 |  |  |  | 904 | push @p, $p if $good; | 
| 676 |  |  |  |  |  |  | } | 
| 677 |  |  |  |  |  |  | } else { | 
| 678 | 46 |  |  |  |  | 5934 | for my $r (@racc) { | 
| 679 | 106 |  |  |  |  | 526 | my($good, $p) = (1, $lo + $r); | 
| 680 | 106 |  |  |  |  | 19785 | for my $c (@cl) { | 
| 681 | 140 |  |  |  |  | 273 | $nummr++; | 
| 682 | 140 | 100 |  |  |  | 429 | if (!Math::Prime::Util::is_strong_pseudoprime($p+$c,2)) { $good = 0; last; } | 
|  | 100 |  |  |  |  | 197 |  | 
|  | 100 |  |  |  |  | 195 |  | 
| 683 |  |  |  |  |  |  | } | 
| 684 | 106 | 100 |  |  |  | 684 | next unless $good; | 
| 685 | 6 |  |  |  |  | 17 | for my $c (@cl) { | 
| 686 | 12 |  |  |  |  | 1691 | $numlucas++; | 
| 687 | 12 | 50 |  |  |  | 45 | if (!Math::Prime::Util::is_extra_strong_lucas_pseudoprime($p+$c)) { $good = 0; last; } | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 688 |  |  |  |  |  |  | } | 
| 689 | 6 | 50 |  |  |  | 995 | push @p, $p if $good; | 
| 690 |  |  |  |  |  |  | } | 
| 691 |  |  |  |  |  |  | } | 
| 692 |  |  |  |  |  |  |  | 
| 693 | 70 |  |  |  |  | 272 | $lo += $pr; | 
| 694 |  |  |  |  |  |  | } | 
| 695 | 12 | 50 |  |  |  | 1662 | print "cluster sieve ran $nummr MR and $numlucas Lucas tests\n" if $_verbose; | 
| 696 | 12 |  |  |  |  | 11227 | @p; | 
| 697 |  |  |  |  |  |  | } | 
| 698 |  |  |  |  |  |  |  | 
| 699 |  |  |  |  |  |  |  | 
| 700 |  |  |  |  |  |  | sub _n_ramanujan_primes { | 
| 701 | 0 |  |  | 0 |  | 0 | my($n) = @_; | 
| 702 | 0 | 0 |  |  |  | 0 | return [] if $n <= 0; | 
| 703 | 0 |  |  |  |  | 0 | my $max = nth_prime_upper(int(48/19*$n)+1); | 
| 704 | 0 |  |  |  |  | 0 | my @L = (2, (0) x $n-1); | 
| 705 | 0 |  |  |  |  | 0 | my $s = 1; | 
| 706 | 0 |  |  |  |  | 0 | for (my $k = 7; $k <= $max; $k += 2) { | 
| 707 | 0 | 0 |  |  |  | 0 | $s++ if is_prime($k); | 
| 708 | 0 | 0 |  |  |  | 0 | $L[$s] = $k+1 if $s < $n; | 
| 709 | 0 | 0 | 0 |  |  | 0 | $s-- if ($k&3) == 1 && is_prime(($k+1)>>1); | 
| 710 | 0 | 0 |  |  |  | 0 | $L[$s] = $k+2 if $s < $n; | 
| 711 |  |  |  |  |  |  | } | 
| 712 | 0 |  |  |  |  | 0 | \@L; | 
| 713 |  |  |  |  |  |  | } | 
| 714 |  |  |  |  |  |  |  | 
| 715 |  |  |  |  |  |  | sub _ramanujan_primes { | 
| 716 | 0 |  |  | 0 |  | 0 | my($low,$high) = @_; | 
| 717 | 0 | 0 |  |  |  | 0 | ($low,$high) = (2, $low) unless defined $high; | 
| 718 | 0 | 0 | 0 |  |  | 0 | return [] if ($low > $high) || ($high < 2); | 
| 719 | 0 |  |  |  |  | 0 | my $nn = prime_count_upper($high) >> 1; | 
| 720 | 0 |  |  |  |  | 0 | my $L = _n_ramanujan_primes($nn); | 
| 721 | 0 |  | 0 |  |  | 0 | shift @$L while @$L && $L->[0] < $low; | 
| 722 | 0 |  | 0 |  |  | 0 | pop @$L while @$L && $L->[-1] > $high; | 
| 723 | 0 |  |  |  |  | 0 | $L; | 
| 724 |  |  |  |  |  |  | } | 
| 725 |  |  |  |  |  |  |  | 
| 726 |  |  |  |  |  |  | sub is_ramanujan_prime { | 
| 727 | 0 |  |  | 0 | 0 | 0 | my($n) = @_; | 
| 728 | 0 | 0 |  |  |  | 0 | return 1 if $n == 2; | 
| 729 | 0 | 0 |  |  |  | 0 | return 0 if $n < 11; | 
| 730 | 0 |  |  |  |  | 0 | my $L = _ramanujan_primes($n,$n); | 
| 731 | 0 | 0 |  |  |  | 0 | return (scalar(@$L) > 0) ? 1 : 0; | 
| 732 |  |  |  |  |  |  | } | 
| 733 |  |  |  |  |  |  |  | 
| 734 |  |  |  |  |  |  | sub nth_ramanujan_prime { | 
| 735 | 0 |  |  | 0 | 0 | 0 | my($n) = @_; | 
| 736 | 0 | 0 |  |  |  | 0 | return undef if $n <= 0;  ## no critic qw(ProhibitExplicitReturnUndef) | 
| 737 | 0 |  |  |  |  | 0 | my $L = _n_ramanujan_primes($n); | 
| 738 | 0 |  |  |  |  | 0 | return $L->[$n-1]; | 
| 739 |  |  |  |  |  |  | } | 
| 740 |  |  |  |  |  |  |  | 
| 741 |  |  |  |  |  |  | sub next_prime { | 
| 742 | 4959 |  |  | 4959 | 0 | 245475 | my($n) = @_; | 
| 743 | 4959 |  |  |  |  | 12199 | _validate_positive_integer($n); | 
| 744 | 4958 | 100 |  |  |  | 15825 | return $_prime_next_small[$n] if $n <= $#_prime_next_small; | 
| 745 |  |  |  |  |  |  | # This turns out not to be faster. | 
| 746 |  |  |  |  |  |  | # return $_primes_small[1+_tiny_prime_count($n)] if $n < $_primes_small[-1]; | 
| 747 |  |  |  |  |  |  |  | 
| 748 | 933 | 100 | 100 |  |  | 5022 | return Math::BigInt->new(MPU_32BIT ? "4294967311" : "18446744073709551629") | 
| 749 |  |  |  |  |  |  | if ref($n) ne 'Math::BigInt' && $n >= MPU_MAXPRIME; | 
| 750 |  |  |  |  |  |  | # n is now either 1) not bigint and < maxprime, or (2) bigint and >= uvmax | 
| 751 |  |  |  |  |  |  |  | 
| 752 | 928 | 50 | 66 |  |  | 2008 | if ($n > 4294967295 && Math::Prime::Util::prime_get_config()->{'gmp'}) { | 
| 753 | 0 |  |  |  |  | 0 | return Math::Prime::Util::_reftyped($_[0], Math::Prime::Util::GMP::next_prime($n)); | 
| 754 |  |  |  |  |  |  | } | 
| 755 |  |  |  |  |  |  |  | 
| 756 | 928 | 100 |  |  |  | 1926 | if (ref($n) eq 'Math::BigInt') { | 
| 757 | 11 |  | 100 |  |  | 27 | do { | 
|  |  |  | 66 |  |  |  |  | 
| 758 | 115 |  |  |  |  | 199905 | $n += $_wheeladvance30[$n%30]; | 
| 759 |  |  |  |  |  |  | } while !Math::BigInt::bgcd($n, B_PRIM767)->is_one || | 
| 760 |  |  |  |  |  |  | !_miller_rabin_2($n) || !is_extra_strong_lucas_pseudoprime($n); | 
| 761 |  |  |  |  |  |  | } else { | 
| 762 | 917 |  | 100 |  |  | 1322 | do { | 
| 763 | 4260 |  |  |  |  | 11581 | $n += $_wheeladvance30[$n%30]; | 
| 764 |  |  |  |  |  |  | } while !($n%7) || !_is_prime7($n); | 
| 765 |  |  |  |  |  |  | } | 
| 766 | 928 |  |  |  |  | 6779 | $n; | 
| 767 |  |  |  |  |  |  | } | 
| 768 |  |  |  |  |  |  |  | 
| 769 |  |  |  |  |  |  | sub prev_prime { | 
| 770 | 157 |  |  | 157 | 0 | 3213 | my($n) = @_; | 
| 771 | 157 |  |  |  |  | 345 | _validate_positive_integer($n); | 
| 772 | 157 | 100 |  |  |  | 301 | return (undef,undef,undef,2,3,3,5,5,7,7,7,7)[$n] if $n <= 11; | 
| 773 | 156 | 50 | 66 |  |  | 509 | if ($n > 4294967295 && Math::Prime::Util::prime_get_config()->{'gmp'}) { | 
| 774 | 0 |  |  |  |  | 0 | return Math::Prime::Util::_reftyped($_[0], Math::Prime::Util::GMP::prev_prime($n)); | 
| 775 |  |  |  |  |  |  | } | 
| 776 |  |  |  |  |  |  |  | 
| 777 | 156 | 100 |  |  |  | 323 | if (ref($n) eq 'Math::BigInt') { | 
| 778 | 2 |  | 100 |  |  | 5 | do { | 
|  |  |  | 100 |  |  |  |  | 
| 779 | 22 |  |  |  |  | 44818 | $n -= $_wheelretreat30[$n%30]; | 
| 780 |  |  |  |  |  |  | } while !Math::BigInt::bgcd($n, B_PRIM767)->is_one || | 
| 781 |  |  |  |  |  |  | !_miller_rabin_2($n) || !is_extra_strong_lucas_pseudoprime($n); | 
| 782 |  |  |  |  |  |  | } else { | 
| 783 | 154 |  | 100 |  |  | 194 | do { | 
| 784 | 3082 |  |  |  |  | 7214 | $n -= $_wheelretreat30[$n%30]; | 
| 785 |  |  |  |  |  |  | } while !($n%7) || !_is_prime7($n); | 
| 786 |  |  |  |  |  |  | } | 
| 787 | 156 |  |  |  |  | 1349 | $n; | 
| 788 |  |  |  |  |  |  | } | 
| 789 |  |  |  |  |  |  |  | 
| 790 |  |  |  |  |  |  | sub partitions { | 
| 791 | 57 |  |  | 57 | 0 | 106 | my $n = shift; | 
| 792 |  |  |  |  |  |  |  | 
| 793 | 57 |  |  |  |  | 161 | my $d = int(sqrt($n+1)); | 
| 794 | 57 |  |  |  |  | 151 | my @pent = (1, map { (($_*(3*$_+1))>>1, (($_+1)*(3*$_+2))>>1) } 1 .. $d); | 
|  | 422 |  |  |  |  | 821 |  | 
| 795 | 57 | 100 |  |  |  | 156 | my $ZERO = ($n >= ((~0 > 4294967295) ? 400 : 270)) ? BZERO : 0; | 
| 796 | 57 |  |  |  |  | 111 | my @part = ($ZERO+1); | 
| 797 | 57 |  |  |  |  | 936 | foreach my $j (scalar @part .. $n) { | 
| 798 | 9683 |  |  |  |  | 1130776 | my ($psum1, $psum2, $k) = ($ZERO, $ZERO, 1); | 
| 799 | 9683 |  |  |  |  | 14598 | foreach my $p (@pent) { | 
| 800 | 474063 | 100 |  |  |  | 27246547 | last if $p > $j; | 
| 801 | 464380 | 100 |  |  |  | 728457 | if ((++$k) & 2) { $psum1 += $part[ $j - $p ] } | 
|  | 237074 |  |  |  |  | 491790 |  | 
| 802 | 227306 |  |  |  |  | 472979 | else            { $psum2 += $part[ $j - $p ] } | 
| 803 |  |  |  |  |  |  | } | 
| 804 | 9683 |  |  |  |  | 19375 | $part[$j] = $psum1 - $psum2; | 
| 805 |  |  |  |  |  |  | } | 
| 806 | 57 |  |  |  |  | 4146 | return $part[$n]; | 
| 807 |  |  |  |  |  |  | } | 
| 808 |  |  |  |  |  |  |  | 
| 809 |  |  |  |  |  |  | sub primorial { | 
| 810 | 67 |  |  | 67 | 0 | 127 | my $n = shift; | 
| 811 |  |  |  |  |  |  |  | 
| 812 | 67 |  |  |  |  | 108 | my @plist = @{primes($n)}; | 
|  | 67 |  |  |  |  | 171 |  | 
| 813 | 67 |  |  |  |  | 195 | my $max = (MPU_32BIT) ? 29 : (OLD_PERL_VERSION) ? 43 : 53; | 
| 814 |  |  |  |  |  |  |  | 
| 815 |  |  |  |  |  |  | # If small enough, multiply the small primes. | 
| 816 | 67 | 100 |  |  |  | 169 | if ($n < $max) { | 
| 817 | 30 |  |  |  |  | 69 | my $pn = 1; | 
| 818 | 30 |  |  |  |  | 114 | $pn *= $_ for @plist; | 
| 819 | 30 |  |  |  |  | 168 | return $pn; | 
| 820 |  |  |  |  |  |  | } | 
| 821 |  |  |  |  |  |  |  | 
| 822 |  |  |  |  |  |  | # Otherwise, combine them as UVs, then combine using product tree. | 
| 823 | 37 |  |  |  |  | 65 | my $i = 0; | 
| 824 | 37 |  |  |  |  | 84 | while ($i < $#plist) { | 
| 825 | 960 |  |  |  |  | 1485 | my $m = $plist[$i] * $plist[$i+1]; | 
| 826 | 960 | 100 |  |  |  | 1428 | if ($m <= INTMAX) { splice(@plist, $i, 2, $m); } | 
|  | 893 |  |  |  |  | 2204 |  | 
| 827 | 67 |  |  |  |  | 134 | else              { $i++;                      } | 
| 828 |  |  |  |  |  |  | } | 
| 829 | 37 |  |  |  |  | 134 | vecprod(@plist); | 
| 830 |  |  |  |  |  |  | } | 
| 831 |  |  |  |  |  |  |  | 
| 832 |  |  |  |  |  |  | sub consecutive_integer_lcm { | 
| 833 | 103 |  |  | 103 | 0 | 195 | my $n = shift; | 
| 834 |  |  |  |  |  |  |  | 
| 835 | 103 |  |  |  |  | 159 | my $max = (MPU_32BIT) ? 22 : (OLD_PERL_VERSION) ? 37 : 46; | 
| 836 | 103 | 100 |  |  |  | 408 | my $pn = ref($n) ? ref($n)->new(1) : ($n >= $max) ? Math::BigInt->bone() : 1; | 
|  |  | 50 |  |  |  |  |  | 
| 837 | 103 |  |  |  |  | 2925 | for (my $p = 2; $p <= $n; $p = next_prime($p)) { | 
| 838 | 1789 |  |  |  |  | 4023 | my($p_power, $pmin) = ($p, int($n/$p)); | 
| 839 | 1789 |  |  |  |  | 3567 | $p_power *= $p while $p_power <= $pmin; | 
| 840 | 1789 |  |  |  |  | 3987 | $pn *= $p_power; | 
| 841 |  |  |  |  |  |  | } | 
| 842 | 103 | 100 |  |  |  | 304 | $pn = _bigint_to_int($pn) if $pn <= BMAX; | 
| 843 | 103 |  |  |  |  | 2626 | return $pn; | 
| 844 |  |  |  |  |  |  | } | 
| 845 |  |  |  |  |  |  |  | 
| 846 |  |  |  |  |  |  | sub jordan_totient { | 
| 847 | 25 |  |  | 25 | 0 | 2682 | my($k, $n) = @_; | 
| 848 | 25 | 0 |  |  |  | 74 | return ($n == 1) ? 1 : 0  if $k == 0; | 
|  |  | 50 |  |  |  |  |  | 
| 849 | 25 | 50 |  |  |  | 482 | return euler_phi($n)      if $k == 1; | 
| 850 | 25 | 0 |  |  |  | 308 | return ($n == 1) ? 1 : 0  if $n <= 1; | 
|  |  | 50 |  |  |  |  |  | 
| 851 |  |  |  |  |  |  |  | 
| 852 |  |  |  |  |  |  | return Math::Prime::Util::_reftyped($_[0], Math::Prime::Util::GMP::jordan_totient($k, $n)) | 
| 853 | 25 | 50 |  |  |  | 291 | if $Math::Prime::Util::_GMPfunc{"jordan_totient"}; | 
| 854 |  |  |  |  |  |  |  | 
| 855 |  |  |  |  |  |  |  | 
| 856 | 25 |  |  |  |  | 126 | my @pe = Math::Prime::Util::factor_exp($n); | 
| 857 | 25 | 100 |  |  |  | 148 | $n = Math::BigInt->new("$n") unless ref($n) eq 'Math::BigInt'; | 
| 858 | 25 |  |  |  |  | 1048 | my $totient = BONE->copy; | 
| 859 | 25 |  |  |  |  | 571 | foreach my $f (@pe) { | 
| 860 | 38 |  |  |  |  | 187 | my ($p, $e) = @$f; | 
| 861 | 38 |  |  |  |  | 109 | $p = Math::BigInt->new("$p")->bpow($k); | 
| 862 | 38 |  |  |  |  | 12890 | $totient->bmul($p->copy->bdec()); | 
| 863 | 38 |  |  |  |  | 5079 | $totient->bmul($p) for 2 .. $e; | 
| 864 |  |  |  |  |  |  | } | 
| 865 | 25 | 100 |  |  |  | 477 | $totient = _bigint_to_int($totient) if $totient->bacmp(BMAX) <= 0; | 
| 866 | 25 |  |  |  |  | 704 | return $totient; | 
| 867 |  |  |  |  |  |  | } | 
| 868 |  |  |  |  |  |  |  | 
| 869 |  |  |  |  |  |  | sub euler_phi { | 
| 870 | 108 | 100 |  | 108 | 1 | 12537 | return euler_phi_range(@_) if scalar @_ > 1; | 
| 871 | 105 |  |  |  |  | 157 | my($n) = @_; | 
| 872 | 105 | 50 | 33 |  |  | 300 | return 0 if defined $n && $n < 0; | 
| 873 |  |  |  |  |  |  |  | 
| 874 |  |  |  |  |  |  | return Math::Prime::Util::_reftyped($_[0],Math::Prime::Util::GMP::totient($n)) | 
| 875 | 105 | 50 |  |  |  | 407 | if $Math::Prime::Util::_GMPfunc{"totient"}; | 
| 876 |  |  |  |  |  |  |  | 
| 877 | 105 |  |  |  |  | 227 | _validate_positive_integer($n); | 
| 878 | 105 | 100 |  |  |  | 184 | return $n if $n <= 1; | 
| 879 |  |  |  |  |  |  |  | 
| 880 | 101 |  |  |  |  | 264 | my $totient = $n - $n + 1; | 
| 881 |  |  |  |  |  |  |  | 
| 882 |  |  |  |  |  |  | # Fast reduction of multiples of 2, may also reduce n for factoring | 
| 883 | 101 | 100 |  |  |  | 520 | if (ref($n) eq 'Math::BigInt') { | 
| 884 | 1 |  |  |  |  | 5 | my $s = 0; | 
| 885 | 1 | 50 |  |  |  | 5 | if ($n->is_even) { | 
| 886 | 1 |  |  |  |  | 18 | do { $n->brsft(BONE); $s++; } while $n->is_even; | 
|  | 1 |  |  |  |  | 8 |  | 
|  | 1 |  |  |  |  | 138 |  | 
| 887 | 1 | 50 |  |  |  | 15 | $totient->blsft($s-1) if $s > 1; | 
| 888 |  |  |  |  |  |  | } | 
| 889 |  |  |  |  |  |  | } else { | 
| 890 | 100 |  |  |  |  | 194 | while (($n % 4) == 0) { $n >>= 1;  $totient <<= 1; } | 
|  | 49 |  |  |  |  | 64 |  | 
|  | 49 |  |  |  |  | 84 |  | 
| 891 | 100 | 100 |  |  |  | 173 | if (($n % 2) == 0) { $n >>= 1; } | 
|  | 50 |  |  |  |  | 73 |  | 
| 892 |  |  |  |  |  |  | } | 
| 893 |  |  |  |  |  |  |  | 
| 894 | 101 |  |  |  |  | 355 | my @pe = Math::Prime::Util::factor_exp($n); | 
| 895 |  |  |  |  |  |  |  | 
| 896 | 101 | 100 | 100 |  |  | 340 | if ($#pe == 0 && $pe[0]->[1] == 1) { | 
|  |  | 100 |  |  |  |  |  | 
| 897 | 49 | 50 |  |  |  | 94 | if (ref($n) ne 'Math::BigInt') { $totient *= $n-1; } | 
|  | 49 |  |  |  |  | 71 |  | 
| 898 | 0 |  |  |  |  | 0 | else                           { $totient->bmul($n->bdec()); } | 
| 899 |  |  |  |  |  |  | } elsif (ref($n) ne 'Math::BigInt') { | 
| 900 | 51 |  |  |  |  | 94 | foreach my $f (@pe) { | 
| 901 | 83 |  |  |  |  | 138 | my ($p, $e) = @$f; | 
| 902 | 83 |  |  |  |  | 105 | $totient *= $p - 1; | 
| 903 | 83 |  |  |  |  | 165 | $totient *= $p for 2 .. $e; | 
| 904 |  |  |  |  |  |  | } | 
| 905 |  |  |  |  |  |  | } else { | 
| 906 | 1 |  |  |  |  | 5 | my $zero = $n->copy->bzero; | 
| 907 | 1 |  |  |  |  | 53 | foreach my $f (@pe) { | 
| 908 | 10 |  |  |  |  | 26 | my ($p, $e) = @$f; | 
| 909 | 10 |  |  |  |  | 1056 | $p = $zero->copy->badd("$p"); | 
| 910 | 10 |  |  |  |  | 1548 | $totient->bmul($p->copy->bdec()); | 
| 911 | 10 |  |  |  |  | 1279 | $totient->bmul($p) for 2 .. $e; | 
| 912 |  |  |  |  |  |  | } | 
| 913 |  |  |  |  |  |  | } | 
| 914 | 101 | 50 | 66 |  |  | 214 | $totient = _bigint_to_int($totient) if ref($totient) eq 'Math::BigInt' | 
| 915 |  |  |  |  |  |  | && $totient->bacmp(BMAX) <= 0; | 
| 916 | 101 |  |  |  |  | 280 | return $totient; | 
| 917 |  |  |  |  |  |  | } | 
| 918 |  |  |  |  |  |  |  | 
| 919 |  |  |  |  |  |  | sub inverse_totient { | 
| 920 | 0 |  |  | 0 | 0 | 0 | my($n) = @_; | 
| 921 | 0 |  |  |  |  | 0 | _validate_positive_integer($n); | 
| 922 |  |  |  |  |  |  |  | 
| 923 | 0 | 0 |  |  |  | 0 | return wantarray ? (1,2) : 2 if $n == 1; | 
|  |  | 0 |  |  |  |  |  | 
| 924 | 0 | 0 | 0 |  |  | 0 | return wantarray ? () : 0 if $n < 1 || ($n & 1); | 
|  |  | 0 |  |  |  |  |  | 
| 925 |  |  |  |  |  |  |  | 
| 926 | 0 | 0 | 0 |  |  | 0 | $n = Math::Prime::Util::_to_bigint("$n") if !ref($n) && $n > 2**49; | 
| 927 | 0 |  |  |  |  | 0 | my $do_bigint = ref($n); | 
| 928 |  |  |  |  |  |  |  | 
| 929 | 0 | 0 |  |  |  | 0 | if (is_prime($n >> 1)) {   # Coleman Remark 3.3 (Thm 3.1) and Prop 6.2 | 
| 930 | 0 | 0 |  |  |  | 0 | return wantarray ? () : 0             if !is_prime($n+1); | 
|  |  | 0 |  |  |  |  |  | 
| 931 | 0 | 0 |  |  |  | 0 | return wantarray ? ($n+1, 2*$n+2) : 2 if $n >= 10; | 
|  |  | 0 |  |  |  |  |  | 
| 932 |  |  |  |  |  |  | } | 
| 933 |  |  |  |  |  |  |  | 
| 934 | 0 | 0 |  |  |  | 0 | if (!wantarray) { | 
| 935 | 0 |  |  |  |  | 0 | my %r = ( 1 => 1 ); | 
| 936 | 0 |  |  | 0 |  | 0 | Math::Prime::Util::fordivisors(sub { my $d = $_; | 
| 937 | 0 | 0 |  |  |  | 0 | $d = $do_bigint->new("$d") if $do_bigint; | 
| 938 | 0 |  |  |  |  | 0 | my $p = $d+1; | 
| 939 | 0 | 0 |  |  |  | 0 | if (Math::Prime::Util::is_prime($p)) { | 
| 940 | 0 |  |  |  |  | 0 | my($dp,@sumi,@sumv) = ($d); | 
| 941 | 0 |  |  |  |  | 0 | for my $v (1 .. 1 + Math::Prime::Util::valuation($n, $p)) { | 
| 942 | 0 |  |  |  |  | 0 | Math::Prime::Util::fordivisors(sub { my $d2 = $_; | 
| 943 | 0 | 0 |  |  |  | 0 | if (defined $r{$d2}) { push @sumi, $d2*$dp; push @sumv, $r{$d2}; } | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 944 | 0 |  |  |  |  | 0 | }, $n / $dp); | 
| 945 | 0 |  |  |  |  | 0 | $dp *= $p; | 
| 946 |  |  |  |  |  |  | } | 
| 947 | 0 |  |  |  |  | 0 | $r{ $sumi[$_] } += $sumv[$_]  for 0 .. $#sumi; | 
| 948 |  |  |  |  |  |  | } | 
| 949 | 0 |  |  |  |  | 0 | }, $n); | 
| 950 | 0 | 0 |  |  |  | 0 | return (defined $r{$n}) ? $r{$n} : 0; | 
| 951 |  |  |  |  |  |  | } else { | 
| 952 | 0 |  |  |  |  | 0 | my %r = ( 1 => [1] ); | 
| 953 | 0 |  |  | 0 |  | 0 | Math::Prime::Util::fordivisors(sub { my $d = $_; | 
| 954 | 0 | 0 |  |  |  | 0 | $d = $do_bigint->new("$d") if $do_bigint; | 
| 955 | 0 |  |  |  |  | 0 | my $p = $d+1; | 
| 956 | 0 | 0 |  |  |  | 0 | if (Math::Prime::Util::is_prime($p)) { | 
| 957 | 0 |  |  |  |  | 0 | my($dp,$pp,@T) = ($d,$p); | 
| 958 | 0 |  |  |  |  | 0 | for my $v (1 .. 1 + Math::Prime::Util::valuation($n, $p)) { | 
| 959 | 0 |  |  |  |  | 0 | Math::Prime::Util::fordivisors(sub { my $d2 = $_; | 
| 960 | 0 | 0 |  |  |  | 0 | push @T, [ $d2*$dp, [map { $_ * $pp } @{ $r{$d2} }] ] if defined $r{$d2}; | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 961 | 0 |  |  |  |  | 0 | }, $n / $dp); | 
| 962 | 0 |  |  |  |  | 0 | $dp *= $p; | 
| 963 | 0 |  |  |  |  | 0 | $pp *= $p; | 
| 964 |  |  |  |  |  |  | } | 
| 965 | 0 |  |  |  |  | 0 | push @{$r{$_->[0]}}, @{$_->[1]} for @T; | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 966 |  |  |  |  |  |  | } | 
| 967 | 0 |  |  |  |  | 0 | }, $n); | 
| 968 | 0 | 0 |  |  |  | 0 | return () unless defined $r{$n}; | 
| 969 | 0 |  |  |  |  | 0 | delete @r{ grep { $_ != $n } keys %r };  # Delete all intermediate results | 
|  | 0 |  |  |  |  | 0 |  | 
| 970 | 0 |  |  |  |  | 0 | my @result = sort { $a <=> $b } @{$r{$n}}; | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 971 | 0 |  |  |  |  | 0 | return @result; | 
| 972 |  |  |  |  |  |  | } | 
| 973 |  |  |  |  |  |  | } | 
| 974 |  |  |  |  |  |  |  | 
| 975 |  |  |  |  |  |  | sub euler_phi_range { | 
| 976 | 3 |  |  | 3 | 1 | 11 | my($lo, $hi) = @_; | 
| 977 | 3 |  |  |  |  | 13 | _validate_integer($lo); | 
| 978 | 3 |  |  |  |  | 10 | _validate_integer($hi); | 
| 979 |  |  |  |  |  |  |  | 
| 980 | 3 |  |  |  |  | 5 | my @totients; | 
| 981 | 3 |  | 66 |  |  | 20 | while ($lo < 0 && $lo <= $hi) { | 
| 982 | 5 |  |  |  |  | 11 | push @totients, 0; | 
| 983 | 5 |  |  |  |  | 11 | $lo++; | 
| 984 |  |  |  |  |  |  | } | 
| 985 | 3 | 50 |  |  |  | 10 | return @totients if $hi < $lo; | 
| 986 |  |  |  |  |  |  |  | 
| 987 | 3 | 50 | 33 |  |  | 22 | if ($hi > 2**30 || $hi-$lo < 100) { | 
| 988 | 3 |  |  |  |  | 9 | while ($lo <= $hi) { | 
| 989 | 101 |  |  |  |  | 195 | push @totients, euler_phi($lo++); | 
| 990 |  |  |  |  |  |  | } | 
| 991 |  |  |  |  |  |  | } else { | 
| 992 | 0 |  |  |  |  | 0 | my @tot = (0 .. $hi); | 
| 993 | 0 |  |  |  |  | 0 | foreach my $i (2 .. $hi) { | 
| 994 | 0 | 0 |  |  |  | 0 | next unless $tot[$i] == $i; | 
| 995 | 0 |  |  |  |  | 0 | $tot[$i] = $i-1; | 
| 996 | 0 |  |  |  |  | 0 | foreach my $j (2 .. int($hi / $i)) { | 
| 997 | 0 |  |  |  |  | 0 | $tot[$i*$j] -= $tot[$i*$j]/$i; | 
| 998 |  |  |  |  |  |  | } | 
| 999 |  |  |  |  |  |  | } | 
| 1000 | 0 | 0 |  |  |  | 0 | splice(@tot, 0, $lo) if $lo > 0; | 
| 1001 | 0 |  |  |  |  | 0 | push @totients, @tot; | 
| 1002 |  |  |  |  |  |  | } | 
| 1003 | 3 |  |  |  |  | 49 | @totients; | 
| 1004 |  |  |  |  |  |  | } | 
| 1005 |  |  |  |  |  |  |  | 
| 1006 |  |  |  |  |  |  | sub moebius { | 
| 1007 | 102 | 100 |  | 102 | 1 | 9663 | return moebius_range(@_) if scalar @_ > 1; | 
| 1008 | 99 |  |  |  |  | 211 | my($n) = @_; | 
| 1009 | 99 | 50 | 33 |  |  | 428 | $n = -$n if defined $n && $n < 0; | 
| 1010 | 99 | 100 |  |  |  | 1691 | _validate_num($n) || _validate_positive_integer($n); | 
| 1011 | 99 | 0 |  |  |  | 207 | return ($n == 1) ? 1 : 0  if $n <= 1; | 
|  |  | 50 |  |  |  |  |  | 
| 1012 | 99 | 100 | 66 |  |  | 1435 | return 0 if ($n >= 49) && (!($n % 4) || !($n % 9) || !($n % 25) || !($n%49) ); | 
|  |  |  | 100 |  |  |  |  | 
| 1013 | 98 |  |  |  |  | 9816 | my @factors = Math::Prime::Util::factor($n); | 
| 1014 | 98 |  |  |  |  | 280 | foreach my $i (1 .. $#factors) { | 
| 1015 | 106 | 100 |  |  |  | 319 | return 0 if $factors[$i] == $factors[$i-1]; | 
| 1016 |  |  |  |  |  |  | } | 
| 1017 | 66 | 100 |  |  |  | 449 | return ((scalar @factors) % 2) ? -1 : 1; | 
| 1018 |  |  |  |  |  |  | } | 
| 1019 |  |  |  |  |  |  | sub is_square_free { | 
| 1020 | 4 | 100 |  | 4 | 0 | 937 | return (Math::Prime::Util::moebius($_[0]) != 0) ? 1 : 0; | 
| 1021 |  |  |  |  |  |  | } | 
| 1022 |  |  |  |  |  |  | sub is_semiprime { | 
| 1023 | 1 |  |  | 1 | 0 | 5 | my($n) = @_; | 
| 1024 | 1 |  |  |  |  | 4 | _validate_positive_integer($n); | 
| 1025 | 1 | 50 |  |  |  | 4 | return ($n == 4) if $n < 6; | 
| 1026 | 1 | 0 |  |  |  | 143 | return (Math::Prime::Util::is_prob_prime($n>>1) ? 1 : 0) if ($n % 2) == 0; | 
|  |  | 50 |  |  |  |  |  | 
| 1027 | 1 | 0 |  |  |  | 414 | return (Math::Prime::Util::is_prob_prime($n/3)  ? 1 : 0) if ($n % 3) == 0; | 
|  |  | 50 |  |  |  |  |  | 
| 1028 | 1 | 0 |  |  |  | 351 | return (Math::Prime::Util::is_prob_prime($n/5)  ? 1 : 0) if ($n % 5) == 0; | 
|  |  | 50 |  |  |  |  |  | 
| 1029 |  |  |  |  |  |  | { | 
| 1030 | 1 |  |  |  |  | 330 | my @f = trial_factor($n, 4999); | 
|  | 1 |  |  |  |  | 6 |  | 
| 1031 | 1 | 50 |  |  |  | 35 | return 0 if @f > 2; | 
| 1032 | 0 | 0 |  |  |  | 0 | return (_is_prime7($f[1]) ? 1 : 0) if @f == 2; | 
|  |  | 0 |  |  |  |  |  | 
| 1033 |  |  |  |  |  |  | } | 
| 1034 | 0 | 0 |  |  |  | 0 | return 0 if _is_prime7($n); | 
| 1035 |  |  |  |  |  |  | { | 
| 1036 | 0 |  |  |  |  | 0 | my @f = pminus1_factor ($n, 250_000); | 
| 1037 | 0 | 0 |  |  |  | 0 | return 0 if @f > 2; | 
| 1038 | 0 | 0 |  |  |  | 0 | return (_is_prime7($f[1]) ? 1 : 0) if @f == 2; | 
|  |  | 0 |  |  |  |  |  | 
| 1039 |  |  |  |  |  |  | } | 
| 1040 |  |  |  |  |  |  | { | 
| 1041 | 0 |  |  |  |  | 0 | my @f = pbrent_factor ($n, 128*1024, 3, 1); | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 1042 | 0 | 0 |  |  |  | 0 | return 0 if @f > 2; | 
| 1043 | 0 | 0 |  |  |  | 0 | return (_is_prime7($f[1]) ? 1 : 0) if @f == 2; | 
|  |  | 0 |  |  |  |  |  | 
| 1044 |  |  |  |  |  |  | } | 
| 1045 | 0 | 0 |  |  |  | 0 | return (scalar(Math::Prime::Util::factor($n)) == 2) ? 1 : 0; | 
| 1046 |  |  |  |  |  |  | } | 
| 1047 |  |  |  |  |  |  |  | 
| 1048 |  |  |  |  |  |  | sub _totpred { | 
| 1049 | 370 |  |  | 370 |  | 39746 | my($n, $maxd) = @_; | 
| 1050 | 370 | 50 | 100 |  |  | 1865 | return 0 if $maxd <= 1 || (ref($n) ? $n->is_odd() : ($n & 1)); | 
|  |  | 100 |  |  |  |  |  | 
| 1051 | 131 | 50 | 33 |  |  | 2233 | $n = Math::BigInt->new("$n") unless ref($n) || $n < INTMAX; | 
| 1052 | 131 |  |  |  |  | 379 | $n >>= 1; | 
| 1053 | 131 | 100 | 100 |  |  | 27540 | return 1 if $n == 1 || ($n < $maxd && Math::Prime::Util::is_prime(2*$n+1)); | 
|  |  |  | 66 |  |  |  |  | 
| 1054 | 130 |  |  |  |  | 33093 | for my $d (Math::Prime::Util::divisors($n)) { | 
| 1055 | 1001 | 100 |  |  |  | 81061 | last if $d >= $maxd; | 
| 1056 | 881 | 100 |  |  |  | 23015 | my $p = ($d < (INTMAX >> 1))  ?  ($d<<1)+1  :  Math::Prime::Util::vecprod(2,$d)+1; | 
| 1057 | 881 | 100 |  |  |  | 3737 | next unless Math::Prime::Util::is_prime($p); | 
| 1058 | 335 |  |  |  |  | 854 | my $r = int($n / $d); | 
| 1059 | 335 |  |  |  |  | 110429 | while (1) { | 
| 1060 | 368 | 100 | 100 |  |  | 11144 | return 1 if $r == $p || _totpred($r, $d); | 
| 1061 | 364 | 100 |  |  |  | 2041 | last if $r % $p; | 
| 1062 | 33 |  |  |  |  | 7274 | $r = int($r / $p); | 
| 1063 |  |  |  |  |  |  | } | 
| 1064 |  |  |  |  |  |  | } | 
| 1065 | 126 |  |  |  |  | 3770 | 0; | 
| 1066 |  |  |  |  |  |  | } | 
| 1067 |  |  |  |  |  |  | sub is_totient { | 
| 1068 | 3 |  |  | 3 | 0 | 36 | my($n) = @_; | 
| 1069 | 3 |  |  |  |  | 11 | _validate_positive_integer($n); | 
| 1070 | 3 | 50 |  |  |  | 10 | return 1 if $n == 1; | 
| 1071 | 3 | 50 |  |  |  | 373 | return 0 if $n <= 0; | 
| 1072 | 3 |  |  |  |  | 546 | return _totpred($n,$n); | 
| 1073 |  |  |  |  |  |  | } | 
| 1074 |  |  |  |  |  |  |  | 
| 1075 |  |  |  |  |  |  |  | 
| 1076 |  |  |  |  |  |  | sub moebius_range { | 
| 1077 | 6 |  |  | 6 | 1 | 15 | my($lo, $hi) = @_; | 
| 1078 | 6 |  |  |  |  | 18 | _validate_integer($lo); | 
| 1079 | 6 |  |  |  |  | 15 | _validate_integer($hi); | 
| 1080 | 6 | 50 |  |  |  | 19 | return () if $hi < $lo; | 
| 1081 | 6 | 50 |  |  |  | 14 | return moebius($lo) if $lo == $hi; | 
| 1082 | 6 | 100 |  |  |  | 15 | if ($lo < 0) { | 
| 1083 | 2 | 100 |  |  |  | 6 | if ($hi < 0) { | 
| 1084 | 1 |  |  |  |  | 7 | return reverse(moebius_range(-$hi,-$lo)); | 
| 1085 |  |  |  |  |  |  | } else { | 
| 1086 | 1 |  |  |  |  | 3 | return (reverse(moebius_range(1,-$lo)), moebius_range(0,$hi)); | 
| 1087 |  |  |  |  |  |  | } | 
| 1088 |  |  |  |  |  |  | } | 
| 1089 | 4 | 50 |  |  |  | 12 | if ($hi > 2**32) { | 
| 1090 | 0 |  |  |  |  | 0 | my @mu; | 
| 1091 | 0 |  |  |  |  | 0 | while ($lo <= $hi) { | 
| 1092 | 0 |  |  |  |  | 0 | push @mu, moebius($lo++); | 
| 1093 |  |  |  |  |  |  | } | 
| 1094 | 0 |  |  |  |  | 0 | return @mu; | 
| 1095 |  |  |  |  |  |  | } | 
| 1096 | 4 |  |  |  |  | 13 | my @mu = map { 1 } $lo .. $hi; | 
|  | 44 |  |  |  |  | 64 |  | 
| 1097 | 4 | 100 |  |  |  | 14 | $mu[0] = 0 if $lo == 0; | 
| 1098 | 4 |  |  |  |  | 17 | my($p, $sqrtn) = (2, int(sqrt($hi)+0.5)); | 
| 1099 | 4 |  |  |  |  | 13 | while ($p <= $sqrtn) { | 
| 1100 | 14 |  |  |  |  | 24 | my $i = $p * $p; | 
| 1101 | 14 | 100 |  |  |  | 35 | $i = $i * int($lo/$i) + (($lo % $i)  ? $i : 0)  if $i < $lo; | 
|  |  | 100 |  |  |  |  |  | 
| 1102 | 14 |  |  |  |  | 32 | while ($i <= $hi) { | 
| 1103 | 15 |  |  |  |  | 25 | $mu[$i-$lo] = 0; | 
| 1104 | 15 |  |  |  |  | 27 | $i += $p * $p; | 
| 1105 |  |  |  |  |  |  | } | 
| 1106 | 14 |  |  |  |  | 25 | $i = $p; | 
| 1107 | 14 | 100 |  |  |  | 40 | $i = $i * int($lo/$i) + (($lo % $i)  ? $i : 0)  if $i < $lo; | 
|  |  | 100 |  |  |  |  |  | 
| 1108 | 14 |  |  |  |  | 29 | while ($i <= $hi) { | 
| 1109 | 49 |  |  |  |  | 63 | $mu[$i-$lo] *= -$p; | 
| 1110 | 49 |  |  |  |  | 85 | $i += $p; | 
| 1111 |  |  |  |  |  |  | } | 
| 1112 | 14 |  |  |  |  | 38 | $p = next_prime($p); | 
| 1113 |  |  |  |  |  |  | } | 
| 1114 | 4 |  |  |  |  | 14 | foreach my $i ($lo .. $hi) { | 
| 1115 | 44 |  |  |  |  | 57 | my $m = $mu[$i-$lo]; | 
| 1116 | 44 | 100 |  |  |  | 79 | $m *= -1 if abs($m) != $i; | 
| 1117 | 44 |  |  |  |  | 73 | $mu[$i-$lo] = ($m>0) - ($m<0); | 
| 1118 |  |  |  |  |  |  | } | 
| 1119 | 4 |  |  |  |  | 55 | return @mu; | 
| 1120 |  |  |  |  |  |  | } | 
| 1121 |  |  |  |  |  |  |  | 
| 1122 |  |  |  |  |  |  | sub mertens { | 
| 1123 | 1 |  |  | 1 | 0 | 3 | my($n) = @_; | 
| 1124 |  |  |  |  |  |  | # This is the most basic Deléglise and Rivat algorithm.  u = n^1/2 | 
| 1125 |  |  |  |  |  |  | # and no segmenting is done.  Their algorithm uses u = n^1/3, breaks | 
| 1126 |  |  |  |  |  |  | # the summation into two parts, and calculates those in segments.  Their | 
| 1127 |  |  |  |  |  |  | # computation time growth is half of this code. | 
| 1128 | 1 | 50 |  |  |  | 4 | return $n if $n <= 1; | 
| 1129 | 1 |  |  |  |  | 4 | my $u = int(sqrt($n)); | 
| 1130 | 1 |  |  |  |  | 19 | my @mu = (0, Math::Prime::Util::moebius(1, $u)); # Hold values of mu for 0-u | 
| 1131 | 1 |  |  |  |  | 3 | my $musum = 0; | 
| 1132 | 1 |  |  |  |  | 3 | my @M = map { $musum += $_; } @mu;     # Hold values of M for 0-u | 
|  | 65 |  |  |  |  | 91 |  | 
| 1133 | 1 |  |  |  |  | 2 | my $sum = $M[$u]; | 
| 1134 | 1 |  |  |  |  | 4 | foreach my $m (1 .. $u) { | 
| 1135 | 64 | 100 |  |  |  | 110 | next if $mu[$m] == 0; | 
| 1136 | 39 |  |  |  |  | 49 | my $inner_sum = 0; | 
| 1137 | 39 |  |  |  |  | 59 | my $lower = int($u/$m) + 1; | 
| 1138 | 39 |  |  |  |  | 62 | my $last_nmk = int($n/($m*$lower)); | 
| 1139 | 39 |  |  |  |  | 63 | my ($denom, $this_k, $next_k) = ($m, 0, int($n/($m*1))); | 
| 1140 | 39 |  |  |  |  | 60 | for my $nmk (1 .. $last_nmk) { | 
| 1141 | 2048 |  |  |  |  | 2405 | $denom += $m; | 
| 1142 | 2048 |  |  |  |  | 2627 | $this_k = int($n/$denom); | 
| 1143 | 2048 | 100 |  |  |  | 3252 | next if $this_k == $next_k; | 
| 1144 | 982 |  |  |  |  | 1372 | ($this_k, $next_k) = ($next_k, $this_k); | 
| 1145 | 982 |  |  |  |  | 1375 | $inner_sum += $M[$nmk] * ($this_k - $next_k); | 
| 1146 |  |  |  |  |  |  | } | 
| 1147 | 39 |  |  |  |  | 80 | $sum -= $mu[$m] * $inner_sum; | 
| 1148 |  |  |  |  |  |  | } | 
| 1149 | 1 |  |  |  |  | 11 | return $sum; | 
| 1150 |  |  |  |  |  |  | } | 
| 1151 |  |  |  |  |  |  |  | 
| 1152 |  |  |  |  |  |  | sub ramanujan_sum { | 
| 1153 | 0 |  |  | 0 | 0 | 0 | my($k,$n) = @_; | 
| 1154 | 0 | 0 | 0 |  |  | 0 | return 0 if $k < 1 || $n <  1; | 
| 1155 | 0 |  |  |  |  | 0 | my $g = $k / Math::Prime::Util::gcd($k,$n); | 
| 1156 | 0 |  |  |  |  | 0 | my $m = Math::Prime::Util::moebius($g); | 
| 1157 | 0 | 0 | 0 |  |  | 0 | return $m if $m == 0 || $k == $g; | 
| 1158 | 0 |  |  |  |  | 0 | $m * (Math::Prime::Util::euler_phi($k) / Math::Prime::Util::euler_phi($g)); | 
| 1159 |  |  |  |  |  |  | } | 
| 1160 |  |  |  |  |  |  |  | 
| 1161 |  |  |  |  |  |  | sub liouville { | 
| 1162 | 4 |  |  | 4 | 0 | 1057 | my($n) = @_; | 
| 1163 | 4 |  |  |  |  | 28 | my $l = (-1) ** scalar Math::Prime::Util::factor($n); | 
| 1164 | 4 |  |  |  |  | 39 | return $l; | 
| 1165 |  |  |  |  |  |  | } | 
| 1166 |  |  |  |  |  |  |  | 
| 1167 |  |  |  |  |  |  | # Exponential of Mangoldt function (A014963). | 
| 1168 |  |  |  |  |  |  | # Return p if n = p^m [p prime, m >= 1], 1 otherwise. | 
| 1169 |  |  |  |  |  |  | sub exp_mangoldt { | 
| 1170 | 5 |  |  | 5 | 0 | 12 | my($n) = @_; | 
| 1171 | 5 |  |  |  |  | 8 | my $p; | 
| 1172 | 5 | 100 |  |  |  | 38 | return 1 unless Math::Prime::Util::is_prime_power($n,\$p); | 
| 1173 | 3 |  |  |  |  | 14 | $p; | 
| 1174 |  |  |  |  |  |  | } | 
| 1175 |  |  |  |  |  |  |  | 
| 1176 |  |  |  |  |  |  | sub carmichael_lambda { | 
| 1177 | 3 |  |  | 3 | 0 | 1439 | my($n) = @_; | 
| 1178 | 3 | 50 |  |  |  | 16 | return euler_phi($n) if $n < 8;          # = phi(n) for n < 8 | 
| 1179 | 3 | 50 |  |  |  | 258 | return $n >> 2 if ($n & ($n-1)) == 0;    # = phi(n)/2 = n/4 for 2^k, k>2 | 
| 1180 |  |  |  |  |  |  |  | 
| 1181 | 3 |  |  |  |  | 2323 | my @pe = Math::Prime::Util::factor_exp($n); | 
| 1182 | 3 | 50 | 66 |  |  | 25 | $pe[0]->[1]-- if $pe[0]->[0] == 2 && $pe[0]->[1] > 2; | 
| 1183 |  |  |  |  |  |  |  | 
| 1184 | 3 |  |  |  |  | 8 | my $lcm; | 
| 1185 | 3 | 100 |  |  |  | 16 | if (!ref($n)) { | 
| 1186 |  |  |  |  |  |  | $lcm = Math::Prime::Util::lcm( | 
| 1187 | 1 |  |  |  |  | 4 | map { ($_->[0] ** ($_->[1]-1)) * ($_->[0]-1) } @pe | 
|  | 3 |  |  |  |  | 15 |  | 
| 1188 |  |  |  |  |  |  | ); | 
| 1189 |  |  |  |  |  |  | } else { | 
| 1190 |  |  |  |  |  |  | $lcm = Math::BigInt::blcm( | 
| 1191 | 14 |  |  |  |  | 4284 | map { $_->[0]->copy->bpow($_->[1]->copy->bdec)->bmul($_->[0]->copy->bdec) } | 
| 1192 | 2 |  |  |  |  | 7 | map { [ map { Math::BigInt->new("$_") } @$_ ] } | 
|  | 14 |  |  |  |  | 423 |  | 
|  | 28 |  |  |  |  | 603 |  | 
| 1193 |  |  |  |  |  |  | @pe | 
| 1194 |  |  |  |  |  |  | ); | 
| 1195 | 2 | 100 |  |  |  | 2616 | $lcm = _bigint_to_int($lcm) if $lcm->bacmp(BMAX) <= 0; | 
| 1196 |  |  |  |  |  |  | } | 
| 1197 | 3 |  |  |  |  | 81 | $lcm; | 
| 1198 |  |  |  |  |  |  | } | 
| 1199 |  |  |  |  |  |  |  | 
| 1200 |  |  |  |  |  |  | sub is_carmichael { | 
| 1201 | 1 |  |  | 1 | 0 | 5 | my($n) = @_; | 
| 1202 | 1 |  |  |  |  | 6 | _validate_positive_integer($n); | 
| 1203 |  |  |  |  |  |  |  | 
| 1204 |  |  |  |  |  |  | # This works fine, but very slow | 
| 1205 |  |  |  |  |  |  | # return !is_prime($n) && ($n % carmichael_lambda($n)) == 1; | 
| 1206 |  |  |  |  |  |  |  | 
| 1207 | 1 | 50 | 33 |  |  | 6 | return 0 if $n < 561 || ($n % 2) == 0; | 
| 1208 | 1 | 50 | 33 |  |  | 682 | return 0 if (!($n % 9) || !($n % 25) || !($n%49) || !($n%121)); | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
| 1209 |  |  |  |  |  |  |  | 
| 1210 |  |  |  |  |  |  | # Check Korselt's criterion for small divisors | 
| 1211 | 1 |  |  |  |  | 892 | my $fn = $n; | 
| 1212 | 1 |  |  |  |  | 3 | for my $a (5,7,11,13,17,19,23,29,31,37,41,43) { | 
| 1213 | 12 | 50 |  |  |  | 3802 | if (($fn % $a) == 0) { | 
| 1214 | 0 | 0 |  |  |  | 0 | return 0 if (($n-1) % ($a-1)) != 0;   # Korselt | 
| 1215 | 0 |  |  |  |  | 0 | $fn /= $a; | 
| 1216 | 0 | 0 |  |  |  | 0 | return 0 unless $fn % $a;             # not square free | 
| 1217 |  |  |  |  |  |  | } | 
| 1218 |  |  |  |  |  |  | } | 
| 1219 | 1 | 50 |  |  |  | 351 | return 0 if Math::Prime::Util::powmod(2, $n-1, $n) != 1; | 
| 1220 |  |  |  |  |  |  |  | 
| 1221 |  |  |  |  |  |  | # After pre-tests, it's reasonably likely $n is a Carmichael number or prime | 
| 1222 |  |  |  |  |  |  |  | 
| 1223 |  |  |  |  |  |  | # Use probabilistic test if too large to reasonably factor. | 
| 1224 | 1 | 50 |  |  |  | 169 | if (length($fn) > 50) { | 
| 1225 | 0 | 0 |  |  |  | 0 | return 0 if Math::Prime::Util::is_prime($n); | 
| 1226 | 0 |  |  |  |  | 0 | for my $t (13 .. 150) { | 
| 1227 | 0 |  |  |  |  | 0 | my $a = $_primes_small[$t]; | 
| 1228 | 0 |  |  |  |  | 0 | my $gcd = Math::Prime::Util::gcd($a, $fn); | 
| 1229 | 0 | 0 |  |  |  | 0 | if ($gcd == 1) { | 
| 1230 | 0 | 0 |  |  |  | 0 | return 0 if Math::Prime::Util::powmod($a, $n-1, $n) != 1; | 
| 1231 |  |  |  |  |  |  | } else { | 
| 1232 | 0 | 0 |  |  |  | 0 | return 0 if $gcd != $a;              # Not square free | 
| 1233 | 0 | 0 |  |  |  | 0 | return 0 if (($n-1) % ($a-1)) != 0;  # factor doesn't divide | 
| 1234 | 0 |  |  |  |  | 0 | $fn /= $a; | 
| 1235 |  |  |  |  |  |  | } | 
| 1236 |  |  |  |  |  |  | } | 
| 1237 | 0 |  |  |  |  | 0 | return 1; | 
| 1238 |  |  |  |  |  |  | } | 
| 1239 |  |  |  |  |  |  |  | 
| 1240 |  |  |  |  |  |  | # Verify with factoring. | 
| 1241 | 1 |  |  |  |  | 39 | my @pe = Math::Prime::Util::factor_exp($n); | 
| 1242 | 1 | 50 |  |  |  | 7 | return 0 if scalar(@pe) < 3; | 
| 1243 | 1 |  |  |  |  | 5 | for my $pe (@pe) { | 
| 1244 | 3 | 50 | 33 |  |  | 1759 | return 0 if $pe->[1] > 1 || (($n-1) % ($pe->[0]-1)) != 0; | 
| 1245 |  |  |  |  |  |  | } | 
| 1246 | 1 |  |  |  |  | 756 | 1; | 
| 1247 |  |  |  |  |  |  | } | 
| 1248 |  |  |  |  |  |  |  | 
| 1249 |  |  |  |  |  |  | sub is_quasi_carmichael { | 
| 1250 | 0 |  |  | 0 | 0 | 0 | my($n) = @_; | 
| 1251 | 0 |  |  |  |  | 0 | _validate_positive_integer($n); | 
| 1252 |  |  |  |  |  |  |  | 
| 1253 | 0 | 0 |  |  |  | 0 | return 0 if $n < 35; | 
| 1254 | 0 | 0 | 0 |  |  | 0 | return 0 if (!($n % 4) || !($n % 9) || !($n % 25) || !($n%49) || !($n%121)); | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
| 1255 |  |  |  |  |  |  |  | 
| 1256 | 0 |  |  |  |  | 0 | my @pe = Math::Prime::Util::factor_exp($n); | 
| 1257 |  |  |  |  |  |  | # Not quasi-Carmichael if prime | 
| 1258 | 0 | 0 |  |  |  | 0 | return 0 if scalar(@pe) < 2; | 
| 1259 |  |  |  |  |  |  | # Not quasi-Carmichael if not square free | 
| 1260 | 0 |  |  |  |  | 0 | for my $pe (@pe) { | 
| 1261 | 0 | 0 |  |  |  | 0 | return 0 if $pe->[1] > 1; | 
| 1262 |  |  |  |  |  |  | } | 
| 1263 | 0 |  |  |  |  | 0 | my @f = map { $_->[0] } @pe; | 
|  | 0 |  |  |  |  | 0 |  | 
| 1264 | 0 |  |  |  |  | 0 | my $nbases = 0; | 
| 1265 | 0 | 0 |  |  |  | 0 | if ($n < 2000) { | 
| 1266 |  |  |  |  |  |  | # In theory for performance, but mainly keeping to show direct method. | 
| 1267 | 0 |  |  |  |  | 0 | my $lim = $f[-1]; | 
| 1268 | 0 |  |  |  |  | 0 | $lim = (($n-$lim*$lim) + $lim - 1) / $lim; | 
| 1269 | 0 |  |  |  |  | 0 | for my $b (1 .. $f[0]-1) { | 
| 1270 | 0 |  |  |  |  | 0 | my $nb = $n - $b; | 
| 1271 | 0 | 0 |  | 0 |  | 0 | $nbases++ if Math::Prime::Util::vecall(sub { $nb % ($_-$b) == 0 }, @f); | 
|  | 0 |  |  |  |  | 0 |  | 
| 1272 |  |  |  |  |  |  | } | 
| 1273 | 0 | 0 |  |  |  | 0 | if (scalar(@f) > 2) { | 
| 1274 | 0 |  |  |  |  | 0 | for my $b (1 .. $lim-1) { | 
| 1275 | 0 |  |  |  |  | 0 | my $nb = $n + $b; | 
| 1276 | 0 | 0 |  | 0 |  | 0 | $nbases++ if Math::Prime::Util::vecall(sub { $nb % ($_+$b) == 0 }, @f); | 
|  | 0 |  |  |  |  | 0 |  | 
| 1277 |  |  |  |  |  |  | } | 
| 1278 |  |  |  |  |  |  | } | 
| 1279 |  |  |  |  |  |  | } else { | 
| 1280 | 0 |  |  |  |  | 0 | my($spf,$lpf) = ($f[0], $f[-1]); | 
| 1281 | 0 | 0 |  |  |  | 0 | if (scalar(@f) == 2) { | 
| 1282 | 0 |  |  |  |  | 0 | foreach my $d (Math::Prime::Util::divisors($n/$spf - 1)) { | 
| 1283 | 0 |  |  |  |  | 0 | my $k = $spf - $d; | 
| 1284 | 0 |  |  |  |  | 0 | my $p = $n - $k; | 
| 1285 | 0 | 0 |  |  |  | 0 | last if $d >= $spf; | 
| 1286 | 0 | 0 |  | 0 |  | 0 | $nbases++ if Math::Prime::Util::vecall(sub { my $j = $_-$k;  $j && ($p % $j) == 0 }, @f); | 
|  | 0 | 0 |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 1287 |  |  |  |  |  |  | } | 
| 1288 |  |  |  |  |  |  | } else { | 
| 1289 | 0 |  |  |  |  | 0 | foreach my $d (Math::Prime::Util::divisors($lpf * ($n/$lpf - 1))) { | 
| 1290 | 0 |  |  |  |  | 0 | my $k = $lpf - $d; | 
| 1291 | 0 |  |  |  |  | 0 | my $p = $n - $k; | 
| 1292 | 0 | 0 | 0 |  |  | 0 | next if $k == 0 || $k >= $spf; | 
| 1293 | 0 | 0 |  | 0 |  | 0 | $nbases++ if Math::Prime::Util::vecall(sub { my $j = $_-$k;  $j && ($p % $j) == 0 }, @f); | 
|  | 0 | 0 |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 1294 |  |  |  |  |  |  | } | 
| 1295 |  |  |  |  |  |  | } | 
| 1296 |  |  |  |  |  |  | } | 
| 1297 | 0 |  |  |  |  | 0 | $nbases; | 
| 1298 |  |  |  |  |  |  | } | 
| 1299 |  |  |  |  |  |  |  | 
| 1300 |  |  |  |  |  |  | sub is_pillai { | 
| 1301 | 0 |  |  | 0 | 0 | 0 | my($p) = @_; | 
| 1302 | 0 | 0 | 0 |  |  | 0 | return 0 if defined($p) && int($p) < 0; | 
| 1303 | 0 |  |  |  |  | 0 | _validate_positive_integer($p); | 
| 1304 | 0 | 0 |  |  |  | 0 | return 0 if $p <= 2; | 
| 1305 |  |  |  |  |  |  |  | 
| 1306 | 0 |  |  |  |  | 0 | my $pm1 = $p-1; | 
| 1307 | 0 |  |  |  |  | 0 | my $nfac = 5040 % $p; | 
| 1308 | 0 |  |  |  |  | 0 | for (my $n = 8; $n < $p; $n++) { | 
| 1309 | 0 |  |  |  |  | 0 | $nfac = Math::Prime::Util::mulmod($nfac, $n, $p); | 
| 1310 | 0 | 0 | 0 |  |  | 0 | return $n if $nfac == $pm1 && ($p % $n) != 1; | 
| 1311 |  |  |  |  |  |  | } | 
| 1312 | 0 |  |  |  |  | 0 | 0; | 
| 1313 |  |  |  |  |  |  | } | 
| 1314 |  |  |  |  |  |  |  | 
| 1315 |  |  |  |  |  |  | sub is_fundamental { | 
| 1316 | 2 |  |  | 2 | 0 | 23 | my($n) = @_; | 
| 1317 | 2 |  |  |  |  | 11 | _validate_integer($n); | 
| 1318 | 2 |  |  |  |  | 9 | my $neg = ($n < 0); | 
| 1319 | 2 | 100 |  |  |  | 458 | $n = -$n if $neg; | 
| 1320 | 2 |  |  |  |  | 54 | my $r = $n & 15; | 
| 1321 | 2 | 50 |  |  |  | 751 | if ($r) { | 
| 1322 | 2 |  |  |  |  | 64 | my $r4 = $r & 3; | 
| 1323 | 2 | 100 |  |  |  | 478 | if (!$neg) { | 
| 1324 | 1 | 0 |  |  |  | 4 | return (($r ==  4) ? 0 : is_square_free($n >> 2)) if $r4 == 0; | 
|  |  | 50 |  |  |  |  |  | 
| 1325 | 1 | 50 |  |  |  | 172 | return is_square_free($n) if $r4 == 1; | 
| 1326 |  |  |  |  |  |  | } else { | 
| 1327 | 1 | 50 |  |  |  | 5 | return (($r == 12) ? 0 : is_square_free($n >> 2)) if $r4 == 0; | 
|  |  | 50 |  |  |  |  |  | 
| 1328 | 0 | 0 |  |  |  | 0 | return is_square_free($n) if $r4 == 3; | 
| 1329 |  |  |  |  |  |  | } | 
| 1330 |  |  |  |  |  |  | } | 
| 1331 | 0 |  |  |  |  | 0 | 0; | 
| 1332 |  |  |  |  |  |  | } | 
| 1333 |  |  |  |  |  |  |  | 
| 1334 |  |  |  |  |  |  | my @_ds_overflow =  # We'll use BigInt math if the input is larger than this. | 
| 1335 |  |  |  |  |  |  | (~0 > 4294967295) | 
| 1336 |  |  |  |  |  |  | ? (124, 3000000000000000000, 3000000000, 2487240, 64260, 7026) | 
| 1337 |  |  |  |  |  |  | : ( 50,           845404560,      52560,    1548,   252,   84); | 
| 1338 |  |  |  |  |  |  | sub divisor_sum { | 
| 1339 | 920 |  |  | 920 | 0 | 66985 | my($n, $k) = @_; | 
| 1340 | 920 | 0 | 0 |  |  | 2109 | return ((defined $k && $k==0) ? 2 : 1) if $n == 0; | 
|  |  | 50 |  |  |  |  |  | 
| 1341 | 920 | 100 |  |  |  | 3253 | return 1 if $n == 1; | 
| 1342 |  |  |  |  |  |  |  | 
| 1343 | 836 | 100 | 100 |  |  | 3923 | if (defined $k && ref($k) eq 'CODE') { | 
| 1344 | 831 |  |  |  |  | 1275 | my $sum = $n-$n; | 
| 1345 | 831 |  |  |  |  | 1481 | my $refn = ref($n); | 
| 1346 | 831 |  |  |  |  | 3712 | foreach my $d (Math::Prime::Util::divisors($n)) { | 
| 1347 | 3486 | 100 |  |  |  | 20699 | $sum += $k->( $refn ? $refn->new("$d") : $d ); | 
| 1348 |  |  |  |  |  |  | } | 
| 1349 | 831 |  |  |  |  | 7205 | return $sum; | 
| 1350 |  |  |  |  |  |  | } | 
| 1351 |  |  |  |  |  |  |  | 
| 1352 | 5 | 50 | 100 |  |  | 28 | croak "Second argument must be a code ref or number" | 
|  |  |  | 66 |  |  |  |  | 
| 1353 |  |  |  |  |  |  | unless !defined $k || _validate_num($k) || _validate_positive_integer($k); | 
| 1354 | 5 | 100 |  |  |  | 16 | $k = 1 if !defined $k; | 
| 1355 |  |  |  |  |  |  |  | 
| 1356 |  |  |  |  |  |  | return Math::Prime::Util::_reftyped($_[0], Math::Prime::Util::GMP::sigma($n, $k)) | 
| 1357 | 5 | 50 |  |  |  | 18 | if $Math::Prime::Util::_GMPfunc{"sigma"}; | 
| 1358 |  |  |  |  |  |  |  | 
| 1359 | 5 | 50 |  |  |  | 36 | my $will_overflow = ($k == 0) ? (length($n) >= $_ds_overflow[0]) | 
|  |  | 100 |  |  |  |  |  | 
| 1360 |  |  |  |  |  |  | : ($k <= 5) ? ($n >= $_ds_overflow[$k]) | 
| 1361 |  |  |  |  |  |  | : 1; | 
| 1362 |  |  |  |  |  |  |  | 
| 1363 |  |  |  |  |  |  | # The standard way is: | 
| 1364 |  |  |  |  |  |  | #    my $pk = $f ** $k;  $product *= ($pk ** ($e+1) - 1) / ($pk - 1); | 
| 1365 |  |  |  |  |  |  | # But we get less overflow using: | 
| 1366 |  |  |  |  |  |  | #    my $pk = $f ** $k;  $product *= $pk**E for E in 0 .. e | 
| 1367 |  |  |  |  |  |  | # Also separate BigInt and do fiddly bits for better performance. | 
| 1368 |  |  |  |  |  |  |  | 
| 1369 | 5 |  |  |  |  | 504 | my @factors = Math::Prime::Util::factor_exp($n); | 
| 1370 | 5 |  |  |  |  | 13 | my $product = 1; | 
| 1371 | 5 |  |  |  |  | 10 | my @fm; | 
| 1372 | 5 | 100 | 33 |  |  | 48 | if ($k == 0) { | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 1373 | 2 |  |  |  |  | 9 | $product = Math::Prime::Util::vecprod(map { $_->[1]+1 } @factors); | 
|  | 98 |  |  |  |  | 304 |  | 
| 1374 |  |  |  |  |  |  | } elsif (!$will_overflow) { | 
| 1375 | 0 |  |  |  |  | 0 | foreach my $f (@factors) { | 
| 1376 | 0 |  |  |  |  | 0 | my ($p, $e) = @$f; | 
| 1377 | 0 |  |  |  |  | 0 | my $pk = $p ** $k; | 
| 1378 | 0 |  |  |  |  | 0 | my $fmult = $pk + 1; | 
| 1379 | 0 |  |  |  |  | 0 | foreach my $E (2 .. $e) { $fmult += $pk**$E } | 
|  | 0 |  |  |  |  | 0 |  | 
| 1380 | 0 |  |  |  |  | 0 | $product *= $fmult; | 
| 1381 |  |  |  |  |  |  | } | 
| 1382 |  |  |  |  |  |  | } elsif (ref($n) && ref($n) ne 'Math::BigInt') { | 
| 1383 |  |  |  |  |  |  | # This can help a lot for Math::GMP, etc. | 
| 1384 | 0 |  |  |  |  | 0 | $product = ref($n)->new(1); | 
| 1385 | 0 |  |  |  |  | 0 | foreach my $f (@factors) { | 
| 1386 | 0 |  |  |  |  | 0 | my ($p, $e) = @$f; | 
| 1387 | 0 |  |  |  |  | 0 | my $pk = ref($n)->new($p) ** $k; | 
| 1388 | 0 |  |  |  |  | 0 | my $fmult = $pk;  $fmult++; | 
|  | 0 |  |  |  |  | 0 |  | 
| 1389 | 0 | 0 |  |  |  | 0 | if ($e >= 2) { | 
| 1390 | 0 |  |  |  |  | 0 | my $pke = $pk; | 
| 1391 | 0 |  |  |  |  | 0 | for (2 .. $e) { $pke *= $pk; $fmult += $pke; } | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 1392 |  |  |  |  |  |  | } | 
| 1393 | 0 |  |  |  |  | 0 | $product *= $fmult; | 
| 1394 |  |  |  |  |  |  | } | 
| 1395 |  |  |  |  |  |  | } elsif ($k == 1) { | 
| 1396 | 2 |  |  |  |  | 8 | foreach my $f (@factors) { | 
| 1397 | 52 |  |  |  |  | 100 | my ($p, $e) = @$f; | 
| 1398 | 52 |  |  |  |  | 140 | my $pk = Math::BigInt->new("$p"); | 
| 1399 | 52 | 100 |  |  |  | 1979 | if ($e == 1) { push @fm, $pk->binc; next; } | 
|  | 37 |  |  |  |  | 84 |  | 
|  | 37 |  |  |  |  | 1367 |  | 
| 1400 | 15 |  |  |  |  | 35 | my $fmult = $pk->copy->binc; | 
| 1401 | 15 |  |  |  |  | 839 | my $pke = $pk->copy; | 
| 1402 | 15 |  |  |  |  | 331 | for my $E (2 .. $e) { | 
| 1403 | 214 |  |  |  |  | 11401 | $pke->bmul($pk); | 
| 1404 | 214 |  |  |  |  | 12183 | $fmult->badd($pke); | 
| 1405 |  |  |  |  |  |  | } | 
| 1406 | 15 |  |  |  |  | 889 | push @fm, $fmult; | 
| 1407 |  |  |  |  |  |  | } | 
| 1408 | 2 |  |  |  |  | 23 | $product = Math::Prime::Util::vecprod(@fm); | 
| 1409 |  |  |  |  |  |  | } else { | 
| 1410 | 1 |  |  |  |  | 6 | my $bik = Math::BigInt->new("$k"); | 
| 1411 | 1 |  |  |  |  | 48 | foreach my $f (@factors) { | 
| 1412 | 27 |  |  |  |  | 53 | my ($p, $e) = @$f; | 
| 1413 | 27 |  |  |  |  | 79 | my $pk = Math::BigInt->new("$p")->bpow($bik); | 
| 1414 | 27 | 50 |  |  |  | 6027 | if ($e == 1) { push @fm, $pk->binc; next; } | 
|  | 27 |  |  |  |  | 67 |  | 
|  | 27 |  |  |  |  | 983 |  | 
| 1415 | 0 |  |  |  |  | 0 | my $fmult = $pk->copy->binc; | 
| 1416 | 0 |  |  |  |  | 0 | my $pke = $pk->copy; | 
| 1417 | 0 |  |  |  |  | 0 | for my $E (2 .. $e) { | 
| 1418 | 0 |  |  |  |  | 0 | $pke->bmul($pk); | 
| 1419 | 0 |  |  |  |  | 0 | $fmult->badd($pke); | 
| 1420 |  |  |  |  |  |  | } | 
| 1421 | 0 |  |  |  |  | 0 | push @fm, $fmult; | 
| 1422 |  |  |  |  |  |  | } | 
| 1423 | 1 |  |  |  |  | 7 | $product = Math::Prime::Util::vecprod(@fm); | 
| 1424 |  |  |  |  |  |  | } | 
| 1425 | 5 |  |  |  |  | 103 | $product; | 
| 1426 |  |  |  |  |  |  | } | 
| 1427 |  |  |  |  |  |  |  | 
| 1428 |  |  |  |  |  |  | ############################################################################# | 
| 1429 |  |  |  |  |  |  | #                       Lehmer prime count | 
| 1430 |  |  |  |  |  |  | # | 
| 1431 |  |  |  |  |  |  | #my @_s0 = (0); | 
| 1432 |  |  |  |  |  |  | #my @_s1 = (0,1); | 
| 1433 |  |  |  |  |  |  | #my @_s2 = (0,1,1,1,1,2); | 
| 1434 |  |  |  |  |  |  | my @_s3 = (0,1,1,1,1,1,1,2,2,2,2,3,3,4,4,4,4,5,5,6,6,6,6,7,7,7,7,7,7,8); | 
| 1435 |  |  |  |  |  |  | my @_s4 = (0,1,1,1,1,1,1,1,1,1,1,2,2,3,3,3,3,4,4,5,5,5,5,6,6,6,6,6,6,7,7,8,8,8,8,8,8,9,9,9,9,10,10,11,11,11,11,12,12,12,12,12,12,13,13,13,13,13,13,14,14,15,15,15,15,15,15,16,16,16,16,17,17,18,18,18,18,18,18,19,19,19,19,20,20,20,20,20,20,21,21,21,21,21,21,21,21,22,22,22,22,23,23,24,24,24,24,25,25,26,26,26,26,27,27,27,27,27,27,27,27,28,28,28,28,28,28,29,29,29,29,30,30,30,30,30,30,31,31,32,32,32,32,33,33,33,33,33,33,34,34,35,35,35,35,35,35,36,36,36,36,36,36,37,37,37,37,38,38,39,39,39,39,40,40,40,40,40,40,41,41,42,42,42,42,42,42,43,43,43,43,44,44,45,45,45,45,46,46,47,47,47,47,47,47,47,47,47,47,48); | 
| 1436 |  |  |  |  |  |  | sub _tablephi { | 
| 1437 | 1089 |  |  | 1089 |  | 1528 | my($x, $a) = @_; | 
| 1438 | 1089 | 50 |  |  |  | 2932 | if ($a == 0) { return $x; } | 
|  | 0 | 50 |  |  |  | 0 |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 1439 | 0 |  |  |  |  | 0 | elsif ($a == 1) { return $x-int($x/2); } | 
| 1440 | 0 |  |  |  |  | 0 | elsif ($a == 2) { return $x-int($x/2) - int($x/3) + int($x/6); } | 
| 1441 | 3 |  |  |  |  | 20 | elsif ($a == 3) { return  8 * int($x /  30) + $_s3[$x %  30]; } | 
| 1442 | 5 |  |  |  |  | 30 | elsif ($a == 4) { return 48 * int($x / 210) + $_s4[$x % 210]; } | 
| 1443 | 0 |  |  |  |  | 0 | elsif ($a == 5) { my $xp = int($x/11); | 
| 1444 | 0 |  |  |  |  | 0 | return ( (48 * int($x   / 210) + $_s4[$x   % 210]) - | 
| 1445 |  |  |  |  |  |  | (48 * int($xp  / 210) + $_s4[$xp  % 210]) ); } | 
| 1446 | 1081 |  |  |  |  | 1969 | else            { my ($xp,$x2) = (int($x/11),int($x/13)); | 
| 1447 | 1081 |  |  |  |  | 1577 | my $x2p = int($x2/11); | 
| 1448 | 1081 |  |  |  |  | 4144 | return ( (48 * int($x   / 210) + $_s4[$x   % 210]) - | 
| 1449 |  |  |  |  |  |  | (48 * int($xp  / 210) + $_s4[$xp  % 210]) - | 
| 1450 |  |  |  |  |  |  | (48 * int($x2  / 210) + $_s4[$x2  % 210]) + | 
| 1451 |  |  |  |  |  |  | (48 * int($x2p / 210) + $_s4[$x2p % 210]) ); } | 
| 1452 |  |  |  |  |  |  | } | 
| 1453 |  |  |  |  |  |  |  | 
| 1454 |  |  |  |  |  |  | sub legendre_phi { | 
| 1455 | 21 |  |  | 21 | 0 | 70 | my ($x, $a, $primes) = @_; | 
| 1456 | 21 | 100 |  |  |  | 86 | return _tablephi($x,$a) if $a <= 6; | 
| 1457 | 10 | 50 |  |  |  | 42 | $primes = primes(Math::Prime::Util::nth_prime_upper($a+1)) unless defined $primes; | 
| 1458 | 10 | 0 |  |  |  | 44 | return ($x > 0 ? 1 : 0) if $x < $primes->[$a]; | 
|  |  | 50 |  |  |  |  |  | 
| 1459 |  |  |  |  |  |  |  | 
| 1460 | 10 |  |  |  |  | 19 | my $sum = 0; | 
| 1461 | 10 |  |  |  |  | 54 | my %vals = ( $x => 1 ); | 
| 1462 | 10 |  |  |  |  | 38 | while ($a > 6) { | 
| 1463 | 71 |  |  |  |  | 146 | my $primea = $primes->[$a-1]; | 
| 1464 | 71 |  |  |  |  | 99 | my %newvals; | 
| 1465 | 71 |  |  |  |  | 189 | while (my($v,$c) = each %vals) { | 
| 1466 | 2212 |  |  |  |  | 3722 | my $sval = int($v / $primea); | 
| 1467 | 2212 | 100 |  |  |  | 3192 | if ($sval < $primea) { | 
| 1468 | 1011 |  |  |  |  | 2191 | $sum -= $c; | 
| 1469 |  |  |  |  |  |  | } else { | 
| 1470 | 1201 |  |  |  |  | 3722 | $newvals{$sval} -= $c; | 
| 1471 |  |  |  |  |  |  | } | 
| 1472 |  |  |  |  |  |  | } | 
| 1473 |  |  |  |  |  |  | # merge newvals into vals | 
| 1474 | 71 |  |  |  |  | 181 | while (my($v,$c) = each %newvals) { | 
| 1475 | 1114 |  |  |  |  | 1638 | $vals{$v} += $c; | 
| 1476 | 1114 | 50 |  |  |  | 2693 | delete $vals{$v} if $vals{$v} == 0; | 
| 1477 |  |  |  |  |  |  | } | 
| 1478 | 71 |  |  |  |  | 213 | $a--; | 
| 1479 |  |  |  |  |  |  | } | 
| 1480 | 10 |  |  |  |  | 43 | while (my($v,$c) = each %vals) { | 
| 1481 | 1078 |  |  |  |  | 1727 | $sum += $c * _tablephi($v, $a); | 
| 1482 |  |  |  |  |  |  | } | 
| 1483 | 10 |  |  |  |  | 120 | return $sum; | 
| 1484 |  |  |  |  |  |  | } | 
| 1485 |  |  |  |  |  |  |  | 
| 1486 |  |  |  |  |  |  | sub _sieve_prime_count { | 
| 1487 | 61 |  |  | 61 |  | 99 | my $high = shift; | 
| 1488 | 61 | 100 |  |  |  | 138 | return (0,0,1,2,2,3,3)[$high] if $high < 7; | 
| 1489 | 58 | 100 |  |  |  | 142 | $high-- unless ($high & 1); | 
| 1490 | 58 |  |  |  |  | 81 | return 1 + ${_sieve_erat($high)} =~ tr/0//; | 
|  | 58 |  |  |  |  | 120 |  | 
| 1491 |  |  |  |  |  |  | } | 
| 1492 |  |  |  |  |  |  |  | 
| 1493 |  |  |  |  |  |  | sub _count_with_sieve { | 
| 1494 | 8427 |  |  | 8427 |  | 13259 | my ($sref, $low, $high) = @_; | 
| 1495 | 8427 | 100 |  |  |  | 15198 | ($low, $high) = (2, $low) if !defined $high; | 
| 1496 | 8427 |  |  |  |  | 10432 | my $count = 0; | 
| 1497 | 8427 | 100 |  |  |  | 12499 | if   ($low < 3) { $low = 3; $count++; } | 
|  | 5458 |  |  |  |  | 6597 |  | 
|  | 5458 |  |  |  |  | 6513 |  | 
| 1498 | 2969 |  |  |  |  | 3748 | else            { $low |= 1; } | 
| 1499 | 8427 | 100 |  |  |  | 13697 | $high-- unless ($high & 1); | 
| 1500 | 8427 | 50 |  |  |  | 13052 | return $count if $low > $high; | 
| 1501 | 8427 |  |  |  |  | 11230 | my $sbeg = $low >> 1; | 
| 1502 | 8427 |  |  |  |  | 10267 | my $send = $high >> 1; | 
| 1503 |  |  |  |  |  |  |  | 
| 1504 | 8427 | 100 | 66 |  |  | 22390 | if ( !defined $sref || $send >= length($$sref) ) { | 
| 1505 |  |  |  |  |  |  | # outside our range, so call the segment siever. | 
| 1506 | 498 |  |  |  |  | 914 | my $seg_ref = _sieve_segment($low, $high); | 
| 1507 | 498 |  |  |  |  | 2053 | return $count + $$seg_ref =~ tr/0//; | 
| 1508 |  |  |  |  |  |  | } | 
| 1509 | 7929 |  |  |  |  | 20134 | return $count + substr($$sref, $sbeg, $send-$sbeg+1) =~ tr/0//; | 
| 1510 |  |  |  |  |  |  | } | 
| 1511 |  |  |  |  |  |  |  | 
| 1512 |  |  |  |  |  |  | sub _lehmer_pi { | 
| 1513 | 76 |  |  | 76 |  | 897 | my $x = shift; | 
| 1514 | 76 | 100 |  |  |  | 212 | return _sieve_prime_count($x) if $x < 1_000; | 
| 1515 | 21 | 50 |  |  |  | 67 | do { require Math::BigFloat; Math::BigFloat->import(); } | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 1516 |  |  |  |  |  |  | if ref($x) eq 'Math::BigInt'; | 
| 1517 | 21 | 50 |  |  |  | 89 | my $z = (ref($x) ne 'Math::BigInt') | 
| 1518 |  |  |  |  |  |  | ? int(sqrt($x+0.5)) | 
| 1519 |  |  |  |  |  |  | : int(Math::BigFloat->new($x)->badd(0.5)->bsqrt->bfloor->bstr); | 
| 1520 | 21 |  |  |  |  | 102 | my $a = _lehmer_pi(int(sqrt($z)+0.5)); | 
| 1521 | 21 |  |  |  |  | 48 | my $b = _lehmer_pi($z); | 
| 1522 | 21 | 50 |  |  |  | 148 | my $c = _lehmer_pi(int( (ref($x) ne 'Math::BigInt') | 
| 1523 |  |  |  |  |  |  | ? $x**(1/3)+0.5 | 
| 1524 |  |  |  |  |  |  | : Math::BigFloat->new($x)->broot(3)->badd(0.5)->bfloor | 
| 1525 |  |  |  |  |  |  | )); | 
| 1526 | 21 | 50 |  |  |  | 61 | ($z, $a, $b, $c) = map { (ref($_) =~ /^Math::Big/) ? _bigint_to_int($_) : $_ } | 
|  | 84 |  |  |  |  | 211 |  | 
| 1527 |  |  |  |  |  |  | ($z, $a, $b, $c); | 
| 1528 |  |  |  |  |  |  |  | 
| 1529 |  |  |  |  |  |  | # Generate at least b primes. | 
| 1530 | 21 | 50 |  |  |  | 120 | my $bth_prime_upper = ($b <= 10) ? 29 : int($b*(log($b) + log(log($b)))) + 1; | 
| 1531 | 21 |  |  |  |  | 83 | my $primes = primes( $bth_prime_upper ); | 
| 1532 |  |  |  |  |  |  |  | 
| 1533 | 21 |  |  |  |  | 92 | my $sum = int(($b + $a - 2) * ($b - $a + 1) / 2); | 
| 1534 | 21 |  |  |  |  | 90 | $sum += legendre_phi($x, $a, $primes); | 
| 1535 |  |  |  |  |  |  |  | 
| 1536 |  |  |  |  |  |  | # Get a big sieve for our primecounts.  The C code compromises with either | 
| 1537 |  |  |  |  |  |  | # b*10 or x^3/5, as that cuts out all the inner loop sieves and about half | 
| 1538 |  |  |  |  |  |  | # of the big outer loop counts. | 
| 1539 |  |  |  |  |  |  | # Our sieve count isn't nearly as optimized here, so error on the side of | 
| 1540 |  |  |  |  |  |  | # more primes.  This uses a lot more memory but saves a lot of time. | 
| 1541 | 21 |  |  |  |  | 102 | my $sref = _sieve_erat( int($x / $primes->[$a] / 5) ); | 
| 1542 |  |  |  |  |  |  |  | 
| 1543 | 21 |  |  |  |  | 68 | my ($lastw, $lastwpc) = (0,0); | 
| 1544 | 21 |  |  |  |  | 242 | foreach my $i (reverse $a+1 .. $b) { | 
| 1545 | 2990 |  |  |  |  | 5427 | my $w = int($x / $primes->[$i-1]); | 
| 1546 | 2990 |  |  |  |  | 4805 | $lastwpc += _count_with_sieve($sref,$lastw+1, $w); | 
| 1547 | 2990 |  |  |  |  | 4111 | $lastw = $w; | 
| 1548 | 2990 |  |  |  |  | 3584 | $sum -= $lastwpc; | 
| 1549 |  |  |  |  |  |  | #$sum -= _count_with_sieve($sref,$w); | 
| 1550 | 2990 | 100 |  |  |  | 5279 | if ($i <= $c) { | 
| 1551 | 252 |  |  |  |  | 703 | my $bi = _count_with_sieve($sref,int(sqrt($w)+0.5)); | 
| 1552 | 252 |  |  |  |  | 673 | foreach my $j ($i .. $bi) { | 
| 1553 | 5185 |  |  |  |  | 10305 | $sum = $sum - _count_with_sieve($sref,int($w / $primes->[$j-1])) + $j - 1; | 
| 1554 |  |  |  |  |  |  | } | 
| 1555 |  |  |  |  |  |  | } | 
| 1556 |  |  |  |  |  |  | } | 
| 1557 | 21 |  |  |  |  | 274 | $sum; | 
| 1558 |  |  |  |  |  |  | } | 
| 1559 |  |  |  |  |  |  | ############################################################################# | 
| 1560 |  |  |  |  |  |  |  | 
| 1561 |  |  |  |  |  |  |  | 
| 1562 |  |  |  |  |  |  | sub prime_count { | 
| 1563 | 20 |  |  | 20 | 0 | 13117 | my($low,$high) = @_; | 
| 1564 | 20 | 100 |  |  |  | 80 | if (!defined $high) { | 
| 1565 | 7 |  |  |  |  | 15 | $high = $low; | 
| 1566 | 7 |  |  |  |  | 13 | $low = 2; | 
| 1567 |  |  |  |  |  |  | } | 
| 1568 | 20 |  |  |  |  | 77 | _validate_positive_integer($low); | 
| 1569 | 20 |  |  |  |  | 50 | _validate_positive_integer($high); | 
| 1570 |  |  |  |  |  |  |  | 
| 1571 | 20 |  |  |  |  | 45 | my $count = 0; | 
| 1572 |  |  |  |  |  |  |  | 
| 1573 | 20 | 100 | 100 |  |  | 89 | $count++ if ($low <= 2) && ($high >= 2);   # Count 2 | 
| 1574 | 20 | 100 |  |  |  | 172 | $low = 3 if $low < 3; | 
| 1575 |  |  |  |  |  |  |  | 
| 1576 | 20 | 100 |  |  |  | 176 | $low++ if ($low % 2) == 0;   # Make low go to odd number. | 
| 1577 | 20 | 100 |  |  |  | 602 | $high-- if ($high % 2) == 0; # Make high go to odd number. | 
| 1578 | 20 | 100 |  |  |  | 492 | return $count if $low > $high; | 
| 1579 |  |  |  |  |  |  |  | 
| 1580 | 18 | 100 | 66 |  |  | 273 | if (   ref($low) eq 'Math::BigInt' || ref($high) eq 'Math::BigInt' | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
| 1581 |  |  |  |  |  |  | || ($high-$low) < 10 | 
| 1582 |  |  |  |  |  |  | || ($high-$low) < int($low/100_000_000_000) ) { | 
| 1583 |  |  |  |  |  |  | # Trial primes seems best.  Needs some tuning. | 
| 1584 | 2 |  |  |  |  | 11 | my $curprime = next_prime($low-1); | 
| 1585 | 2 |  |  |  |  | 13 | while ($curprime <= $high) { | 
| 1586 | 5 |  |  |  |  | 113 | $count++; | 
| 1587 | 5 |  |  |  |  | 18 | $curprime = next_prime($curprime); | 
| 1588 |  |  |  |  |  |  | } | 
| 1589 | 2 |  |  |  |  | 73 | return $count; | 
| 1590 |  |  |  |  |  |  | } | 
| 1591 |  |  |  |  |  |  |  | 
| 1592 |  |  |  |  |  |  | # TODO: Needs tuning | 
| 1593 | 16 | 100 |  |  |  | 51 | if ($high > 50_000) { | 
| 1594 | 10 | 100 |  |  |  | 49 | if ( ($high / ($high-$low+1)) < 100 ) { | 
| 1595 | 5 |  |  |  |  | 20 | $count += _lehmer_pi($high); | 
| 1596 | 5 | 100 |  |  |  | 27 | $count -= ($low == 3) ? 1 : _lehmer_pi($low-1); | 
| 1597 | 5 |  |  |  |  | 56 | return $count; | 
| 1598 |  |  |  |  |  |  | } | 
| 1599 |  |  |  |  |  |  | } | 
| 1600 |  |  |  |  |  |  |  | 
| 1601 | 11 | 100 |  |  |  | 42 | return (_sieve_prime_count($high) - 1 + $count) if $low == 3; | 
| 1602 |  |  |  |  |  |  |  | 
| 1603 | 7 |  |  |  |  | 22 | my $sieveref = _sieve_segment($low,$high); | 
| 1604 | 7 |  |  |  |  | 35 | $count += $$sieveref =~ tr/0//; | 
| 1605 | 7 |  |  |  |  | 93 | return $count; | 
| 1606 |  |  |  |  |  |  | } | 
| 1607 |  |  |  |  |  |  |  | 
| 1608 |  |  |  |  |  |  |  | 
| 1609 |  |  |  |  |  |  | sub nth_prime { | 
| 1610 | 20 |  |  | 20 | 0 | 7881 | my($n) = @_; | 
| 1611 | 20 |  |  |  |  | 86 | _validate_positive_integer($n); | 
| 1612 |  |  |  |  |  |  |  | 
| 1613 | 20 | 50 |  |  |  | 55 | return undef if $n <= 0;  ## no critic qw(ProhibitExplicitReturnUndef) | 
| 1614 | 20 | 100 |  |  |  | 104 | return $_primes_small[$n] if $n <= $#_primes_small; | 
| 1615 |  |  |  |  |  |  |  | 
| 1616 | 10 | 50 | 33 |  |  | 42 | if ($n > MPU_MAXPRIMEIDX && ref($n) ne 'Math::BigFloat') { | 
| 1617 | 0 | 0 |  |  |  | 0 | do { require Math::BigFloat; Math::BigFloat->import(); } | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 1618 |  |  |  |  |  |  | if !defined $Math::BigFloat::VERSION; | 
| 1619 | 0 |  |  |  |  | 0 | $n = Math::BigFloat->new("$n") | 
| 1620 |  |  |  |  |  |  | } | 
| 1621 |  |  |  |  |  |  |  | 
| 1622 | 10 |  |  |  |  | 21 | my $prime = 0; | 
| 1623 | 10 |  |  |  |  | 19 | my $count = 1; | 
| 1624 | 10 |  |  |  |  | 20 | my $start = 3; | 
| 1625 |  |  |  |  |  |  |  | 
| 1626 | 10 |  |  |  |  | 56 | my $logn = log($n); | 
| 1627 | 10 |  |  |  |  | 25 | my $loglogn = log($logn); | 
| 1628 | 10 | 50 |  |  |  | 54 | my $nth_prime_upper = ($n <= 10) ? 29 : int($n*($logn + $loglogn)) + 1; | 
| 1629 | 10 | 100 |  |  |  | 66 | if ($nth_prime_upper > 100000) { | 
| 1630 |  |  |  |  |  |  | # Use fast Lehmer prime count combined with lower bound to get close. | 
| 1631 | 3 |  |  |  |  | 14 | my $nth_prime_lower = int($n * ($logn + $loglogn - 1.0 + (($loglogn-2.10)/$logn))); | 
| 1632 | 3 | 100 |  |  |  | 14 | $nth_prime_lower-- unless $nth_prime_lower % 2; | 
| 1633 | 3 |  |  |  |  | 13 | $count = _lehmer_pi($nth_prime_lower); | 
| 1634 | 3 |  |  |  |  | 13 | $start = $nth_prime_lower + 2; | 
| 1635 |  |  |  |  |  |  | } | 
| 1636 |  |  |  |  |  |  |  | 
| 1637 |  |  |  |  |  |  | { | 
| 1638 |  |  |  |  |  |  | # Make sure incr is an even number. | 
| 1639 | 10 | 100 |  |  |  | 25 | my $incr = ($n < 1000) ? 1000 : ($n < 10000) ? 10000 : 100000; | 
|  | 10 | 50 |  |  |  | 46 |  | 
| 1640 | 10 |  |  |  |  | 16 | my $sieveref; | 
| 1641 | 10 |  |  |  |  | 15 | while (1) { | 
| 1642 | 35 |  |  |  |  | 104 | $sieveref = _sieve_segment($start, $start+$incr); | 
| 1643 | 35 |  |  |  |  | 409 | my $segcount = $$sieveref =~ tr/0//; | 
| 1644 | 35 | 100 |  |  |  | 117 | last if ($count + $segcount) >= $n; | 
| 1645 | 25 |  |  |  |  | 43 | $count += $segcount; | 
| 1646 | 25 |  |  |  |  | 53 | $start += $incr+2; | 
| 1647 |  |  |  |  |  |  | } | 
| 1648 |  |  |  |  |  |  | # Our count is somewhere in this segment.  Need to look for it. | 
| 1649 | 10 |  |  |  |  | 24 | $prime = $start - 2; | 
| 1650 | 10 |  |  |  |  | 60 | while ($count < $n) { | 
| 1651 | 18451 |  |  |  |  | 22137 | $prime += 2; | 
| 1652 | 18451 | 100 |  |  |  | 37056 | $count++ if !substr($$sieveref, ($prime-$start)>>1, 1); | 
| 1653 |  |  |  |  |  |  | } | 
| 1654 |  |  |  |  |  |  | } | 
| 1655 | 10 |  |  |  |  | 511 | $prime; | 
| 1656 |  |  |  |  |  |  | } | 
| 1657 |  |  |  |  |  |  |  | 
| 1658 |  |  |  |  |  |  | # The nth prime will be less or equal to this number | 
| 1659 |  |  |  |  |  |  | sub nth_prime_upper { | 
| 1660 | 1 |  |  | 1 | 0 | 1790 | my($n) = @_; | 
| 1661 | 1 |  |  |  |  | 7 | _validate_positive_integer($n); | 
| 1662 |  |  |  |  |  |  |  | 
| 1663 | 1 | 50 |  |  |  | 4 | return undef if $n <= 0;  ## no critic qw(ProhibitExplicitReturnUndef) | 
| 1664 | 1 | 50 |  |  |  | 5 | return $_primes_small[$n] if $n <= $#_primes_small; | 
| 1665 |  |  |  |  |  |  |  | 
| 1666 | 1 | 50 | 33 |  |  | 10 | $n = _upgrade_to_float($n) if $n > MPU_MAXPRIMEIDX || $n > 2**45; | 
| 1667 |  |  |  |  |  |  |  | 
| 1668 | 1 |  |  |  |  | 82 | my $flogn  = log($n); | 
| 1669 | 1 |  |  |  |  | 48628 | my $flog2n = log($flogn);  # Note distinction between log_2(n) and log^2(n) | 
| 1670 |  |  |  |  |  |  |  | 
| 1671 | 1 |  |  |  |  | 36483 | my $upper; | 
| 1672 | 1 | 50 |  |  |  | 4 | if      ($n >= 46254381) {  # Axler 2017 Corollary 1.2 | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 1673 | 1 |  |  |  |  | 262 | $upper = $n * ( $flogn  +  $flog2n-1.0  +  (($flog2n-2.00)/$flogn)  -  (($flog2n*$flog2n - 6*$flog2n + 10.667)/(2*$flogn*$flogn)) ); | 
| 1674 |  |  |  |  |  |  | } elsif ($n >=  8009824) {  # Axler 2013 page viii Korollar G | 
| 1675 | 0 |  |  |  |  | 0 | $upper = $n * ( $flogn  +  $flog2n-1.0  +  (($flog2n-2.00)/$flogn)  -  (($flog2n*$flog2n - 6*$flog2n + 10.273)/(2*$flogn*$flogn)) ); | 
| 1676 |  |  |  |  |  |  | } elsif ($n >=  688383) {   # Dusart 2010 page 2 | 
| 1677 | 0 |  |  |  |  | 0 | $upper = $n * ( $flogn  +  $flog2n - 1.0 + (($flog2n-2.00)/$flogn) ); | 
| 1678 |  |  |  |  |  |  | } elsif ($n >=  178974) {   # Dusart 2010 page 7 | 
| 1679 | 0 |  |  |  |  | 0 | $upper = $n * ( $flogn  +  $flog2n - 1.0 + (($flog2n-1.95)/$flogn) ); | 
| 1680 |  |  |  |  |  |  | } elsif ($n >=   39017) {   # Dusart 1999 page 14 | 
| 1681 | 0 |  |  |  |  | 0 | $upper = $n * ( $flogn  +  $flog2n - 0.9484 ); | 
| 1682 |  |  |  |  |  |  | } elsif ($n >=       6) {   # Modified Robin 1983, for 6-39016 only | 
| 1683 | 0 |  |  |  |  | 0 | $upper = $n * ( $flogn  +  0.6000 * $flog2n ); | 
| 1684 |  |  |  |  |  |  | } else { | 
| 1685 | 0 |  |  |  |  | 0 | $upper = $n * ( $flogn  +  $flog2n ); | 
| 1686 |  |  |  |  |  |  | } | 
| 1687 |  |  |  |  |  |  |  | 
| 1688 | 1 |  |  |  |  | 5951 | return int($upper + 1.0); | 
| 1689 |  |  |  |  |  |  | } | 
| 1690 |  |  |  |  |  |  |  | 
| 1691 |  |  |  |  |  |  | # The nth prime will be greater than or equal to this number | 
| 1692 |  |  |  |  |  |  | sub nth_prime_lower { | 
| 1693 | 3 |  |  | 3 | 0 | 2301 | my($n) = @_; | 
| 1694 | 3 | 50 |  |  |  | 15 | _validate_num($n) || _validate_positive_integer($n); | 
| 1695 |  |  |  |  |  |  |  | 
| 1696 | 3 | 50 |  |  |  | 10 | return undef if $n <= 0;  ## no critic qw(ProhibitExplicitReturnUndef) | 
| 1697 | 3 | 50 |  |  |  | 12 | return $_primes_small[$n] if $n <= $#_primes_small; | 
| 1698 |  |  |  |  |  |  |  | 
| 1699 | 3 | 50 | 66 |  |  | 24 | $n = _upgrade_to_float($n) if $n > MPU_MAXPRIMEIDX || $n > 2**45; | 
| 1700 |  |  |  |  |  |  |  | 
| 1701 | 3 |  |  |  |  | 324 | my $flogn  = log($n); | 
| 1702 | 3 |  |  |  |  | 145899 | my $flog2n = log($flogn);  # Note distinction between log_2(n) and log^2(n) | 
| 1703 |  |  |  |  |  |  |  | 
| 1704 |  |  |  |  |  |  | # Dusart 1999 page 14, for all n >= 2 | 
| 1705 |  |  |  |  |  |  | #my $lower = $n * ($flogn + $flog2n - 1.0 + (($flog2n-2.25)/$flogn)); | 
| 1706 |  |  |  |  |  |  | # Dusart 2010 page 2, for all n >= 3 | 
| 1707 |  |  |  |  |  |  | #my $lower = $n * ($flogn + $flog2n - 1.0 + (($flog2n-2.10)/$flogn)); | 
| 1708 |  |  |  |  |  |  | # Axler 2013 page viii Korollar I, for all n >= 2 | 
| 1709 |  |  |  |  |  |  | #my $lower = $n * ($flogn + $flog2n-1.0 + (($flog2n-2.00)/$flogn) - (($flog2n*$flog2n - 6*$flog2n + 11.847)/(2*$flogn*$flogn)) ); | 
| 1710 |  |  |  |  |  |  | # Axler 2017 Corollary 1.4 | 
| 1711 | 3 |  |  |  |  | 110463 | my $lower = $n * ($flogn + $flog2n-1.0 + (($flog2n-2.00)/$flogn) - (($flog2n*$flog2n - 6*$flog2n + 11.508)/(2*$flogn*$flogn)) ); | 
| 1712 |  |  |  |  |  |  |  | 
| 1713 | 3 |  |  |  |  | 17110 | return int($lower + 0.999999999); | 
| 1714 |  |  |  |  |  |  | } | 
| 1715 |  |  |  |  |  |  |  | 
| 1716 |  |  |  |  |  |  | sub inverse_li { | 
| 1717 | 0 |  |  | 0 | 0 | 0 | my($n) = @_; | 
| 1718 | 0 | 0 |  |  |  | 0 | _validate_num($n) || _validate_positive_integer($n); | 
| 1719 |  |  |  |  |  |  |  | 
| 1720 | 0 | 0 |  |  |  | 0 | return (0,2,3,5,6,8)[$n] if $n <= 5; | 
| 1721 | 0 | 0 | 0 |  |  | 0 | $n = _upgrade_to_float($n) if $n > MPU_MAXPRIMEIDX || $n > 2**45; | 
| 1722 | 0 |  |  |  |  | 0 | my $t = $n * log($n); | 
| 1723 |  |  |  |  |  |  |  | 
| 1724 |  |  |  |  |  |  | # Iterator Halley's method until error term grows | 
| 1725 | 0 |  |  |  |  | 0 | my $old_term = MPU_INFINITY; | 
| 1726 | 0 |  |  |  |  | 0 | for my $iter (1 .. 10000) { | 
| 1727 | 0 |  |  |  |  | 0 | my $dn = Math::Prime::Util::LogarithmicIntegral($t) - $n; | 
| 1728 | 0 |  |  |  |  | 0 | my $term = $dn * log($t) / (1.0 + $dn/(2*$t)); | 
| 1729 | 0 | 0 |  |  |  | 0 | last if abs($term) >= abs($old_term); | 
| 1730 | 0 |  |  |  |  | 0 | $old_term = $term; | 
| 1731 | 0 |  |  |  |  | 0 | $t -= $term; | 
| 1732 | 0 | 0 |  |  |  | 0 | last if abs($term) < 1e-6; | 
| 1733 |  |  |  |  |  |  | } | 
| 1734 | 0 | 0 |  |  |  | 0 | if (ref($t)) { | 
| 1735 | 0 |  |  |  |  | 0 | $t = Math::BigInt->new($t->bceil->bstr); | 
| 1736 | 0 | 0 |  |  |  | 0 | $t = _bigint_to_int($t) if $t->bacmp(BMAX) <= 0; | 
| 1737 |  |  |  |  |  |  | } else { | 
| 1738 | 0 |  |  |  |  | 0 | $t = int($t+0.999999); | 
| 1739 |  |  |  |  |  |  | } | 
| 1740 | 0 |  |  |  |  | 0 | $t; | 
| 1741 |  |  |  |  |  |  | } | 
| 1742 |  |  |  |  |  |  | sub _inverse_R { | 
| 1743 | 0 |  |  | 0 |  | 0 | my($n) = @_; | 
| 1744 | 0 | 0 |  |  |  | 0 | _validate_num($n) || _validate_positive_integer($n); | 
| 1745 |  |  |  |  |  |  |  | 
| 1746 | 0 | 0 |  |  |  | 0 | return (0,2,3,5,6,8)[$n] if $n <= 5; | 
| 1747 | 0 | 0 | 0 |  |  | 0 | $n = _upgrade_to_float($n) if $n > MPU_MAXPRIMEIDX || $n > 2**45; | 
| 1748 | 0 |  |  |  |  | 0 | my $t = $n * log($n); | 
| 1749 |  |  |  |  |  |  |  | 
| 1750 |  |  |  |  |  |  | # Iterator Halley's method until error term grows | 
| 1751 | 0 |  |  |  |  | 0 | my $old_term = MPU_INFINITY; | 
| 1752 | 0 |  |  |  |  | 0 | for my $iter (1 .. 10000) { | 
| 1753 | 0 |  |  |  |  | 0 | my $dn = Math::Prime::Util::RiemannR($t) - $n; | 
| 1754 | 0 |  |  |  |  | 0 | my $term = $dn * log($t) / (1.0 + $dn/(2*$t)); | 
| 1755 | 0 | 0 |  |  |  | 0 | last if abs($term) >= abs($old_term); | 
| 1756 | 0 |  |  |  |  | 0 | $old_term = $term; | 
| 1757 | 0 |  |  |  |  | 0 | $t -= $term; | 
| 1758 | 0 | 0 |  |  |  | 0 | last if abs($term) < 1e-6; | 
| 1759 |  |  |  |  |  |  | } | 
| 1760 | 0 | 0 |  |  |  | 0 | if (ref($t)) { | 
| 1761 | 0 |  |  |  |  | 0 | $t = Math::BigInt->new($t->bceil->bstr); | 
| 1762 | 0 | 0 |  |  |  | 0 | $t = _bigint_to_int($t) if $t->bacmp(BMAX) <= 0; | 
| 1763 |  |  |  |  |  |  | } else { | 
| 1764 | 0 |  |  |  |  | 0 | $t = int($t+0.999999); | 
| 1765 |  |  |  |  |  |  | } | 
| 1766 | 0 |  |  |  |  | 0 | $t; | 
| 1767 |  |  |  |  |  |  | } | 
| 1768 |  |  |  |  |  |  |  | 
| 1769 |  |  |  |  |  |  | sub nth_prime_approx { | 
| 1770 | 1 |  |  | 1 | 0 | 777 | my($n) = @_; | 
| 1771 | 1 | 50 |  |  |  | 5 | _validate_num($n) || _validate_positive_integer($n); | 
| 1772 |  |  |  |  |  |  |  | 
| 1773 | 1 | 50 |  |  |  | 5 | return undef if $n <= 0;  ## no critic qw(ProhibitExplicitReturnUndef) | 
| 1774 | 1 | 50 |  |  |  | 5 | return $_primes_small[$n] if $n <= $#_primes_small; | 
| 1775 |  |  |  |  |  |  |  | 
| 1776 |  |  |  |  |  |  | # Once past 10^12 or so, inverse_li gives better results. | 
| 1777 | 1 | 50 |  |  |  | 4 | return Math::Prime::Util::inverse_li($n) if $n > 1e12; | 
| 1778 |  |  |  |  |  |  |  | 
| 1779 | 1 | 50 | 33 |  |  | 8 | $n = _upgrade_to_float($n) | 
| 1780 |  |  |  |  |  |  | if ref($n) eq 'Math::BigInt' || $n >= MPU_MAXPRIMEIDX; | 
| 1781 |  |  |  |  |  |  |  | 
| 1782 | 1 |  |  |  |  | 4 | my $flogn  = log($n); | 
| 1783 | 1 |  |  |  |  | 2 | my $flog2n = log($flogn); | 
| 1784 |  |  |  |  |  |  |  | 
| 1785 |  |  |  |  |  |  | # Cipolla 1902: | 
| 1786 |  |  |  |  |  |  | #    m=0   fn * ( flogn + flog2n - 1 ); | 
| 1787 |  |  |  |  |  |  | #    m=1   + ((flog2n - 2)/flogn) ); | 
| 1788 |  |  |  |  |  |  | #    m=2   - (((flog2n*flog2n) - 6*flog2n + 11) / (2*flogn*flogn)) | 
| 1789 |  |  |  |  |  |  | #    + O((flog2n/flogn)^3) | 
| 1790 |  |  |  |  |  |  | # | 
| 1791 |  |  |  |  |  |  | # Shown in Dusart 1999 page 12, as well as other sources such as: | 
| 1792 |  |  |  |  |  |  | #   http://www.emis.de/journals/JIPAM/images/153_02_JIPAM/153_02.pdf | 
| 1793 |  |  |  |  |  |  | # where the main issue you run into is that you're doing polynomial | 
| 1794 |  |  |  |  |  |  | # interpolation, so it oscillates like crazy with many high-order terms. | 
| 1795 |  |  |  |  |  |  | # Hence I'm leaving it at m=2. | 
| 1796 |  |  |  |  |  |  |  | 
| 1797 | 1 |  |  |  |  | 8 | my $approx = $n * ( $flogn + $flog2n - 1 | 
| 1798 |  |  |  |  |  |  | + (($flog2n - 2)/$flogn) | 
| 1799 |  |  |  |  |  |  | - ((($flog2n*$flog2n) - 6*$flog2n + 11) / (2*$flogn*$flogn)) | 
| 1800 |  |  |  |  |  |  | ); | 
| 1801 |  |  |  |  |  |  |  | 
| 1802 |  |  |  |  |  |  | # Apply a correction to help keep values close. | 
| 1803 | 1 |  |  |  |  | 3 | my $order = $flog2n/$flogn; | 
| 1804 | 1 |  |  |  |  | 2 | $order = $order*$order*$order * $n; | 
| 1805 |  |  |  |  |  |  |  | 
| 1806 | 1 | 50 |  |  |  | 13 | if    ($n <        259) { $approx += 10.4 * $order; } | 
|  | 0 | 50 |  |  |  | 0 |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 1807 | 0 |  |  |  |  | 0 | elsif ($n <        775) { $approx +=  6.3 * $order; } | 
| 1808 | 0 |  |  |  |  | 0 | elsif ($n <       1271) { $approx +=  5.3 * $order; } | 
| 1809 | 0 |  |  |  |  | 0 | elsif ($n <       2000) { $approx +=  4.7 * $order; } | 
| 1810 | 0 |  |  |  |  | 0 | elsif ($n <       4000) { $approx +=  3.9 * $order; } | 
| 1811 | 0 |  |  |  |  | 0 | elsif ($n <      12000) { $approx +=  2.8 * $order; } | 
| 1812 | 0 |  |  |  |  | 0 | elsif ($n <     150000) { $approx +=  1.2 * $order; } | 
| 1813 | 1 |  |  |  |  | 3 | elsif ($n <   20000000) { $approx +=  0.11 * $order; } | 
| 1814 | 0 |  |  |  |  | 0 | elsif ($n <  100000000) { $approx +=  0.008 * $order; } | 
| 1815 | 0 |  |  |  |  | 0 | elsif ($n <  500000000) { $approx += -0.038 * $order; } | 
| 1816 | 0 |  |  |  |  | 0 | elsif ($n < 2000000000) { $approx += -0.054 * $order; } | 
| 1817 | 0 |  |  |  |  | 0 | else                    { $approx += -0.058 * $order; } | 
| 1818 |  |  |  |  |  |  | # If we want the asymptotic approximation to be >= actual, use -0.010. | 
| 1819 |  |  |  |  |  |  |  | 
| 1820 | 1 |  |  |  |  | 4 | return int($approx + 0.5); | 
| 1821 |  |  |  |  |  |  | } | 
| 1822 |  |  |  |  |  |  |  | 
| 1823 |  |  |  |  |  |  | ############################################################################# | 
| 1824 |  |  |  |  |  |  |  | 
| 1825 |  |  |  |  |  |  | sub prime_count_approx { | 
| 1826 | 5 |  |  | 5 | 0 | 31250 | my($x) = @_; | 
| 1827 | 5 | 100 |  |  |  | 28 | _validate_num($x) || _validate_positive_integer($x); | 
| 1828 |  |  |  |  |  |  |  | 
| 1829 |  |  |  |  |  |  | # Turn on high precision FP if they gave us a big number. | 
| 1830 | 5 | 100 | 66 |  |  | 37 | $x = _upgrade_to_float($x) if ref($_[0]) eq 'Math::BigInt' && $x > 1e16; | 
| 1831 |  |  |  |  |  |  | #    Method             10^10 %error  10^19 %error | 
| 1832 |  |  |  |  |  |  | #    -----------------  ------------  ------------ | 
| 1833 |  |  |  |  |  |  | #    n/(log(n)-1)        .22%          .058% | 
| 1834 |  |  |  |  |  |  | #    n/(ln(n)-1-1/ln(n)) .032%         .0041% | 
| 1835 |  |  |  |  |  |  | #    average bounds      .0005%        .0000002% | 
| 1836 |  |  |  |  |  |  | #    asymp               .0006%        .00000004% | 
| 1837 |  |  |  |  |  |  | #    li(n)               .0007%        .00000004% | 
| 1838 |  |  |  |  |  |  | #    li(n)-li(n^.5)/2    .0004%        .00000001% | 
| 1839 |  |  |  |  |  |  | #    R(n)                .0004%        .00000001% | 
| 1840 |  |  |  |  |  |  | # | 
| 1841 |  |  |  |  |  |  | # Also consider: http://trac.sagemath.org/sage_trac/ticket/8135 | 
| 1842 |  |  |  |  |  |  |  | 
| 1843 |  |  |  |  |  |  | # Asymp: | 
| 1844 |  |  |  |  |  |  | #   my $l1 = log($x);  my $l2 = $l1*$l1;  my $l4 = $l2*$l2; | 
| 1845 |  |  |  |  |  |  | #   my $result = int( $x/$l1 + $x/$l2 + 2*$x/($l2*$l1) + 6*$x/($l4) + 24*$x/($l4*$l1) + 120*$x/($l4*$l2) + 720*$x/($l4*$l2*$l1) + 5040*$x/($l4*$l4) + 40320*$x/($l4*$l4*$l1) + 0.5 ); | 
| 1846 |  |  |  |  |  |  | # my $result = int( (prime_count_upper($x) + prime_count_lower($x)) / 2); | 
| 1847 |  |  |  |  |  |  | # my $result = int( LogarithmicIntegral($x) ); | 
| 1848 |  |  |  |  |  |  | # my $result = int(LogarithmicIntegral($x) - LogarithmicIntegral(sqrt($x))/2); | 
| 1849 |  |  |  |  |  |  | # my $result = RiemannR($x) + 0.5; | 
| 1850 |  |  |  |  |  |  |  | 
| 1851 |  |  |  |  |  |  | # Make sure we get enough accuracy, and also not too much more than needed | 
| 1852 | 5 | 100 |  |  |  | 485 | $x->accuracy(length($x->copy->as_int->bstr())+2) if ref($x) =~ /^Math::Big/; | 
| 1853 |  |  |  |  |  |  |  | 
| 1854 | 5 |  |  |  |  | 1107 | my $result; | 
| 1855 | 5 | 100 | 66 |  |  | 50 | if ($Math::Prime::Util::_GMPfunc{"riemannr"} || !ref($x)) { | 
| 1856 |  |  |  |  |  |  | # Fast if we have our GMP backend, and ok for native. | 
| 1857 | 1 |  |  |  |  | 5 | $result = Math::Prime::Util::PP::RiemannR($x); | 
| 1858 |  |  |  |  |  |  | } else { | 
| 1859 | 4 | 50 |  |  |  | 16 | $x = _upgrade_to_float($x) unless ref($x) eq 'Math::BigFloat'; | 
| 1860 | 4 |  |  |  |  | 17 | $result = Math::BigFloat->new(0); | 
| 1861 | 4 | 50 | 33 |  |  | 577 | $result->accuracy($x->accuracy) if ref($x) && $x->accuracy; | 
| 1862 | 4 |  |  |  |  | 350 | $result += Math::BigFloat->new(LogarithmicIntegral($x)); | 
| 1863 | 4 |  |  |  |  | 1544 | $result -= Math::BigFloat->new(LogarithmicIntegral(sqrt($x))/2); | 
| 1864 | 4 | 50 |  |  |  | 3260 | my $intx = ref($x) ? Math::BigInt->new($x->bfround(0)) : $x; | 
| 1865 | 4 |  |  |  |  | 2024 | for my $k (3 .. 1000) { | 
| 1866 | 88 |  |  |  |  | 44746 | my $m = moebius($k); | 
| 1867 | 88 | 100 |  |  |  | 200 | next unless $m != 0; | 
| 1868 |  |  |  |  |  |  | # With Math::BigFloat and the Calc backend, FP root is ungodly slow. | 
| 1869 |  |  |  |  |  |  | # Use integer root instead.  For more accuracy (not useful here): | 
| 1870 |  |  |  |  |  |  | # my $v = Math::BigFloat->new( "" . rootint($x->as_int,$k) ); | 
| 1871 |  |  |  |  |  |  | # $v->accuracy(length($v)+5); | 
| 1872 |  |  |  |  |  |  | # $v = $v - Math::BigFloat->new(($v**$k - $x))->bdiv($k * $v**($k-1)); | 
| 1873 |  |  |  |  |  |  | # my $term = LogarithmicIntegral($v)/$k; | 
| 1874 | 56 |  |  |  |  | 125 | my $term = LogarithmicIntegral(rootint($intx,$k)) / $k; | 
| 1875 | 56 | 100 |  |  |  | 241 | last if $term < .25; | 
| 1876 | 52 | 100 |  |  |  | 121 | if ($m == 1) { $result->badd(Math::BigFloat->new($term)) } | 
|  | 22 |  |  |  |  | 92 |  | 
| 1877 | 30 |  |  |  |  | 111 | else         { $result->bsub(Math::BigFloat->new($term)) } | 
| 1878 |  |  |  |  |  |  | } | 
| 1879 |  |  |  |  |  |  | } | 
| 1880 |  |  |  |  |  |  |  | 
| 1881 | 5 | 100 |  |  |  | 30 | if (ref($result)) { | 
| 1882 | 4 | 50 |  |  |  | 16 | return $result unless ref($result) eq 'Math::BigFloat'; | 
| 1883 |  |  |  |  |  |  | # Math::BigInt::FastCalc 0.19 implements as_int incorrectly. | 
| 1884 | 4 |  |  |  |  | 22 | return Math::BigInt->new($result->bfround(0)->bstr); | 
| 1885 |  |  |  |  |  |  | } | 
| 1886 | 1 |  |  |  |  | 5 | int($result+0.5); | 
| 1887 |  |  |  |  |  |  | } | 
| 1888 |  |  |  |  |  |  |  | 
| 1889 |  |  |  |  |  |  | sub prime_count_lower { | 
| 1890 | 11 |  |  | 11 | 0 | 9462 | my($x) = @_; | 
| 1891 | 11 | 100 |  |  |  | 55 | _validate_num($x) || _validate_positive_integer($x); | 
| 1892 |  |  |  |  |  |  |  | 
| 1893 | 11 | 100 |  |  |  | 53 | return _tiny_prime_count($x) if $x < $_primes_small[-1]; | 
| 1894 |  |  |  |  |  |  |  | 
| 1895 |  |  |  |  |  |  | return Math::Prime::Util::_reftyped($_[0], Math::Prime::Util::GMP::prime_count_lower($x)) | 
| 1896 | 10 | 50 |  |  |  | 1029 | if $Math::Prime::Util::_GMPfunc{"prime_count_lower"}; | 
| 1897 |  |  |  |  |  |  |  | 
| 1898 | 10 | 100 | 66 |  |  | 80 | $x = _upgrade_to_float($x) | 
| 1899 |  |  |  |  |  |  | if ref($x) eq 'Math::BigInt' || ref($_[0]) eq 'Math::BigInt'; | 
| 1900 |  |  |  |  |  |  |  | 
| 1901 | 10 |  |  |  |  | 938 | my($result,$a); | 
| 1902 | 10 |  |  |  |  | 45 | my $fl1 = log($x); | 
| 1903 | 10 |  |  |  |  | 757923 | my $fl2 = $fl1*$fl1; | 
| 1904 | 10 | 100 |  |  |  | 2374 | my $one = (ref($x) eq 'Math::BigFloat') ? $x->copy->bone : $x-$x+1.0; | 
| 1905 |  |  |  |  |  |  |  | 
| 1906 |  |  |  |  |  |  | # Chebyshev            1*x/logx       x >= 17 | 
| 1907 |  |  |  |  |  |  | # Rosser & Schoenfeld  x/(logx-1/2)   x >= 67 | 
| 1908 |  |  |  |  |  |  | # Dusart 1999          x/logx*(1+1/logx+1.8/logxlogx)  x >= 32299 | 
| 1909 |  |  |  |  |  |  | # Dusart 2010          x/logx*(1+1/logx+2.0/logxlogx)  x >= 88783 | 
| 1910 |  |  |  |  |  |  | # Axler 2014 (1.2)     ""+...                          x >= 1332450001 | 
| 1911 |  |  |  |  |  |  | # Axler 2014 (1.2)     x/(logx-1-1/logx-...)           x >= 1332479531 | 
| 1912 |  |  |  |  |  |  | # Büthe 2015 (1.9)     li(x)-(sqrtx/logx)*(...)        x <= 10^19 | 
| 1913 |  |  |  |  |  |  | # Büthe 2014 Th 2      li(x)-logx*sqrtx/8Pi    x > 2657, x <= 1.4*10^25 | 
| 1914 |  |  |  |  |  |  |  | 
| 1915 | 10 | 50 | 66 |  |  | 1565 | if ($x < 599) {                         # Decent for small numbers | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 1916 | 0 |  |  |  |  | 0 | $result = $x / ($fl1 - 0.7); | 
| 1917 |  |  |  |  |  |  | } elsif ($x < 52600000) {               # Dusart 2010 tweaked | 
| 1918 | 1 | 50 |  |  |  | 15 | if    ($x <       2700) { $a = 0.30; } | 
|  | 0 | 50 |  |  |  | 0 |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 1919 | 0 |  |  |  |  | 0 | elsif ($x <       5500) { $a = 0.90; } | 
| 1920 | 0 |  |  |  |  | 0 | elsif ($x <      19400) { $a = 1.30; } | 
| 1921 | 0 |  |  |  |  | 0 | elsif ($x <      32299) { $a = 1.60; } | 
| 1922 | 0 |  |  |  |  | 0 | elsif ($x <      88783) { $a = 1.83; } | 
| 1923 | 0 |  |  |  |  | 0 | elsif ($x <     176000) { $a = 1.99; } | 
| 1924 | 0 |  |  |  |  | 0 | elsif ($x <     315000) { $a = 2.11; } | 
| 1925 | 0 |  |  |  |  | 0 | elsif ($x <    1100000) { $a = 2.19; } | 
| 1926 | 1 |  |  |  |  | 3 | elsif ($x <    4500000) { $a = 2.31; } | 
| 1927 | 0 |  |  |  |  | 0 | else                    { $a = 2.35; } | 
| 1928 | 1 |  |  |  |  | 4 | $result = ($x/$fl1) * ($one + $one/$fl1 + $a/$fl2); | 
| 1929 |  |  |  |  |  |  | } elsif ($x < 1.4e25 || Math::Prime::Util::prime_get_config()->{'assume_rh'}){ | 
| 1930 |  |  |  |  |  |  | # Büthe 2014/2015 | 
| 1931 | 8 |  |  |  |  | 6608 | my $lix = LogarithmicIntegral($x); | 
| 1932 | 8 |  |  |  |  | 41 | my $sqx = sqrt($x); | 
| 1933 | 8 | 100 |  |  |  | 32750 | if ($x < 1e19) { | 
| 1934 | 1 |  |  |  |  | 5 | $result = $lix - ($sqx/$fl1) * (1.94 + 3.88/$fl1 + 27.57/$fl2); | 
| 1935 |  |  |  |  |  |  | } else { | 
| 1936 | 7 | 50 |  |  |  | 2891 | if (ref($x) eq 'Math::BigFloat') { | 
| 1937 | 7 |  |  |  |  | 35 | my $xdigits = _find_big_acc($x); | 
| 1938 | 7 |  |  |  |  | 31 | $result = $lix - ($fl1*$sqx / (Math::BigFloat->bpi($xdigits)*8)); | 
| 1939 |  |  |  |  |  |  | } else { | 
| 1940 | 0 |  |  |  |  | 0 | $result = $lix - ($fl1*$sqx / PI_TIMES_8); | 
| 1941 |  |  |  |  |  |  | } | 
| 1942 |  |  |  |  |  |  | } | 
| 1943 |  |  |  |  |  |  | } else {                                # Axler 2014 1.4 | 
| 1944 | 1 |  |  |  |  | 5 | my($fl3,$fl4) = ($fl2*$fl1,$fl2*$fl2); | 
| 1945 | 1 |  |  |  |  | 826 | my($fl5,$fl6) = ($fl4*$fl1,$fl4*$fl2); | 
| 1946 | 1 |  |  |  |  | 1174 | $result = $x / ($fl1 - $one - $one/$fl1 - 2.65/$fl2 - 13.35/$fl3 - 70.3/$fl4 - 455.6275/$fl5 - 3404.4225/$fl6); | 
| 1947 |  |  |  |  |  |  | } | 
| 1948 |  |  |  |  |  |  |  | 
| 1949 | 10 | 100 |  |  |  | 43147 | return Math::BigInt->new($result->bfloor->bstr()) if ref($result) eq 'Math::BigFloat'; | 
| 1950 | 2 |  |  |  |  | 11 | return int($result); | 
| 1951 |  |  |  |  |  |  | } | 
| 1952 |  |  |  |  |  |  |  | 
| 1953 |  |  |  |  |  |  | sub prime_count_upper { | 
| 1954 | 11 |  |  | 11 | 0 | 4317 | my($x) = @_; | 
| 1955 | 11 | 100 |  |  |  | 61 | _validate_num($x) || _validate_positive_integer($x); | 
| 1956 |  |  |  |  |  |  |  | 
| 1957 |  |  |  |  |  |  | # Give an exact answer for what we have in our little table. | 
| 1958 | 11 | 100 |  |  |  | 50 | return _tiny_prime_count($x) if $x < $_primes_small[-1]; | 
| 1959 |  |  |  |  |  |  |  | 
| 1960 |  |  |  |  |  |  | return Math::Prime::Util::_reftyped($_[0], Math::Prime::Util::GMP::prime_count_upper($x)) | 
| 1961 | 10 | 50 |  |  |  | 1062 | if $Math::Prime::Util::_GMPfunc{"prime_count_upper"}; | 
| 1962 |  |  |  |  |  |  |  | 
| 1963 | 10 | 100 | 66 |  |  | 91 | $x = _upgrade_to_float($x) | 
| 1964 |  |  |  |  |  |  | if ref($x) eq 'Math::BigInt' || ref($_[0]) eq 'Math::BigInt'; | 
| 1965 |  |  |  |  |  |  |  | 
| 1966 |  |  |  |  |  |  | # Chebyshev:            1.25506*x/logx       x >= 17 | 
| 1967 |  |  |  |  |  |  | # Rosser & Schoenfeld:  x/(logx-3/2)         x >= 67 | 
| 1968 |  |  |  |  |  |  | # Panaitopol 1999:      x/(logx-1.112)       x >= 4 | 
| 1969 |  |  |  |  |  |  | # Dusart 1999:          x/logx*(1+1/logx+2.51/logxlogx)   x >= 355991 | 
| 1970 |  |  |  |  |  |  | # Dusart 2010:          x/logx*(1+1/logx+2.334/logxlogx)  x >= 2_953_652_287 | 
| 1971 |  |  |  |  |  |  | # Axler 2014:           x/(logx-1-1/logx-3.35/logxlogx...) x >= e^3.804 | 
| 1972 |  |  |  |  |  |  | # Büthe 2014 7.4        Schoenfeld bounds hold to x <= 1.4e25 | 
| 1973 |  |  |  |  |  |  | # Axler 2017 Prop 2.2   Schoenfeld bounds hold to x <= 5.5e25 | 
| 1974 |  |  |  |  |  |  | # Skewes                li(x)                x < 1e14 | 
| 1975 |  |  |  |  |  |  |  | 
| 1976 | 10 |  |  |  |  | 942 | my($result,$a); | 
| 1977 | 10 |  |  |  |  | 42 | my $fl1 = log($x); | 
| 1978 | 10 |  |  |  |  | 755905 | my $fl2 = $fl1 * $fl1; | 
| 1979 | 10 | 100 |  |  |  | 2360 | my $one = (ref($x) eq 'Math::BigFloat') ? $x->copy->bone : $x-$x+1.0; | 
| 1980 |  |  |  |  |  |  |  | 
| 1981 | 10 | 50 | 33 |  |  | 1589 | if ($x < 15900) {              # Tweaked Rosser-type | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 1982 | 0 | 0 |  |  |  | 0 | $a = ($x < 1621) ? 1.048 : ($x < 5000) ? 1.071 : 1.098; | 
|  |  | 0 |  |  |  |  |  | 
| 1983 | 0 |  |  |  |  | 0 | $result = ($x / ($fl1 - $a)) + 1.0; | 
| 1984 |  |  |  |  |  |  | } elsif ($x < 821800000) {     # Tweaked Dusart 2010 | 
| 1985 | 2 | 50 |  |  |  | 32 | if    ($x <      24000) { $a = 2.30; } | 
|  | 0 | 50 |  |  |  | 0 |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 1986 | 0 |  |  |  |  | 0 | elsif ($x <      59000) { $a = 2.48; } | 
| 1987 | 0 |  |  |  |  | 0 | elsif ($x <     350000) { $a = 2.52; } | 
| 1988 | 0 |  |  |  |  | 0 | elsif ($x <     355991) { $a = 2.54; } | 
| 1989 | 0 |  |  |  |  | 0 | elsif ($x <     356000) { $a = 2.51; } | 
| 1990 | 1 |  |  |  |  | 3 | elsif ($x <    3550000) { $a = 2.50; } | 
| 1991 | 0 |  |  |  |  | 0 | elsif ($x <    3560000) { $a = 2.49; } | 
| 1992 | 0 |  |  |  |  | 0 | elsif ($x <    5000000) { $a = 2.48; } | 
| 1993 | 0 |  |  |  |  | 0 | elsif ($x <    8000000) { $a = 2.47; } | 
| 1994 | 0 |  |  |  |  | 0 | elsif ($x <   13000000) { $a = 2.46; } | 
| 1995 | 0 |  |  |  |  | 0 | elsif ($x <   18000000) { $a = 2.45; } | 
| 1996 | 0 |  |  |  |  | 0 | elsif ($x <   31000000) { $a = 2.44; } | 
| 1997 | 0 |  |  |  |  | 0 | elsif ($x <   41000000) { $a = 2.43; } | 
| 1998 | 0 |  |  |  |  | 0 | elsif ($x <   48000000) { $a = 2.42; } | 
| 1999 | 0 |  |  |  |  | 0 | elsif ($x <  119000000) { $a = 2.41; } | 
| 2000 | 0 |  |  |  |  | 0 | elsif ($x <  182000000) { $a = 2.40; } | 
| 2001 | 0 |  |  |  |  | 0 | elsif ($x <  192000000) { $a = 2.395; } | 
| 2002 | 0 |  |  |  |  | 0 | elsif ($x <  213000000) { $a = 2.390; } | 
| 2003 | 0 |  |  |  |  | 0 | elsif ($x <  271000000) { $a = 2.385; } | 
| 2004 | 0 |  |  |  |  | 0 | elsif ($x <  322000000) { $a = 2.380; } | 
| 2005 | 0 |  |  |  |  | 0 | elsif ($x <  400000000) { $a = 2.375; } | 
| 2006 | 1 |  |  |  |  | 2 | elsif ($x <  510000000) { $a = 2.370; } | 
| 2007 | 0 |  |  |  |  | 0 | elsif ($x <  682000000) { $a = 2.367; } | 
| 2008 | 0 |  |  |  |  | 0 | elsif ($x < 2953652287) { $a = 2.362; } | 
| 2009 | 0 |  |  |  |  | 0 | else                    { $a = 2.334; } # Dusart 2010, page 2 | 
| 2010 | 2 |  |  |  |  | 7 | $result = ($x/$fl1) * ($one + $one/$fl1 + $a/$fl2) + $one; | 
| 2011 |  |  |  |  |  |  | } elsif ($x < 1e19) {                     # Skewes number lower limit | 
| 2012 | 0 | 0 |  |  |  | 0 | $a = ($x < 110e7) ? 0.032 : ($x < 1001e7) ? 0.027 : ($x < 10126e7) ? 0.021 : 0.0; | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 2013 | 0 |  |  |  |  | 0 | $result = LogarithmicIntegral($x) - $a * $fl1*sqrt($x)/PI_TIMES_8; | 
| 2014 |  |  |  |  |  |  | } elsif ($x < 5.5e25 || Math::Prime::Util::prime_get_config()->{'assume_rh'}) { | 
| 2015 |  |  |  |  |  |  | # Schoenfeld / Büthe 2014 Th 7.4 | 
| 2016 | 8 |  |  |  |  | 12812 | my $lix = LogarithmicIntegral($x); | 
| 2017 | 8 |  |  |  |  | 49 | my $sqx = sqrt($x); | 
| 2018 | 8 | 50 |  |  |  | 37251 | if (ref($x) eq 'Math::BigFloat') { | 
| 2019 | 8 |  |  |  |  | 40 | my $xdigits = _find_big_acc($x); | 
| 2020 | 8 |  |  |  |  | 40 | $result = $lix + ($fl1*$sqx / (Math::BigFloat->bpi($xdigits)*8)); | 
| 2021 |  |  |  |  |  |  | } else { | 
| 2022 | 0 |  |  |  |  | 0 | $result = $lix + ($fl1*$sqx / PI_TIMES_8); | 
| 2023 |  |  |  |  |  |  | } | 
| 2024 |  |  |  |  |  |  | } else {                                  # Axler 2014 1.3 | 
| 2025 | 0 |  |  |  |  | 0 | my($fl3,$fl4) = ($fl2*$fl1,$fl2*$fl2); | 
| 2026 | 0 |  |  |  |  | 0 | my($fl5,$fl6) = ($fl4*$fl1,$fl4*$fl2); | 
| 2027 | 0 |  |  |  |  | 0 | $result = $x / ($fl1 - $one - $one/$fl1 - 3.35/$fl2 - 12.65/$fl3 - 71.7/$fl4 - 466.1275/$fl5 - 3489.8225/$fl6); | 
| 2028 |  |  |  |  |  |  | } | 
| 2029 |  |  |  |  |  |  |  | 
| 2030 | 10 | 100 |  |  |  | 27636 | return Math::BigInt->new($result->bfloor->bstr()) if ref($result) eq 'Math::BigFloat'; | 
| 2031 | 2 |  |  |  |  | 10 | return int($result); | 
| 2032 |  |  |  |  |  |  | } | 
| 2033 |  |  |  |  |  |  |  | 
| 2034 |  |  |  |  |  |  | sub twin_prime_count { | 
| 2035 | 1 |  |  | 1 | 0 | 4 | my($low,$high) = @_; | 
| 2036 | 1 | 50 |  |  |  | 4 | if (defined $high) { _validate_positive_integer($low); } | 
|  | 0 |  |  |  |  | 0 |  | 
| 2037 | 1 |  |  |  |  | 3 | else               { ($low,$high) = (2, $low);         } | 
| 2038 | 1 |  |  |  |  | 5 | _validate_positive_integer($high); | 
| 2039 | 1 |  |  |  |  | 1 | my $sum = 0; | 
| 2040 | 1 |  |  |  |  | 5 | while ($low <= $high) { | 
| 2041 | 1 |  |  |  |  | 3 | my $seghigh = ($high-$high) + $low + 1e7 - 1; | 
| 2042 | 1 | 50 |  |  |  | 4 | $seghigh = $high if $seghigh > $high; | 
| 2043 | 1 |  |  |  |  | 3 | $sum += scalar(@{Math::Prime::Util::twin_primes($low,$seghigh)}); | 
|  | 1 |  |  |  |  | 6 |  | 
| 2044 | 1 |  |  |  |  | 8 | $low = $seghigh + 1; | 
| 2045 |  |  |  |  |  |  | } | 
| 2046 | 1 |  |  |  |  | 9 | $sum; | 
| 2047 |  |  |  |  |  |  | } | 
| 2048 |  |  |  |  |  |  | sub _semiprime_count { | 
| 2049 | 0 |  |  | 0 |  | 0 | my $n = shift; | 
| 2050 | 0 |  |  |  |  | 0 | my($sum,$pc) = (0,0); | 
| 2051 |  |  |  |  |  |  | Math::Prime::Util::forprimes( sub { | 
| 2052 | 0 |  |  | 0 |  | 0 | $sum += Math::Prime::Util::prime_count(int($n/$_))-$pc++; | 
| 2053 | 0 |  |  |  |  | 0 | }, sqrtint($n)); | 
| 2054 | 0 |  |  |  |  | 0 | $sum; | 
| 2055 |  |  |  |  |  |  | } | 
| 2056 |  |  |  |  |  |  | sub semiprime_count { | 
| 2057 | 0 |  |  | 0 | 0 | 0 | my($low,$high) = @_; | 
| 2058 | 0 | 0 |  |  |  | 0 | if (defined $high) { _validate_positive_integer($low); } | 
|  | 0 |  |  |  |  | 0 |  | 
| 2059 | 0 |  |  |  |  | 0 | else               { ($low,$high) = (2, $low);         } | 
| 2060 | 0 |  |  |  |  | 0 | _validate_positive_integer($high); | 
| 2061 |  |  |  |  |  |  | # todo: threshold of fast count vs. walk | 
| 2062 | 0 | 0 |  |  |  | 0 | my $sum = _semiprime_count($high) - (($low < 4) ? 0 : semiprime_count($low-1)); | 
| 2063 | 0 |  |  |  |  | 0 | $sum; | 
| 2064 |  |  |  |  |  |  | } | 
| 2065 |  |  |  |  |  |  | sub ramanujan_prime_count { | 
| 2066 | 0 |  |  | 0 | 0 | 0 | my($low,$high) = @_; | 
| 2067 | 0 | 0 |  |  |  | 0 | if (defined $high) { _validate_positive_integer($low); } | 
|  | 0 |  |  |  |  | 0 |  | 
| 2068 | 0 |  |  |  |  | 0 | else               { ($low,$high) = (2, $low);         } | 
| 2069 | 0 |  |  |  |  | 0 | _validate_positive_integer($high); | 
| 2070 | 0 |  |  |  |  | 0 | my $sum = 0; | 
| 2071 | 0 |  |  |  |  | 0 | while ($low <= $high) { | 
| 2072 | 0 |  |  |  |  | 0 | my $seghigh = ($high-$high) + $low + 1e9 - 1; | 
| 2073 | 0 | 0 |  |  |  | 0 | $seghigh = $high if $seghigh > $high; | 
| 2074 | 0 |  |  |  |  | 0 | $sum += scalar(@{Math::Prime::Util::ramanujan_primes($low,$seghigh)}); | 
|  | 0 |  |  |  |  | 0 |  | 
| 2075 | 0 |  |  |  |  | 0 | $low = $seghigh + 1; | 
| 2076 |  |  |  |  |  |  | } | 
| 2077 | 0 |  |  |  |  | 0 | $sum; | 
| 2078 |  |  |  |  |  |  | } | 
| 2079 |  |  |  |  |  |  |  | 
| 2080 |  |  |  |  |  |  | sub twin_prime_count_approx { | 
| 2081 | 2 |  |  | 2 | 0 | 2875 | my($n) = @_; | 
| 2082 | 2 | 50 |  |  |  | 10 | return twin_prime_count(3,$n) if $n < 2000; | 
| 2083 | 2 | 50 |  |  |  | 293 | $n = _upgrade_to_float($n) if ref($n); | 
| 2084 | 2 |  |  |  |  | 248 | my $logn = log($n); | 
| 2085 |  |  |  |  |  |  | # The loss of full Ei precision is a few orders of magnitude less than the | 
| 2086 |  |  |  |  |  |  | # accuracy of the estimate, so save huge time and don't bother. | 
| 2087 | 2 |  |  |  |  | 97116 | my $li2 = Math::Prime::Util::ExponentialIntegral("$logn") + 2.8853900817779268147198494 - ($n/$logn); | 
| 2088 |  |  |  |  |  |  |  | 
| 2089 |  |  |  |  |  |  | # Empirical correction factor | 
| 2090 | 2 |  |  |  |  | 3467 | my $fm; | 
| 2091 | 2 | 50 |  |  |  | 10 | if    ($n <     4000) { $fm = 0.2952; } | 
|  | 0 | 50 |  |  |  | 0 |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 2092 | 0 |  |  |  |  | 0 | elsif ($n <     8000) { $fm = 0.3151; } | 
| 2093 | 0 |  |  |  |  | 0 | elsif ($n <    16000) { $fm = 0.3090; } | 
| 2094 | 0 |  |  |  |  | 0 | elsif ($n <    32000) { $fm = 0.3096; } | 
| 2095 | 0 |  |  |  |  | 0 | elsif ($n <    64000) { $fm = 0.3100; } | 
| 2096 | 0 |  |  |  |  | 0 | elsif ($n <   128000) { $fm = 0.3089; } | 
| 2097 | 0 |  |  |  |  | 0 | elsif ($n <   256000) { $fm = 0.3099; } | 
| 2098 | 0 |  |  |  |  | 0 | elsif ($n <   600000) { my($x0, $x1, $y0, $y1) = (1e6, 6e5, .3091, .3059); | 
| 2099 | 0 |  |  |  |  | 0 | $fm = $y0 + ($n - $x0) * ($y1-$y0) / ($x1 - $x0); } | 
| 2100 | 0 |  |  |  |  | 0 | elsif ($n <  1000000) { my($x0, $x1, $y0, $y1) = (6e5, 1e6, .3062, .3042); | 
| 2101 | 0 |  |  |  |  | 0 | $fm = $y0 + ($n - $x0) * ($y1-$y0) / ($x1 - $x0); } | 
| 2102 | 0 |  |  |  |  | 0 | elsif ($n <  4000000) { my($x0, $x1, $y0, $y1) = (1e6, 4e6, .3067, .3041); | 
| 2103 | 0 |  |  |  |  | 0 | $fm = $y0 + ($n - $x0) * ($y1-$y0) / ($x1 - $x0); } | 
| 2104 | 0 |  |  |  |  | 0 | elsif ($n < 16000000) { my($x0, $x1, $y0, $y1) = (4e6, 16e6, .3033, .2983); | 
| 2105 | 0 |  |  |  |  | 0 | $fm = $y0 + ($n - $x0) * ($y1-$y0) / ($x1 - $x0); } | 
| 2106 | 0 |  |  |  |  | 0 | elsif ($n < 32000000) { my($x0, $x1, $y0, $y1) = (16e6, 32e6, .2980, .2965); | 
| 2107 | 0 |  |  |  |  | 0 | $fm = $y0 + ($n - $x0) * ($y1-$y0) / ($x1 - $x0); } | 
| 2108 | 2 | 50 |  |  |  | 8389 | $li2 *= $fm * log(12+$logn)  if defined $fm; | 
| 2109 |  |  |  |  |  |  |  | 
| 2110 | 2 |  |  |  |  | 9 | return int(1.32032363169373914785562422 * $li2 + 0.5); | 
| 2111 |  |  |  |  |  |  | } | 
| 2112 |  |  |  |  |  |  |  | 
| 2113 |  |  |  |  |  |  | sub semiprime_count_approx { | 
| 2114 | 0 |  |  | 0 | 0 | 0 | my($n) = @_; | 
| 2115 | 0 | 0 |  |  |  | 0 | return 0 if $n < 4; | 
| 2116 | 0 |  |  |  |  | 0 | _validate_positive_integer($n); | 
| 2117 | 0 |  |  |  |  | 0 | $n = "$n" + 0.00000001; | 
| 2118 | 0 |  |  |  |  | 0 | my $l1 = log($n); | 
| 2119 | 0 |  |  |  |  | 0 | my $l2 = log($l1); | 
| 2120 |  |  |  |  |  |  | #my $est = $n * $l2 / $l1; | 
| 2121 | 0 |  |  |  |  | 0 | my $est = $n * ($l2 + 0.302) / $l1; | 
| 2122 | 0 |  |  |  |  | 0 | int(0.5+$est); | 
| 2123 |  |  |  |  |  |  | } | 
| 2124 |  |  |  |  |  |  |  | 
| 2125 |  |  |  |  |  |  | sub nth_twin_prime { | 
| 2126 | 1 |  |  | 1 | 0 | 2836 | my($n) = @_; | 
| 2127 | 1 | 50 |  |  |  | 5 | return undef if $n < 0;  ## no critic qw(ProhibitExplicitReturnUndef) | 
| 2128 | 1 | 50 |  |  |  | 4 | return (undef,3,5,11,17,29,41)[$n] if $n <= 6; | 
| 2129 |  |  |  |  |  |  |  | 
| 2130 | 1 |  |  |  |  | 68 | my $p = Math::Prime::Util::nth_twin_prime_approx($n+200); | 
| 2131 | 1 |  |  |  |  | 7 | my $tp = Math::Prime::Util::twin_primes($p); | 
| 2132 | 1 |  |  |  |  | 9 | while ($n > scalar(@$tp)) { | 
| 2133 | 0 |  |  |  |  | 0 | $n -= scalar(@$tp); | 
| 2134 | 0 |  |  |  |  | 0 | $tp = Math::Prime::Util::twin_primes($p+1,$p+1e5); | 
| 2135 | 0 |  |  |  |  | 0 | $p += 1e5; | 
| 2136 |  |  |  |  |  |  | } | 
| 2137 | 1 |  |  |  |  | 24 | return $tp->[$n-1]; | 
| 2138 |  |  |  |  |  |  | } | 
| 2139 |  |  |  |  |  |  |  | 
| 2140 |  |  |  |  |  |  | sub nth_twin_prime_approx { | 
| 2141 | 0 |  |  | 0 | 0 | 0 | my($n) = @_; | 
| 2142 | 0 |  |  |  |  | 0 | _validate_positive_integer($n); | 
| 2143 | 0 | 0 |  |  |  | 0 | return nth_twin_prime($n) if $n < 6; | 
| 2144 | 0 | 0 | 0 |  |  | 0 | $n = _upgrade_to_float($n) if ref($n) || $n > 127e14;   # TODO lower for 32-bit | 
| 2145 | 0 |  |  |  |  | 0 | my $logn = log($n); | 
| 2146 | 0 |  |  |  |  | 0 | my $nlogn2 = $n * $logn * $logn; | 
| 2147 |  |  |  |  |  |  |  | 
| 2148 | 0 | 0 | 0 |  |  | 0 | return int(5.158 * $nlogn2/log(9+log($n*$n))) if $n > 59 && $n <= 1092; | 
| 2149 |  |  |  |  |  |  |  | 
| 2150 | 0 |  |  |  |  | 0 | my $lo = int(0.7 * $nlogn2); | 
| 2151 | 0 | 0 |  |  |  | 0 | my $hi = int( ($n > 1e16) ? 1.1 * $nlogn2 | 
|  |  | 0 |  |  |  |  |  | 
| 2152 |  |  |  |  |  |  | : ($n >  480) ? 1.7 * $nlogn2 | 
| 2153 |  |  |  |  |  |  | : 2.3 * $nlogn2 + 3 ); | 
| 2154 |  |  |  |  |  |  |  | 
| 2155 |  |  |  |  |  |  | _binary_search($n, $lo, $hi, | 
| 2156 | 0 |  |  | 0 |  | 0 | sub{Math::Prime::Util::twin_prime_count_approx(shift)}, | 
| 2157 | 0 |  |  | 0 |  | 0 | sub{ ($_[2]-$_[1])/$_[1] < 1e-15 } ); | 
|  | 0 |  |  |  |  | 0 |  | 
| 2158 |  |  |  |  |  |  | } | 
| 2159 |  |  |  |  |  |  |  | 
| 2160 |  |  |  |  |  |  | sub nth_semiprime { | 
| 2161 | 0 |  |  | 0 | 0 | 0 | my $n = shift; | 
| 2162 | 0 | 0 |  |  |  | 0 | return undef if $n < 0;  ## no critic qw(ProhibitExplicitReturnUndef) | 
| 2163 | 0 | 0 |  |  |  | 0 | return (undef,4,6,9,10,14,15,21,22)[$n] if $n <= 8; | 
| 2164 | 0 |  |  |  |  | 0 | my $logn = log($n); | 
| 2165 | 0 |  |  |  |  | 0 | my $est = 0.966 * $n * $logn / log($logn); | 
| 2166 |  |  |  |  |  |  | 1+_binary_search($n, int(0.9*$est)-1, int(1.15*$est)+1, | 
| 2167 | 0 |  |  | 0 |  | 0 | sub{Math::Prime::Util::semiprime_count(shift)}); | 
|  | 0 |  |  |  |  | 0 |  | 
| 2168 |  |  |  |  |  |  | } | 
| 2169 |  |  |  |  |  |  |  | 
| 2170 |  |  |  |  |  |  | sub nth_semiprime_approx { | 
| 2171 | 0 |  |  | 0 | 0 | 0 | my $n = shift; | 
| 2172 | 0 | 0 |  |  |  | 0 | return undef if $n < 0;  ## no critic qw(ProhibitExplicitReturnUndef) | 
| 2173 | 0 |  |  |  |  | 0 | _validate_positive_integer($n); | 
| 2174 | 0 | 0 |  |  |  | 0 | return (undef,4,6,9,10,14,15,21,22)[$n] if $n <= 8; | 
| 2175 | 0 |  |  |  |  | 0 | $n = "$n" + 0.00000001; | 
| 2176 | 0 |  |  |  |  | 0 | my $l1 = log($n); | 
| 2177 | 0 |  |  |  |  | 0 | my $l2 = log($l1); | 
| 2178 | 0 |  |  |  |  | 0 | my $est = 0.966 * $n * $l1 / $l2; | 
| 2179 | 0 |  |  |  |  | 0 | int(0.5+$est); | 
| 2180 |  |  |  |  |  |  | } | 
| 2181 |  |  |  |  |  |  |  | 
| 2182 |  |  |  |  |  |  | sub nth_ramanujan_prime_upper { | 
| 2183 | 0 |  |  | 0 | 0 | 0 | my $n = shift; | 
| 2184 | 0 | 0 |  |  |  | 0 | return (0,2,11)[$n] if $n <= 2; | 
| 2185 | 0 | 0 |  |  |  | 0 | $n = Math::BigInt->new("$n") if $n > (~0/3); | 
| 2186 | 0 |  |  |  |  | 0 | my $nth = nth_prime_upper(3*$n); | 
| 2187 | 0 | 0 |  |  |  | 0 | return $nth if $n < 10000; | 
| 2188 | 0 | 0 |  |  |  | 0 | $nth = Math::BigInt->new("$nth") if $nth > (~0/177); | 
| 2189 | 0 | 0 |  |  |  | 0 | if ($n < 1000000) { $nth = (177 * $nth) >> 8; } | 
|  | 0 | 0 |  |  |  | 0 |  | 
| 2190 | 0 |  |  |  |  | 0 | elsif ($n < 1e10) { $nth = (175 * $nth) >> 8; } | 
| 2191 | 0 |  |  |  |  | 0 | else              { $nth = (133 * $nth) >> 8; } | 
| 2192 | 0 | 0 | 0 |  |  | 0 | $nth = _bigint_to_int($nth) if ref($nth) && $nth->bacmp(BMAX) <= 0; | 
| 2193 | 0 |  |  |  |  | 0 | $nth; | 
| 2194 |  |  |  |  |  |  | } | 
| 2195 |  |  |  |  |  |  | sub nth_ramanujan_prime_lower { | 
| 2196 | 0 |  |  | 0 | 0 | 0 | my $n = shift; | 
| 2197 | 0 | 0 |  |  |  | 0 | return (0,2,11)[$n] if $n <= 2; | 
| 2198 | 0 | 0 |  |  |  | 0 | $n = Math::BigInt->new("$n") if $n > (~0/2); | 
| 2199 | 0 |  |  |  |  | 0 | my $nth = nth_prime_lower(2*$n); | 
| 2200 | 0 | 0 |  |  |  | 0 | $nth = Math::BigInt->new("$nth") if $nth > (~0/275); | 
| 2201 | 0 | 0 |  |  |  | 0 | if ($n < 10000)   { $nth = (275 * $nth) >> 8; } | 
|  | 0 | 0 |  |  |  | 0 |  | 
| 2202 | 0 |  |  |  |  | 0 | elsif ($n < 1e10) { $nth = (262 * $nth) >> 8; } | 
| 2203 | 0 | 0 | 0 |  |  | 0 | $nth = _bigint_to_int($nth) if ref($nth) && $nth->bacmp(BMAX) <= 0; | 
| 2204 | 0 |  |  |  |  | 0 | $nth; | 
| 2205 |  |  |  |  |  |  | } | 
| 2206 |  |  |  |  |  |  | sub nth_ramanujan_prime_approx { | 
| 2207 | 0 |  |  | 0 | 0 | 0 | my $n = shift; | 
| 2208 | 0 | 0 |  |  |  | 0 | return (0,2,11)[$n] if $n <= 2; | 
| 2209 | 0 |  |  |  |  | 0 | my($lo,$hi) = (nth_ramanujan_prime_lower($n),nth_ramanujan_prime_upper($n)); | 
| 2210 | 0 |  |  |  |  | 0 | $lo + (($hi-$lo)>>1); | 
| 2211 |  |  |  |  |  |  | } | 
| 2212 |  |  |  |  |  |  | sub ramanujan_prime_count_upper { | 
| 2213 | 0 |  |  | 0 | 0 | 0 | my $n = shift; | 
| 2214 | 0 | 0 |  |  |  | 0 | return (($n < 2) ? 0 : 1) if $n < 11; | 
|  |  | 0 |  |  |  |  |  | 
| 2215 | 0 |  |  |  |  | 0 | my $lo = int(prime_count_lower($n) / 3); | 
| 2216 | 0 |  |  |  |  | 0 | my $hi = prime_count_upper($n) >> 1; | 
| 2217 |  |  |  |  |  |  | 1+_binary_search($n, $lo, $hi, | 
| 2218 | 0 |  |  | 0 |  | 0 | sub{Math::Prime::Util::nth_ramanujan_prime_lower(shift)}); | 
|  | 0 |  |  |  |  | 0 |  | 
| 2219 |  |  |  |  |  |  | } | 
| 2220 |  |  |  |  |  |  | sub ramanujan_prime_count_lower { | 
| 2221 | 0 |  |  | 0 | 0 | 0 | my $n = shift; | 
| 2222 | 0 | 0 |  |  |  | 0 | return (($n < 2) ? 0 : 1) if $n < 11; | 
|  |  | 0 |  |  |  |  |  | 
| 2223 | 0 |  |  |  |  | 0 | my $lo = int(prime_count_lower($n) / 3); | 
| 2224 | 0 |  |  |  |  | 0 | my $hi = prime_count_upper($n) >> 1; | 
| 2225 |  |  |  |  |  |  | _binary_search($n, $lo, $hi, | 
| 2226 | 0 |  |  | 0 |  | 0 | sub{Math::Prime::Util::nth_ramanujan_prime_upper(shift)}); | 
|  | 0 |  |  |  |  | 0 |  | 
| 2227 |  |  |  |  |  |  | } | 
| 2228 |  |  |  |  |  |  | sub ramanujan_prime_count_approx { | 
| 2229 | 0 |  |  | 0 | 0 | 0 | my $n = shift; | 
| 2230 | 0 | 0 |  |  |  | 0 | return (($n < 2) ? 0 : 1) if $n < 11; | 
|  |  | 0 |  |  |  |  |  | 
| 2231 |  |  |  |  |  |  | #$n = _upgrade_to_float($n) if ref($n) || $n > 2e16; | 
| 2232 | 0 |  |  |  |  | 0 | my $lo = ramanujan_prime_count_lower($n); | 
| 2233 | 0 |  |  |  |  | 0 | my $hi = ramanujan_prime_count_upper($n); | 
| 2234 |  |  |  |  |  |  | _binary_search($n, $lo, $hi, | 
| 2235 | 0 |  |  | 0 |  | 0 | sub{Math::Prime::Util::nth_ramanujan_prime_approx(shift)}, | 
| 2236 | 0 |  |  | 0 |  | 0 | sub{ ($_[2]-$_[1])/$_[1] < 1e-15 } ); | 
|  | 0 |  |  |  |  | 0 |  | 
| 2237 |  |  |  |  |  |  | } | 
| 2238 |  |  |  |  |  |  |  | 
| 2239 |  |  |  |  |  |  | sub _sum_primes_n { | 
| 2240 | 0 |  |  | 0 |  | 0 | my $n = shift; | 
| 2241 | 0 | 0 |  |  |  | 0 | return (0,0,2,5,5)[$n] if $n < 5; | 
| 2242 | 0 |  |  |  |  | 0 | my $r = Math::Prime::Util::sqrtint($n); | 
| 2243 | 0 |  |  |  |  | 0 | my $r2 = $r + int($n/($r+1)); | 
| 2244 | 0 |  |  |  |  | 0 | my(@V,@S); | 
| 2245 | 0 |  |  |  |  | 0 | for my $k (0 .. $r2) { | 
| 2246 | 0 | 0 |  |  |  | 0 | my $v = ($k <= $r) ? $k : int($n/($r2-$k+1)); | 
| 2247 | 0 |  |  |  |  | 0 | $V[$k] = $v; | 
| 2248 | 0 |  |  |  |  | 0 | $S[$k] = (($v*($v+1)) >> 1) - 1; | 
| 2249 |  |  |  |  |  |  | } | 
| 2250 | 0 |  |  | 0 |  | 0 | Math::Prime::Util::forprimes( sub { my $p = $_; | 
| 2251 | 0 |  |  |  |  | 0 | my $sp = $S[$p-1]; | 
| 2252 | 0 |  |  |  |  | 0 | my $p2 = $p*$p; | 
| 2253 | 0 |  |  |  |  | 0 | for my $v (reverse @V) { | 
| 2254 | 0 | 0 |  |  |  | 0 | last if $v < $p2; | 
| 2255 | 0 |  |  |  |  | 0 | my($a,$b) = ($v,int($v/$p)); | 
| 2256 | 0 | 0 |  |  |  | 0 | $a = $r2 - int($n/$a) + 1 if $a > $r; | 
| 2257 | 0 | 0 |  |  |  | 0 | $b = $r2 - int($n/$b) + 1 if $b > $r; | 
| 2258 | 0 |  |  |  |  | 0 | $S[$a] -= $p * ($S[$b] - $sp); | 
| 2259 |  |  |  |  |  |  | } | 
| 2260 | 0 |  |  |  |  | 0 | }, 2, $r); | 
| 2261 | 0 |  |  |  |  | 0 | $S[$r2]; | 
| 2262 |  |  |  |  |  |  | } | 
| 2263 |  |  |  |  |  |  |  | 
| 2264 |  |  |  |  |  |  | sub sum_primes { | 
| 2265 | 0 |  |  | 0 | 0 | 0 | my($low,$high) = @_; | 
| 2266 | 0 | 0 |  |  |  | 0 | if (defined $high) { _validate_positive_integer($low); } | 
|  | 0 |  |  |  |  | 0 |  | 
| 2267 | 0 |  |  |  |  | 0 | else               { ($low,$high) = (2, $low);         } | 
| 2268 | 0 |  |  |  |  | 0 | _validate_positive_integer($high); | 
| 2269 | 0 |  |  |  |  | 0 | my $sum = 0; | 
| 2270 | 0 | 0 |  |  |  | 0 | $sum = BZERO->copy if ( (MPU_32BIT && $high >        323_380) || | 
| 2271 |  |  |  |  |  |  | (MPU_64BIT && $high > 29_505_444_490) ); | 
| 2272 |  |  |  |  |  |  |  | 
| 2273 |  |  |  |  |  |  | # It's very possible we're here because they've counted too high.  Skip fwd. | 
| 2274 | 0 | 0 | 0 |  |  | 0 | if ($low <= 2 && $high >= 29505444491) { | 
| 2275 | 0 |  |  |  |  | 0 | $low = 29505444503; | 
| 2276 | 0 |  |  |  |  | 0 | $sum = Math::BigInt->new("18446744087046669523"); | 
| 2277 |  |  |  |  |  |  | } | 
| 2278 |  |  |  |  |  |  |  | 
| 2279 | 0 | 0 |  |  |  | 0 | return $sum if $low > $high; | 
| 2280 |  |  |  |  |  |  |  | 
| 2281 |  |  |  |  |  |  | # We have to make some decision about whether to use our PP prime sum or loop | 
| 2282 |  |  |  |  |  |  | # doing the XS sieve.  TODO: Be smarter here? | 
| 2283 | 0 | 0 | 0 |  |  | 0 | if (!Math::Prime::Util::prime_get_config()->{'xs'} && !ref($sum) && !MPU_32BIT && ($high-$low) > 1000000) { | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
| 2284 |  |  |  |  |  |  | # Unfortunately with bigints this is horrifically slow, but we have to do it. | 
| 2285 | 0 | 0 |  |  |  | 0 | $high = BZERO->copy + $high  if $high >= (1 << (MPU_MAXBITS/2))-1; | 
| 2286 | 0 |  |  |  |  | 0 | $sum = _sum_primes_n($high); | 
| 2287 | 0 | 0 |  |  |  | 0 | $sum -= _sum_primes_n($low-1) if $low > 2; | 
| 2288 | 0 |  |  |  |  | 0 | return $sum; | 
| 2289 |  |  |  |  |  |  | } | 
| 2290 |  |  |  |  |  |  |  | 
| 2291 | 0 |  | 0 |  |  | 0 | my $xssum = (MPU_64BIT && $high < 6e14 && Math::Prime::Util::prime_get_config()->{'xs'}); | 
| 2292 | 0 | 0 | 0 |  |  | 0 | my $step = ($xssum && $high > 5e13) ? 1_000_000 : 11_000_000; | 
| 2293 | 0 |  |  |  |  | 0 | Math::Prime::Util::prime_precalc(sqrtint($high)); | 
| 2294 | 0 |  |  |  |  | 0 | while ($low <= $high) { | 
| 2295 | 0 |  |  |  |  | 0 | my $next = $low + $step - 1; | 
| 2296 | 0 | 0 |  |  |  | 0 | $next = $high if $next > $high; | 
| 2297 |  |  |  |  |  |  | $sum += ($xssum) ? Math::Prime::Util::sum_primes($low,$next) | 
| 2298 | 0 | 0 |  |  |  | 0 | : Math::Prime::Util::vecsum( @{Math::Prime::Util::primes($low,$next)} ); | 
|  | 0 |  |  |  |  | 0 |  | 
| 2299 | 0 | 0 |  |  |  | 0 | last if $next == $high; | 
| 2300 | 0 |  |  |  |  | 0 | $low = $next+1; | 
| 2301 |  |  |  |  |  |  | } | 
| 2302 | 0 |  |  |  |  | 0 | $sum; | 
| 2303 |  |  |  |  |  |  | } | 
| 2304 |  |  |  |  |  |  | sub print_primes { | 
| 2305 | 0 |  |  | 0 | 0 | 0 | my($low,$high,$fd) = @_; | 
| 2306 | 0 | 0 |  |  |  | 0 | if (defined $high) { _validate_positive_integer($low); } | 
|  | 0 |  |  |  |  | 0 |  | 
| 2307 | 0 |  |  |  |  | 0 | else               { ($low,$high) = (2, $low);         } | 
| 2308 | 0 |  |  |  |  | 0 | _validate_positive_integer($high); | 
| 2309 |  |  |  |  |  |  |  | 
| 2310 | 0 | 0 |  |  |  | 0 | $fd = fileno(STDOUT) unless defined $fd; | 
| 2311 | 0 |  |  |  |  | 0 | open(my $fh, ">>&=", $fd);  # TODO .... or die | 
| 2312 |  |  |  |  |  |  |  | 
| 2313 | 0 | 0 |  |  |  | 0 | if ($high >= $low) { | 
| 2314 | 0 |  |  |  |  | 0 | my $p1 = $low; | 
| 2315 | 0 |  |  |  |  | 0 | while ($p1 <= $high) { | 
| 2316 | 0 |  |  |  |  | 0 | my $p2 = $p1 + 15_000_000 - 1; | 
| 2317 | 0 | 0 |  |  |  | 0 | $p2 = $high if $p2 > $high; | 
| 2318 | 0 | 0 |  |  |  | 0 | if ($Math::Prime::Util::_GMPfunc{"sieve_primes"}) { | 
| 2319 | 0 |  |  |  |  | 0 | print $fh "$_\n" for Math::Prime::Util::GMP::sieve_primes($p1,$p2,0); | 
| 2320 |  |  |  |  |  |  | } else { | 
| 2321 | 0 |  |  |  |  | 0 | print $fh "$_\n" for @{primes($p1,$p2)}; | 
|  | 0 |  |  |  |  | 0 |  | 
| 2322 |  |  |  |  |  |  | } | 
| 2323 | 0 |  |  |  |  | 0 | $p1 = $p2+1; | 
| 2324 |  |  |  |  |  |  | } | 
| 2325 |  |  |  |  |  |  | } | 
| 2326 | 0 |  |  |  |  | 0 | close($fh); | 
| 2327 |  |  |  |  |  |  | } | 
| 2328 |  |  |  |  |  |  |  | 
| 2329 |  |  |  |  |  |  |  | 
| 2330 |  |  |  |  |  |  | ############################################################################# | 
| 2331 |  |  |  |  |  |  |  | 
| 2332 |  |  |  |  |  |  | sub _mulmod { | 
| 2333 | 43023 |  |  | 43023 |  | 65989 | my($x, $y, $n) = @_; | 
| 2334 | 43023 | 100 |  |  |  | 86564 | return (($x * $y) % $n) if ($x|$y) < MPU_HALFWORD; | 
| 2335 |  |  |  |  |  |  | #return (($x * $y) % $n) if ($x|$y) < MPU_HALFWORD || $y == 0 || $x < int(~0/$y); | 
| 2336 | 43023 |  |  |  |  | 52475 | my $r = 0; | 
| 2337 | 43023 | 50 |  |  |  | 67979 | $x %= $n if $x >= $n; | 
| 2338 | 43023 | 50 |  |  |  | 65510 | $y %= $n if $y >= $n; | 
| 2339 | 43023 | 100 |  |  |  | 65313 | ($x,$y) = ($y,$x) if $x < $y; | 
| 2340 | 43023 | 100 |  |  |  | 60795 | if ($n <= (~0 >> 1)) { | 
| 2341 | 40495 |  |  |  |  | 66555 | while ($y > 1) { | 
| 2342 | 1902318 | 100 |  |  |  | 2998351 | if ($y & 1) { $r += $x;  $r -= $n if $r >= $n; } | 
|  | 929259 | 100 |  |  |  | 1126446 |  | 
|  | 929259 |  |  |  |  | 1480297 |  | 
| 2343 | 1902318 |  |  |  |  | 2283159 | $y >>= 1; | 
| 2344 | 1902318 | 100 |  |  |  | 2301183 | $x += $x;  $x -= $n if $x >= $n; | 
|  | 1902318 |  |  |  |  | 3650964 |  | 
| 2345 |  |  |  |  |  |  | } | 
| 2346 | 40495 | 100 |  |  |  | 68167 | if ($y & 1) { $r += $x;  $r -= $n if $r >= $n; } | 
|  | 40495 | 50 |  |  |  | 49103 |  | 
|  | 40495 |  |  |  |  | 67950 |  | 
| 2347 |  |  |  |  |  |  | } else { | 
| 2348 | 2528 |  |  |  |  | 695 | while ($y > 1) { | 
| 2349 | 26018 | 100 |  |  |  | 41151 | if ($y & 1) { $r = $n-$r;  $r = ($x >= $r) ? $x-$r : $n-$r+$x; } | 
|  | 12752 | 100 |  |  |  | 15823 |  | 
|  | 12752 |  |  |  |  | 19815 |  | 
| 2350 | 26018 |  |  |  |  | 31051 | $y >>= 1; | 
| 2351 | 26018 | 100 |  |  |  | 50847 | $x = ($x > ($n - $x))  ?  ($x - $n) + $x  :  $x + $x; | 
| 2352 |  |  |  |  |  |  | } | 
| 2353 | 2528 | 100 |  |  |  | 717 | if ($y & 1) { $r = $n-$r;  $r = ($x >= $r) ? $x-$r : $n-$r+$x; } | 
|  | 424 | 50 |  |  |  | 532 |  | 
|  | 424 |  |  |  |  | 719 |  | 
| 2354 |  |  |  |  |  |  | } | 
| 2355 | 43023 |  |  |  |  | 71429 | $r; | 
| 2356 |  |  |  |  |  |  | } | 
| 2357 |  |  |  |  |  |  | sub _addmod { | 
| 2358 | 33314 |  |  | 33314 |  | 297978 | my($x, $y, $n) = @_; | 
| 2359 | 33314 | 50 |  |  |  | 56125 | $x %= $n if $x >= $n; | 
| 2360 | 33314 | 100 |  |  |  | 73576 | $y %= $n if $y >= $n; | 
| 2361 | 33314 | 100 |  |  |  | 68227 | if (($n-$x) <= $y) { | 
| 2362 | 215 | 100 |  |  |  | 39068 | ($x,$y) = ($y,$x) if $y > $x; | 
| 2363 | 215 |  |  |  |  | 12884 | $x -= $n; | 
| 2364 |  |  |  |  |  |  | } | 
| 2365 | 33314 |  |  |  |  | 114045 | $x + $y; | 
| 2366 |  |  |  |  |  |  | } | 
| 2367 |  |  |  |  |  |  |  | 
| 2368 |  |  |  |  |  |  | # Note that Perl 5.6.2 with largish 64-bit numbers will break.  As usual. | 
| 2369 |  |  |  |  |  |  | sub _native_powmod { | 
| 2370 | 3602 |  |  | 3602 |  | 5853 | my($n, $power, $m) = @_; | 
| 2371 | 3602 |  |  |  |  | 4669 | my $t = 1; | 
| 2372 | 3602 |  |  |  |  | 4892 | $n = $n % $m; | 
| 2373 | 3602 |  |  |  |  | 5858 | while ($power) { | 
| 2374 | 66865 | 100 |  |  |  | 109097 | $t = ($t * $n) % $m if ($power & 1); | 
| 2375 | 66865 |  |  |  |  | 79417 | $power >>= 1; | 
| 2376 | 66865 | 100 |  |  |  | 127844 | $n = ($n * $n) % $m if $power; | 
| 2377 |  |  |  |  |  |  | } | 
| 2378 | 3602 |  |  |  |  | 5554 | $t; | 
| 2379 |  |  |  |  |  |  | } | 
| 2380 |  |  |  |  |  |  |  | 
| 2381 |  |  |  |  |  |  | sub _powmod { | 
| 2382 | 186 |  |  | 186 |  | 449 | my($n, $power, $m) = @_; | 
| 2383 | 186 |  |  |  |  | 300 | my $t = 1; | 
| 2384 |  |  |  |  |  |  |  | 
| 2385 | 186 | 50 |  |  |  | 441 | $n %= $m if $n >= $m; | 
| 2386 | 186 | 100 |  |  |  | 421 | if ($m < MPU_HALFWORD) { | 
| 2387 | 12 |  |  |  |  | 46 | while ($power) { | 
| 2388 | 219 | 100 |  |  |  | 336 | $t = ($t * $n) % $m if ($power & 1); | 
| 2389 | 219 |  |  |  |  | 240 | $power >>= 1; | 
| 2390 | 219 | 100 |  |  |  | 540 | $n = ($n * $n) % $m if $power; | 
| 2391 |  |  |  |  |  |  | } | 
| 2392 |  |  |  |  |  |  | } else { | 
| 2393 | 174 |  |  |  |  | 455 | while ($power) { | 
| 2394 | 7013 | 100 |  |  |  | 12963 | $t = _mulmod($t, $n, $m) if ($power & 1); | 
| 2395 | 7013 |  |  |  |  | 9400 | $power >>= 1; | 
| 2396 | 7013 | 100 |  |  |  | 13467 | $n = _mulmod($n, $n, $m) if $power; | 
| 2397 |  |  |  |  |  |  | } | 
| 2398 |  |  |  |  |  |  | } | 
| 2399 | 186 |  |  |  |  | 482 | $t; | 
| 2400 |  |  |  |  |  |  | } | 
| 2401 |  |  |  |  |  |  |  | 
| 2402 |  |  |  |  |  |  | # Make sure to work around RT71548, Math::BigInt::Lite, | 
| 2403 |  |  |  |  |  |  | # and use correct lcm semantics. | 
| 2404 |  |  |  |  |  |  | sub gcd { | 
| 2405 |  |  |  |  |  |  | # First see if all inputs are non-bigints  5-10x faster if so. | 
| 2406 | 7 | 100 |  | 7 | 0 | 417 | if (0 == scalar(grep { ref($_) } @_)) { | 
|  | 16 |  |  |  |  | 54 |  | 
| 2407 | 1 |  | 50 |  |  | 7 | my($x,$y) = (shift || 0, 0); | 
| 2408 | 1 |  |  |  |  | 4 | while (@_) { | 
| 2409 | 2 |  |  |  |  | 5 | $y = shift; | 
| 2410 | 2 |  |  |  |  | 5 | while ($y) {  ($x,$y) = ($y, $x % $y);  } | 
|  | 4 |  |  |  |  | 10 |  | 
| 2411 | 2 | 100 |  |  |  | 8 | $x = -$x if $x < 0; | 
| 2412 |  |  |  |  |  |  | } | 
| 2413 | 1 |  |  |  |  | 6 | return $x; | 
| 2414 |  |  |  |  |  |  | } | 
| 2415 |  |  |  |  |  |  | my $gcd = Math::BigInt::bgcd( map { | 
| 2416 | 6 | 50 | 66 |  |  | 18 | my $v = (($_ < 2147483647 && !ref($_)) || ref($_) eq 'Math::BigInt') ? $_ : "$_"; | 
|  | 13 |  |  |  |  | 54 |  | 
| 2417 | 13 |  |  |  |  | 1692 | $v; | 
| 2418 |  |  |  |  |  |  | } @_ ); | 
| 2419 | 6 | 50 |  |  |  | 24513 | $gcd = _bigint_to_int($gcd) if $gcd->bacmp(BMAX) <= 0; | 
| 2420 | 6 |  |  |  |  | 177 | return $gcd; | 
| 2421 |  |  |  |  |  |  | } | 
| 2422 |  |  |  |  |  |  | sub lcm { | 
| 2423 | 4 | 50 |  | 4 | 0 | 528 | return 0 unless @_; | 
| 2424 |  |  |  |  |  |  | my $lcm = Math::BigInt::blcm( map { | 
| 2425 | 4 | 50 | 66 |  |  | 13 | my $v = (($_ < 2147483647 && !ref($_)) || ref($_) eq 'Math::BigInt') ? $_ : "$_"; | 
|  | 12 |  |  |  |  | 44 |  | 
| 2426 | 12 | 50 |  |  |  | 1199 | return 0 if $v == 0; | 
| 2427 | 12 | 50 |  |  |  | 1505 | $v = -$v if $v < 0; | 
| 2428 | 12 |  |  |  |  | 1506 | $v; | 
| 2429 |  |  |  |  |  |  | } @_ ); | 
| 2430 | 4 | 100 |  |  |  | 5900 | $lcm = _bigint_to_int($lcm) if $lcm->bacmp(BMAX) <= 0; | 
| 2431 | 4 |  |  |  |  | 137 | return $lcm; | 
| 2432 |  |  |  |  |  |  | } | 
| 2433 |  |  |  |  |  |  | sub gcdext { | 
| 2434 | 3 |  |  | 3 | 0 | 145 | my($x,$y) = @_; | 
| 2435 | 3 | 50 |  |  |  | 16 | if ($x == 0) { return (0, (-1,0,1)[($y>=0)+($y>0)], abs($y)); } | 
|  | 0 |  |  |  |  | 0 |  | 
| 2436 | 3 | 50 |  |  |  | 222 | if ($y == 0) { return ((-1,0,1)[($x>=0)+($x>0)], 0, abs($x)); } | 
|  | 0 |  |  |  |  | 0 |  | 
| 2437 |  |  |  |  |  |  |  | 
| 2438 | 3 | 50 |  |  |  | 182 | if ($Math::Prime::Util::_GMPfunc{"gcdext"}) { | 
| 2439 | 0 |  |  |  |  | 0 | my($a,$b,$g) = Math::Prime::Util::GMP::gcdext($x,$y); | 
| 2440 | 0 |  |  |  |  | 0 | $a = Math::Prime::Util::_reftyped($_[0], $a); | 
| 2441 | 0 |  |  |  |  | 0 | $b = Math::Prime::Util::_reftyped($_[0], $b); | 
| 2442 | 0 |  |  |  |  | 0 | $g = Math::Prime::Util::_reftyped($_[0], $g); | 
| 2443 | 0 |  |  |  |  | 0 | return ($a,$b,$g); | 
| 2444 |  |  |  |  |  |  | } | 
| 2445 |  |  |  |  |  |  |  | 
| 2446 | 3 |  |  |  |  | 12 | my($a,$b,$g,$u,$v,$w); | 
| 2447 | 3 | 100 | 66 |  |  | 20 | if (abs($x) < (~0>>1) && abs($y) < (~0>>1)) { | 
| 2448 | 1 | 50 |  |  |  | 6 | $x = _bigint_to_int($x) if ref($x) eq 'Math::BigInt'; | 
| 2449 | 1 | 50 |  |  |  | 3 | $y = _bigint_to_int($y) if ref($y) eq 'Math::BigInt'; | 
| 2450 | 1 |  |  |  |  | 4 | ($a,$b,$g,$u,$v,$w) = (1,0,$x,0,1,$y); | 
| 2451 | 1 |  |  |  |  | 5 | while ($w != 0) { | 
| 2452 | 10 |  |  |  |  | 14 | my $r = $g % $w; | 
| 2453 | 10 |  |  |  |  | 17 | my $q = int(($g-$r)/$w); | 
| 2454 | 10 |  |  |  |  | 27 | ($a,$b,$g,$u,$v,$w) = ($u,$v,$w,$a-$q*$u,$b-$q*$v,$r); | 
| 2455 |  |  |  |  |  |  | } | 
| 2456 |  |  |  |  |  |  | } else { | 
| 2457 | 2 |  |  |  |  | 196 | ($a,$b,$g,$u,$v,$w) = (BONE->copy,BZERO->copy,Math::BigInt->new("$x"), | 
| 2458 |  |  |  |  |  |  | BZERO->copy,BONE->copy,Math::BigInt->new("$y")); | 
| 2459 | 2 |  |  |  |  | 520 | while ($w != 0) { | 
| 2460 |  |  |  |  |  |  | # Using the array bdiv is logical, but is the wrong sign. | 
| 2461 | 109 |  |  |  |  | 62138 | my $r = $g->copy->bmod($w); | 
| 2462 | 109 |  |  |  |  | 21227 | my $q = $g->copy->bsub($r)->bdiv($w); | 
| 2463 | 109 |  |  |  |  | 35198 | ($a,$b,$g,$u,$v,$w) = ($u,$v,$w,$a-$q*$u,$b-$q*$v,$r); | 
| 2464 |  |  |  |  |  |  | } | 
| 2465 | 2 | 100 |  |  |  | 1263 | $a = _bigint_to_int($a) if $a->bacmp(BMAX) <= 0; | 
| 2466 | 2 | 100 |  |  |  | 105 | $b = _bigint_to_int($b) if $b->bacmp(BMAX) <= 0; | 
| 2467 | 2 | 50 |  |  |  | 62 | $g = _bigint_to_int($g) if $g->bacmp(BMAX) <= 0; | 
| 2468 |  |  |  |  |  |  | } | 
| 2469 | 3 | 50 |  |  |  | 92 | if ($g < 0) { ($a,$b,$g) = (-$a,-$b,-$g); } | 
|  | 0 |  |  |  |  | 0 |  | 
| 2470 | 3 |  |  |  |  | 57 | return ($a,$b,$g); | 
| 2471 |  |  |  |  |  |  | } | 
| 2472 |  |  |  |  |  |  |  | 
| 2473 |  |  |  |  |  |  | sub chinese { | 
| 2474 | 7 | 50 |  | 7 | 0 | 4953 | return 0 unless scalar @_; | 
| 2475 | 7 | 50 |  |  |  | 23 | return $_[0]->[0] % $_[0]->[1] if scalar @_ == 1; | 
| 2476 | 7 |  |  |  |  | 16 | my($lcm, $sum); | 
| 2477 |  |  |  |  |  |  |  | 
| 2478 | 7 | 50 | 33 |  |  | 26 | if ($Math::Prime::Util::_GMPfunc{"chinese"} && $Math::Prime::Util::GMP::VERSION >= 0.42) { | 
| 2479 | 0 |  |  |  |  | 0 | $sum = Math::Prime::Util::GMP::chinese(@_); | 
| 2480 | 0 | 0 |  |  |  | 0 | if (defined $sum) { | 
| 2481 | 0 |  |  |  |  | 0 | $sum = Math::BigInt->new("$sum"); | 
| 2482 | 0 | 0 | 0 |  |  | 0 | $sum = _bigint_to_int($sum) if ref($sum) && $sum->bacmp(BMAX) <= 0; | 
| 2483 |  |  |  |  |  |  | } | 
| 2484 | 0 |  |  |  |  | 0 | return $sum; | 
| 2485 |  |  |  |  |  |  | } | 
| 2486 | 7 |  |  |  |  | 32 | foreach my $aref (sort { $b->[1] <=> $a->[1] } @_) { | 
|  | 7 |  |  |  |  | 37 |  | 
| 2487 | 14 |  |  |  |  | 81 | my($ai, $ni) = @$aref; | 
| 2488 | 14 | 50 | 50 |  |  | 73 | $ai = Math::BigInt->new("$ai") if !ref($ai) && (abs($ai) > (~0>>1) || OLD_PERL_VERSION); | 
|  |  |  | 66 |  |  |  |  | 
| 2489 | 14 | 100 | 100 |  |  | 56 | $ni = Math::BigInt->new("$ni") if !ref($ni) && (abs($ni) > (~0>>1) || OLD_PERL_VERSION); | 
|  |  |  | 66 |  |  |  |  | 
| 2490 | 14 | 100 |  |  |  | 140 | if (!defined $lcm) { | 
| 2491 | 7 |  |  |  |  | 25 | ($sum,$lcm) = ($ai % $ni, $ni); | 
| 2492 | 7 |  |  |  |  | 312 | next; | 
| 2493 |  |  |  |  |  |  | } | 
| 2494 |  |  |  |  |  |  | # gcdext | 
| 2495 | 7 |  |  |  |  | 24 | my($u,$v,$g,$s,$t,$w) = (1,0,$lcm,0,1,$ni); | 
| 2496 | 7 |  |  |  |  | 22 | while ($w != 0) { | 
| 2497 | 166 |  |  |  |  | 19361 | my $r = $g % $w; | 
| 2498 | 166 | 100 |  |  |  | 6101 | my $q = ref($g)  ?  $g->copy->bsub($r)->bdiv($w)  :  int(($g-$r)/$w); | 
| 2499 | 166 |  |  |  |  | 10782 | ($u,$v,$g,$s,$t,$w) = ($s,$t,$w,$u-$q*$s,$v-$q*$t,$r); | 
| 2500 |  |  |  |  |  |  | } | 
| 2501 | 7 | 50 |  |  |  | 1517 | ($u,$v,$g) = (-$u,-$v,-$g)  if $g < 0; | 
| 2502 | 7 | 50 | 66 |  |  | 359 | return if $g != 1 && ($sum % $g) != ($ai % $g);  # Not co-prime | 
| 2503 | 7 | 100 |  |  |  | 543 | $s = -$s if $s < 0; | 
| 2504 | 7 | 100 |  |  |  | 366 | $t = -$t if $t < 0; | 
| 2505 |  |  |  |  |  |  | # Convert to bigint if necessary.  Performance goes to hell. | 
| 2506 | 7 | 100 | 100 |  |  | 362 | if (!ref($lcm) && ($lcm*$s) > ~0) { $lcm = Math::BigInt->new("$lcm"); } | 
|  | 4 |  |  |  |  | 20 |  | 
| 2507 | 7 | 100 |  |  |  | 275 | if (ref($lcm)) { | 
| 2508 | 6 |  |  |  |  | 27 | $lcm->bmul("$s"); | 
| 2509 | 6 |  |  |  |  | 1373 | my $m1 = Math::BigInt->new("$v")->bmul("$s")->bmod($lcm); | 
| 2510 | 6 |  |  |  |  | 2444 | my $m2 = Math::BigInt->new("$u")->bmul("$t")->bmod($lcm); | 
| 2511 | 6 |  |  |  |  | 2246 | $m1->bmul("$sum")->bmod($lcm); | 
| 2512 | 6 |  |  |  |  | 2882 | $m2->bmul("$ai")->bmod($lcm); | 
| 2513 | 6 |  |  |  |  | 2937 | $sum = $m1->badd($m2)->bmod($lcm); | 
| 2514 |  |  |  |  |  |  | } else { | 
| 2515 | 1 |  |  |  |  | 3 | $lcm *= $s; | 
| 2516 | 1 | 50 |  |  |  | 4 | $u += $lcm if $u < 0; | 
| 2517 | 1 | 50 |  |  |  | 4 | $v += $lcm if $v < 0; | 
| 2518 | 1 |  |  |  |  | 4 | my $vs = _mulmod($v,$s,$lcm); | 
| 2519 | 1 |  |  |  |  | 4 | my $ut = _mulmod($u,$t,$lcm); | 
| 2520 | 1 |  |  |  |  | 3 | my $m1 = _mulmod($sum,$vs,$lcm); | 
| 2521 | 1 |  |  |  |  | 3 | my $m2 = _mulmod($ut,$ai % $lcm,$lcm); | 
| 2522 | 1 |  |  |  |  | 3 | $sum = _addmod($m1, $m2, $lcm); | 
| 2523 |  |  |  |  |  |  | } | 
| 2524 |  |  |  |  |  |  | } | 
| 2525 | 7 | 100 | 100 |  |  | 1496 | $sum = _bigint_to_int($sum) if ref($sum) && $sum->bacmp(BMAX) <= 0; | 
| 2526 | 7 |  |  |  |  | 178 | $sum; | 
| 2527 |  |  |  |  |  |  | } | 
| 2528 |  |  |  |  |  |  |  | 
| 2529 |  |  |  |  |  |  | sub _from_128 { | 
| 2530 | 0 |  |  | 0 |  | 0 | my($hi, $lo) = @_; | 
| 2531 | 0 | 0 | 0 |  |  | 0 | return 0 unless defined $hi && defined $lo; | 
| 2532 |  |  |  |  |  |  | #print "hi $hi lo $lo\n"; | 
| 2533 | 0 |  |  |  |  | 0 | (Math::BigInt->new("$hi") << MPU_MAXBITS) + $lo; | 
| 2534 |  |  |  |  |  |  | } | 
| 2535 |  |  |  |  |  |  |  | 
| 2536 |  |  |  |  |  |  | sub vecsum { | 
| 2537 | 528 | 0 |  | 528 | 0 | 3752 | return Math::Prime::Util::_reftyped($_[0], @_ ? $_[0] : 0)  if @_ <= 1; | 
|  |  | 50 |  |  |  |  |  | 
| 2538 |  |  |  |  |  |  |  | 
| 2539 |  |  |  |  |  |  | return Math::Prime::Util::_reftyped($_[0], Math::Prime::Util::GMP::vecsum(@_)) | 
| 2540 | 528 | 50 |  |  |  | 1527 | if $Math::Prime::Util::_GMPfunc{"vecsum"}; | 
| 2541 | 528 |  |  |  |  | 1064 | my $sum = 0; | 
| 2542 | 528 |  |  |  |  | 964 | my $neglim = -(INTMAX >> 1) - 1; | 
| 2543 | 528 |  |  |  |  | 1401 | foreach my $v (@_) { | 
| 2544 | 2072 |  |  |  |  | 5939 | $sum += $v; | 
| 2545 | 2072 | 100 | 100 |  |  | 63787 | if ($sum > (INTMAX-250) || $sum < $neglim) { | 
| 2546 | 514 |  |  |  |  | 35437 | $sum = BZERO->copy; | 
| 2547 | 514 |  |  |  |  | 14030 | $sum->badd("$_") for @_; | 
| 2548 | 514 |  |  |  |  | 5038601 | return $sum; | 
| 2549 |  |  |  |  |  |  | } | 
| 2550 |  |  |  |  |  |  | } | 
| 2551 | 14 |  |  |  |  | 75 | $sum; | 
| 2552 |  |  |  |  |  |  | } | 
| 2553 |  |  |  |  |  |  |  | 
| 2554 |  |  |  |  |  |  | sub vecprod { | 
| 2555 | 14078 | 50 |  | 14078 | 0 | 65511 | return 1 unless @_; | 
| 2556 |  |  |  |  |  |  | return Math::Prime::Util::_reftyped($_[0], Math::Prime::Util::GMP::vecprod(@_)) | 
| 2557 | 14078 | 50 |  |  |  | 36715 | if $Math::Prime::Util::_GMPfunc{"vecprod"}; | 
| 2558 |  |  |  |  |  |  | # Product tree: | 
| 2559 | 14078 |  |  |  |  | 37262 | my $prod = _product(0, $#_, [map { Math::BigInt->new("$_") } @_]); | 
|  | 29884 |  |  |  |  | 2542544 |  | 
| 2560 |  |  |  |  |  |  | # Linear: | 
| 2561 |  |  |  |  |  |  | # my $prod = BONE->copy;  $prod *= "$_" for @_; | 
| 2562 | 14078 | 100 | 66 |  |  | 6654014 | $prod = _bigint_to_int($prod) if $prod->bacmp(BMAX) <= 0 && $prod->bcmp(-(BMAX>>1)) > 0; | 
| 2563 | 14078 |  |  |  |  | 324183 | $prod; | 
| 2564 |  |  |  |  |  |  | } | 
| 2565 |  |  |  |  |  |  |  | 
| 2566 |  |  |  |  |  |  | sub vecmin { | 
| 2567 | 1 | 50 |  | 1 | 0 | 5 | return unless @_; | 
| 2568 | 1 |  |  |  |  | 2 | my $min = shift; | 
| 2569 | 1 | 50 |  |  |  | 3 | for (@_) { $min = $_ if $_ < $min; } | 
|  | 2 |  |  |  |  | 8 |  | 
| 2570 | 1 |  |  |  |  | 4 | $min; | 
| 2571 |  |  |  |  |  |  | } | 
| 2572 |  |  |  |  |  |  | sub vecmax { | 
| 2573 | 1 | 50 |  | 1 | 0 | 5 | return unless @_; | 
| 2574 | 1 |  |  |  |  | 3 | my $max = shift; | 
| 2575 | 1 | 50 |  |  |  | 3 | for (@_) { $max = $_ if $_ > $max; } | 
|  | 2 |  |  |  |  | 7 |  | 
| 2576 | 1 |  |  |  |  | 5 | $max; | 
| 2577 |  |  |  |  |  |  | } | 
| 2578 |  |  |  |  |  |  |  | 
| 2579 |  |  |  |  |  |  | sub vecextract { | 
| 2580 | 0 |  |  | 0 | 0 | 0 | my($aref, $mask) = @_; | 
| 2581 |  |  |  |  |  |  |  | 
| 2582 | 0 | 0 |  |  |  | 0 | return @$aref[@$mask] if ref($mask) eq 'ARRAY'; | 
| 2583 |  |  |  |  |  |  |  | 
| 2584 |  |  |  |  |  |  | # This is concise but very slow. | 
| 2585 |  |  |  |  |  |  | # map { $aref->[$_] }  grep { $mask & (1 << $_) }  0 .. $#$aref; | 
| 2586 |  |  |  |  |  |  |  | 
| 2587 | 0 |  |  |  |  | 0 | my($i, @v) = (0); | 
| 2588 | 0 |  |  |  |  | 0 | while ($mask) { | 
| 2589 | 0 | 0 |  |  |  | 0 | push @v, $i if $mask & 1; | 
| 2590 | 0 |  |  |  |  | 0 | $mask >>= 1; | 
| 2591 | 0 |  |  |  |  | 0 | $i++; | 
| 2592 |  |  |  |  |  |  | } | 
| 2593 | 0 |  |  |  |  | 0 | @$aref[@v]; | 
| 2594 |  |  |  |  |  |  | } | 
| 2595 |  |  |  |  |  |  |  | 
| 2596 |  |  |  |  |  |  | sub sumdigits { | 
| 2597 | 0 |  |  | 0 | 0 | 0 | my($n,$base) = @_; | 
| 2598 | 0 |  |  |  |  | 0 | my $sum = 0; | 
| 2599 | 0 | 0 | 0 |  |  | 0 | $base =  2 if !defined $base && $n =~ s/^0b//; | 
| 2600 | 0 | 0 | 0 |  |  | 0 | $base = 16 if !defined $base && $n =~ s/^0x//; | 
| 2601 | 0 | 0 | 0 |  |  | 0 | if (!defined $base || $base == 10) { | 
| 2602 | 0 |  |  |  |  | 0 | $n =~ tr/0123456789//cd; | 
| 2603 | 0 |  |  |  |  | 0 | $sum += $_ for (split(//,$n)); | 
| 2604 |  |  |  |  |  |  | } else { | 
| 2605 | 0 | 0 |  |  |  | 0 | croak "sumdigits: invalid base $base" if $base < 2; | 
| 2606 | 0 |  |  |  |  | 0 | my $cmap = substr("0123456789abcdefghijklmnopqrstuvwxyz",0,$base); | 
| 2607 | 0 |  |  |  |  | 0 | for my $c (split(//,lc($n))) { | 
| 2608 | 0 |  |  |  |  | 0 | my $p = index($cmap,$c); | 
| 2609 | 0 | 0 |  |  |  | 0 | $sum += $p if $p > 0; | 
| 2610 |  |  |  |  |  |  | } | 
| 2611 |  |  |  |  |  |  | } | 
| 2612 | 0 |  |  |  |  | 0 | $sum; | 
| 2613 |  |  |  |  |  |  | } | 
| 2614 |  |  |  |  |  |  |  | 
| 2615 |  |  |  |  |  |  | sub invmod { | 
| 2616 | 4 |  |  | 4 | 0 | 13 | my($a,$n) = @_; | 
| 2617 | 4 | 50 | 33 |  |  | 17 | return if $n == 0 || $a == 0; | 
| 2618 | 4 | 50 |  |  |  | 346 | return 0 if $n == 1; | 
| 2619 | 4 | 100 |  |  |  | 127 | $n = -$n if $n < 0;  # Pari semantics | 
| 2620 | 4 | 50 |  |  |  | 176 | if ($n > ~0) { | 
| 2621 | 0 |  |  |  |  | 0 | my $invmod = Math::BigInt->new("$a")->bmodinv("$n"); | 
| 2622 | 0 | 0 | 0 |  |  | 0 | return if !defined $invmod || $invmod->is_nan; | 
| 2623 | 0 | 0 |  |  |  | 0 | $invmod = _bigint_to_int($invmod) if $invmod->bacmp(BMAX) <= 0; | 
| 2624 | 0 |  |  |  |  | 0 | return $invmod; | 
| 2625 |  |  |  |  |  |  | } | 
| 2626 | 4 |  |  |  |  | 171 | my($t,$nt,$r,$nr) = (0, 1, $n, $a % $n); | 
| 2627 | 4 |  |  |  |  | 186 | while ($nr != 0) { | 
| 2628 |  |  |  |  |  |  | # Use mod before divide to force correct behavior with high bit set | 
| 2629 | 13 |  |  |  |  | 929 | my $quot = int( ($r-($r % $nr))/$nr ); | 
| 2630 | 13 |  |  |  |  | 1452 | ($nt,$t) = ($t-$quot*$nt,$nt); | 
| 2631 | 13 |  |  |  |  | 869 | ($nr,$r) = ($r-$quot*$nr,$nr); | 
| 2632 |  |  |  |  |  |  | } | 
| 2633 | 4 | 100 |  |  |  | 360 | return if $r > 1; | 
| 2634 | 3 | 100 |  |  |  | 121 | $t += $n if $t < 0; | 
| 2635 | 3 |  |  |  |  | 171 | $t; | 
| 2636 |  |  |  |  |  |  | } | 
| 2637 |  |  |  |  |  |  |  | 
| 2638 |  |  |  |  |  |  | sub _verify_sqrtmod { | 
| 2639 | 1 |  |  | 1 |  | 4 | my($r,$a,$n) = @_; | 
| 2640 | 1 | 50 |  |  |  | 5 | if (ref($r)) { | 
| 2641 | 1 | 50 |  |  |  | 6 | return if $r->copy->bmul($r)->bmod($n)->bcmp($a); | 
| 2642 | 1 | 50 |  |  |  | 668 | $r = _bigint_to_int($r) if $r->bacmp(BMAX) <= 0; | 
| 2643 |  |  |  |  |  |  | } else { | 
| 2644 | 0 | 0 |  |  |  | 0 | return unless (($r*$r) % $n) == $a; | 
| 2645 |  |  |  |  |  |  | } | 
| 2646 | 1 | 50 |  |  |  | 29 | $r = $n-$r if $n-$r < $r; | 
| 2647 | 1 |  |  |  |  | 217 | $r; | 
| 2648 |  |  |  |  |  |  | } | 
| 2649 |  |  |  |  |  |  |  | 
| 2650 |  |  |  |  |  |  | sub sqrtmod { | 
| 2651 | 1 |  |  | 1 | 0 | 5 | my($a,$n) = @_; | 
| 2652 | 1 | 50 |  |  |  | 7 | return if $n == 0; | 
| 2653 | 1 | 50 | 33 |  |  | 9 | if ($n <= 2 || $a <= 1) { | 
| 2654 | 0 |  |  |  |  | 0 | $a %= $n; | 
| 2655 | 0 | 0 |  |  |  | 0 | return ((($a*$a) % $n) == $a) ? $a : undef; | 
| 2656 |  |  |  |  |  |  | } | 
| 2657 |  |  |  |  |  |  |  | 
| 2658 | 1 | 50 |  |  |  | 5 | if ($n < 10000000) { | 
| 2659 |  |  |  |  |  |  | # Horrible trial search | 
| 2660 | 0 |  |  |  |  | 0 | $a = _bigint_to_int($a); | 
| 2661 | 0 |  |  |  |  | 0 | $n = _bigint_to_int($n); | 
| 2662 | 0 |  |  |  |  | 0 | $a %= $n; | 
| 2663 | 0 | 0 |  |  |  | 0 | return 1 if $a == 1; | 
| 2664 | 0 |  |  |  |  | 0 | my $lim = ($n+1) >> 1; | 
| 2665 | 0 |  |  |  |  | 0 | for my $r (2 .. $lim) { | 
| 2666 | 0 | 0 |  |  |  | 0 | return $r if (($r*$r) % $n) == $a; | 
| 2667 |  |  |  |  |  |  | } | 
| 2668 | 0 |  |  |  |  | 0 | undef; | 
| 2669 |  |  |  |  |  |  | } | 
| 2670 |  |  |  |  |  |  |  | 
| 2671 | 1 | 50 |  |  |  | 9 | $a = Math::BigInt->new("$a") unless ref($a) eq 'Math::BigInt'; | 
| 2672 | 1 | 50 |  |  |  | 99 | $n = Math::BigInt->new("$n") unless ref($n) eq 'Math::BigInt'; | 
| 2673 | 1 |  |  |  |  | 57 | $a->bmod($n); | 
| 2674 | 1 |  |  |  |  | 145 | my $r; | 
| 2675 |  |  |  |  |  |  |  | 
| 2676 | 1 | 50 |  |  |  | 6 | if (($n % 4) == 3) { | 
| 2677 | 1 |  |  |  |  | 341 | $r = $a->copy->bmodpow(($n+1)>>2, $n); | 
| 2678 | 1 |  |  |  |  | 54893 | return _verify_sqrtmod($r, $a, $n); | 
| 2679 |  |  |  |  |  |  | } | 
| 2680 | 0 | 0 |  |  |  | 0 | if (($n % 8) == 5) { | 
| 2681 | 0 |  |  |  |  | 0 | my $q = $a->copy->bmodpow(($n-1)>>2, $n); | 
| 2682 | 0 | 0 |  |  |  | 0 | if ($q->is_one) { | 
| 2683 | 0 |  |  |  |  | 0 | $r = $a->copy->bmodpow(($n+3)>>3, $n); | 
| 2684 |  |  |  |  |  |  | } else { | 
| 2685 | 0 |  |  |  |  | 0 | my $v = $a->copy->bmul(4)->bmodpow(($n-5)>>3, $n); | 
| 2686 | 0 |  |  |  |  | 0 | $r = $a->copy->bmul(2)->bmul($v)->bmod($n); | 
| 2687 |  |  |  |  |  |  | } | 
| 2688 | 0 |  |  |  |  | 0 | return _verify_sqrtmod($r, $a, $n); | 
| 2689 |  |  |  |  |  |  | } | 
| 2690 |  |  |  |  |  |  |  | 
| 2691 | 0 | 0 | 0 |  |  | 0 | return if $n->is_odd && !$a->copy->bmodpow(($n-1)>>1,$n)->is_one(); | 
| 2692 |  |  |  |  |  |  |  | 
| 2693 |  |  |  |  |  |  | # Horrible trial search.  Need to use Tonelli-Shanks here. | 
| 2694 | 0 |  |  |  |  | 0 | $r = Math::BigInt->new(2); | 
| 2695 | 0 |  |  |  |  | 0 | my $lim = int( ($n+1) / 2 ); | 
| 2696 | 0 |  |  |  |  | 0 | while ($r < $lim) { | 
| 2697 | 0 | 0 |  |  |  | 0 | return $r if $r->copy->bmul($r)->bmod($n) == $a; | 
| 2698 | 0 |  |  |  |  | 0 | $r++; | 
| 2699 |  |  |  |  |  |  | } | 
| 2700 | 0 |  |  |  |  | 0 | undef; | 
| 2701 |  |  |  |  |  |  | } | 
| 2702 |  |  |  |  |  |  |  | 
| 2703 |  |  |  |  |  |  | sub addmod { | 
| 2704 | 19419 |  |  | 19419 | 0 | 5205013 | my($a, $b, $n) = @_; | 
| 2705 | 19419 | 50 |  |  |  | 55459 | return 0 if $n <= 1; | 
| 2706 | 19419 | 50 | 66 |  |  | 2243819 | return _addmod($a,$b,$n) if $n < INTMAX && $a>=0 && $a=0 && $b | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
| 2707 | 18987 |  |  |  |  | 2313982 | my $ret = Math::BigInt->new("$a")->badd("$b")->bmod("$n"); | 
| 2708 | 18987 | 100 |  |  |  | 22754910 | $ret = _bigint_to_int($ret) if $ret->bacmp(BMAX) <= 0; | 
| 2709 | 18987 |  |  |  |  | 565680 | $ret; | 
| 2710 |  |  |  |  |  |  | } | 
| 2711 |  |  |  |  |  |  |  | 
| 2712 |  |  |  |  |  |  | sub mulmod { | 
| 2713 | 7368 |  |  | 7368 | 0 | 25090 | my($a, $b, $n) = @_; | 
| 2714 | 7368 | 50 |  |  |  | 24538 | return 0 if $n <= 1; | 
| 2715 | 7368 | 0 | 33 |  |  | 886947 | return _mulmod($a,$b,$n) if $n < INTMAX && $a>0 && $a0 && $b | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
| 2716 |  |  |  |  |  |  | return Math::Prime::Util::_reftyped($_[0], Math::Prime::Util::GMP::mulmod($a,$b,$n)) | 
| 2717 | 7368 | 50 |  |  |  | 902575 | if $Math::Prime::Util::_GMPfunc{"mulmod"}; | 
| 2718 | 7368 |  |  |  |  | 22294 | my $ret = Math::BigInt->new("$a")->bmod("$n")->bmul("$b")->bmod("$n"); | 
| 2719 | 7368 | 100 |  |  |  | 94418968 | $ret = _bigint_to_int($ret) if $ret->bacmp(BMAX) <= 0; | 
| 2720 | 7368 |  |  |  |  | 232687 | $ret; | 
| 2721 |  |  |  |  |  |  | } | 
| 2722 |  |  |  |  |  |  | sub divmod { | 
| 2723 | 0 |  |  | 0 | 0 | 0 | my($a, $b, $n) = @_; | 
| 2724 | 0 | 0 |  |  |  | 0 | return 0 if $n <= 1; | 
| 2725 | 0 |  |  |  |  | 0 | my $ret = Math::BigInt->new("$b")->bmodinv("$n")->bmul("$a")->bmod("$n"); | 
| 2726 | 0 | 0 |  |  |  | 0 | if ($ret->is_nan) { | 
| 2727 | 0 |  |  |  |  | 0 | $ret = undef; | 
| 2728 |  |  |  |  |  |  | } else { | 
| 2729 | 0 | 0 |  |  |  | 0 | $ret = _bigint_to_int($ret) if $ret->bacmp(BMAX) <= 0; | 
| 2730 |  |  |  |  |  |  | } | 
| 2731 | 0 |  |  |  |  | 0 | $ret; | 
| 2732 |  |  |  |  |  |  | } | 
| 2733 |  |  |  |  |  |  | sub powmod { | 
| 2734 | 22 |  |  | 22 | 0 | 83 | my($a, $b, $n) = @_; | 
| 2735 | 22 | 50 |  |  |  | 85 | return 0 if $n <= 1; | 
| 2736 | 22 | 50 |  |  |  | 2716 | if ($Math::Prime::Util::_GMPfunc{"powmod"}) { | 
| 2737 | 0 |  |  |  |  | 0 | my $r = Math::Prime::Util::GMP::powmod($a,$b,$n); | 
| 2738 | 0 | 0 |  |  |  | 0 | return (defined $r) ? Math::Prime::Util::_reftyped($_[0], $r) : undef; | 
| 2739 |  |  |  |  |  |  | } | 
| 2740 | 22 |  |  |  |  | 72 | my $ret = Math::BigInt->new("$a")->bmod("$n")->bmodpow("$b","$n"); | 
| 2741 | 22 | 50 |  |  |  | 493389 | if ($ret->is_nan) { | 
| 2742 | 0 |  |  |  |  | 0 | $ret = undef; | 
| 2743 |  |  |  |  |  |  | } else { | 
| 2744 | 22 | 100 |  |  |  | 215 | $ret = _bigint_to_int($ret) if $ret->bacmp(BMAX) <= 0; | 
| 2745 |  |  |  |  |  |  | } | 
| 2746 | 22 |  |  |  |  | 803 | $ret; | 
| 2747 |  |  |  |  |  |  | } | 
| 2748 |  |  |  |  |  |  |  | 
| 2749 |  |  |  |  |  |  | # no validation, x is allowed to be negative, y must be >= 0 | 
| 2750 |  |  |  |  |  |  | sub _gcd_ui { | 
| 2751 | 62278 |  |  | 62278 |  | 99198 | my($x, $y) = @_; | 
| 2752 | 62278 | 100 |  |  |  | 111751 | if ($y < $x) { ($x, $y) = ($y, $x); } | 
|  | 27618 | 100 |  |  |  | 47073 |  | 
| 2753 | 3 |  |  |  |  | 5 | elsif ($x < 0) { $x = -$x; } | 
| 2754 | 62278 |  |  |  |  | 107308 | while ($y > 0) { | 
| 2755 | 1136998 |  |  |  |  | 1986085 | ($x, $y) = ($y, $x % $y); | 
| 2756 |  |  |  |  |  |  | } | 
| 2757 | 62278 |  |  |  |  | 93900 | $x; | 
| 2758 |  |  |  |  |  |  | } | 
| 2759 |  |  |  |  |  |  |  | 
| 2760 |  |  |  |  |  |  | sub is_power { | 
| 2761 | 1194 |  |  | 1194 | 0 | 332170 | my ($n, $a, $refp) = @_; | 
| 2762 | 1194 | 50 | 66 |  |  | 4483 | croak("is_power third argument not a scalar reference") if defined($refp) && !ref($refp); | 
| 2763 | 1194 |  |  |  |  | 3277 | _validate_integer($n); | 
| 2764 | 1194 | 100 | 66 |  |  | 3209 | return 0 if abs($n) <= 3 && !$a; | 
| 2765 |  |  |  |  |  |  |  | 
| 2766 | 1190 | 0 | 0 |  |  | 96651 | if ($Math::Prime::Util::_GMPfunc{"is_power"} && | 
|  |  |  | 33 |  |  |  |  | 
| 2767 |  |  |  |  |  |  | ($Math::Prime::Util::GMP::VERSION >= 0.42 || | 
| 2768 |  |  |  |  |  |  | ($Math::Prime::Util::GMP::VERSION >= 0.28 && $n > 0))) { | 
| 2769 | 0 | 0 |  |  |  | 0 | $a = 0 unless defined $a; | 
| 2770 | 0 |  |  |  |  | 0 | my $k = Math::Prime::Util::GMP::is_power($n,$a); | 
| 2771 | 0 | 0 |  |  |  | 0 | return 0 unless $k > 0; | 
| 2772 | 0 | 0 |  |  |  | 0 | if (defined $refp) { | 
| 2773 | 0 | 0 |  |  |  | 0 | $a = $k unless $a; | 
| 2774 | 0 |  |  |  |  | 0 | my $isneg = ($n < 0); | 
| 2775 | 0 | 0 |  |  |  | 0 | $n =~ s/^-// if $isneg; | 
| 2776 | 0 |  |  |  |  | 0 | $$refp = Math::Prime::Util::rootint($n, $a); | 
| 2777 | 0 | 0 |  |  |  | 0 | $$refp = Math::Prime::Util::_reftyped($_[0], $$refp) if $$refp > INTMAX; | 
| 2778 | 0 | 0 |  |  |  | 0 | $$refp = -$$refp if $isneg; | 
| 2779 |  |  |  |  |  |  | } | 
| 2780 | 0 |  |  |  |  | 0 | return $k; | 
| 2781 |  |  |  |  |  |  | } | 
| 2782 |  |  |  |  |  |  |  | 
| 2783 | 1190 | 50 | 66 |  |  | 4589 | if (defined $a && $a != 0) { | 
| 2784 | 0 | 0 |  |  |  | 0 | return 1 if $a == 1;                  # Everything is a 1st power | 
| 2785 | 0 | 0 | 0 |  |  | 0 | return 0 if $n < 0 && $a % 2 == 0;    # Negative n never an even power | 
| 2786 | 0 | 0 |  |  |  | 0 | if ($a == 2) { | 
| 2787 | 0 | 0 |  |  |  | 0 | if (_is_perfect_square($n)) { | 
| 2788 | 0 | 0 |  |  |  | 0 | $$refp = int(sqrt($n)) if defined $refp; | 
| 2789 | 0 |  |  |  |  | 0 | return 1; | 
| 2790 |  |  |  |  |  |  | } | 
| 2791 |  |  |  |  |  |  | } else { | 
| 2792 | 0 | 0 |  |  |  | 0 | $n = Math::BigInt->new("$n") unless ref($n) eq 'Math::BigInt'; | 
| 2793 | 0 |  |  |  |  | 0 | my $root = $n->copy->babs->broot($a)->bfloor; | 
| 2794 | 0 | 0 |  |  |  | 0 | $root->bneg if $n->is_neg; | 
| 2795 | 0 | 0 |  |  |  | 0 | if ($root->copy->bpow($a) == $n) { | 
| 2796 | 0 | 0 |  |  |  | 0 | $$refp = $root if defined $refp; | 
| 2797 | 0 |  |  |  |  | 0 | return 1; | 
| 2798 |  |  |  |  |  |  | } | 
| 2799 |  |  |  |  |  |  | } | 
| 2800 |  |  |  |  |  |  | } else { | 
| 2801 | 1190 | 100 |  |  |  | 4040 | $n = Math::BigInt->new("$n") unless ref($n) eq 'Math::BigInt'; | 
| 2802 | 1190 | 100 |  |  |  | 23101 | if ($n < 0) { | 
| 2803 | 256 |  |  |  |  | 39452 | my $absn = $n->copy->babs; | 
| 2804 | 256 |  |  |  |  | 7776 | my $root = is_power($absn, 0, $refp); | 
| 2805 | 256 | 50 |  |  |  | 910 | return 0 unless $root; | 
| 2806 | 256 | 100 |  |  |  | 819 | if ($root % 2 == 0) { | 
| 2807 | 128 |  |  |  |  | 512 | my $power = valuation($root, 2); | 
| 2808 | 128 |  |  |  |  | 281 | $root >>= $power; | 
| 2809 | 128 | 100 |  |  |  | 366 | return 0 if $root == 1; | 
| 2810 | 122 |  |  |  |  | 374 | $power = BTWO->copy->bpow($power); | 
| 2811 | 122 | 100 |  |  |  | 32198 | $$refp = $$refp ** $power if defined $refp; | 
| 2812 |  |  |  |  |  |  | } | 
| 2813 | 250 | 100 |  |  |  | 13836 | $$refp = -$$refp if defined $refp; | 
| 2814 | 250 |  |  |  |  | 6825 | return $root; | 
| 2815 |  |  |  |  |  |  | } | 
| 2816 | 934 |  |  |  |  | 153933 | my $e = 2; | 
| 2817 | 934 |  |  |  |  | 1383 | while (1) { | 
| 2818 | 3768 |  |  |  |  | 10445 | my $root = $n->copy()->broot($e)->bfloor; | 
| 2819 | 3768 | 100 |  |  |  | 6513921 | last if $root->is_one(); | 
| 2820 | 3505 | 100 |  |  |  | 47737 | if ($root->copy->bpow($e) == $n) { | 
| 2821 | 671 |  |  |  |  | 311085 | my $next = is_power($root, 0, $refp); | 
| 2822 | 671 | 100 | 100 |  |  | 2707 | $$refp = $root if !$next && defined $refp; | 
| 2823 | 671 | 100 |  |  |  | 1424 | $e *= $next if $next != 0; | 
| 2824 | 671 |  |  |  |  | 2152 | return $e; | 
| 2825 |  |  |  |  |  |  | } | 
| 2826 | 2834 |  |  |  |  | 1456033 | $e = next_prime($e); | 
| 2827 |  |  |  |  |  |  | } | 
| 2828 |  |  |  |  |  |  | } | 
| 2829 | 263 |  |  |  |  | 3829 | 0; | 
| 2830 |  |  |  |  |  |  | } | 
| 2831 |  |  |  |  |  |  |  | 
| 2832 |  |  |  |  |  |  | sub is_square { | 
| 2833 | 1 |  |  | 1 | 0 | 6 | my($n) = @_; | 
| 2834 | 1 | 50 |  |  |  | 8 | return 0 if $n < 0; | 
| 2835 |  |  |  |  |  |  | #is_power($n,2); | 
| 2836 | 1 |  |  |  |  | 5 | _validate_integer($n); | 
| 2837 | 1 |  |  |  |  | 4 | _is_perfect_square($n); | 
| 2838 |  |  |  |  |  |  | } | 
| 2839 |  |  |  |  |  |  |  | 
| 2840 |  |  |  |  |  |  | sub is_prime_power { | 
| 2841 | 0 |  |  | 0 | 0 | 0 | my ($n, $refp) = @_; | 
| 2842 | 0 | 0 | 0 |  |  | 0 | croak("is_prime_power second argument not a scalar reference") if defined($refp) && !ref($refp); | 
| 2843 | 0 | 0 |  |  |  | 0 | return 0 if $n <= 1; | 
| 2844 |  |  |  |  |  |  |  | 
| 2845 | 0 | 0 |  |  |  | 0 | if (Math::Prime::Util::is_prime($n)) { $$refp = $n if defined $refp; return 1; } | 
|  | 0 | 0 |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 2846 | 0 |  |  |  |  | 0 | my $r; | 
| 2847 | 0 |  |  |  |  | 0 | my $k = Math::Prime::Util::is_power($n,0,\$r); | 
| 2848 | 0 | 0 |  |  |  | 0 | if ($k) { | 
| 2849 | 0 | 0 | 0 |  |  | 0 | $r = _bigint_to_int($r) if ref($r) && $r->bacmp(BMAX) <= 0; | 
| 2850 | 0 | 0 |  |  |  | 0 | return 0 unless Math::Prime::Util::is_prime($r); | 
| 2851 | 0 | 0 |  |  |  | 0 | $$refp = $r if defined $refp; | 
| 2852 |  |  |  |  |  |  | } | 
| 2853 | 0 |  |  |  |  | 0 | $k; | 
| 2854 |  |  |  |  |  |  | } | 
| 2855 |  |  |  |  |  |  |  | 
| 2856 |  |  |  |  |  |  | sub is_polygonal { | 
| 2857 | 2 |  |  | 2 | 0 | 21 | my ($n, $k, $refp) = @_; | 
| 2858 | 2 | 50 | 33 |  |  | 8 | croak("is_polygonal third argument not a scalar reference") if defined($refp) && !ref($refp); | 
| 2859 | 2 | 50 |  |  |  | 6 | croak("is_polygonal: k must be >= 3") if $k < 3; | 
| 2860 | 2 | 50 |  |  |  | 9 | return 0 if $n <= 0; | 
| 2861 | 2 | 0 |  |  |  | 6 | if ($n == 1) { $$refp = 1 if defined $refp; return 1; } | 
|  | 0 | 50 |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 2862 |  |  |  |  |  |  |  | 
| 2863 | 2 | 50 |  |  |  | 8 | if ($Math::Prime::Util::_GMPfunc{"polygonal_nth"}) { | 
| 2864 | 0 |  |  |  |  | 0 | my $nth = Math::Prime::Util::GMP::polygonal_nth($n, $k); | 
| 2865 | 0 | 0 |  |  |  | 0 | return 0 unless $nth; | 
| 2866 | 0 |  |  |  |  | 0 | $nth = Math::Prime::Util::_reftyped($_[0], $nth); | 
| 2867 | 0 | 0 |  |  |  | 0 | $$refp = $nth if defined $refp; | 
| 2868 | 0 |  |  |  |  | 0 | return 1; | 
| 2869 |  |  |  |  |  |  | } | 
| 2870 |  |  |  |  |  |  |  | 
| 2871 | 2 |  |  |  |  | 4 | my($D,$R); | 
| 2872 | 2 | 50 |  |  |  | 5 | if ($k == 4) { | 
| 2873 | 0 | 0 |  |  |  | 0 | return 0 unless _is_perfect_square($n); | 
| 2874 | 0 | 0 |  |  |  | 0 | $$refp = sqrtint($n) if defined $refp; | 
| 2875 | 0 |  |  |  |  | 0 | return 1; | 
| 2876 |  |  |  |  |  |  | } | 
| 2877 | 2 | 50 | 33 |  |  | 8 | if ($n <= MPU_HALFWORD && $k <= MPU_HALFWORD) { | 
| 2878 | 0 | 0 |  |  |  | 0 | $D = ($k==3) ? 1+($n<<3) : (8*$k-16)*$n + ($k-4)*($k-4); | 
| 2879 | 0 | 0 |  |  |  | 0 | return 0 unless _is_perfect_square($D); | 
| 2880 | 0 |  |  |  |  | 0 | $D = $k-4 + Math::Prime::Util::sqrtint($D); | 
| 2881 | 0 |  |  |  |  | 0 | $R = 2*$k-4; | 
| 2882 |  |  |  |  |  |  | } else { | 
| 2883 | 2 | 50 |  |  |  | 4 | if ($k == 3) { | 
| 2884 | 2 |  |  |  |  | 7 | $D = vecsum(1, vecprod($n, 8)); | 
| 2885 |  |  |  |  |  |  | } else { | 
| 2886 | 0 |  |  |  |  | 0 | $D = vecsum(vecprod($n, vecprod(8, $k) - 16),  vecprod($k-4,$k-4));; | 
| 2887 |  |  |  |  |  |  | } | 
| 2888 | 2 | 100 |  |  |  | 8 | return 0 unless _is_perfect_square($D); | 
| 2889 | 1 |  |  |  |  | 54 | $D = vecsum( sqrtint($D), $k-4 ); | 
| 2890 | 1 |  |  |  |  | 7 | $R = vecprod(2, $k) - 4; | 
| 2891 |  |  |  |  |  |  | } | 
| 2892 | 1 | 50 |  |  |  | 4 | return 0 if ($D % $R) != 0; | 
| 2893 | 1 | 50 |  |  |  | 365 | $$refp = $D / $R if defined $refp; | 
| 2894 | 1 |  |  |  |  | 6 | 1; | 
| 2895 |  |  |  |  |  |  | } | 
| 2896 |  |  |  |  |  |  |  | 
| 2897 |  |  |  |  |  |  | sub valuation { | 
| 2898 | 132 |  |  | 132 | 0 | 3198 | my($n, $k) = @_; | 
| 2899 | 132 | 50 | 33 |  |  | 636 | $n = -$n if defined $n && $n < 0; | 
| 2900 | 132 | 100 |  |  |  | 798 | _validate_num($n) || _validate_positive_integer($n); | 
| 2901 | 132 | 50 | 33 |  |  | 571 | return 0 if $n < 2 || $k < 2; | 
| 2902 | 132 |  |  |  |  | 687 | my $v = 0; | 
| 2903 | 132 | 100 |  |  |  | 377 | if ($k == 2) { # Accelerate power of 2 | 
| 2904 | 130 | 100 |  |  |  | 303 | if (ref($n) eq 'Math::BigInt') {   # This can pay off for big inputs | 
| 2905 | 1 | 50 |  |  |  | 5 | return 0 unless $n->is_even; | 
| 2906 | 1 |  |  |  |  | 26 | my $s = $n->as_bin;              # We could do same for k=10 | 
| 2907 | 1 |  |  |  |  | 1137 | return length($s) - rindex($s,'1') - 1; | 
| 2908 |  |  |  |  |  |  | } | 
| 2909 | 129 |  |  |  |  | 428 | while (!($n & 0xFFFF) ) {  $n >>=16;  $v +=16;  } | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 3 |  | 
| 2910 | 129 |  |  |  |  | 413 | while (!($n & 0x000F) ) {  $n >>= 4;  $v += 4;  } | 
|  | 19 |  |  |  |  | 64 |  | 
|  | 19 |  |  |  |  | 58 |  | 
| 2911 |  |  |  |  |  |  | } | 
| 2912 | 131 |  |  |  |  | 427 | while ( !($n % $k) ) { | 
| 2913 | 198 |  |  |  |  | 1436 | $n /= $k; | 
| 2914 | 198 |  |  |  |  | 15311 | $v++; | 
| 2915 |  |  |  |  |  |  | } | 
| 2916 | 131 |  |  |  |  | 502 | $v; | 
| 2917 |  |  |  |  |  |  | } | 
| 2918 |  |  |  |  |  |  |  | 
| 2919 |  |  |  |  |  |  | sub hammingweight { | 
| 2920 | 0 |  |  | 0 | 0 | 0 | my $n = shift; | 
| 2921 | 0 |  |  |  |  | 0 | return 0 + (Math::BigInt->new("$n")->as_bin() =~ tr/1//); | 
| 2922 |  |  |  |  |  |  | } | 
| 2923 |  |  |  |  |  |  |  | 
| 2924 |  |  |  |  |  |  | my @_digitmap = (0..9, 'a'..'z'); | 
| 2925 |  |  |  |  |  |  | my %_mapdigit = map { $_digitmap[$_] => $_ } 0 .. $#_digitmap; | 
| 2926 |  |  |  |  |  |  | sub _splitdigits { | 
| 2927 | 3 |  |  | 3 |  | 12 | my($n, $base, $len) = @_;    # n is num or bigint, base is in range | 
| 2928 | 3 |  |  |  |  | 9 | my @d; | 
| 2929 | 3 | 50 |  |  |  | 22 | if ($base == 10) { | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 2930 | 0 |  |  |  |  | 0 | @d = split(//,"$n"); | 
| 2931 |  |  |  |  |  |  | } elsif ($base == 2) { | 
| 2932 | 2 |  |  |  |  | 7 | @d = split(//,substr(Math::BigInt->new("$n")->as_bin,2)); | 
| 2933 |  |  |  |  |  |  | } elsif ($base == 16) { | 
| 2934 | 0 |  |  |  |  | 0 | @d = map { $_mapdigit{$_} } split(//,substr(Math::BigInt->new("$n")->as_hex,2)); | 
|  | 0 |  |  |  |  | 0 |  | 
| 2935 |  |  |  |  |  |  | } else { | 
| 2936 | 1 |  |  |  |  | 4 | while ($n >= 1) { | 
| 2937 | 339 |  |  |  |  | 251561 | my $rem = $n % $base; | 
| 2938 | 339 |  |  |  |  | 97437 | unshift @d, $rem; | 
| 2939 | 339 |  |  |  |  | 958 | $n = ($n-$rem)/$base;    # Always an exact division | 
| 2940 |  |  |  |  |  |  | } | 
| 2941 |  |  |  |  |  |  | } | 
| 2942 | 3 | 50 | 33 |  |  | 12684 | if ($len >= 0 && $len != scalar(@d)) { | 
| 2943 | 0 |  |  |  |  | 0 | while (@d < $len) { unshift @d, 0; } | 
|  | 0 |  |  |  |  | 0 |  | 
| 2944 | 0 |  |  |  |  | 0 | while (@d > $len) { shift @d; } | 
|  | 0 |  |  |  |  | 0 |  | 
| 2945 |  |  |  |  |  |  | } | 
| 2946 | 3 |  |  |  |  | 444 | @d; | 
| 2947 |  |  |  |  |  |  | } | 
| 2948 |  |  |  |  |  |  |  | 
| 2949 |  |  |  |  |  |  | sub todigits { | 
| 2950 | 3 |  |  | 3 | 0 | 334 | my($n,$base,$len) = @_; | 
| 2951 | 3 | 50 |  |  |  | 15 | $base = 10 unless defined $base; | 
| 2952 | 3 | 50 |  |  |  | 15 | $len = -1 unless defined $len; | 
| 2953 | 3 | 50 |  |  |  | 11 | die "Invalid base: $base" if $base < 2; | 
| 2954 | 3 | 50 |  |  |  | 14 | return if $n == 0; | 
| 2955 | 3 | 50 |  |  |  | 554 | $n = -$n if $n < 0; | 
| 2956 | 3 | 50 |  |  |  | 506 | _validate_num($n) || _validate_positive_integer($n); | 
| 2957 | 3 |  |  |  |  | 16 | _splitdigits($n, $base, $len); | 
| 2958 |  |  |  |  |  |  | } | 
| 2959 |  |  |  |  |  |  |  | 
| 2960 |  |  |  |  |  |  | sub todigitstring { | 
| 2961 | 0 |  |  | 0 | 0 | 0 | my($n,$base,$len) = @_; | 
| 2962 | 0 | 0 |  |  |  | 0 | $base = 10 unless defined $base; | 
| 2963 | 0 | 0 |  |  |  | 0 | $len = -1 unless defined $len; | 
| 2964 | 0 |  |  |  |  | 0 | $n =~ s/^-//; | 
| 2965 | 0 | 0 | 0 |  |  | 0 | return substr(Math::BigInt->new("$n")->as_bin,2) if $base ==  2 && $len < 0; | 
| 2966 | 0 | 0 | 0 |  |  | 0 | return substr(Math::BigInt->new("$n")->as_oct,1) if $base ==  8 && $len < 0; | 
| 2967 | 0 | 0 | 0 |  |  | 0 | return substr(Math::BigInt->new("$n")->as_hex,2) if $base == 16 && $len < 0; | 
| 2968 | 0 | 0 |  |  |  | 0 | my @d = ($n == 0) ? () : _splitdigits($n, $base, $len); | 
| 2969 | 0 | 0 |  |  |  | 0 | return join("", @d) if $base <= 10; | 
| 2970 | 0 | 0 |  |  |  | 0 | die "Invalid base for string: $base" if $base > 36; | 
| 2971 | 0 |  |  |  |  | 0 | join("", map { $_digitmap[$_] } @d); | 
|  | 0 |  |  |  |  | 0 |  | 
| 2972 |  |  |  |  |  |  | } | 
| 2973 |  |  |  |  |  |  |  | 
| 2974 |  |  |  |  |  |  | sub fromdigits { | 
| 2975 | 1 |  |  | 1 | 0 | 5 | my($r, $base) = @_; | 
| 2976 | 1 | 50 |  |  |  | 4 | $base = 10 unless defined $base; | 
| 2977 | 1 | 50 | 33 |  |  | 6 | return $r if $base == 10 && ref($r) =~ /^Math::/; | 
| 2978 | 1 |  |  |  |  | 2 | my $n; | 
| 2979 | 1 | 50 | 33 |  |  | 61 | if (ref($r) && ref($r) !~ /^Math::/) { | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 2980 | 0 | 0 |  |  |  | 0 | croak "fromdigits first argument must be a string or array reference" | 
| 2981 |  |  |  |  |  |  | unless ref($r) eq 'ARRAY'; | 
| 2982 | 0 |  |  |  |  | 0 | ($n,$base) = (BZERO->copy, BZERO + $base); | 
| 2983 | 0 |  |  |  |  | 0 | for my $d (@$r) { | 
| 2984 | 0 |  |  |  |  | 0 | $n = $n * $base + $d; | 
| 2985 |  |  |  |  |  |  | } | 
| 2986 |  |  |  |  |  |  | } elsif ($base == 2) { | 
| 2987 | 0 |  |  |  |  | 0 | $n = Math::BigInt->from_bin("0b$r"); | 
| 2988 |  |  |  |  |  |  | } elsif ($base == 8) { | 
| 2989 | 0 |  |  |  |  | 0 | $n = Math::BigInt->from_oct("0$r"); | 
| 2990 |  |  |  |  |  |  | } elsif ($base == 16) { | 
| 2991 | 0 |  |  |  |  | 0 | $n = Math::BigInt->from_hex("0x$r"); | 
| 2992 |  |  |  |  |  |  | } else { | 
| 2993 | 1 |  |  |  |  | 9 | $r =~ s/^0*//; | 
| 2994 | 1 |  |  |  |  | 6 | ($n,$base) = (BZERO->copy, BZERO + $base); | 
| 2995 |  |  |  |  |  |  | #for my $d (map { $_mapdigit{$_} } split(//,$r)) { | 
| 2996 |  |  |  |  |  |  | #  croak "Invalid digit for base $base" unless defined $d && $d < $base; | 
| 2997 |  |  |  |  |  |  | #  $n = $n * $base + $d; | 
| 2998 |  |  |  |  |  |  | #} | 
| 2999 | 1 |  |  |  |  | 234 | for my $c (split(//, lc($r))) { | 
| 3000 | 16 |  |  |  |  | 1922 | $n->bmul($base); | 
| 3001 | 16 | 50 |  |  |  | 946 | if ($c ne '0') { | 
| 3002 | 16 |  |  |  |  | 32 | my $d = index("0123456789abcdefghijklmnopqrstuvwxyz", $c); | 
| 3003 | 16 | 50 |  |  |  | 30 | croak "Invalid digit for base $base" unless $d >= 0; | 
| 3004 | 16 |  |  |  |  | 32 | $n->badd($d); | 
| 3005 |  |  |  |  |  |  | } | 
| 3006 |  |  |  |  |  |  | } | 
| 3007 |  |  |  |  |  |  | } | 
| 3008 | 1 | 50 |  |  |  | 141 | $n = _bigint_to_int($n) if $n->bacmp(BMAX) <= 0; | 
| 3009 | 1 |  |  |  |  | 53 | $n; | 
| 3010 |  |  |  |  |  |  | } | 
| 3011 |  |  |  |  |  |  |  | 
| 3012 |  |  |  |  |  |  | sub sqrtint { | 
| 3013 | 1 |  |  | 1 | 0 | 5 | my($n) = @_; | 
| 3014 | 1 |  |  |  |  | 3 | my $sqrt = Math::BigInt->new("$n")->bsqrt; | 
| 3015 | 1 |  |  |  |  | 1343 | return Math::Prime::Util::_reftyped($_[0], "$sqrt"); | 
| 3016 |  |  |  |  |  |  | } | 
| 3017 |  |  |  |  |  |  |  | 
| 3018 |  |  |  |  |  |  | sub rootint { | 
| 3019 | 58 |  |  | 58 | 0 | 133 | my ($n, $k, $refp) = @_; | 
| 3020 | 58 | 50 |  |  |  | 126 | croak "rootint: k must be > 0" unless $k > 0; | 
| 3021 |  |  |  |  |  |  | # Math::BigInt returns NaN for any root of a negative n. | 
| 3022 | 58 |  |  |  |  | 197 | my $root = Math::BigInt->new("$n")->babs->broot("$k"); | 
| 3023 | 58 | 50 |  |  |  | 43317 | if (defined $refp) { | 
| 3024 | 0 | 0 |  |  |  | 0 | croak("logint third argument not a scalar reference") unless ref($refp); | 
| 3025 | 0 |  |  |  |  | 0 | $$refp = $root->copy->bpow($k); | 
| 3026 |  |  |  |  |  |  | } | 
| 3027 | 58 |  |  |  |  | 177 | return Math::Prime::Util::_reftyped($_[0], "$root"); | 
| 3028 |  |  |  |  |  |  | } | 
| 3029 |  |  |  |  |  |  |  | 
| 3030 |  |  |  |  |  |  | sub logint { | 
| 3031 | 0 |  |  | 0 | 0 | 0 | my ($n, $b, $refp) = @_; | 
| 3032 | 0 | 0 | 0 |  |  | 0 | croak("logint third argument not a scalar reference") if defined($refp) && !ref($refp); | 
| 3033 |  |  |  |  |  |  |  | 
| 3034 | 0 | 0 |  |  |  | 0 | if ($Math::Prime::Util::_GMPfunc{"logint"}) { | 
| 3035 | 0 |  |  |  |  | 0 | my $e = Math::Prime::Util::GMP::logint($n, $b); | 
| 3036 | 0 | 0 |  |  |  | 0 | if (defined $refp) { | 
| 3037 | 0 |  |  |  |  | 0 | my $r = Math::Prime::Util::GMP::powmod($b, $e, $n); | 
| 3038 | 0 | 0 |  |  |  | 0 | $r = $n if $r == 0; | 
| 3039 | 0 |  |  |  |  | 0 | $$refp = Math::Prime::Util::_reftyped($_[0], $r); | 
| 3040 |  |  |  |  |  |  | } | 
| 3041 | 0 |  |  |  |  | 0 | return Math::Prime::Util::_reftyped($_[0], $e); | 
| 3042 |  |  |  |  |  |  | } | 
| 3043 |  |  |  |  |  |  |  | 
| 3044 | 0 | 0 |  |  |  | 0 | croak "logint: n must be > 0" unless $n > 0; | 
| 3045 | 0 | 0 |  |  |  | 0 | croak "logint: missing base" unless defined $b; | 
| 3046 | 0 | 0 |  |  |  | 0 | if ($b == 10) { | 
| 3047 | 0 |  |  |  |  | 0 | my $e = length($n)-1; | 
| 3048 | 0 | 0 |  |  |  | 0 | $$refp = Math::BigInt->new("1" . "0"x$e) if defined $refp; | 
| 3049 | 0 |  |  |  |  | 0 | return $e; | 
| 3050 |  |  |  |  |  |  | } | 
| 3051 | 0 | 0 |  |  |  | 0 | if ($b == 2) { | 
| 3052 | 0 |  |  |  |  | 0 | my $e = length(Math::BigInt->new("$n")->as_bin)-2-1; | 
| 3053 | 0 | 0 |  |  |  | 0 | $$refp = Math::BigInt->from_bin("1" . "0"x$e) if defined $refp; | 
| 3054 | 0 |  |  |  |  | 0 | return $e; | 
| 3055 |  |  |  |  |  |  | } | 
| 3056 | 0 | 0 |  |  |  | 0 | croak "logint: base must be > 1" unless $b > 1; | 
| 3057 |  |  |  |  |  |  |  | 
| 3058 | 0 |  |  |  |  | 0 | my $e = Math::BigInt->new("$n")->blog("$b"); | 
| 3059 | 0 | 0 |  |  |  | 0 | $$refp = Math::BigInt->new("$b")->bpow($e) if defined $refp; | 
| 3060 | 0 |  |  |  |  | 0 | return Math::Prime::Util::_reftyped($_[0], "$e"); | 
| 3061 |  |  |  |  |  |  | } | 
| 3062 |  |  |  |  |  |  |  | 
| 3063 |  |  |  |  |  |  | # Seidel (Luschny), core using Trizen's simplications from Math::BigNum. | 
| 3064 |  |  |  |  |  |  | # http://oeis.org/wiki/User:Peter_Luschny/ComputationAndAsymptoticsOfBernoulliNumbers#Bernoulli_numbers__after_Seidel | 
| 3065 |  |  |  |  |  |  | sub _bernoulli_seidel { | 
| 3066 | 103 |  |  | 103 |  | 199 | my($n) = @_; | 
| 3067 | 103 | 50 |  |  |  | 230 | return (1,1) if $n == 0; | 
| 3068 | 103 | 50 | 33 |  |  | 393 | return (0,1) if $n > 1 && $n % 2; | 
| 3069 |  |  |  |  |  |  |  | 
| 3070 | 103 |  |  |  |  | 300 | my $oacc = Math::BigInt->accuracy();  Math::BigInt->accuracy(undef); | 
|  | 103 |  |  |  |  | 1317 |  | 
| 3071 | 103 |  |  |  |  | 1756 | my @D = (BZERO->copy, BONE->copy, map { BZERO->copy } 1 .. ($n>>1)-1); | 
|  | 2374 |  |  |  |  | 46196 |  | 
| 3072 | 103 |  |  |  |  | 2296 | my ($h, $w) = (1, 1); | 
| 3073 |  |  |  |  |  |  |  | 
| 3074 | 103 |  |  |  |  | 266 | foreach my $i (0 .. $n-1) { | 
| 3075 | 4954 | 100 |  |  |  | 17472198 | if ($w ^= 1) { | 
| 3076 | 2477 |  |  |  |  | 8407 | $D[$_]->badd($D[$_-1]) for 1 .. $h-1; | 
| 3077 |  |  |  |  |  |  | } else { | 
| 3078 | 2477 |  |  |  |  | 4066 | $w = $h++; | 
| 3079 | 2477 |  |  |  |  | 7401 | $D[$w]->badd($D[$w+1]) while --$w; | 
| 3080 |  |  |  |  |  |  | } | 
| 3081 |  |  |  |  |  |  | } | 
| 3082 | 103 |  |  |  |  | 227122 | my $num = $D[$h-1]; | 
| 3083 | 103 |  |  |  |  | 406 | my $den = BONE->copy->blsft($n+1)->bsub(BTWO); | 
| 3084 | 103 |  |  |  |  | 53825 | my $gcd = Math::BigInt::bgcd($num, $den); | 
| 3085 | 103 |  |  |  |  | 78626 | $num /= $gcd; | 
| 3086 | 103 |  |  |  |  | 39588 | $den /= $gcd; | 
| 3087 | 103 | 100 |  |  |  | 20936 | $num->bneg() if ($n % 4) == 0; | 
| 3088 | 103 |  |  |  |  | 1028 | Math::BigInt->accuracy($oacc); | 
| 3089 | 103 |  |  |  |  | 4277 | ($num,$den); | 
| 3090 |  |  |  |  |  |  | } | 
| 3091 |  |  |  |  |  |  |  | 
| 3092 |  |  |  |  |  |  | sub bernfrac { | 
| 3093 | 111 |  |  | 111 | 0 | 223 | my $n = shift; | 
| 3094 | 111 | 100 |  |  |  | 301 | return (BONE,BONE) if $n == 0; | 
| 3095 | 107 | 100 |  |  |  | 294 | return (BONE,BTWO) if $n == 1;    # We're choosing 1/2 instead of -1/2 | 
| 3096 | 105 | 100 | 66 |  |  | 490 | return (BZERO,BONE) if $n < 0 || $n & 1; | 
| 3097 |  |  |  |  |  |  |  | 
| 3098 |  |  |  |  |  |  | # We should have used one of the GMP functions before coming here. | 
| 3099 |  |  |  |  |  |  |  | 
| 3100 | 103 |  |  |  |  | 243 | _bernoulli_seidel($n); | 
| 3101 |  |  |  |  |  |  | } | 
| 3102 |  |  |  |  |  |  |  | 
| 3103 |  |  |  |  |  |  | sub stirling { | 
| 3104 | 518 |  |  | 518 | 0 | 89268 | my($n, $m, $type) = @_; | 
| 3105 | 518 | 50 |  |  |  | 1806 | return 1 if $m == $n; | 
| 3106 | 518 | 50 | 33 |  |  | 3928 | return 0 if $n == 0 || $m == 0 || $m > $n; | 
|  |  |  | 33 |  |  |  |  | 
| 3107 | 518 | 100 |  |  |  | 1472 | $type = 1 unless defined $type; | 
| 3108 | 518 | 50 | 100 |  |  | 2653 | croak "stirling type must be 1, 2, or 3" unless $type == 1 || $type == 2 || $type == 3; | 
|  |  |  | 66 |  |  |  |  | 
| 3109 | 518 | 50 |  |  |  | 1304 | if ($m == 1) { | 
| 3110 | 0 | 0 |  |  |  | 0 | return 1 if $type == 2; | 
| 3111 | 0 | 0 |  |  |  | 0 | return factorial($n) if $type == 3; | 
| 3112 | 0 | 0 |  |  |  | 0 | return factorial($n-1) if $n&1; | 
| 3113 | 0 |  |  |  |  | 0 | return vecprod(-1, factorial($n-1)); | 
| 3114 |  |  |  |  |  |  | } | 
| 3115 |  |  |  |  |  |  | return Math::Prime::Util::_reftyped($_[0], Math::Prime::Util::GMP::stirling($n,$m,$type)) | 
| 3116 | 518 | 50 |  |  |  | 1494 | if $Math::Prime::Util::_GMPfunc{"stirling"}; | 
| 3117 |  |  |  |  |  |  | # Go through vecsum with quoted negatives to make sure we don't overflow. | 
| 3118 | 518 |  |  |  |  | 910 | my $s; | 
| 3119 | 518 | 100 |  |  |  | 1632 | if ($type == 3) { | 
|  |  | 100 |  |  |  |  |  | 
| 3120 | 5 |  |  |  |  | 377 | $s = Math::Prime::Util::vecprod( Math::Prime::Util::binomial($n,$m), Math::Prime::Util::binomial($n-1,$m-1), Math::Prime::Util::factorial($n-$m) ); | 
| 3121 |  |  |  |  |  |  | } elsif ($type == 2) { | 
| 3122 | 465 |  |  |  |  | 923 | my @terms; | 
| 3123 | 465 |  |  |  |  | 1340 | for my $j (1 .. $m) { | 
| 3124 | 14941 |  |  |  |  | 561031 | my $t = Math::Prime::Util::vecprod( | 
| 3125 |  |  |  |  |  |  | Math::BigInt->new($j) ** $n, | 
| 3126 |  |  |  |  |  |  | Math::Prime::Util::binomial($m,$j) | 
| 3127 |  |  |  |  |  |  | ); | 
| 3128 | 14941 | 100 |  |  |  | 726407 | push @terms, (($m-$j) & 1)  ?  "-$t"  :  $t; | 
| 3129 |  |  |  |  |  |  | } | 
| 3130 | 465 |  |  |  |  | 18796 | $s = Math::Prime::Util::vecsum(@terms) / factorial($m); | 
| 3131 |  |  |  |  |  |  | } else { | 
| 3132 | 48 |  |  |  |  | 93 | my @terms; | 
| 3133 | 48 |  |  |  |  | 154 | for my $k (1 .. $n-$m) { | 
| 3134 | 782 |  |  |  |  | 51488 | my $t = Math::Prime::Util::vecprod( | 
| 3135 |  |  |  |  |  |  | Math::Prime::Util::binomial($k + $n - 1, $k + $n - $m), | 
| 3136 |  |  |  |  |  |  | Math::Prime::Util::binomial(2 * $n - $m, $n - $k - $m), | 
| 3137 |  |  |  |  |  |  | Math::Prime::Util::stirling($k - $m + $n, $k, 2), | 
| 3138 |  |  |  |  |  |  | ); | 
| 3139 | 782 | 100 |  |  |  | 7023 | push @terms, ($k & 1)  ?  "-$t"  :  $t; | 
| 3140 |  |  |  |  |  |  | } | 
| 3141 | 48 |  |  |  |  | 2372 | $s = Math::Prime::Util::vecsum(@terms); | 
| 3142 |  |  |  |  |  |  | } | 
| 3143 | 518 |  |  |  |  | 496267 | $s; | 
| 3144 |  |  |  |  |  |  | } | 
| 3145 |  |  |  |  |  |  |  | 
| 3146 |  |  |  |  |  |  | sub _harmonic_split { # From Fredrik Johansson | 
| 3147 | 1259 |  |  | 1259 |  | 34837 | my($a,$b) = @_; | 
| 3148 | 1259 | 100 |  |  |  | 2814 | return (BONE, $a) if $b - $a == BONE; | 
| 3149 | 1047 | 100 |  |  |  | 150502 | return ($a+$a+BONE, $a*$a+$a) if $b - $a == BTWO;   # Cut down recursion | 
| 3150 | 590 |  |  |  |  | 83339 | my $m = $a->copy->badd($b)->brsft(BONE); | 
| 3151 | 590 |  |  |  |  | 96301 | my ($p,$q) = _harmonic_split($a, $m); | 
| 3152 | 590 |  |  |  |  | 164028 | my ($r,$s) = _harmonic_split($m, $b); | 
| 3153 | 590 |  |  |  |  | 217148 | ($p*$s+$q*$r, $q*$s); | 
| 3154 |  |  |  |  |  |  | } | 
| 3155 |  |  |  |  |  |  |  | 
| 3156 |  |  |  |  |  |  | sub harmfrac { | 
| 3157 | 79 |  |  | 79 | 0 | 160 | my($n) = @_; | 
| 3158 | 79 | 50 |  |  |  | 156 | return (BZERO,BONE) if $n <= 0; | 
| 3159 | 79 | 50 |  |  |  | 372 | $n = Math::BigInt->new("$n") unless ref($n) eq 'Math::BigInt'; | 
| 3160 | 79 |  |  |  |  | 3778 | my($p,$q) = _harmonic_split($n-$n+1, $n+1); | 
| 3161 | 79 |  |  |  |  | 27594 | my $gcd = Math::BigInt::bgcd($p,$q); | 
| 3162 | 79 |  |  |  |  | 97203 | ( scalar $p->bdiv($gcd), scalar $q->bdiv($gcd) ); | 
| 3163 |  |  |  |  |  |  | } | 
| 3164 |  |  |  |  |  |  |  | 
| 3165 |  |  |  |  |  |  | sub harmreal { | 
| 3166 | 21 |  |  | 21 | 0 | 48 | my($n, $precision) = @_; | 
| 3167 |  |  |  |  |  |  |  | 
| 3168 | 21 | 50 |  |  |  | 44 | do { require Math::BigFloat; Math::BigFloat->import(); } unless defined $Math::BigFloat::VERSION; | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 3169 | 21 | 50 |  |  |  | 48 | return Math::BigFloat->bzero if $n <= 0; | 
| 3170 |  |  |  |  |  |  |  | 
| 3171 |  |  |  |  |  |  | # Use asymptotic formula for larger $n if possible.  Saves lots of time if | 
| 3172 |  |  |  |  |  |  | # the default Calc backend is being used. | 
| 3173 |  |  |  |  |  |  | { | 
| 3174 | 21 |  |  |  |  | 33 | my $sprec = $precision; | 
|  | 21 |  |  |  |  | 33 |  | 
| 3175 | 21 | 50 |  |  |  | 89 | $sprec = Math::BigFloat->precision unless defined $sprec; | 
| 3176 | 21 | 50 |  |  |  | 286 | $sprec = 40 unless defined $sprec; | 
| 3177 | 21 | 50 | 33 |  |  | 248 | if ( ($sprec <= 23 && $n >    54) || | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
| 3178 |  |  |  |  |  |  | ($sprec <= 30 && $n >   348) || | 
| 3179 |  |  |  |  |  |  | ($sprec <= 40 && $n >  2002) || | 
| 3180 |  |  |  |  |  |  | ($sprec <= 50 && $n > 12644) ) { | 
| 3181 | 0 |  |  |  |  | 0 | $n = Math::BigFloat->new($n, $sprec+5); | 
| 3182 | 0 |  |  |  |  | 0 | my($n2, $one, $h) = ($n*$n, Math::BigFloat->bone, Math::BigFloat->bzero); | 
| 3183 | 0 |  |  |  |  | 0 | my $nt = $n2; | 
| 3184 | 0 |  |  |  |  | 0 | my $eps = Math::BigFloat->new(10)->bpow(-$sprec-4); | 
| 3185 | 0 |  |  |  |  | 0 | foreach my $d (-12, 120, -252, 240, -132, 32760, -12, 8160, -14364, 6600, -276, 65520, -12) { # OEIS A006593 | 
| 3186 | 0 |  |  |  |  | 0 | my $term = $one/($d * $nt); | 
| 3187 | 0 | 0 |  |  |  | 0 | last if $term->bacmp($eps) < 0; | 
| 3188 | 0 |  |  |  |  | 0 | $h += $term; | 
| 3189 | 0 |  |  |  |  | 0 | $nt *= $n2; | 
| 3190 |  |  |  |  |  |  | } | 
| 3191 | 0 |  |  |  |  | 0 | $h->badd(scalar $one->copy->bdiv(2*$n)); | 
| 3192 | 0 |  |  |  |  | 0 | $h->badd(_Euler($sprec)); | 
| 3193 | 0 |  |  |  |  | 0 | $h->badd($n->copy->blog); | 
| 3194 | 0 |  |  |  |  | 0 | $h->round($sprec); | 
| 3195 | 0 |  |  |  |  | 0 | return $h; | 
| 3196 |  |  |  |  |  |  | } | 
| 3197 |  |  |  |  |  |  | } | 
| 3198 |  |  |  |  |  |  |  | 
| 3199 | 21 |  |  |  |  | 59 | my($num,$den) = Math::Prime::Util::harmfrac($n); | 
| 3200 |  |  |  |  |  |  | # Note, with Calc backend this can be very, very slow | 
| 3201 | 21 |  |  |  |  | 7406 | scalar Math::BigFloat->new($num)->bdiv($den, $precision); | 
| 3202 |  |  |  |  |  |  | } | 
| 3203 |  |  |  |  |  |  |  | 
| 3204 |  |  |  |  |  |  | sub is_pseudoprime { | 
| 3205 | 10 |  |  | 10 | 0 | 1331 | my($n, @bases) = @_; | 
| 3206 | 10 | 50 |  |  |  | 27 | return 0 if int($n) < 0; | 
| 3207 | 10 |  |  |  |  | 28 | _validate_positive_integer($n); | 
| 3208 | 10 | 50 |  |  |  | 20 | croak("No bases given to is_pseudoprime") unless scalar(@bases) > 0; | 
| 3209 | 10 | 50 |  |  |  | 17 | return 0+($n >= 2) if $n < 4; | 
| 3210 |  |  |  |  |  |  |  | 
| 3211 | 10 |  |  |  |  | 22 | foreach my $base (@bases) { | 
| 3212 | 10 | 50 |  |  |  | 20 | croak "Base $base is invalid" if $base < 2; | 
| 3213 | 10 | 50 |  |  |  | 19 | $base = $base % $n if $base >= $n; | 
| 3214 | 10 | 50 | 33 |  |  | 37 | if ($base > 1 && $base != $n-1) { | 
| 3215 | 10 | 50 |  |  |  | 29 | my $x = (ref($n) eq 'Math::BigInt') | 
| 3216 |  |  |  |  |  |  | ? $n->copy->bzero->badd($base)->bmodpow($n-1,$n)->is_one | 
| 3217 |  |  |  |  |  |  | : _powmod($base, $n-1, $n); | 
| 3218 | 10 | 50 |  |  |  | 23 | return 0 unless $x == 1; | 
| 3219 |  |  |  |  |  |  | } | 
| 3220 |  |  |  |  |  |  | } | 
| 3221 | 10 |  |  |  |  | 27 | 1; | 
| 3222 |  |  |  |  |  |  | } | 
| 3223 |  |  |  |  |  |  |  | 
| 3224 |  |  |  |  |  |  | sub is_euler_pseudoprime { | 
| 3225 | 0 |  |  | 0 | 0 | 0 | my($n, @bases) = @_; | 
| 3226 | 0 | 0 |  |  |  | 0 | return 0 if int($n) < 0; | 
| 3227 | 0 |  |  |  |  | 0 | _validate_positive_integer($n); | 
| 3228 | 0 | 0 |  |  |  | 0 | croak("No bases given to is_euler_pseudoprime") unless scalar(@bases) > 0; | 
| 3229 | 0 | 0 |  |  |  | 0 | return 0+($n >= 2) if $n < 4; | 
| 3230 |  |  |  |  |  |  |  | 
| 3231 | 0 |  |  |  |  | 0 | foreach my $base (@bases) { | 
| 3232 | 0 | 0 |  |  |  | 0 | croak "Base $base is invalid" if $base < 2; | 
| 3233 | 0 | 0 |  |  |  | 0 | $base = $base % $n if $base >= $n; | 
| 3234 | 0 | 0 | 0 |  |  | 0 | if ($base > 1 && $base != $n-1) { | 
| 3235 | 0 |  |  |  |  | 0 | my $j = kronecker($base, $n); | 
| 3236 | 0 | 0 |  |  |  | 0 | return 0 if $j == 0; | 
| 3237 | 0 | 0 |  |  |  | 0 | $j = ($j > 0) ? 1 : $n-1; | 
| 3238 | 0 | 0 |  |  |  | 0 | my $x = (ref($n) eq 'Math::BigInt') | 
| 3239 |  |  |  |  |  |  | ? $n->copy->bzero->badd($base)->bmodpow(($n-1)/2,$n) | 
| 3240 |  |  |  |  |  |  | : _powmod($base, ($n-1)>>1, $n); | 
| 3241 | 0 | 0 |  |  |  | 0 | return 0 unless $x == $j; | 
| 3242 |  |  |  |  |  |  | } | 
| 3243 |  |  |  |  |  |  | } | 
| 3244 | 0 |  |  |  |  | 0 | 1; | 
| 3245 |  |  |  |  |  |  | } | 
| 3246 |  |  |  |  |  |  |  | 
| 3247 |  |  |  |  |  |  | sub is_euler_plumb_pseudoprime { | 
| 3248 | 0 |  |  | 0 | 0 | 0 | my($n) = @_; | 
| 3249 | 0 | 0 |  |  |  | 0 | return 0 if int($n) < 0; | 
| 3250 | 0 |  |  |  |  | 0 | _validate_positive_integer($n); | 
| 3251 | 0 | 0 |  |  |  | 0 | return 0+($n >= 2) if $n < 4; | 
| 3252 | 0 | 0 |  |  |  | 0 | return 0 if ($n % 2) == 0; | 
| 3253 | 0 |  |  |  |  | 0 | my $nmod8 = $n % 8; | 
| 3254 | 0 |  |  |  |  | 0 | my $exp = 1 + ($nmod8 == 1); | 
| 3255 | 0 |  |  |  |  | 0 | my $ap = Math::Prime::Util::powmod(2, ($n-1) >> $exp, $n); | 
| 3256 | 0 | 0 | 0 |  |  | 0 | if ($ap ==    1) { return ($nmod8 == 1 || $nmod8 == 7); } | 
|  | 0 |  |  |  |  | 0 |  | 
| 3257 | 0 | 0 | 0 |  |  | 0 | if ($ap == $n-1) { return ($nmod8 == 1 || $nmod8 == 3 || $nmod8 == 5); } | 
|  | 0 |  |  |  |  | 0 |  | 
| 3258 | 0 |  |  |  |  | 0 | 0; | 
| 3259 |  |  |  |  |  |  | } | 
| 3260 |  |  |  |  |  |  |  | 
| 3261 |  |  |  |  |  |  | sub _miller_rabin_2 { | 
| 3262 | 3739 |  |  | 3739 |  | 266677 | my($n, $nm1, $s, $d) = @_; | 
| 3263 |  |  |  |  |  |  |  | 
| 3264 | 3739 | 100 |  |  |  | 7477 | if ( ref($n) eq 'Math::BigInt' ) { | 
| 3265 |  |  |  |  |  |  |  | 
| 3266 | 476 | 50 |  |  |  | 1534 | if (!defined $nm1) { | 
| 3267 | 476 |  |  |  |  | 1536 | $nm1 = $n->copy->bdec(); | 
| 3268 | 476 |  |  |  |  | 36992 | $s = 0; | 
| 3269 | 476 |  |  |  |  | 1404 | $d = $nm1->copy; | 
| 3270 | 476 |  |  |  |  | 9409 | do { | 
| 3271 | 976 |  |  |  |  | 62218 | $s++; | 
| 3272 | 976 |  |  |  |  | 3123 | $d->brsft(BONE); | 
| 3273 |  |  |  |  |  |  | } while $d->is_even; | 
| 3274 |  |  |  |  |  |  | } | 
| 3275 | 476 |  |  |  |  | 59458 | my $x = BTWO->copy->bmodpow($d,$n); | 
| 3276 | 476 | 100 | 100 |  |  | 43238431 | return 1 if $x->is_one || $x->bcmp($nm1) == 0; | 
| 3277 | 365 |  |  |  |  | 22929 | foreach my $r (1 .. $s-1) { | 
| 3278 | 356 |  |  |  |  | 5271 | $x->bmul($x)->bmod($n); | 
| 3279 | 356 | 50 |  |  |  | 160980 | last if $x->is_one; | 
| 3280 | 356 | 100 |  |  |  | 4879 | return 1 if $x->bcmp($nm1) == 0; | 
| 3281 |  |  |  |  |  |  | } | 
| 3282 |  |  |  |  |  |  |  | 
| 3283 |  |  |  |  |  |  | } else { | 
| 3284 |  |  |  |  |  |  |  | 
| 3285 | 3263 | 50 |  |  |  | 5490 | if (!defined $nm1) { | 
| 3286 | 3263 |  |  |  |  | 4250 | $nm1 = $n-1; | 
| 3287 | 3263 |  |  |  |  | 4259 | $s = 0; | 
| 3288 | 3263 |  |  |  |  | 4426 | $d = $nm1; | 
| 3289 | 3263 |  |  |  |  | 6243 | while ( ($d & 1) == 0 ) { | 
| 3290 | 7574 |  |  |  |  | 9208 | $s++; | 
| 3291 | 7574 |  |  |  |  | 12994 | $d >>= 1; | 
| 3292 |  |  |  |  |  |  | } | 
| 3293 |  |  |  |  |  |  | } | 
| 3294 |  |  |  |  |  |  |  | 
| 3295 | 3263 | 100 |  |  |  | 5226 | if ($n < MPU_HALFWORD) { | 
| 3296 | 3206 |  |  |  |  | 6030 | my $x = _native_powmod(2, $d, $n); | 
| 3297 | 3206 | 100 | 100 |  |  | 9571 | return 1 if $x == 1 || $x == $nm1; | 
| 3298 | 3196 |  |  |  |  | 6334 | foreach my $r (1 .. $s-1) { | 
| 3299 | 3807 |  |  |  |  | 4988 | $x = ($x*$x) % $n; | 
| 3300 | 3807 | 100 |  |  |  | 6024 | last if $x == 1; | 
| 3301 | 3804 | 100 |  |  |  | 7287 | return 1 if $x == $n-1; | 
| 3302 |  |  |  |  |  |  | } | 
| 3303 |  |  |  |  |  |  | } else { | 
| 3304 | 57 |  |  |  |  | 270 | my $x = _powmod(2, $d, $n); | 
| 3305 | 57 | 100 | 66 |  |  | 478 | return 1 if $x == 1 || $x == $nm1; | 
| 3306 | 19 |  |  |  |  | 194 | foreach my $r (1 .. $s-1) { | 
| 3307 | 31 | 50 |  |  |  | 100 | $x = ($x < MPU_HALFWORD) ? ($x*$x) % $n : _mulmod($x, $x, $n); | 
| 3308 | 31 | 50 |  |  |  | 112 | last if $x == 1; | 
| 3309 | 31 | 100 |  |  |  | 118 | return 1 if $x == $n-1; | 
| 3310 |  |  |  |  |  |  | } | 
| 3311 |  |  |  |  |  |  | } | 
| 3312 |  |  |  |  |  |  | } | 
| 3313 | 3194 |  |  |  |  | 18853 | 0; | 
| 3314 |  |  |  |  |  |  | } | 
| 3315 |  |  |  |  |  |  |  | 
| 3316 |  |  |  |  |  |  | sub is_strong_pseudoprime { | 
| 3317 | 3619 |  |  | 3619 | 0 | 33084 | my($n, @bases) = @_; | 
| 3318 | 3619 | 50 |  |  |  | 7700 | return 0 if int($n) < 0; | 
| 3319 | 3619 |  |  |  |  | 57384 | _validate_positive_integer($n); | 
| 3320 | 3619 | 50 |  |  |  | 7193 | croak("No bases given to is_strong_pseudoprime") unless scalar(@bases) > 0; | 
| 3321 |  |  |  |  |  |  |  | 
| 3322 | 3619 | 100 |  |  |  | 6700 | return 0+($n >= 2) if $n < 4; | 
| 3323 | 3615 | 50 |  |  |  | 38544 | return 0 if ($n % 2) == 0; | 
| 3324 |  |  |  |  |  |  |  | 
| 3325 | 3615 | 100 |  |  |  | 106955 | if ($bases[0] == 2) { | 
| 3326 | 3365 | 100 |  |  |  | 5420 | return 0 unless _miller_rabin_2($n); | 
| 3327 | 375 |  |  |  |  | 3184 | shift @bases; | 
| 3328 | 375 | 100 |  |  |  | 1043 | return 1 unless @bases; | 
| 3329 |  |  |  |  |  |  | } | 
| 3330 |  |  |  |  |  |  |  | 
| 3331 | 575 |  |  |  |  | 1306 | my @newbases; | 
| 3332 | 575 |  |  |  |  | 1169 | for my $base (@bases) { | 
| 3333 | 718 | 50 |  |  |  | 1497 | croak "Base $base is invalid" if $base < 2; | 
| 3334 | 718 | 100 |  |  |  | 3806 | $base %= $n if $base >= $n; | 
| 3335 | 718 | 50 | 66 |  |  | 16501 | return 0 if $base == 0 || ($base == $n-1 && ($base % 2) == 1); | 
|  |  |  | 33 |  |  |  |  | 
| 3336 | 718 |  |  |  |  | 66873 | push @newbases, $base; | 
| 3337 |  |  |  |  |  |  | } | 
| 3338 | 575 |  |  |  |  | 1271 | @bases = @newbases; | 
| 3339 |  |  |  |  |  |  |  | 
| 3340 | 575 | 100 |  |  |  | 1489 | if ( ref($n) eq 'Math::BigInt' ) { | 
| 3341 |  |  |  |  |  |  |  | 
| 3342 | 152 |  |  |  |  | 440 | my $nminus1 = $n->copy->bdec(); | 
| 3343 | 152 |  |  |  |  | 11433 | my $s = 0; | 
| 3344 | 152 |  |  |  |  | 412 | my $d = $nminus1->copy; | 
| 3345 | 152 |  |  |  |  | 3105 | do {  # n is > 3 and odd, so n-1 must be even | 
| 3346 | 285 |  |  |  |  | 17942 | $s++; | 
| 3347 | 285 |  |  |  |  | 921 | $d->brsft(BONE); | 
| 3348 |  |  |  |  |  |  | } while $d->is_even; | 
| 3349 |  |  |  |  |  |  | # Different way of doing the above.  Fewer function calls, slower on ave. | 
| 3350 |  |  |  |  |  |  | #my $dbin = $nminus1->as_bin; | 
| 3351 |  |  |  |  |  |  | #my $last1 = rindex($dbin, '1'); | 
| 3352 |  |  |  |  |  |  | #my $s = length($dbin)-2-$last1+1; | 
| 3353 |  |  |  |  |  |  | #my $d = $nminus1->copy->brsft($s); | 
| 3354 |  |  |  |  |  |  |  | 
| 3355 | 152 |  |  |  |  | 18419 | foreach my $ma (@bases) { | 
| 3356 | 194 |  |  |  |  | 2178 | my $x = $n->copy->bzero->badd($ma)->bmodpow($d,$n); | 
| 3357 | 194 | 100 | 100 |  |  | 6808023 | next if $x->is_one || $x->bcmp($nminus1) == 0; | 
| 3358 | 104 |  |  |  |  | 6418 | foreach my $r (1 .. $s-1) { | 
| 3359 | 100 |  |  |  |  | 1273 | $x->bmul($x); $x->bmod($n); | 
|  | 100 |  |  |  |  | 16076 |  | 
| 3360 | 100 | 50 |  |  |  | 28206 | return 0 if $x->is_one; | 
| 3361 | 100 | 100 |  |  |  | 1454 | do { $ma = 0; last; } if $x->bcmp($nminus1) == 0; | 
|  | 41 |  |  |  |  | 1504 |  | 
|  | 41 |  |  |  |  | 104 |  | 
| 3362 |  |  |  |  |  |  | } | 
| 3363 | 104 | 100 |  |  |  | 2195 | return 0 if $ma != 0; | 
| 3364 |  |  |  |  |  |  | } | 
| 3365 |  |  |  |  |  |  |  | 
| 3366 |  |  |  |  |  |  | } else { | 
| 3367 |  |  |  |  |  |  |  | 
| 3368 | 423 |  |  |  |  | 639 | my $s = 0; | 
| 3369 | 423 |  |  |  |  | 612 | my $d = $n - 1; | 
| 3370 | 423 |  |  |  |  | 964 | while ( ($d & 1) == 0 ) { | 
| 3371 | 1744 |  |  |  |  | 2102 | $s++; | 
| 3372 | 1744 |  |  |  |  | 2910 | $d >>= 1; | 
| 3373 |  |  |  |  |  |  | } | 
| 3374 |  |  |  |  |  |  |  | 
| 3375 | 423 | 100 |  |  |  | 809 | if ($n < MPU_HALFWORD) { | 
| 3376 | 382 |  |  |  |  | 593 | foreach my $ma (@bases) { | 
| 3377 | 396 |  |  |  |  | 658 | my $x = _native_powmod($ma, $d, $n); | 
| 3378 | 396 | 100 | 100 |  |  | 1372 | next if ($x == 1) || ($x == ($n-1)); | 
| 3379 | 330 |  |  |  |  | 632 | foreach my $r (1 .. $s-1) { | 
| 3380 | 954 |  |  |  |  | 1304 | $x = ($x*$x) % $n; | 
| 3381 | 954 | 100 |  |  |  | 1606 | return 0 if $x == 1; | 
| 3382 | 953 | 100 |  |  |  | 1768 | last if $x == $n-1; | 
| 3383 |  |  |  |  |  |  | } | 
| 3384 | 329 | 100 |  |  |  | 763 | return 0 if $x != $n-1; | 
| 3385 |  |  |  |  |  |  | } | 
| 3386 |  |  |  |  |  |  | } else { | 
| 3387 | 41 |  |  |  |  | 109 | foreach my $ma (@bases) { | 
| 3388 | 117 |  |  |  |  | 322 | my $x = _powmod($ma, $d, $n); | 
| 3389 | 117 | 100 | 100 |  |  | 782 | next if ($x == 1) || ($x == ($n-1)); | 
| 3390 |  |  |  |  |  |  |  | 
| 3391 | 6 |  |  |  |  | 20 | foreach my $r (1 .. $s-1) { | 
| 3392 | 7 | 100 |  |  |  | 27 | $x = ($x < MPU_HALFWORD) ? ($x*$x) % $n : _mulmod($x, $x, $n); | 
| 3393 | 7 | 50 |  |  |  | 17 | return 0 if $x == 1; | 
| 3394 | 7 | 100 |  |  |  | 23 | last if $x == $n-1; | 
| 3395 |  |  |  |  |  |  | } | 
| 3396 | 6 | 100 |  |  |  | 39 | return 0 if $x != $n-1; | 
| 3397 |  |  |  |  |  |  | } | 
| 3398 |  |  |  |  |  |  | } | 
| 3399 |  |  |  |  |  |  |  | 
| 3400 |  |  |  |  |  |  | } | 
| 3401 | 502 |  |  |  |  | 4818 | 1; | 
| 3402 |  |  |  |  |  |  | } | 
| 3403 |  |  |  |  |  |  |  | 
| 3404 |  |  |  |  |  |  |  | 
| 3405 |  |  |  |  |  |  | # Calculate Kronecker symbol (a|b).  Cohen Algorithm 1.4.10. | 
| 3406 |  |  |  |  |  |  | # Extension of the Jacobi symbol, itself an extension of the Legendre symbol. | 
| 3407 |  |  |  |  |  |  | sub kronecker { | 
| 3408 | 665 |  |  | 665 | 0 | 9388 | my($a, $b) = @_; | 
| 3409 | 665 | 0 |  |  |  | 1667 | return (abs($a) == 1) ? 1 : 0  if $b == 0; | 
|  |  | 50 |  |  |  |  |  | 
| 3410 | 665 |  |  |  |  | 46655 | my $k = 1; | 
| 3411 | 665 | 50 |  |  |  | 1793 | if ($b % 2 == 0) { | 
| 3412 | 0 | 0 |  |  |  | 0 | return 0 if $a % 2 == 0; | 
| 3413 | 0 |  |  |  |  | 0 | my $v = 0; | 
| 3414 | 0 |  |  |  |  | 0 | do { $v++; $b /= 2; } while $b % 2 == 0; | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 3415 | 0 | 0 | 0 |  |  | 0 | $k = -$k if $v % 2 == 1 && ($a % 8 == 3 || $a % 8 == 5); | 
|  |  |  | 0 |  |  |  |  | 
| 3416 |  |  |  |  |  |  | } | 
| 3417 | 665 | 100 |  |  |  | 95949 | if ($b < 0) { | 
| 3418 | 1 |  |  |  |  | 3 | $b = -$b; | 
| 3419 | 1 | 50 |  |  |  | 5 | $k = -$k if $a < 0; | 
| 3420 |  |  |  |  |  |  | } | 
| 3421 | 665 | 100 |  |  |  | 45645 | if ($a < 0) { $a = -$a; $k = -$k if $b % 4 == 3; } | 
|  | 16 | 100 |  |  |  | 42 |  | 
|  | 16 |  |  |  |  | 44 |  | 
| 3422 | 665 | 100 | 100 |  |  | 3773 | $b = _bigint_to_int($b) if ref($b) eq 'Math::BigInt' && $b <= BMAX; | 
| 3423 | 665 | 50 | 66 |  |  | 11730 | $a = _bigint_to_int($a) if ref($a) eq 'Math::BigInt' && $a <= BMAX; | 
| 3424 |  |  |  |  |  |  | # Now:  b > 0, b odd, a >= 0 | 
| 3425 | 665 |  |  |  |  | 1945 | while ($a != 0) { | 
| 3426 | 936 | 100 |  |  |  | 55681 | if ($a % 2 == 0) { | 
| 3427 | 402 |  |  |  |  | 40026 | my $v = 0; | 
| 3428 | 402 |  |  |  |  | 728 | do { $v++; $a /= 2; } while $a % 2 == 0; | 
|  | 672 |  |  |  |  | 24520 |  | 
|  | 672 |  |  |  |  | 2053 |  | 
| 3429 | 402 | 100 | 100 |  |  | 72396 | $k = -$k if $v % 2 == 1 && ($b % 8 == 3 || $b % 8 == 5); | 
|  |  |  | 100 |  |  |  |  | 
| 3430 |  |  |  |  |  |  | } | 
| 3431 | 936 | 100 | 100 |  |  | 61163 | $k = -$k if $a % 4 == 3 && $b % 4 == 3; | 
| 3432 | 936 |  |  |  |  | 100865 | ($a, $b) = ($b % $a, $a); | 
| 3433 |  |  |  |  |  |  | # If a,b are bigints and now small enough, finish as native. | 
| 3434 | 936 | 100 | 100 |  |  | 89649 | if (   ref($a) eq 'Math::BigInt' && $a <= BMAX | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
| 3435 |  |  |  |  |  |  | && ref($b) eq 'Math::BigInt' && $b <= BMAX) { | 
| 3436 | 267 |  |  |  |  | 18128 | return $k * kronecker(_bigint_to_int($a),_bigint_to_int($b)); | 
| 3437 |  |  |  |  |  |  | } | 
| 3438 |  |  |  |  |  |  | } | 
| 3439 | 398 | 50 |  |  |  | 5050 | return ($b == 1) ? $k : 0; | 
| 3440 |  |  |  |  |  |  | } | 
| 3441 |  |  |  |  |  |  |  | 
| 3442 |  |  |  |  |  |  | sub _binomialu { | 
| 3443 | 5235 |  |  | 5235 |  | 13350 | my($r, $n, $k) = (1, @_); | 
| 3444 | 5235 | 0 |  |  |  | 10784 | return ($k == $n) ? 1 : 0 if $k >= $n; | 
|  |  | 50 |  |  |  |  |  | 
| 3445 | 5235 | 100 |  |  |  | 12196 | $k = $n - $k if $k > ($n >> 1); | 
| 3446 | 5235 |  |  |  |  | 12756 | foreach my $d (1 .. $k) { | 
| 3447 | 89359 | 100 |  |  |  | 151169 | if ($r >= int(~0/$n)) { | 
| 3448 | 13809 |  |  |  |  | 19962 | my($g, $nr, $dr); | 
| 3449 | 13809 |  |  |  |  | 27172 | $g = _gcd_ui($n, $d);   $nr = int($n/$g);   $dr = int($d/$g); | 
|  | 13809 |  |  |  |  | 23972 |  | 
|  | 13809 |  |  |  |  | 20499 |  | 
| 3450 | 13809 |  |  |  |  | 22097 | $g = _gcd_ui($r, $dr);  $r  = int($r/$g);   $dr = int($dr/$g); | 
|  | 13809 |  |  |  |  | 20380 |  | 
|  | 13809 |  |  |  |  | 19872 |  | 
| 3451 | 13809 | 100 |  |  |  | 32035 | return 0 if $r >= int(~0/$nr); | 
| 3452 | 8576 |  |  |  |  | 12128 | $r *= $nr; | 
| 3453 | 8576 |  |  |  |  | 13110 | $r = int($r/$dr); | 
| 3454 |  |  |  |  |  |  | } else { | 
| 3455 | 75550 |  |  |  |  | 98518 | $r *= $n; | 
| 3456 | 75550 |  |  |  |  | 102649 | $r = int($r/$d); | 
| 3457 |  |  |  |  |  |  | } | 
| 3458 | 84126 |  |  |  |  | 115348 | $n--; | 
| 3459 |  |  |  |  |  |  | } | 
| 3460 | 2 |  |  |  |  | 5 | $r; | 
| 3461 |  |  |  |  |  |  | } | 
| 3462 |  |  |  |  |  |  |  | 
| 3463 |  |  |  |  |  |  | sub binomial { | 
| 3464 | 5235 |  |  | 5235 | 0 | 111599 | my($n, $k) = @_; | 
| 3465 |  |  |  |  |  |  |  | 
| 3466 |  |  |  |  |  |  | # 1. Try GMP | 
| 3467 |  |  |  |  |  |  | return Math::Prime::Util::_reftyped($_[0], Math::Prime::Util::GMP::binomial($n,$k)) | 
| 3468 | 5235 | 50 |  |  |  | 17069 | if $Math::Prime::Util::_GMPfunc{"binomial"}; | 
| 3469 |  |  |  |  |  |  |  | 
| 3470 |  |  |  |  |  |  | # 2. Exit early for known 0 cases, and adjust k to be positive. | 
| 3471 | 5235 | 50 | 33 |  |  | 14851 | if ($n >= 0) {  return 0 if $k < 0 || $k > $n;  } | 
|  | 5234 | 100 |  |  |  | 24669 |  | 
| 3472 | 1 | 50 | 33 |  |  | 8 | else         {  return 0 if $k < 0 && $k > $n;  } | 
| 3473 | 5235 | 100 |  |  |  | 11981 | $k = $n - $k if $k < 0; | 
| 3474 |  |  |  |  |  |  |  | 
| 3475 |  |  |  |  |  |  | # 3. Try to do in integer Perl | 
| 3476 | 5235 |  |  |  |  | 9810 | my $r; | 
| 3477 | 5235 | 100 |  |  |  | 12755 | if ($n >= 0) { | 
| 3478 | 5234 |  |  |  |  | 13577 | $r = _binomialu($n, $k); | 
| 3479 | 5234 | 100 |  |  |  | 13768 | return $r  if $r > 0; | 
| 3480 |  |  |  |  |  |  | } else { | 
| 3481 | 1 |  |  |  |  | 4 | $r = _binomialu(-$n+$k-1, $k); | 
| 3482 | 1 | 50 | 33 |  |  | 8 | return $r   if $r > 0 && !($k & 1); | 
| 3483 | 1 | 50 | 33 |  |  | 10 | return -$r  if $r > 0 && $r <= (~0>>1); | 
| 3484 |  |  |  |  |  |  | } | 
| 3485 |  |  |  |  |  |  |  | 
| 3486 |  |  |  |  |  |  | # 4. Overflow.  Solve using Math::BigInt | 
| 3487 | 5233 | 50 |  |  |  | 11303 | return 1 if $k == 0;        # Work around bug in old | 
| 3488 | 5233 | 50 |  |  |  | 12556 | return $n if $k == $n-1;    # Math::BigInt (fixed in 1.90) | 
| 3489 | 5233 | 50 |  |  |  | 10275 | if ($n >= 0) { | 
| 3490 | 5233 |  |  |  |  | 26044 | $r = Math::BigInt->new(''.$n)->bnok($k); | 
| 3491 | 5233 | 50 |  |  |  | 14384868 | $r = _bigint_to_int($r) if $r->bacmp(BMAX) <= 0; | 
| 3492 |  |  |  |  |  |  | } else { # Math::BigInt is incorrect for negative n | 
| 3493 | 0 |  |  |  |  | 0 | $r = Math::BigInt->new(''.(-$n+$k-1))->bnok($k); | 
| 3494 | 0 | 0 |  |  |  | 0 | if ($k & 1) { | 
| 3495 | 0 |  |  |  |  | 0 | $r->bneg; | 
| 3496 | 0 | 0 |  |  |  | 0 | $r = _bigint_to_int($r) if $r->bacmp(''.(~0>>1)) <= 0; | 
| 3497 |  |  |  |  |  |  | } else { | 
| 3498 | 0 | 0 |  |  |  | 0 | $r = _bigint_to_int($r) if $r->bacmp(BMAX) <= 0; | 
| 3499 |  |  |  |  |  |  | } | 
| 3500 |  |  |  |  |  |  | } | 
| 3501 | 5233 |  |  |  |  | 164706 | $r; | 
| 3502 |  |  |  |  |  |  | } | 
| 3503 |  |  |  |  |  |  |  | 
| 3504 |  |  |  |  |  |  | sub _product { | 
| 3505 | 14994 |  |  | 14994 |  | 845613 | my($a, $b, $r) = @_; | 
| 3506 | 14994 | 100 |  |  |  | 54493 | if ($b <= $a) { | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 3507 | 2 |  |  |  |  | 6 | $r->[$a]; | 
| 3508 |  |  |  |  |  |  | } elsif ($b == $a+1) { | 
| 3509 | 13720 |  |  |  |  | 45554 | $r->[$a] -> bmul( $r->[$b] ); | 
| 3510 |  |  |  |  |  |  | } elsif ($b == $a+2) { | 
| 3511 | 814 |  |  |  |  | 2984 | $r->[$a] -> bmul( $r->[$a+1] ) -> bmul( $r->[$a+2] ); | 
| 3512 |  |  |  |  |  |  | } else { | 
| 3513 | 458 |  |  |  |  | 719 | my $c = $a + (($b-$a+1)>>1); | 
| 3514 | 458 |  |  |  |  | 980 | _product($a, $c-1, $r); | 
| 3515 | 458 |  |  |  |  | 30817 | _product($c, $b, $r); | 
| 3516 | 458 |  |  |  |  | 33216 | $r->[$a] -> bmul( $r->[$c] ); | 
| 3517 |  |  |  |  |  |  | } | 
| 3518 |  |  |  |  |  |  | } | 
| 3519 |  |  |  |  |  |  |  | 
| 3520 |  |  |  |  |  |  | sub factorial { | 
| 3521 | 768 |  |  | 768 | 0 | 154051 | my($n) = @_; | 
| 3522 | 768 | 100 |  |  |  | 2934 | return (1,1,2,6,24,120,720,5040,40320,362880,3628800,39916800,479001600)[$n] if $n <= 12; | 
| 3523 | 564 | 50 |  |  |  | 1764 | return Math::GMP::bfac($n) if ref($n) eq 'Math::GMP'; | 
| 3524 | 564 | 50 |  |  |  | 1523 | do { my $r = Math::GMPz->new(); Math::GMPz::Rmpz_fac_ui($r,$n); return $r; } | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 3525 |  |  |  |  |  |  | if ref($n) eq 'Math::GMPz'; | 
| 3526 | 564 | 50 |  |  |  | 2066 | if (Math::BigInt->config()->{lib} !~ /GMP|Pari/) { | 
| 3527 |  |  |  |  |  |  | # It's not a GMP or GMPz object, and we have a slow bigint library. | 
| 3528 | 564 |  |  |  |  | 28781 | my $r; | 
| 3529 | 564 | 50 | 33 |  |  | 2933 | if (defined $Math::GMPz::VERSION) { | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 3530 | 0 |  |  |  |  | 0 | $r = Math::GMPz->new(); Math::GMPz::Rmpz_fac_ui($r,$n); | 
|  | 0 |  |  |  |  | 0 |  | 
| 3531 |  |  |  |  |  |  | } elsif (defined $Math::GMP::VERSION) { | 
| 3532 | 0 |  |  |  |  | 0 | $r = Math::GMP::bfac($n); | 
| 3533 |  |  |  |  |  |  | } elsif (defined &Math::Prime::Util::GMP::factorial && Math::Prime::Util::prime_get_config()->{'gmp'}) { | 
| 3534 | 0 |  |  |  |  | 0 | $r = Math::Prime::Util::GMP::factorial($n); | 
| 3535 |  |  |  |  |  |  | } | 
| 3536 | 564 | 50 |  |  |  | 1463 | return Math::Prime::Util::_reftyped($_[0], $r)    if defined $r; | 
| 3537 |  |  |  |  |  |  | } | 
| 3538 | 564 |  |  |  |  | 3033 | my $r = Math::BigInt->new($n)->bfac(); | 
| 3539 | 564 | 100 |  |  |  | 18782733 | $r = _bigint_to_int($r) if $r->bacmp(BMAX) <= 0; | 
| 3540 | 564 |  |  |  |  | 14630 | $r; | 
| 3541 |  |  |  |  |  |  | } | 
| 3542 |  |  |  |  |  |  |  | 
| 3543 |  |  |  |  |  |  | sub factorialmod { | 
| 3544 | 0 |  |  | 0 | 0 | 0 | my($n,$m) = @_; | 
| 3545 |  |  |  |  |  |  |  | 
| 3546 |  |  |  |  |  |  | return Math::Prime::Util::GMP::factorialmod($n,$m) | 
| 3547 | 0 | 0 |  |  |  | 0 | if $Math::Prime::Util::_GMPfunc{"factorialmod"}; | 
| 3548 |  |  |  |  |  |  |  | 
| 3549 | 0 | 0 | 0 |  |  | 0 | return 0 if $n >= $m || $m == 1; | 
| 3550 |  |  |  |  |  |  |  | 
| 3551 | 0 | 0 |  |  |  | 0 | if ($n > 10) { | 
| 3552 | 0 |  |  |  |  | 0 | my($s,$t,$e) = (1); | 
| 3553 |  |  |  |  |  |  | Math::Prime::Util::forprimes( sub { | 
| 3554 | 0 |  |  | 0 |  | 0 | ($t,$e) = ($n,0); | 
| 3555 | 0 |  |  |  |  | 0 | while ($t > 0) { | 
| 3556 | 0 |  |  |  |  | 0 | $t = int($t/$_); | 
| 3557 | 0 |  |  |  |  | 0 | $e += $t; | 
| 3558 |  |  |  |  |  |  | } | 
| 3559 | 0 |  |  |  |  | 0 | $s = Math::Prime::Util::mulmod($s, Math::Prime::Util::powmod($_,$e,$m), $m); | 
| 3560 | 0 |  |  |  |  | 0 | }, 2, $n >> 1); | 
| 3561 |  |  |  |  |  |  | Math::Prime::Util::forprimes( sub { | 
| 3562 | 0 |  |  | 0 |  | 0 | $s = Math::Prime::Util::mulmod($s, $_, $m); | 
| 3563 | 0 |  |  |  |  | 0 | }, ($n >> 1)+1, $n); | 
| 3564 | 0 |  |  |  |  | 0 | return $s; | 
| 3565 |  |  |  |  |  |  | } | 
| 3566 |  |  |  |  |  |  |  | 
| 3567 | 0 |  |  |  |  | 0 | return factorial($n) % $m; | 
| 3568 |  |  |  |  |  |  | } | 
| 3569 |  |  |  |  |  |  |  | 
| 3570 |  |  |  |  |  |  | sub _is_perfect_square { | 
| 3571 | 212 |  |  | 212 |  | 56335 | my($n) = @_; | 
| 3572 | 212 | 50 |  |  |  | 1011 | return (1,1,0,0,1)[$n] if $n <= 4; | 
| 3573 |  |  |  |  |  |  |  | 
| 3574 | 212 | 100 |  |  |  | 16227 | if (ref($n) eq 'Math::BigInt') { | 
| 3575 | 140 |  |  |  |  | 677 | my $mc = _bigint_to_int($n & 31); | 
| 3576 | 140 | 100 | 66 |  |  | 6850 | if ($mc==0||$mc==1||$mc==4||$mc==9||$mc==16||$mc==17||$mc==25) { | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
| 3577 | 48 |  |  |  |  | 191 | my $sq = $n->copy->bsqrt->bfloor; | 
| 3578 | 48 |  |  |  |  | 48831 | $sq->bmul($sq); | 
| 3579 | 48 | 100 |  |  |  | 5926 | return 1 if $sq == $n; | 
| 3580 |  |  |  |  |  |  | } | 
| 3581 |  |  |  |  |  |  | } else { | 
| 3582 | 72 |  |  |  |  | 166 | my $mc = $n & 31; | 
| 3583 | 72 | 100 | 33 |  |  | 870 | if ($mc==0||$mc==1||$mc==4||$mc==9||$mc==16||$mc==17||$mc==25) { | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
| 3584 | 8 |  |  |  |  | 31 | my $sq = int(sqrt($n)); | 
| 3585 | 8 | 50 |  |  |  | 36 | return 1 if ($sq*$sq) == $n; | 
| 3586 |  |  |  |  |  |  | } | 
| 3587 |  |  |  |  |  |  | } | 
| 3588 | 210 |  |  |  |  | 3096 | 0; | 
| 3589 |  |  |  |  |  |  | } | 
| 3590 |  |  |  |  |  |  |  | 
| 3591 |  |  |  |  |  |  | sub is_primitive_root { | 
| 3592 | 0 |  |  | 0 | 0 | 0 | my($a, $n) = @_; | 
| 3593 | 0 | 0 |  |  |  | 0 | $n = -$n if $n < 0;  # Ignore sign of n | 
| 3594 | 0 | 0 |  |  |  | 0 | return ($n==1) ? 1 : 0 if $n <= 1; | 
|  |  | 0 |  |  |  |  |  | 
| 3595 | 0 | 0 | 0 |  |  | 0 | $a %= $n if $a < 0 || $a >= $n; | 
| 3596 |  |  |  |  |  |  |  | 
| 3597 |  |  |  |  |  |  | return Math::Prime::Util::GMP::is_primitive_root($a,$n) | 
| 3598 | 0 | 0 |  |  |  | 0 | if $Math::Prime::Util::_GMPfunc{"is_primitive_root"}; | 
| 3599 |  |  |  |  |  |  |  | 
| 3600 | 0 | 0 | 0 |  |  | 0 | if ($Math::Prime::Util::_GMPfunc{"znorder"} && $Math::Prime::Util::_GMPfunc{"totient"}) { | 
| 3601 | 0 |  |  |  |  | 0 | my $order = Math::Prime::Util::GMP::znorder($a,$n); | 
| 3602 | 0 | 0 |  |  |  | 0 | return 0 unless defined $order; | 
| 3603 | 0 |  |  |  |  | 0 | my $totient = Math::Prime::Util::GMP::totient($n); | 
| 3604 | 0 | 0 |  |  |  | 0 | return ($order eq $totient) ? 1 : 0; | 
| 3605 |  |  |  |  |  |  | } | 
| 3606 |  |  |  |  |  |  |  | 
| 3607 | 0 | 0 |  |  |  | 0 | return 0 if Math::Prime::Util::gcd($a, $n) != 1; | 
| 3608 | 0 |  |  |  |  | 0 | my $s = Math::Prime::Util::euler_phi($n); | 
| 3609 | 0 | 0 | 0 |  |  | 0 | return 0 if ($s % 2) == 0 && Math::Prime::Util::powmod($a, $s/2, $n) == 1; | 
| 3610 | 0 | 0 | 0 |  |  | 0 | return 0 if ($s % 3) == 0 && Math::Prime::Util::powmod($a, $s/3, $n) == 1; | 
| 3611 | 0 | 0 | 0 |  |  | 0 | return 0 if ($s % 5) == 0 && Math::Prime::Util::powmod($a, $s/5, $n) == 1; | 
| 3612 | 0 |  |  |  |  | 0 | foreach my $f (Math::Prime::Util::factor_exp($s)) { | 
| 3613 | 0 |  |  |  |  | 0 | my $fp = $f->[0]; | 
| 3614 | 0 | 0 | 0 |  |  | 0 | return 0 if $fp > 5 && Math::Prime::Util::powmod($a, $s/$fp, $n) == 1; | 
| 3615 |  |  |  |  |  |  | } | 
| 3616 | 0 |  |  |  |  | 0 | 1; | 
| 3617 |  |  |  |  |  |  | } | 
| 3618 |  |  |  |  |  |  |  | 
| 3619 |  |  |  |  |  |  | sub znorder { | 
| 3620 | 10 |  |  | 10 | 0 | 1602 | my($a, $n) = @_; | 
| 3621 | 10 | 50 |  |  |  | 34 | return if $n <= 0; | 
| 3622 | 10 | 50 |  |  |  | 728 | return 1 if $n == 1; | 
| 3623 | 10 | 50 |  |  |  | 793 | return if $a <= 0; | 
| 3624 | 10 | 50 |  |  |  | 555 | return 1 if $a == 1; | 
| 3625 |  |  |  |  |  |  |  | 
| 3626 |  |  |  |  |  |  | return Math::Prime::Util::_reftyped($_[0], Math::Prime::Util::GMP::znorder($a,$n)) | 
| 3627 | 10 | 50 |  |  |  | 341 | if $Math::Prime::Util::_GMPfunc{"znorder"}; | 
| 3628 |  |  |  |  |  |  |  | 
| 3629 |  |  |  |  |  |  | # Sadly, Calc/FastCalc are horrendously slow for this function. | 
| 3630 | 10 | 100 |  |  |  | 99 | return if Math::Prime::Util::gcd($a, $n) > 1; | 
| 3631 |  |  |  |  |  |  |  | 
| 3632 |  |  |  |  |  |  | # The answer is one of the divisors of phi(n) and lambda(n). | 
| 3633 | 8 |  |  |  |  | 201 | my $lambda = Math::Prime::Util::carmichael_lambda($n); | 
| 3634 | 8 | 100 |  |  |  | 103 | $a = Math::BigInt->new("$a") unless ref($a) eq 'Math::BigInt'; | 
| 3635 |  |  |  |  |  |  |  | 
| 3636 |  |  |  |  |  |  | # This is easy and usually fast, but can bog down with too many divisors. | 
| 3637 | 8 | 100 |  |  |  | 362 | if ($lambda <= 2**64) { | 
| 3638 | 7 |  |  |  |  | 90 | foreach my $k (Math::Prime::Util::divisors($lambda)) { | 
| 3639 | 54 | 100 |  |  |  | 2074 | return $k if Math::Prime::Util::powmod($a,$k,$n) == 1; | 
| 3640 |  |  |  |  |  |  | } | 
| 3641 | 0 |  |  |  |  | 0 | return; | 
| 3642 |  |  |  |  |  |  | } | 
| 3643 |  |  |  |  |  |  |  | 
| 3644 |  |  |  |  |  |  | # Algorithm 1.7 from A. Das applied to Carmichael Lambda. | 
| 3645 | 1 | 50 |  |  |  | 341 | $lambda = Math::BigInt->new("$lambda") unless ref($lambda) eq 'Math::BigInt'; | 
| 3646 | 1 |  |  |  |  | 7 | my $k = Math::BigInt->bone; | 
| 3647 | 1 |  |  |  |  | 80 | foreach my $f (Math::Prime::Util::factor_exp($lambda)) { | 
| 3648 | 7 |  |  |  |  | 1104 | my($pi, $ei, $enum) = (Math::BigInt->new("$f->[0]"), $f->[1], 0); | 
| 3649 | 7 |  |  |  |  | 364 | my $phidiv = $lambda / ($pi**$ei); | 
| 3650 | 7 |  |  |  |  | 4150 | my $b = Math::Prime::Util::powmod($a,$phidiv,$n); | 
| 3651 | 7 |  |  |  |  | 39 | while ($b != 1) { | 
| 3652 | 10 | 50 |  |  |  | 1649 | return if $enum++ >= $ei; | 
| 3653 | 10 |  |  |  |  | 56 | $b = Math::Prime::Util::powmod($b,$pi,$n); | 
| 3654 | 10 |  |  |  |  | 342 | $k *= $pi; | 
| 3655 |  |  |  |  |  |  | } | 
| 3656 |  |  |  |  |  |  | } | 
| 3657 | 1 | 50 |  |  |  | 230 | $k = _bigint_to_int($k) if $k->bacmp(BMAX) <= 0; | 
| 3658 | 1 |  |  |  |  | 36 | return $k; | 
| 3659 |  |  |  |  |  |  | } | 
| 3660 |  |  |  |  |  |  |  | 
| 3661 |  |  |  |  |  |  | sub _dlp_trial { | 
| 3662 | 2 |  |  | 2 |  | 10 | my ($a,$g,$p,$limit) = @_; | 
| 3663 | 2 | 50 | 33 |  |  | 16 | $limit = $p if !defined $limit || $limit > $p; | 
| 3664 | 2 |  |  |  |  | 179 | my $t = $g->copy; | 
| 3665 |  |  |  |  |  |  |  | 
| 3666 | 2 | 50 |  |  |  | 57 | if ($limit < 1_000_000_000) { | 
| 3667 | 2 |  |  |  |  | 11 | for my $k (1 .. $limit) { | 
| 3668 | 213 | 100 |  |  |  | 15061 | return $k if $t == $a; | 
| 3669 | 212 |  |  |  |  | 21512 | $t = Math::Prime::Util::mulmod($t, $g, $p); | 
| 3670 |  |  |  |  |  |  | } | 
| 3671 | 1 |  |  |  |  | 91 | return 0; | 
| 3672 |  |  |  |  |  |  | } | 
| 3673 |  |  |  |  |  |  |  | 
| 3674 | 0 |  |  |  |  | 0 | for (my $k = BONE->copy; $k < $limit; $k->binc) { | 
| 3675 | 0 | 0 |  |  |  | 0 | if ($t == $a) { | 
| 3676 | 0 | 0 |  |  |  | 0 | $k = _bigint_to_int($k) if $k->bacmp(BMAX) <= 0; | 
| 3677 | 0 |  |  |  |  | 0 | return $k; | 
| 3678 |  |  |  |  |  |  | } | 
| 3679 | 0 |  |  |  |  | 0 | $t->bmul($g)->bmod($p); | 
| 3680 |  |  |  |  |  |  | } | 
| 3681 | 0 |  |  |  |  | 0 | 0; | 
| 3682 |  |  |  |  |  |  | } | 
| 3683 |  |  |  |  |  |  | sub _dlp_bsgs { | 
| 3684 | 1 |  |  | 1 |  | 4 | my ($a,$g,$p,$n,$_verbose) = @_; | 
| 3685 | 1 |  |  |  |  | 7 | my $invg = invmod($g, $p); | 
| 3686 | 1 | 50 |  |  |  | 4 | return unless defined $invg; | 
| 3687 | 1 |  |  |  |  | 6 | my $maxm = Math::Prime::Util::sqrtint($n)+1; | 
| 3688 | 1 |  |  |  |  | 61 | my $b = ($p + $maxm - 1) / $maxm; | 
| 3689 |  |  |  |  |  |  | # Limit for time and space. | 
| 3690 | 1 | 50 |  |  |  | 658 | $b = ($b > 4_000_000) ? 4_000_000 : int("$b"); | 
| 3691 | 1 | 50 |  |  |  | 143 | $maxm = ($maxm > $b) ? $b : int("$maxm"); | 
| 3692 |  |  |  |  |  |  |  | 
| 3693 | 1 |  |  |  |  | 4 | my %hash; | 
| 3694 | 1 |  |  |  |  | 4 | my $am = BONE->copy; | 
| 3695 | 1 |  |  |  |  | 28 | my $gm = Math::Prime::Util::powmod($invg, $maxm, $p); | 
| 3696 | 1 |  |  |  |  | 82 | my $key = $a->copy; | 
| 3697 | 1 |  |  |  |  | 24 | my $r; | 
| 3698 |  |  |  |  |  |  |  | 
| 3699 | 1 |  |  |  |  | 5 | foreach my $m (0 .. $b) { | 
| 3700 |  |  |  |  |  |  | # Baby Step | 
| 3701 | 87 | 50 |  |  |  | 3655 | if ($m <= $maxm) { | 
| 3702 | 87 |  |  |  |  | 146 | $r = $hash{"$am"}; | 
| 3703 | 87 | 50 |  |  |  | 202 | if (defined $r) { | 
| 3704 | 0 | 0 |  |  |  | 0 | print "  bsgs found in stage 1 after $m tries\n" if $_verbose; | 
| 3705 | 0 |  |  |  |  | 0 | $r = Math::Prime::Util::addmod($m, Math::Prime::Util::mulmod($r,$maxm,$p), $p); | 
| 3706 | 0 |  |  |  |  | 0 | return $r; | 
| 3707 |  |  |  |  |  |  | } | 
| 3708 | 87 |  |  |  |  | 276 | $hash{"$am"} = $m; | 
| 3709 | 87 |  |  |  |  | 234 | $am = Math::Prime::Util::mulmod($am,$g,$p); | 
| 3710 | 87 | 50 |  |  |  | 6275 | if ($am == $a) { | 
| 3711 | 0 | 0 |  |  |  | 0 | print "  bsgs found during bs\n" if $_verbose; | 
| 3712 | 0 |  |  |  |  | 0 | return $m+1; | 
| 3713 |  |  |  |  |  |  | } | 
| 3714 |  |  |  |  |  |  | } | 
| 3715 |  |  |  |  |  |  |  | 
| 3716 |  |  |  |  |  |  | # Giant Step | 
| 3717 | 87 |  |  |  |  | 9255 | $r = $hash{"$key"}; | 
| 3718 | 87 | 100 |  |  |  | 202 | if (defined $r) { | 
| 3719 | 1 | 50 |  |  |  | 5 | print "  bsgs found in stage 2 after $m tries\n" if $_verbose; | 
| 3720 | 1 |  |  |  |  | 5 | $r = Math::Prime::Util::addmod($r, Math::Prime::Util::mulmod($m,$maxm,$p), $p); | 
| 3721 | 1 |  |  |  |  | 100 | return $r; | 
| 3722 |  |  |  |  |  |  | } | 
| 3723 | 86 | 50 |  |  |  | 351 | $hash{"$key"} = $m if $m <= $maxm; | 
| 3724 | 86 |  |  |  |  | 305 | $key = Math::Prime::Util::mulmod($key,$gm,$p); | 
| 3725 |  |  |  |  |  |  | } | 
| 3726 | 0 |  |  |  |  | 0 | 0; | 
| 3727 |  |  |  |  |  |  | } | 
| 3728 |  |  |  |  |  |  |  | 
| 3729 |  |  |  |  |  |  | sub znlog { | 
| 3730 |  |  |  |  |  |  | my ($a,$g,$p) = | 
| 3731 | 2 | 100 |  | 2 | 0 | 156 | map { ref($_) eq 'Math::BigInt' ? $_ : Math::BigInt->new("$_") } @_; | 
|  | 6 |  |  |  |  | 109 |  | 
| 3732 | 2 |  |  |  |  | 47 | $a->bmod($p); | 
| 3733 | 2 |  |  |  |  | 281 | $g->bmod($p); | 
| 3734 | 2 | 50 | 33 |  |  | 322 | return 0 if $a == 1 || $g == 0 || $p < 2; | 
|  |  |  | 33 |  |  |  |  | 
| 3735 | 2 |  |  |  |  | 952 | my $_verbose = Math::Prime::Util::prime_get_config()->{'verbose'}; | 
| 3736 |  |  |  |  |  |  |  | 
| 3737 |  |  |  |  |  |  | # For large p, znorder can be very slow.  Do trial test first. | 
| 3738 | 2 |  |  |  |  | 12 | my $x = _dlp_trial($a, $g, $p, 200); | 
| 3739 | 2 | 100 |  |  |  | 56 | if ($x == 0) { | 
| 3740 | 1 |  |  |  |  | 5 | my $n = znorder($g, $p); | 
| 3741 | 1 | 50 | 33 |  |  | 104 | if (defined $n && $n > 1000) { | 
| 3742 | 1 | 50 |  |  |  | 10 | $n = Math::BigInt->new("$n") unless ref($n) eq 'Math::BigInt'; | 
| 3743 | 1 |  |  |  |  | 51 | $x = _dlp_bsgs($a, $g, $p, $n, $_verbose); | 
| 3744 | 1 | 50 | 33 |  |  | 8 | $x = _bigint_to_int($x) if ref($x) && $x->bacmp(BMAX) <= 0; | 
| 3745 | 1 | 50 | 33 |  |  | 18 | return $x if $x > 0 && $g->copy->bmodpow($x, $p) == $a; | 
| 3746 | 0 | 0 | 0 |  |  | 0 | print "  BSGS giving up\n" if $x == 0 && $_verbose; | 
| 3747 | 0 | 0 | 0 |  |  | 0 | print "  BSGS incorrect answer $x\n" if $x > 0 && $_verbose > 1; | 
| 3748 |  |  |  |  |  |  | } | 
| 3749 | 0 |  |  |  |  | 0 | $x = _dlp_trial($a,$g,$p); | 
| 3750 |  |  |  |  |  |  | } | 
| 3751 | 1 | 50 | 33 |  |  | 7 | $x = _bigint_to_int($x) if ref($x) && $x->bacmp(BMAX) <= 0; | 
| 3752 | 1 | 50 |  |  |  | 7 | return ($x == 0) ? undef : $x; | 
| 3753 |  |  |  |  |  |  | } | 
| 3754 |  |  |  |  |  |  |  | 
| 3755 |  |  |  |  |  |  | sub znprimroot { | 
| 3756 | 8 |  |  | 8 | 0 | 125 | my($n) = @_; | 
| 3757 | 8 | 100 |  |  |  | 22 | $n = -$n if $n < 0; | 
| 3758 | 8 | 100 |  |  |  | 203 | if ($n <= 4) { | 
| 3759 | 2 | 100 |  |  |  | 6 | return if $n == 0; | 
| 3760 | 1 |  |  |  |  | 4 | return $n-1; | 
| 3761 |  |  |  |  |  |  | } | 
| 3762 | 6 | 100 |  |  |  | 128 | return if $n % 4 == 0; | 
| 3763 | 5 |  |  |  |  | 354 | my $a = 1; | 
| 3764 | 5 |  |  |  |  | 10 | my $phi = $n-1; | 
| 3765 | 5 | 100 |  |  |  | 272 | if (!is_prob_prime($n)) { | 
| 3766 | 2 |  |  |  |  | 6 | $phi = euler_phi($n); | 
| 3767 |  |  |  |  |  |  | # Check that a primitive root exists. | 
| 3768 | 2 | 100 |  |  |  | 18 | return if $phi != Math::Prime::Util::carmichael_lambda($n); | 
| 3769 |  |  |  |  |  |  | } | 
| 3770 | 12 |  |  |  |  | 775 | my @exp = map { Math::BigInt->new("$_") } | 
| 3771 | 4 |  |  |  |  | 198 | map { int($phi/$_->[0]) } | 
|  | 12 |  |  |  |  | 816 |  | 
| 3772 |  |  |  |  |  |  | Math::Prime::Util::factor_exp($phi); | 
| 3773 |  |  |  |  |  |  | #print "phi: $phi  factors: ", join(",",factor($phi)), "\n"; | 
| 3774 |  |  |  |  |  |  | #print "  exponents: ", join(",", @exp), "\n"; | 
| 3775 | 4 |  |  |  |  | 184 | while (1) { | 
| 3776 | 97 |  |  |  |  | 136 | my $fail = 0; | 
| 3777 | 97 |  |  |  |  | 125 | do { $a++ } while Math::Prime::Util::kronecker($a,$n) == 0; | 
|  | 98 |  |  |  |  | 273 |  | 
| 3778 | 97 | 50 |  |  |  | 180 | return if $a >= $n; | 
| 3779 | 97 |  |  |  |  | 327 | foreach my $f (@exp) { | 
| 3780 | 137 | 100 |  |  |  | 2118 | if (Math::Prime::Util::powmod($a,$f,$n) == 1) { | 
| 3781 | 93 |  |  |  |  | 3744 | $fail = 1; | 
| 3782 | 93 |  |  |  |  | 136 | last; | 
| 3783 |  |  |  |  |  |  | } | 
| 3784 |  |  |  |  |  |  | } | 
| 3785 | 97 | 100 |  |  |  | 487 | return $a if !$fail; | 
| 3786 |  |  |  |  |  |  | } | 
| 3787 |  |  |  |  |  |  | } | 
| 3788 |  |  |  |  |  |  |  | 
| 3789 |  |  |  |  |  |  |  | 
| 3790 |  |  |  |  |  |  | # Find first D in sequence (5,-7,9,-11,13,-15,...) where (D|N) == -1 | 
| 3791 |  |  |  |  |  |  | sub _lucas_selfridge_params { | 
| 3792 | 11 |  |  | 11 |  | 22 | my($n) = @_; | 
| 3793 |  |  |  |  |  |  |  | 
| 3794 |  |  |  |  |  |  | # D is typically quite small: 67 max for N < 10^19.  However, it is | 
| 3795 |  |  |  |  |  |  | # theoretically possible D could grow unreasonably.  I'm giving up at 4000M. | 
| 3796 | 11 |  |  |  |  | 18 | my $d = 5; | 
| 3797 | 11 |  |  |  |  | 20 | my $sign = 1; | 
| 3798 | 11 |  |  |  |  | 18 | while (1) { | 
| 3799 | 32 | 100 |  |  |  | 88 | my $gcd = (ref($n) eq 'Math::BigInt') ? Math::BigInt::bgcd($d, $n) | 
| 3800 |  |  |  |  |  |  | : _gcd_ui($d, $n); | 
| 3801 | 32 | 50 | 33 |  |  | 1740 | return (0,0,0) if $gcd > 1 && $gcd != $n;  # Found divisor $d | 
| 3802 | 32 |  |  |  |  | 832 | my $j = kronecker($d * $sign, $n); | 
| 3803 | 32 | 100 |  |  |  | 68 | last if $j == -1; | 
| 3804 | 21 |  |  |  |  | 31 | $d += 2; | 
| 3805 | 21 | 50 |  |  |  | 42 | croak "Could not find Jacobi sequence for $n" if $d > 4_000_000_000; | 
| 3806 | 21 |  |  |  |  | 40 | $sign = -$sign; | 
| 3807 |  |  |  |  |  |  | } | 
| 3808 | 11 |  |  |  |  | 22 | my $D = $sign * $d; | 
| 3809 | 11 |  |  |  |  | 16 | my $P = 1; | 
| 3810 | 11 |  |  |  |  | 26 | my $Q = int( (1 - $D) / 4 ); | 
| 3811 | 11 |  |  |  |  | 32 | ($P, $Q, $D) | 
| 3812 |  |  |  |  |  |  | } | 
| 3813 |  |  |  |  |  |  |  | 
| 3814 |  |  |  |  |  |  | sub _lucas_extrastrong_params { | 
| 3815 | 198 |  |  | 198 |  | 619 | my($n, $increment) = @_; | 
| 3816 | 198 | 100 |  |  |  | 878 | $increment = 1 unless defined $increment; | 
| 3817 |  |  |  |  |  |  |  | 
| 3818 | 198 |  |  |  |  | 591 | my ($P, $Q, $D) = (3, 1, 5); | 
| 3819 | 198 |  |  |  |  | 431 | while (1) { | 
| 3820 | 360 | 100 |  |  |  | 1684 | my $gcd = (ref($n) eq 'Math::BigInt') ? Math::BigInt::bgcd($D, $n) | 
| 3821 |  |  |  |  |  |  | : _gcd_ui($D, $n); | 
| 3822 | 360 | 50 | 33 |  |  | 67567 | return (0,0,0) if $gcd > 1 && $gcd != $n;  # Found divisor $d | 
| 3823 | 360 | 100 |  |  |  | 30229 | last if kronecker($D, $n) == -1; | 
| 3824 | 162 |  |  |  |  | 353 | $P += $increment; | 
| 3825 | 162 | 50 |  |  |  | 405 | croak "Could not find Jacobi sequence for $n" if $P > 65535; | 
| 3826 | 162 |  |  |  |  | 418 | $D = $P*$P - 4; | 
| 3827 |  |  |  |  |  |  | } | 
| 3828 | 198 |  |  |  |  | 929 | ($P, $Q, $D); | 
| 3829 |  |  |  |  |  |  | } | 
| 3830 |  |  |  |  |  |  |  | 
| 3831 |  |  |  |  |  |  | # returns U_k, V_k, Q_k all mod n | 
| 3832 |  |  |  |  |  |  | sub lucas_sequence { | 
| 3833 | 156 |  |  | 156 | 0 | 743 | my($n, $P, $Q, $k) = @_; | 
| 3834 |  |  |  |  |  |  |  | 
| 3835 | 156 | 50 |  |  |  | 549 | croak "lucas_sequence: n must be >= 2" if $n < 2; | 
| 3836 | 156 | 50 |  |  |  | 16820 | croak "lucas_sequence: k must be >= 0" if $k < 0; | 
| 3837 | 156 | 50 |  |  |  | 23933 | croak "lucas_sequence: P out of range" if abs($P) >= $n; | 
| 3838 | 156 | 50 |  |  |  | 12257 | croak "lucas_sequence: Q out of range" if abs($Q) >= $n; | 
| 3839 |  |  |  |  |  |  |  | 
| 3840 | 156 | 50 | 33 |  |  | 10342 | if ($Math::Prime::Util::_GMPfunc{"lucas_sequence"} && $Math::Prime::Util::GMP::VERSION >= 0.30) { | 
| 3841 | 0 | 0 |  |  |  | 0 | return map { ($_ > ''.~0) ? Math::BigInt->new(''.$_) : $_ } | 
|  | 0 |  |  |  |  | 0 |  | 
| 3842 |  |  |  |  |  |  | Math::Prime::Util::GMP::lucas_sequence($n, $P, $Q, $k); | 
| 3843 |  |  |  |  |  |  | } | 
| 3844 |  |  |  |  |  |  |  | 
| 3845 | 156 | 100 |  |  |  | 658 | $n = Math::BigInt->new("$n") unless ref($n) eq 'Math::BigInt'; | 
| 3846 |  |  |  |  |  |  |  | 
| 3847 | 156 |  |  |  |  | 1083 | my $ZERO = $n->copy->bzero; | 
| 3848 | 156 | 100 |  |  |  | 7795 | $P = $ZERO+$P unless ref($P) eq 'Math::BigInt'; | 
| 3849 | 156 | 100 |  |  |  | 25274 | $Q = $ZERO+$Q unless ref($Q) eq 'Math::BigInt'; | 
| 3850 | 156 |  |  |  |  | 22504 | my $D = $P*$P - BTWO*BTWO*$Q; | 
| 3851 | 156 | 50 |  |  |  | 45740 | if ($D->is_zero) { | 
| 3852 | 0 |  |  |  |  | 0 | my $S = ($ZERO+$P) >> 1; | 
| 3853 | 0 |  |  |  |  | 0 | my $U = $S->copy->bmodpow($k-1,$n)->bmul($k)->bmod($n); | 
| 3854 | 0 |  |  |  |  | 0 | my $V = $S->copy->bmodpow($k,$n)->bmul(BTWO)->bmod($n); | 
| 3855 | 0 |  |  |  |  | 0 | my $Qk = ($ZERO+$Q)->bmodpow($k, $n); | 
| 3856 | 0 |  |  |  |  | 0 | return ($U, $V, $Qk); | 
| 3857 |  |  |  |  |  |  | } | 
| 3858 | 156 |  |  |  |  | 2357 | my $U = BONE->copy; | 
| 3859 | 156 |  |  |  |  | 3694 | my $V = $P->copy; | 
| 3860 | 156 |  |  |  |  | 3230 | my $Qk = $Q->copy; | 
| 3861 |  |  |  |  |  |  |  | 
| 3862 | 156 | 50 |  |  |  | 3298 | return (BZERO->copy, BTWO->copy, $Qk) if $k == 0; | 
| 3863 | 156 | 100 |  |  |  | 24849 | $k = Math::BigInt->new("$k") unless ref($k) eq 'Math::BigInt'; | 
| 3864 | 156 |  |  |  |  | 1153 | my $kstr = substr($k->as_bin, 2); | 
| 3865 | 156 |  |  |  |  | 51796 | my $bpos = 0; | 
| 3866 |  |  |  |  |  |  |  | 
| 3867 | 156 | 50 |  |  |  | 531 | if (($n % 2)==0) { | 
|  |  | 100 |  |  |  |  |  | 
| 3868 | 0 |  |  |  |  | 0 | $P->bmod($n); | 
| 3869 | 0 |  |  |  |  | 0 | $Q->bmod($n); | 
| 3870 | 0 |  |  |  |  | 0 | my($Uh,$Vl, $Vh, $Ql, $Qh) = (BONE->copy, BTWO->copy, $P->copy, BONE->copy, BONE->copy); | 
| 3871 | 0 |  |  |  |  | 0 | my ($b,$s) = (length($kstr)-1, 0); | 
| 3872 | 0 | 0 |  |  |  | 0 | if ($kstr =~ /(0+)$/) { $s = length($1); } | 
|  | 0 |  |  |  |  | 0 |  | 
| 3873 | 0 |  |  |  |  | 0 | for my $bpos (0 .. $b-$s-1) { | 
| 3874 | 0 |  |  |  |  | 0 | $Ql->bmul($Qh)->bmod($n); | 
| 3875 | 0 | 0 |  |  |  | 0 | if (substr($kstr,$bpos,1)) { | 
| 3876 | 0 |  |  |  |  | 0 | $Qh = $Ql * $Q; | 
| 3877 | 0 |  |  |  |  | 0 | $Uh->bmul($Vh)->bmod($n); | 
| 3878 | 0 |  |  |  |  | 0 | $Vl->bmul($Vh)->bsub($P * $Ql)->bmod($n); | 
| 3879 | 0 |  |  |  |  | 0 | $Vh->bmul($Vh)->bsub(BTWO * $Qh)->bmod($n); | 
| 3880 |  |  |  |  |  |  | } else { | 
| 3881 | 0 |  |  |  |  | 0 | $Qh = $Ql->copy; | 
| 3882 | 0 |  |  |  |  | 0 | $Uh->bmul($Vl)->bsub($Ql)->bmod($n); | 
| 3883 | 0 |  |  |  |  | 0 | $Vh->bmul($Vl)->bsub($P * $Ql)->bmod($n); | 
| 3884 | 0 |  |  |  |  | 0 | $Vl->bmul($Vl)->bsub(BTWO * $Ql)->bmod($n); | 
| 3885 |  |  |  |  |  |  | } | 
| 3886 |  |  |  |  |  |  | } | 
| 3887 | 0 |  |  |  |  | 0 | $Ql->bmul($Qh); | 
| 3888 | 0 |  |  |  |  | 0 | $Qh = $Ql * $Q; | 
| 3889 | 0 |  |  |  |  | 0 | $Uh->bmul($Vl)->bsub($Ql)->bmod($n); | 
| 3890 | 0 |  |  |  |  | 0 | $Vl->bmul($Vh)->bsub($P * $Ql)->bmod($n); | 
| 3891 | 0 |  |  |  |  | 0 | $Ql->bmul($Qh)->bmod($n); | 
| 3892 | 0 |  |  |  |  | 0 | for (1 .. $s) { | 
| 3893 | 0 |  |  |  |  | 0 | $Uh->bmul($Vl)->bmod($n); | 
| 3894 | 0 |  |  |  |  | 0 | $Vl->bmul($Vl)->bsub(BTWO * $Ql)->bmod($n); | 
| 3895 | 0 |  |  |  |  | 0 | $Ql->bmul($Ql)->bmod($n); | 
| 3896 |  |  |  |  |  |  | } | 
| 3897 | 0 |  |  |  |  | 0 | ($U, $V, $Qk) = ($Uh, $Vl, $Ql); | 
| 3898 |  |  |  |  |  |  | } elsif ($Q->is_one) { | 
| 3899 | 142 |  |  |  |  | 51250 | my $Dinverse = $D->copy->bmodinv($n); | 
| 3900 | 142 | 50 | 33 |  |  | 82927 | if ($P > BTWO && !$Dinverse->is_nan) { | 
| 3901 |  |  |  |  |  |  | # Calculate V_k with U=V_{k+1} | 
| 3902 | 142 |  |  |  |  | 6510 | $U = $P->copy->bmul($P)->bsub(BTWO)->bmod($n); | 
| 3903 | 142 |  |  |  |  | 38363 | while (++$bpos < length($kstr)) { | 
| 3904 | 11913 | 100 |  |  |  | 20264283 | if (substr($kstr,$bpos,1)) { | 
| 3905 | 5892 |  |  |  |  | 15971 | $V->bmul($U)->bsub($P  )->bmod($n); | 
| 3906 | 5892 |  |  |  |  | 10226855 | $U->bmul($U)->bsub(BTWO)->bmod($n); | 
| 3907 |  |  |  |  |  |  | } else { | 
| 3908 | 6021 |  |  |  |  | 15821 | $U->bmul($V)->bsub($P  )->bmod($n); | 
| 3909 | 6021 |  |  |  |  | 9913670 | $V->bmul($V)->bsub(BTWO)->bmod($n); | 
| 3910 |  |  |  |  |  |  | } | 
| 3911 |  |  |  |  |  |  | } | 
| 3912 |  |  |  |  |  |  | # Crandall and Pomerance eq 3.13: U_n = D^-1 (2V_{n+1} - PV_n) | 
| 3913 | 142 |  |  |  |  | 80786 | $U = $Dinverse * (BTWO*$U - $P*$V); | 
| 3914 |  |  |  |  |  |  | } else { | 
| 3915 | 0 |  |  |  |  | 0 | while (++$bpos < length($kstr)) { | 
| 3916 | 0 |  |  |  |  | 0 | $U->bmul($V)->bmod($n); | 
| 3917 | 0 |  |  |  |  | 0 | $V->bmul($V)->bsub(BTWO)->bmod($n); | 
| 3918 | 0 | 0 |  |  |  | 0 | if (substr($kstr,$bpos,1)) { | 
| 3919 | 0 |  |  |  |  | 0 | my $T1 = $U->copy->bmul($D); | 
| 3920 | 0 |  |  |  |  | 0 | $U->bmul($P)->badd( $V); | 
| 3921 | 0 | 0 |  |  |  | 0 | $U->badd($n) if $U->is_odd; | 
| 3922 | 0 |  |  |  |  | 0 | $U->brsft(BONE); | 
| 3923 | 0 |  |  |  |  | 0 | $V->bmul($P)->badd($T1); | 
| 3924 | 0 | 0 |  |  |  | 0 | $V->badd($n) if $V->is_odd; | 
| 3925 | 0 |  |  |  |  | 0 | $V->brsft(BONE); | 
| 3926 |  |  |  |  |  |  | } | 
| 3927 |  |  |  |  |  |  | } | 
| 3928 |  |  |  |  |  |  | } | 
| 3929 |  |  |  |  |  |  | } else { | 
| 3930 | 14 | 100 |  |  |  | 5063 | my $qsign = ($Q == -1) ? -1 : 0; | 
| 3931 | 14 |  |  |  |  | 1398 | while (++$bpos < length($kstr)) { | 
| 3932 | 427 |  |  |  |  | 139126 | $U->bmul($V)->bmod($n); | 
| 3933 | 427 | 100 |  |  |  | 134922 | if    ($qsign ==  1) { $V->bmul($V)->bsub(BTWO)->bmod($n); } | 
|  | 19 | 100 |  |  |  | 41 |  | 
| 3934 | 20 |  |  |  |  | 77 | elsif ($qsign == -1) { $V->bmul($V)->badd(BTWO)->bmod($n); } | 
| 3935 | 388 |  |  |  |  | 891 | else { $V->bmul($V)->bsub($Qk->copy->blsft(BONE))->bmod($n); } | 
| 3936 | 427 | 100 |  |  |  | 226178 | if (substr($kstr,$bpos,1)) { | 
| 3937 | 197 |  |  |  |  | 522 | my $T1 = $U->copy->bmul($D); | 
| 3938 | 197 |  |  |  |  | 16110 | $U->bmul($P)->badd( $V); | 
| 3939 | 197 | 100 |  |  |  | 23572 | $U->badd($n) if $U->is_odd; | 
| 3940 | 197 |  |  |  |  | 8464 | $U->brsft(BONE); | 
| 3941 |  |  |  |  |  |  |  | 
| 3942 | 197 |  |  |  |  | 20541 | $V->bmul($P)->badd($T1); | 
| 3943 | 197 | 100 |  |  |  | 26899 | $V->badd($n) if $V->is_odd; | 
| 3944 | 197 |  |  |  |  | 6618 | $V->brsft(BONE); | 
| 3945 |  |  |  |  |  |  |  | 
| 3946 | 197 | 100 |  |  |  | 25761 | if ($qsign != 0) { $qsign = -1; } | 
|  | 19 |  |  |  |  | 64 |  | 
| 3947 | 178 |  |  |  |  | 492 | else             { $Qk->bmul($Qk)->bmul($Q)->bmod($n); } | 
| 3948 |  |  |  |  |  |  | } else { | 
| 3949 | 230 | 100 |  |  |  | 495 | if ($qsign != 0) { $qsign = 1; } | 
|  | 20 |  |  |  |  | 50 |  | 
| 3950 | 210 |  |  |  |  | 498 | else             { $Qk->bmul($Qk)->bmod($n); } | 
| 3951 |  |  |  |  |  |  | } | 
| 3952 |  |  |  |  |  |  | } | 
| 3953 | 14 | 100 |  |  |  | 3213 | if    ($qsign ==  1) { $Qk->bneg; } | 
|  | 1 | 100 |  |  |  | 7 |  | 
| 3954 | 2 |  |  |  |  | 8 | elsif ($qsign == -1) { $Qk = $n->copy->bdec; } | 
| 3955 |  |  |  |  |  |  | } | 
| 3956 | 156 |  |  |  |  | 77502 | $U->bmod($n); | 
| 3957 | 156 |  |  |  |  | 45895 | $V->bmod($n); | 
| 3958 | 156 |  |  |  |  | 18886 | return ($U, $V, $Qk); | 
| 3959 |  |  |  |  |  |  | } | 
| 3960 |  |  |  |  |  |  | sub _lucasuv { | 
| 3961 | 0 |  |  | 0 |  | 0 | my($P, $Q, $k) = @_; | 
| 3962 |  |  |  |  |  |  |  | 
| 3963 | 0 | 0 |  |  |  | 0 | croak "lucas_sequence: k must be >= 0" if $k < 0; | 
| 3964 | 0 | 0 |  |  |  | 0 | return (0,2) if $k == 0; | 
| 3965 |  |  |  |  |  |  |  | 
| 3966 | 0 | 0 |  |  |  | 0 | $P = Math::BigInt->new("$P") unless ref($P) eq 'Math::BigInt'; | 
| 3967 | 0 | 0 |  |  |  | 0 | $Q = Math::BigInt->new("$Q") unless ref($Q) eq 'Math::BigInt'; | 
| 3968 |  |  |  |  |  |  |  | 
| 3969 |  |  |  |  |  |  | # Simple way, very slow as k increases: | 
| 3970 |  |  |  |  |  |  | #my($U0, $U1) = (BZERO->copy, BONE->copy); | 
| 3971 |  |  |  |  |  |  | #my($V0, $V1) = (BTWO->copy, Math::BigInt->new("$P")); | 
| 3972 |  |  |  |  |  |  | #for (2 .. $k) { | 
| 3973 |  |  |  |  |  |  | #  ($U0,$U1) = ($U1, $P*$U1 - $Q*$U0); | 
| 3974 |  |  |  |  |  |  | #  ($V0,$V1) = ($V1, $P*$V1 - $Q*$V0); | 
| 3975 |  |  |  |  |  |  | #} | 
| 3976 |  |  |  |  |  |  | #return ($U1, $V1); | 
| 3977 |  |  |  |  |  |  |  | 
| 3978 | 0 |  |  |  |  | 0 | my($Uh,$Vl, $Vh, $Ql, $Qh) = (BONE->copy, BTWO->copy, $P->copy, BONE->copy, BONE->copy); | 
| 3979 | 0 | 0 |  |  |  | 0 | $k = Math::BigInt->new("$k") unless ref($k) eq 'Math::BigInt'; | 
| 3980 | 0 |  |  |  |  | 0 | my $kstr = substr($k->as_bin, 2); | 
| 3981 | 0 |  |  |  |  | 0 | my ($n,$s) = (length($kstr)-1, 0); | 
| 3982 | 0 | 0 |  |  |  | 0 | if ($kstr =~ /(0+)$/) { $s = length($1); } | 
|  | 0 |  |  |  |  | 0 |  | 
| 3983 |  |  |  |  |  |  |  | 
| 3984 | 0 | 0 |  |  |  | 0 | if ($Q == -1) { | 
| 3985 |  |  |  |  |  |  | # This could be simplified, and it's running 10x slower than it should. | 
| 3986 | 0 |  |  |  |  | 0 | my ($ql,$qh) = (1,1); | 
| 3987 | 0 |  |  |  |  | 0 | for my $bpos (0 .. $n-$s-1) { | 
| 3988 | 0 |  |  |  |  | 0 | $ql *= $qh; | 
| 3989 | 0 | 0 |  |  |  | 0 | if (substr($kstr,$bpos,1)) { | 
| 3990 | 0 |  |  |  |  | 0 | $qh = -$ql; | 
| 3991 | 0 |  |  |  |  | 0 | $Uh->bmul($Vh); | 
| 3992 | 0 | 0 |  |  |  | 0 | if ($ql == 1) { | 
| 3993 | 0 |  |  |  |  | 0 | $Vl->bmul($Vh)->bsub( $P ); | 
| 3994 | 0 |  |  |  |  | 0 | $Vh->bmul($Vh)->badd( BTWO ); | 
| 3995 |  |  |  |  |  |  | } else { | 
| 3996 | 0 |  |  |  |  | 0 | $Vl->bmul($Vh)->badd( $P ); | 
| 3997 | 0 |  |  |  |  | 0 | $Vh->bmul($Vh)->bsub( BTWO ); | 
| 3998 |  |  |  |  |  |  | } | 
| 3999 |  |  |  |  |  |  | } else { | 
| 4000 | 0 |  |  |  |  | 0 | $qh = $ql; | 
| 4001 | 0 | 0 |  |  |  | 0 | if ($ql == 1) { | 
| 4002 | 0 |  |  |  |  | 0 | $Uh->bmul($Vl)->bdec; | 
| 4003 | 0 |  |  |  |  | 0 | $Vh->bmul($Vl)->bsub($P); | 
| 4004 | 0 |  |  |  |  | 0 | $Vl->bmul($Vl)->bsub(BTWO); | 
| 4005 |  |  |  |  |  |  | } else { | 
| 4006 | 0 |  |  |  |  | 0 | $Uh->bmul($Vl)->binc; | 
| 4007 | 0 |  |  |  |  | 0 | $Vh->bmul($Vl)->badd($P); | 
| 4008 | 0 |  |  |  |  | 0 | $Vl->bmul($Vl)->badd(BTWO); | 
| 4009 |  |  |  |  |  |  | } | 
| 4010 |  |  |  |  |  |  | } | 
| 4011 |  |  |  |  |  |  | } | 
| 4012 | 0 |  |  |  |  | 0 | $ql *= $qh; | 
| 4013 | 0 |  |  |  |  | 0 | $qh = -$ql; | 
| 4014 | 0 | 0 |  |  |  | 0 | if ($ql == 1) { | 
| 4015 | 0 |  |  |  |  | 0 | $Uh->bmul($Vl)->bdec; | 
| 4016 | 0 |  |  |  |  | 0 | $Vl->bmul($Vh)->bsub($P); | 
| 4017 |  |  |  |  |  |  | } else { | 
| 4018 | 0 |  |  |  |  | 0 | $Uh->bmul($Vl)->binc; | 
| 4019 | 0 |  |  |  |  | 0 | $Vl->bmul($Vh)->badd($P); | 
| 4020 |  |  |  |  |  |  | } | 
| 4021 | 0 |  |  |  |  | 0 | $ql *= $qh; | 
| 4022 | 0 |  |  |  |  | 0 | for (1 .. $s) { | 
| 4023 | 0 |  |  |  |  | 0 | $Uh->bmul($Vl); | 
| 4024 | 0 | 0 |  |  |  | 0 | if ($ql == 1) { $Vl->bmul($Vl)->bsub(BTWO); $ql *= $ql; } | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 4025 | 0 |  |  |  |  | 0 | else          { $Vl->bmul($Vl)->badd(BTWO); $ql *= $ql; } | 
|  | 0 |  |  |  |  | 0 |  | 
| 4026 |  |  |  |  |  |  | } | 
| 4027 | 0 | 0 |  |  |  | 0 | return map { ($_ > ''.~0) ? Math::BigInt->new(''.$_) : $_ } ($Uh, $Vl); | 
|  | 0 |  |  |  |  | 0 |  | 
| 4028 |  |  |  |  |  |  | } | 
| 4029 |  |  |  |  |  |  |  | 
| 4030 | 0 |  |  |  |  | 0 | for my $bpos (0 .. $n-$s-1) { | 
| 4031 | 0 |  |  |  |  | 0 | $Ql->bmul($Qh); | 
| 4032 | 0 | 0 |  |  |  | 0 | if (substr($kstr,$bpos,1)) { | 
| 4033 | 0 |  |  |  |  | 0 | $Qh = $Ql * $Q; | 
| 4034 |  |  |  |  |  |  | #$Uh = $Uh * $Vh; | 
| 4035 |  |  |  |  |  |  | #$Vl = $Vh * $Vl - $P * $Ql; | 
| 4036 |  |  |  |  |  |  | #$Vh = $Vh * $Vh - BTWO * $Qh; | 
| 4037 | 0 |  |  |  |  | 0 | $Uh->bmul($Vh); | 
| 4038 | 0 |  |  |  |  | 0 | $Vl->bmul($Vh)->bsub($P * $Ql); | 
| 4039 | 0 |  |  |  |  | 0 | $Vh->bmul($Vh)->bsub(BTWO * $Qh); | 
| 4040 |  |  |  |  |  |  | } else { | 
| 4041 | 0 |  |  |  |  | 0 | $Qh = $Ql->copy; | 
| 4042 |  |  |  |  |  |  | #$Uh = $Uh * $Vl - $Ql; | 
| 4043 |  |  |  |  |  |  | #$Vh = $Vh * $Vl - $P * $Ql; | 
| 4044 |  |  |  |  |  |  | #$Vl = $Vl * $Vl - BTWO * $Ql; | 
| 4045 | 0 |  |  |  |  | 0 | $Uh->bmul($Vl)->bsub($Ql); | 
| 4046 | 0 |  |  |  |  | 0 | $Vh->bmul($Vl)->bsub($P * $Ql); | 
| 4047 | 0 |  |  |  |  | 0 | $Vl->bmul($Vl)->bsub(BTWO * $Ql); | 
| 4048 |  |  |  |  |  |  | } | 
| 4049 |  |  |  |  |  |  | } | 
| 4050 | 0 |  |  |  |  | 0 | $Ql->bmul($Qh); | 
| 4051 | 0 |  |  |  |  | 0 | $Qh = $Ql * $Q; | 
| 4052 | 0 |  |  |  |  | 0 | $Uh->bmul($Vl)->bsub($Ql); | 
| 4053 | 0 |  |  |  |  | 0 | $Vl->bmul($Vh)->bsub($P * $Ql); | 
| 4054 | 0 |  |  |  |  | 0 | $Ql->bmul($Qh); | 
| 4055 | 0 |  |  |  |  | 0 | for (1 .. $s) { | 
| 4056 | 0 |  |  |  |  | 0 | $Uh->bmul($Vl); | 
| 4057 | 0 |  |  |  |  | 0 | $Vl->bmul($Vl)->bsub(BTWO * $Ql); | 
| 4058 | 0 |  |  |  |  | 0 | $Ql->bmul($Ql); | 
| 4059 |  |  |  |  |  |  | } | 
| 4060 | 0 | 0 |  |  |  | 0 | return map { ($_ > ''.~0) ? Math::BigInt->new(''.$_) : $_ } ($Uh, $Vl, $Ql); | 
|  | 0 |  |  |  |  | 0 |  | 
| 4061 |  |  |  |  |  |  | } | 
| 4062 | 0 |  |  | 0 | 0 | 0 | sub lucasu { (_lucasuv(@_))[0] } | 
| 4063 | 0 |  |  | 0 | 0 | 0 | sub lucasv { (_lucasuv(@_))[1] } | 
| 4064 |  |  |  |  |  |  |  | 
| 4065 |  |  |  |  |  |  | sub is_lucas_pseudoprime { | 
| 4066 | 5 |  |  | 5 | 0 | 1665 | my($n) = @_; | 
| 4067 |  |  |  |  |  |  |  | 
| 4068 | 5 | 50 |  |  |  | 22 | return 0+($n >= 2) if $n < 4; | 
| 4069 | 5 | 50 | 33 |  |  | 50 | return 0 if ($n % 2) == 0 || _is_perfect_square($n); | 
| 4070 |  |  |  |  |  |  |  | 
| 4071 | 5 |  |  |  |  | 13 | my ($P, $Q, $D) = _lucas_selfridge_params($n); | 
| 4072 | 5 | 50 |  |  |  | 13 | return 0 if $D == 0;  # We found a divisor in the sequence | 
| 4073 | 5 | 50 |  |  |  | 14 | die "Lucas parameter error: $D, $P, $Q\n" if ($D != $P*$P - 4*$Q); | 
| 4074 |  |  |  |  |  |  |  | 
| 4075 | 5 |  |  |  |  | 15 | my($U, $V, $Qk) = lucas_sequence($n, $P, $Q, $n+1); | 
| 4076 | 5 | 50 |  |  |  | 21 | return ($U == 0) ? 1 : 0; | 
| 4077 |  |  |  |  |  |  | } | 
| 4078 |  |  |  |  |  |  |  | 
| 4079 |  |  |  |  |  |  | sub is_strong_lucas_pseudoprime { | 
| 4080 | 6 |  |  | 6 | 0 | 999 | my($n) = @_; | 
| 4081 |  |  |  |  |  |  |  | 
| 4082 | 6 | 50 |  |  |  | 23 | return 0+($n >= 2) if $n < 4; | 
| 4083 | 6 | 50 | 33 |  |  | 158 | return 0 if ($n % 2) == 0 || _is_perfect_square($n); | 
| 4084 |  |  |  |  |  |  |  | 
| 4085 | 6 |  |  |  |  | 23 | my ($P, $Q, $D) = _lucas_selfridge_params($n); | 
| 4086 | 6 | 50 |  |  |  | 16 | return 0 if $D == 0;  # We found a divisor in the sequence | 
| 4087 | 6 | 50 |  |  |  | 17 | die "Lucas parameter error: $D, $P, $Q\n" if ($D != $P*$P - 4*$Q); | 
| 4088 |  |  |  |  |  |  |  | 
| 4089 | 6 |  |  |  |  | 14 | my $m = $n+1; | 
| 4090 | 6 |  |  |  |  | 185 | my($s, $k) = (0, $m); | 
| 4091 | 6 |  | 66 |  |  | 26 | while ( $k > 0 && !($k % 2) ) { | 
| 4092 | 19 |  |  |  |  | 975 | $s++; | 
| 4093 | 19 |  |  |  |  | 55 | $k >>= 1; | 
| 4094 |  |  |  |  |  |  | } | 
| 4095 | 6 |  |  |  |  | 599 | my($U, $V, $Qk) = lucas_sequence($n, $P, $Q, $k); | 
| 4096 |  |  |  |  |  |  |  | 
| 4097 | 6 | 100 |  |  |  | 24 | return 1 if $U == 0; | 
| 4098 | 4 | 50 |  |  |  | 835 | $V = Math::BigInt->new("$V") unless ref($V) eq 'Math::BigInt'; | 
| 4099 | 4 | 50 |  |  |  | 16 | $Qk = Math::BigInt->new("$Qk") unless ref($Qk) eq 'Math::BigInt'; | 
| 4100 | 4 |  |  |  |  | 15 | foreach my $r (0 .. $s-1) { | 
| 4101 | 11 | 100 |  |  |  | 1590 | return 1 if $V->is_zero; | 
| 4102 | 8 | 100 |  |  |  | 112 | if ($r < ($s-1)) { | 
| 4103 | 7 |  |  |  |  | 21 | $V->bmul($V)->bsub(BTWO*$Qk)->bmod($n); | 
| 4104 | 7 |  |  |  |  | 3210 | $Qk->bmul($Qk)->bmod($n); | 
| 4105 |  |  |  |  |  |  | } | 
| 4106 |  |  |  |  |  |  | } | 
| 4107 | 1 |  |  |  |  | 15 | return 0; | 
| 4108 |  |  |  |  |  |  | } | 
| 4109 |  |  |  |  |  |  |  | 
| 4110 |  |  |  |  |  |  | sub is_extra_strong_lucas_pseudoprime { | 
| 4111 | 142 |  |  | 142 | 0 | 2940 | my($n) = @_; | 
| 4112 |  |  |  |  |  |  |  | 
| 4113 | 142 | 50 |  |  |  | 647 | return 0+($n >= 2) if $n < 4; | 
| 4114 | 142 | 50 | 33 |  |  | 21468 | return 0 if ($n % 2) == 0 || _is_perfect_square($n); | 
| 4115 |  |  |  |  |  |  |  | 
| 4116 | 142 |  |  |  |  | 864 | my ($P, $Q, $D) = _lucas_extrastrong_params($n); | 
| 4117 | 142 | 50 |  |  |  | 575 | return 0 if $D == 0;  # We found a divisor in the sequence | 
| 4118 | 142 | 50 |  |  |  | 579 | die "Lucas parameter error: $D, $P, $Q\n" if ($D != $P*$P - 4*$Q); | 
| 4119 |  |  |  |  |  |  |  | 
| 4120 |  |  |  |  |  |  | # We have to convert n to a bigint or Math::BigInt::GMP's stupid set_si bug | 
| 4121 |  |  |  |  |  |  | # (RT 71548) will hit us and make the test $V == $n-2 always return false. | 
| 4122 | 142 | 100 |  |  |  | 632 | $n = Math::BigInt->new("$n") unless ref($n) eq 'Math::BigInt'; | 
| 4123 |  |  |  |  |  |  |  | 
| 4124 | 142 |  |  |  |  | 841 | my($s, $k) = (0, $n->copy->binc); | 
| 4125 | 142 |  | 66 |  |  | 10643 | while ($k->is_even && !$k->is_zero) { | 
| 4126 | 2772 |  |  |  |  | 366968 | $s++; | 
| 4127 | 2772 |  |  |  |  | 5779 | $k->brsft(BONE); | 
| 4128 |  |  |  |  |  |  | } | 
| 4129 |  |  |  |  |  |  |  | 
| 4130 | 142 |  |  |  |  | 17789 | my($U, $V, $Qk) = lucas_sequence($n, $P, $Q, $k); | 
| 4131 |  |  |  |  |  |  |  | 
| 4132 | 142 | 50 |  |  |  | 718 | $V = Math::BigInt->new("$V") unless ref($V) eq 'Math::BigInt'; | 
| 4133 | 142 | 50 | 66 |  |  | 661 | return 1 if $U == 0 && ($V == BTWO || $V == ($n - BTWO)); | 
|  |  |  | 100 |  |  |  |  | 
| 4134 | 74 |  |  |  |  | 18462 | foreach my $r (0 .. $s-2) { | 
| 4135 | 2628 | 100 |  |  |  | 8271756 | return 1 if $V->is_zero; | 
| 4136 | 2570 |  |  |  |  | 35173 | $V->bmul($V)->bsub(BTWO)->bmod($n); | 
| 4137 |  |  |  |  |  |  | } | 
| 4138 | 16 |  |  |  |  | 144 | return 0; | 
| 4139 |  |  |  |  |  |  | } | 
| 4140 |  |  |  |  |  |  |  | 
| 4141 |  |  |  |  |  |  | sub is_almost_extra_strong_lucas_pseudoprime { | 
| 4142 | 56 |  |  | 56 | 0 | 2284 | my($n, $increment) = @_; | 
| 4143 | 56 | 100 |  |  |  | 182 | $increment = 1 unless defined $increment; | 
| 4144 |  |  |  |  |  |  |  | 
| 4145 | 56 | 50 |  |  |  | 215 | return 0+($n >= 2) if $n < 4; | 
| 4146 | 56 | 50 | 33 |  |  | 347 | return 0 if ($n % 2) == 0 || _is_perfect_square($n); | 
| 4147 |  |  |  |  |  |  |  | 
| 4148 | 56 |  |  |  |  | 271 | my ($P, $Q, $D) = _lucas_extrastrong_params($n, $increment); | 
| 4149 | 56 | 50 |  |  |  | 148 | return 0 if $D == 0;  # We found a divisor in the sequence | 
| 4150 | 56 | 50 |  |  |  | 218 | die "Lucas parameter error: $D, $P, $Q\n" if ($D != $P*$P - 4*$Q); | 
| 4151 |  |  |  |  |  |  |  | 
| 4152 | 56 | 50 |  |  |  | 617 | $n = Math::BigInt->new("$n") unless ref($n) eq 'Math::BigInt'; | 
| 4153 |  |  |  |  |  |  |  | 
| 4154 | 56 |  |  |  |  | 5010 | my $ZERO = $n->copy->bzero; | 
| 4155 | 56 |  |  |  |  | 3048 | my $TWO = $ZERO->copy->binc->binc; | 
| 4156 | 56 |  |  |  |  | 6207 | my $V = $ZERO + $P;           # V_{k} | 
| 4157 | 56 |  |  |  |  | 10093 | my $W = $ZERO + $P*$P-$TWO;   # V_{k+1} | 
| 4158 | 56 |  |  |  |  | 16454 | my $kstr = substr($n->copy->binc()->as_bin, 2); | 
| 4159 | 56 |  |  |  |  | 14076 | $kstr =~ s/(0*)$//; | 
| 4160 | 56 |  |  |  |  | 210 | my $s = length($1); | 
| 4161 | 56 |  |  |  |  | 130 | my $bpos = 0; | 
| 4162 | 56 |  |  |  |  | 230 | while (++$bpos < length($kstr)) { | 
| 4163 | 2468 | 100 |  |  |  | 985992 | if (substr($kstr,$bpos,1)) { | 
| 4164 | 1240 |  |  |  |  | 3142 | $V->bmul($W)->bsub($P  )->bmod($n); | 
| 4165 | 1240 |  |  |  |  | 596823 | $W->bmul($W)->bsub($TWO)->bmod($n); | 
| 4166 |  |  |  |  |  |  | } else { | 
| 4167 | 1228 |  |  |  |  | 3119 | $W->bmul($V)->bsub($P  )->bmod($n); | 
| 4168 | 1228 |  |  |  |  | 592465 | $V->bmul($V)->bsub($TWO)->bmod($n); | 
| 4169 |  |  |  |  |  |  | } | 
| 4170 |  |  |  |  |  |  | } | 
| 4171 |  |  |  |  |  |  |  | 
| 4172 | 56 | 100 | 100 |  |  | 22757 | return 1 if $V == 2 || $V == ($n-$TWO); | 
| 4173 | 36 |  |  |  |  | 10937 | foreach my $r (0 .. $s-2) { | 
| 4174 | 39 | 100 |  |  |  | 1106 | return 1 if $V->is_zero; | 
| 4175 | 36 |  |  |  |  | 618 | $V->bmul($V)->bsub($TWO)->bmod($n); | 
| 4176 |  |  |  |  |  |  | } | 
| 4177 | 33 |  |  |  |  | 14821 | return 0; | 
| 4178 |  |  |  |  |  |  | } | 
| 4179 |  |  |  |  |  |  |  | 
| 4180 |  |  |  |  |  |  | sub is_frobenius_khashin_pseudoprime { | 
| 4181 | 0 |  |  | 0 | 0 | 0 | my($n) = @_; | 
| 4182 | 0 | 0 |  |  |  | 0 | return 0+($n >= 2) if $n < 4; | 
| 4183 | 0 | 0 |  |  |  | 0 | return 0 unless $n % 2; | 
| 4184 | 0 | 0 |  |  |  | 0 | return 0 if _is_perfect_square($n); | 
| 4185 |  |  |  |  |  |  |  | 
| 4186 | 0 | 0 |  |  |  | 0 | $n = Math::BigInt->new("$n") unless ref($n) eq 'Math::BigInt'; | 
| 4187 |  |  |  |  |  |  |  | 
| 4188 | 0 |  |  |  |  | 0 | my($k,$c) = (2,1); | 
| 4189 | 0 | 0 |  |  |  | 0 | if    ($n % 4 == 3) { $c = $n-1; } | 
|  | 0 | 0 |  |  |  | 0 |  | 
| 4190 | 0 |  |  |  |  | 0 | elsif ($n % 8 == 5) { $c = 2; } | 
| 4191 |  |  |  |  |  |  | else { | 
| 4192 | 0 |  |  |  |  | 0 | do { | 
| 4193 | 0 |  |  |  |  | 0 | $c += 2; | 
| 4194 | 0 |  |  |  |  | 0 | $k = kronecker($c, $n); | 
| 4195 |  |  |  |  |  |  | } while $k == 1; | 
| 4196 |  |  |  |  |  |  | } | 
| 4197 | 0 | 0 | 0 |  |  | 0 | return 0 if $k == 0 || ($k == 2 && !($n % 3));; | 
|  |  |  | 0 |  |  |  |  | 
| 4198 |  |  |  |  |  |  |  | 
| 4199 | 0 | 0 |  |  |  | 0 | my $ea = ($k == 2) ? 2 : 1; | 
| 4200 | 0 |  |  |  |  | 0 | my($ra,$rb,$a,$b,$d) = ($ea,1,$ea,1,$n-1); | 
| 4201 | 0 |  |  |  |  | 0 | while (!$d->is_zero) { | 
| 4202 | 0 | 0 |  |  |  | 0 | if ($d->is_odd()) { | 
| 4203 | 0 |  |  |  |  | 0 | ($ra, $rb) = ( (($ra*$a)%$n + ((($rb*$b)%$n)*$c)%$n) % $n, | 
| 4204 |  |  |  |  |  |  | (($rb*$a)%$n + ($ra*$b)%$n) % $n ); | 
| 4205 |  |  |  |  |  |  | } | 
| 4206 | 0 |  |  |  |  | 0 | $d >>= 1; | 
| 4207 | 0 | 0 |  |  |  | 0 | if (!$d->is_zero) { | 
| 4208 | 0 |  |  |  |  | 0 | ($a, $b) = ( (($a*$a)%$n + ((($b*$b)%$n)*$c)%$n) % $n, | 
| 4209 |  |  |  |  |  |  | (($b*$a)%$n + ($a*$b)%$n) % $n ); | 
| 4210 |  |  |  |  |  |  | } | 
| 4211 |  |  |  |  |  |  | } | 
| 4212 | 0 | 0 | 0 |  |  | 0 | return ($ra == $ea && $rb == $n-1) ? 1 : 0; | 
| 4213 |  |  |  |  |  |  | } | 
| 4214 |  |  |  |  |  |  |  | 
| 4215 |  |  |  |  |  |  | sub is_frobenius_underwood_pseudoprime { | 
| 4216 | 1 |  |  | 1 | 0 | 4 | my($n) = @_; | 
| 4217 | 1 | 50 |  |  |  | 5 | return 0+($n >= 2) if $n < 4; | 
| 4218 | 1 | 50 |  |  |  | 135 | return 0 unless $n % 2; | 
| 4219 |  |  |  |  |  |  |  | 
| 4220 | 1 |  |  |  |  | 246 | my($a, $temp1, $temp2); | 
| 4221 | 1 | 50 |  |  |  | 4 | if ($n % 4 == 3) { | 
| 4222 | 1 |  |  |  |  | 288 | $a = 0; | 
| 4223 |  |  |  |  |  |  | } else { | 
| 4224 | 0 |  |  |  |  | 0 | for ($a = 1; $a < 1000000; $a++) { | 
| 4225 | 0 | 0 | 0 |  |  | 0 | next if $a==2 || $a==4 || $a==7 || $a==8 || $a==10 || $a==14 || $a==16 || $a==18; | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
| 4226 | 0 |  |  |  |  | 0 | my $j = kronecker($a*$a - 4, $n); | 
| 4227 | 0 | 0 |  |  |  | 0 | last if $j == -1; | 
| 4228 | 0 | 0 | 0 |  |  | 0 | return 0 if $j == 0 || ($a == 20 && _is_perfect_square($n)); | 
|  |  |  | 0 |  |  |  |  | 
| 4229 |  |  |  |  |  |  | } | 
| 4230 |  |  |  |  |  |  | } | 
| 4231 | 1 |  |  |  |  | 16 | $temp1 = Math::Prime::Util::gcd(($a+4)*(2*$a+5), $n); | 
| 4232 | 1 | 50 | 33 |  |  | 7 | return 0 if $temp1 != 1 && $temp1 != $n; | 
| 4233 |  |  |  |  |  |  |  | 
| 4234 | 1 | 50 |  |  |  | 4 | $n = Math::BigInt->new("$n") unless ref($n) eq 'Math::BigInt'; | 
| 4235 | 1 |  |  |  |  | 4 | my $ZERO = $n->copy->bzero; | 
| 4236 | 1 |  |  |  |  | 58 | my $ONE = $ZERO->copy->binc; | 
| 4237 | 1 |  |  |  |  | 80 | my $TWO = $ONE->copy->binc; | 
| 4238 | 1 |  |  |  |  | 61 | my($s, $t) = ($ONE->copy, $TWO->copy); | 
| 4239 |  |  |  |  |  |  |  | 
| 4240 | 1 |  |  |  |  | 39 | my $ap2 = $TWO + $a; | 
| 4241 | 1 |  |  |  |  | 268 | my $np1string = substr( $n->copy->binc->as_bin, 2); | 
| 4242 | 1 |  |  |  |  | 480 | my $np1len = length($np1string); | 
| 4243 |  |  |  |  |  |  |  | 
| 4244 | 1 |  |  |  |  | 4 | foreach my $bit (1 .. $np1len-1) { | 
| 4245 | 107 |  |  |  |  | 276 | $temp2 = $t+$t; | 
| 4246 | 107 | 50 |  |  |  | 9214 | $temp2 += ($s * $a)  if $a != 0; | 
| 4247 | 107 |  |  |  |  | 260 | $temp1 = $temp2 * $s; | 
| 4248 | 107 |  |  |  |  | 18567 | $temp2 = $t - $s; | 
| 4249 | 107 |  |  |  |  | 14514 | $s += $t; | 
| 4250 | 107 |  |  |  |  | 7431 | $t = ($s * $temp2) % $n; | 
| 4251 | 107 |  |  |  |  | 55123 | $s = $temp1 % $n; | 
| 4252 | 107 | 100 |  |  |  | 35063 | if ( substr( $np1string, $bit, 1 ) ) { | 
| 4253 | 51 | 50 |  |  |  | 121 | if ($a == 0)  { $temp1 = $s + $s; } | 
|  | 51 |  |  |  |  | 129 |  | 
| 4254 | 0 |  |  |  |  | 0 | else          { $temp1 = $s * $ap2; } | 
| 4255 | 51 |  |  |  |  | 4833 | $temp1 += $t; | 
| 4256 | 51 |  |  |  |  | 3275 | $t->badd($t)->bsub($s);   # $t = ($t+$t) - $s; | 
| 4257 | 51 |  |  |  |  | 9092 | $s = $temp1; | 
| 4258 |  |  |  |  |  |  | } | 
| 4259 |  |  |  |  |  |  | } | 
| 4260 | 1 |  |  |  |  | 11 | $temp1 = (2*$a+5) % $n; | 
| 4261 | 1 | 50 | 33 |  |  | 192 | return ($s == 0 && $t == $temp1) ? 1 : 0; | 
| 4262 |  |  |  |  |  |  | } | 
| 4263 |  |  |  |  |  |  |  | 
| 4264 |  |  |  |  |  |  | sub _perrin_signature { | 
| 4265 | 2 |  |  | 2 |  | 7 | my($n) = @_; | 
| 4266 | 2 |  |  |  |  | 9 | my @S = (1,$n-1,3, 3,0,2); | 
| 4267 | 2 | 50 |  |  |  | 526 | return @S if $n <= 1; | 
| 4268 |  |  |  |  |  |  |  | 
| 4269 | 2 |  |  |  |  | 244 | my @nbin = todigits($n,2); | 
| 4270 | 2 |  |  |  |  | 13 | shift @nbin; | 
| 4271 |  |  |  |  |  |  |  | 
| 4272 | 2 |  |  |  |  | 11 | while (@nbin) { | 
| 4273 | 1254 |  |  |  |  | 5918 | my @T = map { addmod(addmod(Math::Prime::Util::mulmod($S[$_],$S[$_],$n), $n-$S[5-$_],$n), $n-$S[5-$_],$n); } 0..5; | 
|  | 7524 |  |  |  |  | 58724 |  | 
| 4274 | 1254 |  |  |  |  | 9483 | my $T01 = addmod($T[2], $n-$T[1], $n); | 
| 4275 | 1254 |  |  |  |  | 13290 | my $T34 = addmod($T[5], $n-$T[4], $n); | 
| 4276 | 1254 |  |  |  |  | 12461 | my $T45 = addmod($T34, $T[3], $n); | 
| 4277 | 1254 | 100 |  |  |  | 12942 | if (shift @nbin) { | 
| 4278 | 645 |  |  |  |  | 31101 | @S = ($T[0], $T01, $T[1], $T[4], $T45, $T[5]); | 
| 4279 |  |  |  |  |  |  | } else { | 
| 4280 | 609 |  |  |  |  | 2945 | @S = ($T01, $T[1], addmod($T01,$T[0],$n), $T34, $T[4], $T45); | 
| 4281 |  |  |  |  |  |  | } | 
| 4282 |  |  |  |  |  |  | } | 
| 4283 | 2 |  |  |  |  | 16 | @S; | 
| 4284 |  |  |  |  |  |  | } | 
| 4285 |  |  |  |  |  |  |  | 
| 4286 |  |  |  |  |  |  | sub is_perrin_pseudoprime { | 
| 4287 | 2 |  |  | 2 | 0 | 5148 | my($n, $restrict) = @_; | 
| 4288 | 2 | 50 |  |  |  | 12 | $restrict = 0 unless defined $restrict; | 
| 4289 | 2 | 50 |  |  |  | 14 | return 0+($n >= 2) if $n < 4; | 
| 4290 | 2 | 50 | 33 |  |  | 12 | return 0 if $restrict > 2 && ($n % 2) == 0; | 
| 4291 |  |  |  |  |  |  |  | 
| 4292 | 2 | 50 |  |  |  | 18 | $n = Math::BigInt->new("$n") unless ref($n) eq 'Math::BigInt'; | 
| 4293 |  |  |  |  |  |  |  | 
| 4294 | 2 |  |  |  |  | 209 | my @S = _perrin_signature($n); | 
| 4295 | 2 | 50 |  |  |  | 11 | return 0 unless $S[4] == 0; | 
| 4296 | 2 | 50 |  |  |  | 197 | return 1 if $restrict == 0; | 
| 4297 | 0 | 0 |  |  |  | 0 | return 0 unless $S[1] == $n-1; | 
| 4298 | 0 | 0 |  |  |  | 0 | return 1 if $restrict == 1; | 
| 4299 | 0 |  |  |  |  | 0 | my $j = kronecker(-23,$n); | 
| 4300 | 0 | 0 |  |  |  | 0 | if ($j == -1) { | 
| 4301 | 0 |  |  |  |  | 0 | my $B = $S[2]; | 
| 4302 | 0 |  |  |  |  | 0 | my $B2 = mulmod($B,$B,$n); | 
| 4303 | 0 |  |  |  |  | 0 | my $A = addmod(addmod(1,mulmod(3,$B,$n),$n),$n-$B2,$n); | 
| 4304 | 0 |  |  |  |  | 0 | my $C = addmod(mulmod(3,$B2,$n),$n-2,$n); | 
| 4305 | 0 | 0 | 0 |  |  | 0 | return 1 if $S[0] == $A && $S[2] == $B && $S[3] == $B && $S[5] == $C && $B != 3 && addmod(mulmod($B2,$B,$n),$n-$B,$n) == 1; | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
| 4306 |  |  |  |  |  |  | } else { | 
| 4307 | 0 | 0 | 0 |  |  | 0 | return 0 if $j == 0 && $n != 23 && $restrict > 2; | 
|  |  |  | 0 |  |  |  |  | 
| 4308 | 0 | 0 | 0 |  |  | 0 | return 1 if $S[0] == 1 && $S[2] == 3 && $S[3] == 3 && $S[5] == 2; | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
| 4309 | 0 | 0 | 0 |  |  | 0 | return 1 if $S[0] == 0 && $S[5] == $n-1 && $S[2] != $S[3] && addmod($S[2],$S[3],$n) == $n-3 && mulmod(addmod($S[2],$n-$S[3],$n),addmod($S[2],$n-$S[3],$n),$n) == $n-(23%$n); | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
| 4310 |  |  |  |  |  |  | } | 
| 4311 | 0 |  |  |  |  | 0 | 0; | 
| 4312 |  |  |  |  |  |  | } | 
| 4313 |  |  |  |  |  |  |  | 
| 4314 |  |  |  |  |  |  | sub is_catalan_pseudoprime { | 
| 4315 | 0 |  |  | 0 | 0 | 0 | my($n) = @_; | 
| 4316 | 0 | 0 |  |  |  | 0 | return 0+($n >= 2) if $n < 4; | 
| 4317 | 0 |  |  |  |  | 0 | my $m = ($n-1)>>1; | 
| 4318 | 0 | 0 |  |  |  | 0 | return (binomial($m<<1,$m) % $n) == (($m&1) ? $n-1 : 1) ? 1 : 0; | 
|  |  | 0 |  |  |  |  |  | 
| 4319 |  |  |  |  |  |  | } | 
| 4320 |  |  |  |  |  |  |  | 
| 4321 |  |  |  |  |  |  | sub is_frobenius_pseudoprime { | 
| 4322 | 1 |  |  | 1 | 0 | 3 | my($n, $P, $Q) = @_; | 
| 4323 | 1 | 50 | 33 |  |  | 7 | ($P,$Q) = (0,0) unless defined $P && defined $Q; | 
| 4324 | 1 | 50 |  |  |  | 5 | return 0+($n >= 2) if $n < 4; | 
| 4325 |  |  |  |  |  |  |  | 
| 4326 | 1 | 50 |  |  |  | 9 | $n = Math::BigInt->new("$n") unless ref($n) eq 'Math::BigInt'; | 
| 4327 | 1 | 50 |  |  |  | 48 | return 0 if $n->is_even; | 
| 4328 |  |  |  |  |  |  |  | 
| 4329 | 1 |  |  |  |  | 20 | my($k, $Vcomp, $D, $Du) = (0, 4); | 
| 4330 | 1 | 50 | 33 |  |  | 6 | if ($P == 0 && $Q == 0) { | 
| 4331 | 1 |  |  |  |  | 2 | ($P,$Q) = (-1,2); | 
| 4332 | 1 |  |  |  |  | 4 | while ($k != -1) { | 
| 4333 | 1 |  |  |  |  | 3 | $P += 2; | 
| 4334 | 1 | 50 |  |  |  | 3 | $P = 5 if $P == 3;  # Skip 3 | 
| 4335 | 1 |  |  |  |  | 3 | $D = $P*$P-4*$Q; | 
| 4336 | 1 | 50 |  |  |  | 5 | $Du = ($D >= 0) ? $D : -$D; | 
| 4337 | 1 | 50 | 33 |  |  | 4 | last if $P >= $n || $Du >= $n;   # TODO: remove? | 
| 4338 | 1 |  |  |  |  | 142 | $k = kronecker($D, $n); | 
| 4339 | 1 | 50 |  |  |  | 5 | return 0 if $k == 0; | 
| 4340 | 1 | 50 | 33 |  |  | 8 | return 0 if $P == 10001 && _is_perfect_square($n); | 
| 4341 |  |  |  |  |  |  | } | 
| 4342 |  |  |  |  |  |  | } else { | 
| 4343 | 0 |  |  |  |  | 0 | $D = $P*$P-4*$Q; | 
| 4344 | 0 | 0 |  |  |  | 0 | $Du = ($D >= 0) ? $D : -$D; | 
| 4345 | 0 | 0 |  |  |  | 0 | croak "Frobenius invalid P,Q: ($P,$Q)" if _is_perfect_square($Du); | 
| 4346 |  |  |  |  |  |  | } | 
| 4347 | 1 | 0 | 33 |  |  | 3 | return (is_prime($n) ? 1 : 0) if $n <= $Du || $n <= abs($Q) || $n <= abs($P); | 
|  |  | 50 | 33 |  |  |  |  | 
| 4348 | 1 | 50 |  |  |  | 338 | return 0 if Math::Prime::Util::gcd(abs($P*$Q*$D), $n) > 1; | 
| 4349 |  |  |  |  |  |  |  | 
| 4350 | 1 | 50 |  |  |  | 59 | if ($k == 0) { | 
| 4351 | 0 |  |  |  |  | 0 | $k = kronecker($D, $n); | 
| 4352 | 0 | 0 |  |  |  | 0 | return 0 if $k == 0; | 
| 4353 | 0 |  |  |  |  | 0 | my $Q2 = (2*abs($Q)) % $n; | 
| 4354 | 0 | 0 |  |  |  | 0 | $Vcomp = ($k == 1) ? 2 : ($Q >= 0) ? $Q2 : $n-$Q2; | 
|  |  | 0 |  |  |  |  |  | 
| 4355 |  |  |  |  |  |  | } | 
| 4356 |  |  |  |  |  |  |  | 
| 4357 | 1 |  |  |  |  | 7 | my($U, $V, $Qk) = lucas_sequence($n, $P, $Q, $n-$k); | 
| 4358 | 1 | 50 | 33 |  |  | 6 | return 1 if $U == 0 && $V == $Vcomp; | 
| 4359 | 1 |  |  |  |  | 270 | 0; | 
| 4360 |  |  |  |  |  |  | } | 
| 4361 |  |  |  |  |  |  |  | 
| 4362 |  |  |  |  |  |  | # Since people have graciously donated millions of CPU years to doing these | 
| 4363 |  |  |  |  |  |  | # tests, it would be rude of us not to use the results.  This means we don't | 
| 4364 |  |  |  |  |  |  | # actually use the pretest and Lucas-Lehmer test coded below for any reasonable | 
| 4365 |  |  |  |  |  |  | # size number. | 
| 4366 |  |  |  |  |  |  | # See: http://www.mersenne.org/report_milestones/ | 
| 4367 |  |  |  |  |  |  | my %_mersenne_primes; | 
| 4368 |  |  |  |  |  |  | undef @_mersenne_primes{2,3,5,7,13,17,19,31,61,89,107,127,521,607,1279,2203,2281,3217,4253,4423,9689,9941,11213,19937,21701,23209,44497,86243,110503,132049,216091,756839,859433,1257787,1398269,2976221,3021377,6972593,13466917,20996011,24036583,25964951,30402457,32582657,37156667,42643801,43112609,57885161,74207281}; | 
| 4369 |  |  |  |  |  |  |  | 
| 4370 |  |  |  |  |  |  | sub is_mersenne_prime { | 
| 4371 | 0 |  |  | 0 | 0 | 0 | my $p = shift; | 
| 4372 |  |  |  |  |  |  |  | 
| 4373 |  |  |  |  |  |  | # Use the known Mersenne primes | 
| 4374 | 0 | 0 |  |  |  | 0 | return 1 if exists $_mersenne_primes{$p}; | 
| 4375 | 0 | 0 |  |  |  | 0 | return 0 if $p < 34007399; # GIMPS has checked all below | 
| 4376 |  |  |  |  |  |  | # Past this we do a generic Mersenne prime test | 
| 4377 |  |  |  |  |  |  |  | 
| 4378 | 0 | 0 |  |  |  | 0 | return 1 if $p == 2; | 
| 4379 | 0 | 0 |  |  |  | 0 | return 0 unless is_prob_prime($p); | 
| 4380 | 0 | 0 | 0 |  |  | 0 | return 0 if $p > 3 && $p % 4 == 3 && $p < ((~0)>>1) && is_prob_prime($p*2+1); | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
| 4381 | 0 |  |  |  |  | 0 | my $mp = BONE->copy->blsft($p)->bdec; | 
| 4382 |  |  |  |  |  |  |  | 
| 4383 |  |  |  |  |  |  | # Definitely faster than using Math::BigInt that doesn't have GMP. | 
| 4384 |  |  |  |  |  |  | return (0 == (Math::Prime::Util::GMP::lucas_sequence($mp, 4, 1, $mp+1))[0]) | 
| 4385 | 0 | 0 |  |  |  | 0 | if $Math::Prime::Util::_GMPfunc{"lucas_sequence"}; | 
| 4386 |  |  |  |  |  |  |  | 
| 4387 | 0 |  |  |  |  | 0 | my $V = Math::BigInt->new(4); | 
| 4388 | 0 |  |  |  |  | 0 | for my $k (3 .. $p) { | 
| 4389 | 0 |  |  |  |  | 0 | $V->bmul($V)->bsub(BTWO)->bmod($mp); | 
| 4390 |  |  |  |  |  |  | } | 
| 4391 | 0 |  |  |  |  | 0 | return $V->is_zero; | 
| 4392 |  |  |  |  |  |  | } | 
| 4393 |  |  |  |  |  |  |  | 
| 4394 |  |  |  |  |  |  |  | 
| 4395 |  |  |  |  |  |  | my $_poly_bignum; | 
| 4396 |  |  |  |  |  |  | sub _poly_new { | 
| 4397 | 206 |  |  | 206 |  | 562 | my @poly = @_; | 
| 4398 | 206 | 50 |  |  |  | 529 | push @poly, 0 unless scalar @poly; | 
| 4399 | 206 | 50 |  |  |  | 516 | if ($_poly_bignum) { | 
| 4400 | 0 | 0 |  |  |  | 0 | @poly = map { (ref $_ eq 'Math::BigInt') | 
|  | 0 |  |  |  |  | 0 |  | 
| 4401 |  |  |  |  |  |  | ?  $_->copy | 
| 4402 |  |  |  |  |  |  | :  Math::BigInt->new("$_"); } @poly; | 
| 4403 |  |  |  |  |  |  | } | 
| 4404 | 206 |  |  |  |  | 521 | return \@poly; | 
| 4405 |  |  |  |  |  |  | } | 
| 4406 |  |  |  |  |  |  |  | 
| 4407 |  |  |  |  |  |  | #sub _poly_print { | 
| 4408 |  |  |  |  |  |  | #  my($poly) = @_; | 
| 4409 |  |  |  |  |  |  | #  carp "poly has null top degree" if $#$poly > 0 && !$poly->[-1]; | 
| 4410 |  |  |  |  |  |  | #  foreach my $d (reverse 1 .. $#$poly) { | 
| 4411 |  |  |  |  |  |  | #    my $coef = $poly->[$d]; | 
| 4412 |  |  |  |  |  |  | #    print "", ($coef != 1) ? $coef : "", ($d > 1) ? "x^$d" : "x", " + " | 
| 4413 |  |  |  |  |  |  | #      if $coef; | 
| 4414 |  |  |  |  |  |  | #  } | 
| 4415 |  |  |  |  |  |  | #  my $p0 = $poly->[0] || 0; | 
| 4416 |  |  |  |  |  |  | #  print "$p0\n"; | 
| 4417 |  |  |  |  |  |  | #} | 
| 4418 |  |  |  |  |  |  |  | 
| 4419 |  |  |  |  |  |  | sub _poly_mod_mul { | 
| 4420 | 1654 |  |  | 1654 |  | 3730 | my($px, $py, $r, $n) = @_; | 
| 4421 |  |  |  |  |  |  |  | 
| 4422 | 1654 |  |  |  |  | 3005 | my $px_degree = $#$px; | 
| 4423 | 1654 |  |  |  |  | 2570 | my $py_degree = $#$py; | 
| 4424 | 1654 | 50 |  |  |  | 6224 | my @res = map { $_poly_bignum ? Math::BigInt->bzero : 0 } 0 .. $r-1; | 
|  | 180410 |  |  |  |  | 266589 |  | 
| 4425 |  |  |  |  |  |  |  | 
| 4426 |  |  |  |  |  |  | # convolve(px, py) mod (X^r-1,n) | 
| 4427 | 1654 |  |  |  |  | 7175 | my @indices_y = grep { $py->[$_] } (0 .. $py_degree); | 
|  | 83490 |  |  |  |  | 107651 |  | 
| 4428 | 1654 |  |  |  |  | 5429 | foreach my $ix (0 .. $px_degree) { | 
| 4429 | 78553 |  |  |  |  | 104461 | my $px_at_ix = $px->[$ix]; | 
| 4430 | 78553 | 100 |  |  |  | 124878 | next unless $px_at_ix; | 
| 4431 | 78516 | 50 |  |  |  | 112927 | if ($_poly_bignum) { | 
| 4432 | 0 |  |  |  |  | 0 | foreach my $iy (@indices_y) { | 
| 4433 | 0 |  |  |  |  | 0 | my $rindex = ($ix + $iy) % $r;  # reduce mod X^r-1 | 
| 4434 | 0 |  |  |  |  | 0 | $res[$rindex]->badd($px_at_ix->copy->bmul($py->[$iy]))->bmod($n); | 
| 4435 |  |  |  |  |  |  | } | 
| 4436 |  |  |  |  |  |  | } else { | 
| 4437 | 78516 |  |  |  |  | 104167 | foreach my $iy (@indices_y) { | 
| 4438 | 7543424 |  |  |  |  | 10045123 | my $rindex = ($ix + $iy) % $r;  # reduce mod X^r-1 | 
| 4439 | 7543424 |  |  |  |  | 11452477 | $res[$rindex] = ($res[$rindex] + $px_at_ix * $py->[$iy]) % $n; | 
| 4440 |  |  |  |  |  |  | } | 
| 4441 |  |  |  |  |  |  | } | 
| 4442 |  |  |  |  |  |  | } | 
| 4443 |  |  |  |  |  |  | # In case we had upper terms go to zero after modulo, reduce the degree. | 
| 4444 | 1654 |  |  |  |  | 37048 | pop @res while !$res[-1]; | 
| 4445 | 1654 |  |  |  |  | 9270 | return \@res; | 
| 4446 |  |  |  |  |  |  | } | 
| 4447 |  |  |  |  |  |  |  | 
| 4448 |  |  |  |  |  |  | sub _poly_mod_pow { | 
| 4449 | 103 |  |  | 103 |  | 387 | my($pn, $power, $r, $mod) = @_; | 
| 4450 | 103 |  |  |  |  | 338 | my $res = _poly_new(1); | 
| 4451 | 103 |  |  |  |  | 696 | my $p = $power; | 
| 4452 |  |  |  |  |  |  |  | 
| 4453 | 103 |  |  |  |  | 264 | while ($p) { | 
| 4454 | 1037 | 100 |  |  |  | 3298 | $res = _poly_mod_mul($res, $pn, $r, $mod) if ($p & 1); | 
| 4455 | 1037 |  |  |  |  | 1961 | $p >>= 1; | 
| 4456 | 1037 | 100 |  |  |  | 3247 | $pn  = _poly_mod_mul($pn,  $pn, $r, $mod) if $p; | 
| 4457 |  |  |  |  |  |  | } | 
| 4458 | 103 |  |  |  |  | 509 | return $res; | 
| 4459 |  |  |  |  |  |  | } | 
| 4460 |  |  |  |  |  |  |  | 
| 4461 |  |  |  |  |  |  | sub _test_anr { | 
| 4462 | 103 |  |  | 103 |  | 371 | my($a, $n, $r) = @_; | 
| 4463 | 103 |  |  |  |  | 479 | my $pp = _poly_mod_pow(_poly_new($a, 1), $n, $r, $n); | 
| 4464 | 103 |  | 50 |  |  | 729 | $pp->[$n % $r] = (($pp->[$n % $r] || 0) -  1) % $n;  # subtract X^(n%r) | 
| 4465 | 103 |  | 50 |  |  | 442 | $pp->[      0] = (($pp->[      0] || 0) - $a) % $n;  # subtract a | 
| 4466 | 103 | 100 |  |  |  | 393 | return 0 if scalar grep { $_ } @$pp; | 
|  | 5057 |  |  |  |  | 6721 |  | 
| 4467 | 102 |  |  |  |  | 549 | 1; | 
| 4468 |  |  |  |  |  |  | } | 
| 4469 |  |  |  |  |  |  |  | 
| 4470 |  |  |  |  |  |  | sub is_aks_prime { | 
| 4471 | 10 |  |  | 10 | 0 | 1384 | my $n = shift; | 
| 4472 | 10 | 100 | 100 |  |  | 56 | return 0 if $n < 2 || is_power($n); | 
| 4473 |  |  |  |  |  |  |  | 
| 4474 | 7 |  |  |  |  | 16 | my($log2n, $limit); | 
| 4475 | 7 | 50 |  |  |  | 21 | if ($n > 2**48) { | 
| 4476 | 0 | 0 |  |  |  | 0 | do { require Math::BigFloat; Math::BigFloat->import(); } | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 4477 |  |  |  |  |  |  | if !defined $Math::BigFloat::VERSION; | 
| 4478 |  |  |  |  |  |  | # limit = floor( log2(n) * log2(n) ).  o_r(n) must be larger than this | 
| 4479 | 0 |  |  |  |  | 0 | my $floatn = Math::BigFloat->new("$n"); | 
| 4480 |  |  |  |  |  |  | #my $sqrtn = _bigint_to_int($floatn->copy->bsqrt->bfloor); | 
| 4481 |  |  |  |  |  |  | # The following line seems to trigger a memory leak in Math::BigFloat::blog | 
| 4482 |  |  |  |  |  |  | # (the part where $MBI is copied to $int) if $n is a Math::BigInt::GMP. | 
| 4483 | 0 |  |  |  |  | 0 | $log2n = $floatn->copy->blog(2); | 
| 4484 | 0 |  |  |  |  | 0 | $limit = _bigint_to_int( ($log2n * $log2n)->bfloor ); | 
| 4485 |  |  |  |  |  |  | } else { | 
| 4486 | 7 |  |  |  |  | 34 | $log2n = log($n)/log(2) + 0.0001;      # Error on large side. | 
| 4487 | 7 |  |  |  |  | 16 | $limit = int( $log2n*$log2n + 0.0001 ); | 
| 4488 |  |  |  |  |  |  | } | 
| 4489 |  |  |  |  |  |  |  | 
| 4490 | 7 |  |  |  |  | 22 | my $r = next_prime($limit); | 
| 4491 | 7 |  |  |  |  | 15 | foreach my $f (@{primes(0,$r-1)}) { | 
|  | 7 |  |  |  |  | 25 |  | 
| 4492 | 147 | 50 |  |  |  | 253 | return 1 if $f == $n; | 
| 4493 | 147 | 100 |  |  |  | 278 | return 0 if !($n % $f); | 
| 4494 |  |  |  |  |  |  | } | 
| 4495 |  |  |  |  |  |  |  | 
| 4496 | 6 |  |  |  |  | 33 | while ($r < $n) { | 
| 4497 | 5 | 100 |  |  |  | 19 | return 0 if !($n % $r); | 
| 4498 |  |  |  |  |  |  | #return 1 if $r >= $sqrtn; | 
| 4499 | 4 | 100 |  |  |  | 18 | last if znorder($n, $r) > $limit;  # Note the arguments! | 
| 4500 | 2 |  |  |  |  | 92 | $r = next_prime($r); | 
| 4501 |  |  |  |  |  |  | } | 
| 4502 |  |  |  |  |  |  |  | 
| 4503 | 5 | 100 |  |  |  | 108 | return 1 if $r >= $n; | 
| 4504 |  |  |  |  |  |  |  | 
| 4505 |  |  |  |  |  |  | # Since r is a prime, phi(r) = r-1 | 
| 4506 | 2 | 50 |  |  |  | 19 | my $rlimit = (ref($log2n) eq 'Math::BigFloat') | 
| 4507 |  |  |  |  |  |  | ? _bigint_to_int( Math::BigFloat->new("$r")->bdec() | 
| 4508 |  |  |  |  |  |  | ->bsqrt->bmul($log2n)->bfloor) | 
| 4509 |  |  |  |  |  |  | : int( (sqrt(($r-1)) * $log2n) + 0.001 ); | 
| 4510 |  |  |  |  |  |  |  | 
| 4511 | 2 |  |  |  |  | 7 | $_poly_bignum = 1; | 
| 4512 | 2 | 50 |  |  |  | 9 | if ( $n < (MPU_HALFWORD-1) ) { | 
| 4513 | 2 |  |  |  |  | 5 | $_poly_bignum = 0; | 
| 4514 |  |  |  |  |  |  | #$n = _bigint_to_int($n) if ref($n) eq 'Math::BigInt'; | 
| 4515 |  |  |  |  |  |  | } else { | 
| 4516 | 0 | 0 |  |  |  | 0 | $n = Math::BigInt->new("$n") unless ref($n) eq 'Math::BigInt'; | 
| 4517 |  |  |  |  |  |  | } | 
| 4518 |  |  |  |  |  |  |  | 
| 4519 | 2 |  |  |  |  | 17 | my $_verbose = Math::Prime::Util::prime_get_config()->{'verbose'}; | 
| 4520 | 2 | 50 |  |  |  | 11 | print "# aks r = $r  s = $rlimit\n" if $_verbose; | 
| 4521 | 2 | 50 |  |  |  | 9 | local $| = 1 if $_verbose > 1; | 
| 4522 | 2 |  |  |  |  | 9 | for (my $a = 1; $a <= $rlimit; $a++) { | 
| 4523 | 103 | 100 |  |  |  | 501 | return 0 unless _test_anr($a, $n, $r); | 
| 4524 | 102 | 50 |  |  |  | 615 | print "." if $_verbose > 1; | 
| 4525 |  |  |  |  |  |  | } | 
| 4526 | 1 | 50 |  |  |  | 8 | print "\n" if $_verbose > 1; | 
| 4527 |  |  |  |  |  |  |  | 
| 4528 | 1 |  |  |  |  | 13 | return 1; | 
| 4529 |  |  |  |  |  |  | } | 
| 4530 |  |  |  |  |  |  |  | 
| 4531 |  |  |  |  |  |  |  | 
| 4532 |  |  |  |  |  |  | sub _basic_factor { | 
| 4533 |  |  |  |  |  |  | # MODIFIES INPUT SCALAR | 
| 4534 | 39 | 0 |  | 39 |  | 163 | return ($_[0] == 1) ? () : ($_[0])   if $_[0] < 4; | 
|  |  | 50 |  |  |  |  |  | 
| 4535 |  |  |  |  |  |  |  | 
| 4536 | 39 |  |  |  |  | 2734 | my @factors; | 
| 4537 | 39 | 100 |  |  |  | 164 | if (ref($_[0]) ne 'Math::BigInt') { | 
| 4538 | 17 |  |  |  |  | 56 | while ( !($_[0] % 2) ) { push @factors, 2;  $_[0] = int($_[0] / 2); } | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 4539 | 17 |  |  |  |  | 53 | while ( !($_[0] % 3) ) { push @factors, 3;  $_[0] = int($_[0] / 3); } | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 4540 | 17 |  |  |  |  | 43 | while ( !($_[0] % 5) ) { push @factors, 5;  $_[0] = int($_[0] / 5); } | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 4541 |  |  |  |  |  |  | } else { | 
| 4542 |  |  |  |  |  |  | # Without this, the bdivs will try to convert the results to BigFloat | 
| 4543 |  |  |  |  |  |  | # and lose precision. | 
| 4544 | 22 | 100 | 66 |  |  | 164 | $_[0]->upgrade(undef) if ref($_[0]) && $_[0]->upgrade(); | 
| 4545 | 22 | 100 |  |  |  | 416 | if (!Math::BigInt::bgcd($_[0], B_PRIM235)->is_one) { | 
| 4546 | 1 |  |  |  |  | 182 | while ( $_[0]->is_even)   { push @factors, 2;  $_[0]->brsft(BONE); } | 
|  | 7 |  |  |  |  | 716 |  | 
|  | 7 |  |  |  |  | 14 |  | 
| 4547 | 1 |  |  |  |  | 115 | foreach my $div (3, 5) { | 
| 4548 | 2 |  |  |  |  | 285 | my ($q, $r) = $_[0]->copy->bdiv($div); | 
| 4549 | 2 |  |  |  |  | 576 | while ($r->is_zero) { | 
| 4550 | 1 |  |  |  |  | 11 | push @factors, $div; | 
| 4551 | 1 |  |  |  |  | 2 | $_[0] = $q; | 
| 4552 | 1 |  |  |  |  | 2 | ($q, $r) = $_[0]->copy->bdiv($div); | 
| 4553 |  |  |  |  |  |  | } | 
| 4554 |  |  |  |  |  |  | } | 
| 4555 |  |  |  |  |  |  | } | 
| 4556 | 22 | 50 | 33 |  |  | 4032 | $_[0] = _bigint_to_int($_[0]) if $] >= 5.008 && $_[0] <= BMAX; | 
| 4557 |  |  |  |  |  |  | } | 
| 4558 |  |  |  |  |  |  |  | 
| 4559 | 39 | 50 | 33 |  |  | 1011 | if ( ($_[0] > 1) && _is_prime7($_[0]) ) { | 
| 4560 | 0 |  |  |  |  | 0 | push @factors, $_[0]; | 
| 4561 | 0 |  |  |  |  | 0 | $_[0] = 1; | 
| 4562 |  |  |  |  |  |  | } | 
| 4563 | 39 |  |  |  |  | 3676 | @factors; | 
| 4564 |  |  |  |  |  |  | } | 
| 4565 |  |  |  |  |  |  |  | 
| 4566 |  |  |  |  |  |  | sub trial_factor { | 
| 4567 | 251 |  |  | 251 | 0 | 1984 | my($n, $limit) = @_; | 
| 4568 |  |  |  |  |  |  |  | 
| 4569 |  |  |  |  |  |  | # Don't use _basic_factor here -- they want a trial forced. | 
| 4570 | 251 |  |  |  |  | 323 | my @factors; | 
| 4571 | 251 | 50 |  |  |  | 463 | if ($n < 4) { | 
| 4572 | 0 | 0 |  |  |  | 0 | @factors = ($n == 1) ? () : ($n); | 
| 4573 | 0 |  |  |  |  | 0 | return @factors; | 
| 4574 |  |  |  |  |  |  | } | 
| 4575 |  |  |  |  |  |  |  | 
| 4576 | 251 |  |  |  |  | 8743 | my $start_idx = 1; | 
| 4577 |  |  |  |  |  |  | # Expand small primes if it would help. | 
| 4578 | 251 | 100 | 66 |  |  | 669 | push @_primes_small, @{primes($_primes_small[-1]+1, 100_003)} | 
|  | 1 |  | 66 |  |  | 131 |  | 
|  |  |  | 100 |  |  |  |  | 
| 4579 |  |  |  |  |  |  | if $n > 400_000_000 | 
| 4580 |  |  |  |  |  |  | && $_primes_small[-1] < 99_000 | 
| 4581 |  |  |  |  |  |  | && (!defined $limit || $limit > $_primes_small[-1]); | 
| 4582 |  |  |  |  |  |  |  | 
| 4583 |  |  |  |  |  |  | # Do initial bigint reduction.  Hopefully reducing it to native int. | 
| 4584 | 251 | 100 |  |  |  | 9511 | if (ref($n) eq 'Math::BigInt') { | 
| 4585 | 77 |  |  |  |  | 296 | $n = $n->copy;  # Don't modify their original input! | 
| 4586 | 77 |  |  |  |  | 1834 | my $newlim = $n->copy->bsqrt; | 
| 4587 | 77 | 50 | 33 |  |  | 91151 | $limit = $newlim if !defined $limit || $limit > $newlim; | 
| 4588 | 77 |  |  |  |  | 6584 | while ($start_idx <= $#_primes_small) { | 
| 4589 | 20534 |  |  |  |  | 4051066 | my $f = $_primes_small[$start_idx++]; | 
| 4590 | 20534 | 100 |  |  |  | 39337 | last if $f > $limit; | 
| 4591 | 20514 | 100 |  |  |  | 42609 | if ($n->copy->bmod($f)->is_zero) { | 
| 4592 | 287 |  |  |  |  | 59091 | do { | 
| 4593 | 555 |  |  |  |  | 133926 | push @factors, $f; | 
| 4594 | 555 |  |  |  |  | 1533 | $n->bdiv($f)->bfloor(); | 
| 4595 |  |  |  |  |  |  | } while $n->copy->bmod($f)->is_zero; | 
| 4596 | 287 | 100 |  |  |  | 144005 | last if $n < BMAX; | 
| 4597 | 230 |  |  |  |  | 8998 | my $newlim = $n->copy->bsqrt; | 
| 4598 | 230 | 50 |  |  |  | 333367 | $limit = $newlim if $limit > $newlim; | 
| 4599 |  |  |  |  |  |  | } | 
| 4600 |  |  |  |  |  |  | } | 
| 4601 | 77 | 50 |  |  |  | 2644 | return @factors if $n->is_one; | 
| 4602 | 77 | 100 |  |  |  | 1670 | $n = _bigint_to_int($n) if $n <= BMAX; | 
| 4603 | 77 | 50 | 66 |  |  | 3969 | return (@factors,$n) if $start_idx <= $#_primes_small && $_primes_small[$start_idx] > $limit; | 
| 4604 |  |  |  |  |  |  | } | 
| 4605 |  |  |  |  |  |  |  | 
| 4606 |  |  |  |  |  |  | { | 
| 4607 | 251 | 100 |  |  |  | 374 | my $newlim = (ref($n) eq 'Math::BigInt') ? $n->copy->bsqrt : int(sqrt($n) + 0.001); | 
|  | 251 |  |  |  |  | 750 |  | 
| 4608 | 251 | 100 | 66 |  |  | 23401 | $limit = $newlim if !defined $limit || $limit > $newlim; | 
| 4609 |  |  |  |  |  |  | } | 
| 4610 |  |  |  |  |  |  |  | 
| 4611 | 251 | 100 |  |  |  | 2437 | if (ref($n) ne 'Math::BigInt') { | 
| 4612 | 231 |  |  |  |  | 500 | for my $i ($start_idx .. $#_primes_small) { | 
| 4613 | 51251 |  |  |  |  | 62253 | my $p = $_primes_small[$i]; | 
| 4614 | 51251 | 100 |  |  |  | 75487 | last if $p > $limit; | 
| 4615 | 51029 | 100 |  |  |  | 81470 | if (($n % $p) == 0) { | 
| 4616 | 308 |  |  |  |  | 383 | do { push @factors, $p;  $n = int($n/$p); } while ($n % $p) == 0; | 
|  | 329 |  |  |  |  | 476 |  | 
|  | 329 |  |  |  |  | 748 |  | 
| 4617 | 308 | 100 |  |  |  | 545 | last if $n == 1; | 
| 4618 | 299 |  |  |  |  | 454 | my $newlim = int( sqrt($n) + 0.001); | 
| 4619 | 299 | 100 |  |  |  | 558 | $limit = $newlim if $newlim < $limit; | 
| 4620 |  |  |  |  |  |  | } | 
| 4621 |  |  |  |  |  |  | } | 
| 4622 | 231 | 50 |  |  |  | 556 | if ($_primes_small[-1] < $limit) { | 
| 4623 | 0 | 0 |  |  |  | 0 | my $inc = (($_primes_small[-1] % 6) == 1) ? 4 : 2; | 
| 4624 | 0 |  |  |  |  | 0 | my $p = $_primes_small[-1] + $inc; | 
| 4625 | 0 |  |  |  |  | 0 | while ($p <= $limit) { | 
| 4626 | 0 | 0 |  |  |  | 0 | if (($n % $p) == 0) { | 
| 4627 | 0 |  |  |  |  | 0 | do { push @factors, $p;  $n = int($n/$p); } while ($n % $p) == 0; | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 4628 | 0 | 0 |  |  |  | 0 | last if $n == 1; | 
| 4629 | 0 |  |  |  |  | 0 | my $newlim = int( sqrt($n) + 0.001); | 
| 4630 | 0 | 0 |  |  |  | 0 | $limit = $newlim if $newlim < $limit; | 
| 4631 |  |  |  |  |  |  | } | 
| 4632 | 0 |  |  |  |  | 0 | $p += ($inc ^= 6); | 
| 4633 |  |  |  |  |  |  | } | 
| 4634 |  |  |  |  |  |  | } | 
| 4635 |  |  |  |  |  |  | } else {   # n is a bigint.  Use mod-210 wheel trial division. | 
| 4636 |  |  |  |  |  |  | # Generating a wheel mod $w starting at $s: | 
| 4637 |  |  |  |  |  |  | # mpu 'my($s,$w,$t)=(11,2*3*5); say join ",",map { ($t,$s)=($_-$s,$_); $t; } grep { gcd($_,$w)==1 } $s+1..$s+$w;' | 
| 4638 |  |  |  |  |  |  | # Should start at $_primes_small[$start_idx], do 11 + next multiple of 210. | 
| 4639 | 20 |  |  |  |  | 181 | my @incs = map { Math::BigInt->new($_) } (2,4,2,4,6,2,6,4,2,4,6,6,2,6,4,2,6,4,6,8,4,2,4,2,4,8,6,4,6,2,4,6,2,6,6,4,2,4,6,2,6,4,2,4,2,10,2,10); | 
|  | 960 |  |  |  |  | 33739 |  | 
| 4640 | 20 |  |  |  |  | 859 | my $f = 11; while ($f <= $_primes_small[$start_idx-1]-210) { $f += 210; } | 
|  | 20 |  |  |  |  | 139 |  | 
|  | 460 |  |  |  |  | 841 |  | 
| 4641 | 20 |  |  |  |  | 90 | ($f, $limit) = map { Math::BigInt->new("$_") } ($f, $limit); | 
|  | 40 |  |  |  |  | 966 |  | 
| 4642 | 20 |  |  |  |  | 854 | SEARCH: while ($f <= $limit) { | 
| 4643 | 20 |  |  |  |  | 772 | foreach my $finc (@incs) { | 
| 4644 | 960 | 50 | 33 |  |  | 53350 | if ($n->copy->bmod($f)->is_zero && $f->bacmp($limit) <= 0) { | 
| 4645 | 0 | 0 |  |  |  | 0 | my $sf = ($f <= BMAX) ? _bigint_to_int($f) : $f->copy; | 
| 4646 | 0 |  |  |  |  | 0 | do { | 
| 4647 | 0 |  |  |  |  | 0 | push @factors, $sf; | 
| 4648 | 0 |  |  |  |  | 0 | $n->bdiv($f)->bfloor(); | 
| 4649 |  |  |  |  |  |  | } while $n->copy->bmod($f)->is_zero; | 
| 4650 | 0 | 0 |  |  |  | 0 | last SEARCH if $n->is_one; | 
| 4651 | 0 |  |  |  |  | 0 | my $newlim = $n->copy->bsqrt; | 
| 4652 | 0 | 0 |  |  |  | 0 | $limit = $newlim if $limit > $newlim; | 
| 4653 |  |  |  |  |  |  | } | 
| 4654 | 960 |  |  |  |  | 118353 | $f->badd($finc); | 
| 4655 |  |  |  |  |  |  | } | 
| 4656 |  |  |  |  |  |  | } | 
| 4657 |  |  |  |  |  |  | } | 
| 4658 | 251 | 100 |  |  |  | 2783 | push @factors, $n  if $n > 1; | 
| 4659 | 251 |  |  |  |  | 3307 | @factors; | 
| 4660 |  |  |  |  |  |  | } | 
| 4661 |  |  |  |  |  |  |  | 
| 4662 |  |  |  |  |  |  | my $_holf_r; | 
| 4663 |  |  |  |  |  |  | my @_fsublist = ( | 
| 4664 |  |  |  |  |  |  | [ "pbrent 32k", sub { pbrent_factor (shift,   32*1024, 1, 1) } ], | 
| 4665 |  |  |  |  |  |  | [ "p-1 1M",     sub { pminus1_factor(shift, 1_000_000, undef, 1); } ], | 
| 4666 |  |  |  |  |  |  | [ "ECM 1k",     sub { ecm_factor    (shift,     1_000,   5_000, 15) } ], | 
| 4667 |  |  |  |  |  |  | [ "pbrent 512k",sub { pbrent_factor (shift,  512*1024, 7, 1) } ], | 
| 4668 |  |  |  |  |  |  | [ "p-1 4M",     sub { pminus1_factor(shift, 4_000_000, undef, 1); } ], | 
| 4669 |  |  |  |  |  |  | [ "ECM 10k",    sub { ecm_factor    (shift,    10_000,  50_000, 10) } ], | 
| 4670 |  |  |  |  |  |  | [ "pbrent 512k",sub { pbrent_factor (shift,  512*1024, 11, 1) } ], | 
| 4671 |  |  |  |  |  |  | [ "HOLF 256k",  sub { holf_factor   (shift, 256*1024, $_holf_r); $_holf_r += 256*1024; } ], | 
| 4672 |  |  |  |  |  |  | [ "p-1 20M",    sub { pminus1_factor(shift,20_000_000); } ], | 
| 4673 |  |  |  |  |  |  | [ "ECM 100k",   sub { ecm_factor    (shift,   100_000, 800_000, 10) } ], | 
| 4674 |  |  |  |  |  |  | [ "HOLF 512k",  sub { holf_factor   (shift, 512*1024, $_holf_r); $_holf_r += 512*1024; } ], | 
| 4675 |  |  |  |  |  |  | [ "pbrent 2M",  sub { pbrent_factor (shift, 2048*1024, 13, 1) } ], | 
| 4676 |  |  |  |  |  |  | [ "HOLF 2M",    sub { holf_factor   (shift, 2048*1024, $_holf_r); $_holf_r += 2048*1024; } ], | 
| 4677 |  |  |  |  |  |  | [ "ECM 1M",     sub { ecm_factor    (shift, 1_000_000, 1_000_000, 10) } ], | 
| 4678 |  |  |  |  |  |  | [ "p-1 100M",   sub { pminus1_factor(shift, 100_000_000, 500_000_000); } ], | 
| 4679 |  |  |  |  |  |  | ); | 
| 4680 |  |  |  |  |  |  |  | 
| 4681 |  |  |  |  |  |  | sub factor { | 
| 4682 | 239 |  |  | 239 | 0 | 3963 | my($n) = @_; | 
| 4683 | 239 |  |  |  |  | 560 | _validate_positive_integer($n); | 
| 4684 | 239 |  |  |  |  | 333 | my @factors; | 
| 4685 |  |  |  |  |  |  |  | 
| 4686 | 239 | 100 |  |  |  | 493 | if ($n < 4) { | 
| 4687 | 1 | 50 |  |  |  | 19 | @factors = ($n == 1) ? () : ($n); | 
| 4688 | 1 |  |  |  |  | 6 | return @factors; | 
| 4689 |  |  |  |  |  |  | } | 
| 4690 | 238 | 100 |  |  |  | 7613 | $n = $n->copy if ref($n) eq 'Math::BigInt'; | 
| 4691 | 238 |  |  |  |  | 1660 | my $lim = 4999;  # How much trial factoring to do | 
| 4692 |  |  |  |  |  |  |  | 
| 4693 |  |  |  |  |  |  | # For native integers, we could save a little time by doing hardcoded trials | 
| 4694 |  |  |  |  |  |  | # by 2-29 here.  Skipping it. | 
| 4695 |  |  |  |  |  |  |  | 
| 4696 | 238 |  |  |  |  | 626 | push @factors, trial_factor($n, $lim); | 
| 4697 | 238 | 100 |  |  |  | 837 | return @factors if $factors[-1] < $lim*$lim; | 
| 4698 | 71 |  |  |  |  | 1860 | $n = pop(@factors); | 
| 4699 |  |  |  |  |  |  |  | 
| 4700 | 71 |  |  |  |  | 355 | my @nstack = ($n); | 
| 4701 | 71 |  |  |  |  | 268 | while (@nstack) { | 
| 4702 | 132 |  |  |  |  | 331 | $n = pop @nstack; | 
| 4703 |  |  |  |  |  |  | # Don't use bignum on $n if it has gotten small enough. | 
| 4704 | 132 | 100 | 100 |  |  | 624 | $n = _bigint_to_int($n) if ref($n) eq 'Math::BigInt' && $n <= BMAX; | 
| 4705 |  |  |  |  |  |  | #print "Looking at $n with stack ", join(",",@nstack), "\n"; | 
| 4706 | 132 |  | 100 |  |  | 1805 | while ( ($n >= ($lim*$lim)) && !_is_prime7($n) ) { | 
| 4707 | 61 |  |  |  |  | 197 | my @ftry; | 
| 4708 | 61 |  |  |  |  | 152 | $_holf_r = 1; | 
| 4709 | 61 |  |  |  |  | 199 | foreach my $sub (@_fsublist) { | 
| 4710 | 126 | 100 |  |  |  | 503 | last if scalar @ftry >= 2; | 
| 4711 | 65 | 50 |  |  |  | 392 | print "  starting $sub->[0]\n" if Math::Prime::Util::prime_get_config()->{'verbose'} > 1; | 
| 4712 | 65 |  |  |  |  | 438 | @ftry = $sub->[1]->($n); | 
| 4713 |  |  |  |  |  |  | } | 
| 4714 | 61 | 50 |  |  |  | 241 | if (scalar @ftry > 1) { | 
| 4715 |  |  |  |  |  |  | #print "  split into ", join(",",@ftry), "\n"; | 
| 4716 | 61 |  |  |  |  | 168 | $n = shift @ftry; | 
| 4717 | 61 | 100 | 66 |  |  | 386 | $n = _bigint_to_int($n) if ref($n) eq 'Math::BigInt' && $n <= BMAX; | 
| 4718 | 61 |  |  |  |  | 906 | push @nstack, @ftry; | 
| 4719 |  |  |  |  |  |  | } else { | 
| 4720 |  |  |  |  |  |  | #warn "trial factor $n\n"; | 
| 4721 | 0 |  |  |  |  | 0 | push @factors, trial_factor($n); | 
| 4722 |  |  |  |  |  |  | #print "  trial into ", join(",",@factors), "\n"; | 
| 4723 | 0 |  |  |  |  | 0 | $n = 1; | 
| 4724 | 0 |  |  |  |  | 0 | last; | 
| 4725 |  |  |  |  |  |  | } | 
| 4726 |  |  |  |  |  |  | } | 
| 4727 | 132 | 50 |  |  |  | 6085 | push @factors, $n  if $n != 1; | 
| 4728 |  |  |  |  |  |  | } | 
| 4729 | 71 |  |  |  |  | 1711 | @factors = sort {$a<=>$b} @factors; | 
|  | 514 |  |  |  |  | 1644 |  | 
| 4730 | 71 |  |  |  |  | 1021 | return @factors; | 
| 4731 |  |  |  |  |  |  | } | 
| 4732 |  |  |  |  |  |  |  | 
| 4733 |  |  |  |  |  |  | sub _found_factor { | 
| 4734 | 96 |  |  | 96 |  | 545 | my($f, $n, $what, @factors) = @_; | 
| 4735 | 96 | 50 | 33 |  |  | 421 | if ($f == 1 || $f == $n) { | 
| 4736 | 0 |  |  |  |  | 0 | push @factors, $n; | 
| 4737 |  |  |  |  |  |  | } else { | 
| 4738 |  |  |  |  |  |  | # Perl 5.6.2 needs things spelled out for it. | 
| 4739 | 96 | 100 |  |  |  | 6550 | my $f2 = (ref($n) eq 'Math::BigInt') ? $n->copy->bdiv($f)->as_int | 
| 4740 |  |  |  |  |  |  | : int($n/$f); | 
| 4741 | 96 |  |  |  |  | 10706 | push @factors, $f; | 
| 4742 | 96 |  |  |  |  | 216 | push @factors, $f2; | 
| 4743 | 96 | 50 |  |  |  | 373 | croak "internal error in $what" unless $f * $f2 == $n; | 
| 4744 |  |  |  |  |  |  | # MPU::GMP prints this type of message if verbose, so do the same. | 
| 4745 | 96 | 50 |  |  |  | 6805 | print "$what found factor $f\n" if Math::Prime::Util::prime_get_config()->{'verbose'} > 0; | 
| 4746 |  |  |  |  |  |  | } | 
| 4747 | 96 |  |  |  |  | 1717 | @factors; | 
| 4748 |  |  |  |  |  |  | } | 
| 4749 |  |  |  |  |  |  |  | 
| 4750 |  |  |  |  |  |  | # TODO: | 
| 4751 | 0 |  |  | 0 | 0 | 0 | sub squfof_factor { trial_factor(@_) } | 
| 4752 |  |  |  |  |  |  |  | 
| 4753 |  |  |  |  |  |  | sub prho_factor { | 
| 4754 | 5 |  |  | 5 | 0 | 3702 | my($n, $rounds, $pa, $skipbasic) = @_; | 
| 4755 | 5 | 100 |  |  |  | 21 | $rounds = 4*1024*1024 unless defined $rounds; | 
| 4756 | 5 | 50 |  |  |  | 15 | $pa = 3 unless defined $pa; | 
| 4757 |  |  |  |  |  |  |  | 
| 4758 | 5 |  |  |  |  | 12 | my @factors; | 
| 4759 | 5 | 50 |  |  |  | 13 | if (!$skipbasic) { | 
| 4760 | 5 |  |  |  |  | 19 | @factors = _basic_factor($n); | 
| 4761 | 5 | 50 |  |  |  | 18 | return @factors if $n < 4; | 
| 4762 |  |  |  |  |  |  | } | 
| 4763 |  |  |  |  |  |  |  | 
| 4764 | 5 |  |  |  |  | 224 | my $inloop = 0; | 
| 4765 | 5 |  |  |  |  | 11 | my $U = 7; | 
| 4766 | 5 |  |  |  |  | 10 | my $V = 7; | 
| 4767 |  |  |  |  |  |  |  | 
| 4768 | 5 | 100 |  |  |  | 22 | if ( ref($n) eq 'Math::BigInt' ) { | 
|  |  | 100 |  |  |  |  |  | 
| 4769 |  |  |  |  |  |  |  | 
| 4770 | 2 |  |  |  |  | 6 | my $zero = $n->copy->bzero; | 
| 4771 | 2 |  |  |  |  | 89 | $pa = $zero->badd("$pa"); | 
| 4772 | 2 |  |  |  |  | 248 | $U = $zero->copy->badd($U); | 
| 4773 | 2 |  |  |  |  | 252 | $V = $zero->copy->badd($V); | 
| 4774 | 2 |  |  |  |  | 243 | for my $i (1 .. $rounds) { | 
| 4775 |  |  |  |  |  |  | # Would use bmuladd here, but old Math::BigInt's barf with scalar $pa. | 
| 4776 | 22 |  |  |  |  | 642 | $U->bmul($U)->badd($pa)->bmod($n); | 
| 4777 | 22 |  |  |  |  | 6713 | $V->bmul($V)->badd($pa); | 
| 4778 | 22 |  |  |  |  | 3244 | $V->bmul($V)->badd($pa)->bmod($n); | 
| 4779 | 22 |  |  |  |  | 9396 | my $f = Math::BigInt::bgcd($U-$V, $n); | 
| 4780 | 22 | 50 |  |  |  | 62122 | if ($f->bacmp($n) == 0) { | 
|  |  | 100 |  |  |  |  |  | 
| 4781 | 0 | 0 |  |  |  | 0 | last if $inloop++;  # We've been here before | 
| 4782 |  |  |  |  |  |  | } elsif (!$f->is_one) { | 
| 4783 | 2 |  |  |  |  | 67 | return _found_factor($f, $n, "prho", @factors); | 
| 4784 |  |  |  |  |  |  | } | 
| 4785 |  |  |  |  |  |  | } | 
| 4786 |  |  |  |  |  |  |  | 
| 4787 |  |  |  |  |  |  | } elsif ($n < MPU_HALFWORD) { | 
| 4788 |  |  |  |  |  |  |  | 
| 4789 | 2 |  |  |  |  | 5 | my $inner = 32; | 
| 4790 | 2 |  |  |  |  | 7 | $rounds = int( ($rounds + $inner-1) / $inner ); | 
| 4791 | 2 |  |  |  |  | 7 | while ($rounds-- > 0) { | 
| 4792 | 2 |  |  |  |  | 5 | my($m, $oldU, $oldV, $f) = (1, $U, $V); | 
| 4793 | 2 |  |  |  |  | 8 | for my $i (1 .. $inner) { | 
| 4794 | 64 |  |  |  |  | 69 | $U = ($U * $U + $pa) % $n; | 
| 4795 | 64 |  |  |  |  | 68 | $V = ($V * $V + $pa) % $n; | 
| 4796 | 64 |  |  |  |  | 70 | $V = ($V * $V + $pa) % $n; | 
| 4797 | 64 | 100 |  |  |  | 73 | $f = ($U > $V) ? $U-$V : $V-$U; | 
| 4798 | 64 |  |  |  |  | 78 | $m = ($m * $f) % $n; | 
| 4799 |  |  |  |  |  |  | } | 
| 4800 | 2 |  |  |  |  | 6 | $f = _gcd_ui( $m, $n ); | 
| 4801 | 2 | 50 |  |  |  | 6 | next if $f == 1; | 
| 4802 | 2 | 100 |  |  |  | 8 | if ($f == $n) { | 
| 4803 | 1 |  |  |  |  | 3 | ($U, $V) = ($oldU, $oldV); | 
| 4804 | 1 |  |  |  |  | 4 | for my $i (1 .. $inner) { | 
| 4805 | 2 |  |  |  |  | 5 | $U = ($U * $U + $pa) % $n; | 
| 4806 | 2 |  |  |  |  | 3 | $V = ($V * $V + $pa) % $n; | 
| 4807 | 2 |  |  |  |  | 4 | $V = ($V * $V + $pa) % $n; | 
| 4808 | 2 | 100 |  |  |  | 4 | $f = ($U > $V) ? $U-$V : $V-$U; | 
| 4809 | 2 |  |  |  |  | 4 | $f = _gcd_ui( $f, $n); | 
| 4810 | 2 | 100 |  |  |  | 5 | last if $f != 1; | 
| 4811 |  |  |  |  |  |  | } | 
| 4812 | 1 | 50 | 33 |  |  | 8 | last if $f == 1 || $f == $n; | 
| 4813 |  |  |  |  |  |  | } | 
| 4814 | 2 |  |  |  |  | 15 | return _found_factor($f, $n, "prho", @factors); | 
| 4815 |  |  |  |  |  |  | } | 
| 4816 |  |  |  |  |  |  |  | 
| 4817 |  |  |  |  |  |  | } else { | 
| 4818 |  |  |  |  |  |  |  | 
| 4819 | 1 |  |  |  |  | 5 | for my $i (1 .. $rounds) { | 
| 4820 | 5 | 50 |  |  |  | 12 | if ($n <= (~0 >> 1)) { | 
| 4821 | 5 | 50 |  |  |  | 11 | $U = _mulmod($U, $U, $n);  $U += $pa;  $U -= $n if $U >= $n; | 
|  | 5 |  |  |  |  | 7 |  | 
|  | 5 |  |  |  |  | 11 |  | 
| 4822 | 5 |  |  |  |  | 8 | $V = _mulmod($V, $V, $n);  $V += $pa;  # Let the mulmod handle it | 
|  | 5 |  |  |  |  | 7 |  | 
| 4823 | 5 | 50 |  |  |  | 7 | $V = _mulmod($V, $V, $n);  $V += $pa;  $V -= $n if $V >= $n; | 
|  | 5 |  |  |  |  | 7 |  | 
|  | 5 |  |  |  |  | 10 |  | 
| 4824 |  |  |  |  |  |  | } else { | 
| 4825 |  |  |  |  |  |  | #$U = _mulmod($U, $U, $n); $U=$n-$U; $U = ($pa>=$U) ? $pa-$U : $n-$U+$pa; | 
| 4826 |  |  |  |  |  |  | #$V = _mulmod($V, $V, $n); $V=$n-$V; $V = ($pa>=$V) ? $pa-$V : $n-$V+$pa; | 
| 4827 |  |  |  |  |  |  | #$V = _mulmod($V, $V, $n); $V=$n-$V; $V = ($pa>=$V) ? $pa-$V : $n-$V+$pa; | 
| 4828 | 0 |  |  |  |  | 0 | $U = _mulmod($U, $U, $n);  $U = _addmod($U, $pa, $n); | 
|  | 0 |  |  |  |  | 0 |  | 
| 4829 | 0 |  |  |  |  | 0 | $V = _mulmod($V, $V, $n);  $V = _addmod($V, $pa, $n); | 
|  | 0 |  |  |  |  | 0 |  | 
| 4830 | 0 |  |  |  |  | 0 | $V = _mulmod($V, $V, $n);  $V = _addmod($V, $pa, $n); | 
|  | 0 |  |  |  |  | 0 |  | 
| 4831 |  |  |  |  |  |  | } | 
| 4832 | 5 |  |  |  |  | 11 | my $f = _gcd_ui( $U-$V,  $n ); | 
| 4833 | 5 | 50 |  |  |  | 13 | if ($f == $n) { | 
|  |  | 100 |  |  |  |  |  | 
| 4834 | 0 | 0 |  |  |  | 0 | last if $inloop++;  # We've been here before | 
| 4835 |  |  |  |  |  |  | } elsif ($f != 1) { | 
| 4836 | 1 |  |  |  |  | 3 | return _found_factor($f, $n, "prho", @factors); | 
| 4837 |  |  |  |  |  |  | } | 
| 4838 |  |  |  |  |  |  | } | 
| 4839 |  |  |  |  |  |  |  | 
| 4840 |  |  |  |  |  |  | } | 
| 4841 | 0 |  |  |  |  | 0 | push @factors, $n; | 
| 4842 | 0 |  |  |  |  | 0 | @factors; | 
| 4843 |  |  |  |  |  |  | } | 
| 4844 |  |  |  |  |  |  |  | 
| 4845 |  |  |  |  |  |  | sub pbrent_factor { | 
| 4846 | 78 |  |  | 78 | 0 | 3506 | my($n, $rounds, $pa, $skipbasic) = @_; | 
| 4847 | 78 | 100 |  |  |  | 243 | $rounds = 4*1024*1024 unless defined $rounds; | 
| 4848 | 78 | 100 |  |  |  | 243 | $pa = 3 unless defined $pa; | 
| 4849 |  |  |  |  |  |  |  | 
| 4850 | 78 |  |  |  |  | 186 | my @factors; | 
| 4851 | 78 | 100 |  |  |  | 238 | if (!$skipbasic) { | 
| 4852 | 17 |  |  |  |  | 66 | @factors = _basic_factor($n); | 
| 4853 | 17 | 50 |  |  |  | 68 | return @factors if $n < 4; | 
| 4854 |  |  |  |  |  |  | } | 
| 4855 |  |  |  |  |  |  |  | 
| 4856 | 78 |  |  |  |  | 1177 | my $Xi = 2; | 
| 4857 | 78 |  |  |  |  | 157 | my $Xm = 2; | 
| 4858 |  |  |  |  |  |  |  | 
| 4859 | 78 | 100 |  |  |  | 365 | if ( ref($n) eq 'Math::BigInt' ) { | 
|  |  | 100 |  |  |  |  |  | 
| 4860 |  |  |  |  |  |  |  | 
| 4861 |  |  |  |  |  |  | # Same code as the GMP version, but runs *much* slower.  Even with | 
| 4862 |  |  |  |  |  |  | # Math::BigInt::GMP it's >200x slower.  With the default Calc backend | 
| 4863 |  |  |  |  |  |  | # it's thousands of times slower. | 
| 4864 | 23 |  |  |  |  | 50 | my $inner = 32; | 
| 4865 | 23 |  |  |  |  | 122 | my $zero = $n->copy->bzero; | 
| 4866 | 23 |  |  |  |  | 1330 | my $saveXi; | 
| 4867 |  |  |  |  |  |  | my $f; | 
| 4868 | 23 |  |  |  |  | 85 | $Xi = $zero->copy->badd($Xi); | 
| 4869 | 23 |  |  |  |  | 4215 | $Xm = $zero->copy->badd($Xm); | 
| 4870 | 23 |  |  |  |  | 3341 | $pa = $zero->copy->badd($pa); | 
| 4871 | 23 |  |  |  |  | 3447 | my $r = 1; | 
| 4872 | 23 |  |  |  |  | 120 | while ($rounds > 0) { | 
| 4873 | 206 | 100 |  |  |  | 621 | my $rleft = ($r > $rounds) ? $rounds : $r; | 
| 4874 | 206 |  |  |  |  | 482 | while ($rleft > 0) { | 
| 4875 | 2334 | 100 |  |  |  | 45328 | my $dorounds = ($rleft > $inner) ? $inner : $rleft; | 
| 4876 | 2334 |  |  |  |  | 6853 | my $m = $zero->copy->bone; | 
| 4877 | 2334 |  |  |  |  | 233767 | $saveXi = $Xi->copy; | 
| 4878 | 2334 |  |  |  |  | 50258 | foreach my $i (1 .. $dorounds) { | 
| 4879 | 71659 |  |  |  |  | 58872634 | $Xi->bmul($Xi)->badd($pa)->bmod($n); | 
| 4880 | 71659 |  |  |  |  | 33592495 | $m->bmul($Xi->copy->bsub($Xm)); | 
| 4881 |  |  |  |  |  |  | } | 
| 4882 | 2334 |  |  |  |  | 3434761 | $rleft -= $dorounds; | 
| 4883 | 2334 |  |  |  |  | 5341 | $rounds -= $dorounds; | 
| 4884 | 2334 |  |  |  |  | 8745 | $m->bmod($n); | 
| 4885 | 2334 |  |  |  |  | 5809515 | $f = Math::BigInt::bgcd($m,  $n); | 
| 4886 | 2334 | 100 |  |  |  | 9368886 | last unless $f->is_one; | 
| 4887 |  |  |  |  |  |  | } | 
| 4888 | 206 | 100 |  |  |  | 3905 | if ($f->is_one) { | 
| 4889 | 185 |  |  |  |  | 2306 | $r *= 2; | 
| 4890 | 185 |  |  |  |  | 484 | $Xm = $Xi->copy; | 
| 4891 | 185 |  |  |  |  | 4327 | next; | 
| 4892 |  |  |  |  |  |  | } | 
| 4893 | 21 | 50 |  |  |  | 351 | if ($f == $n) {  # back up to determine the factor | 
| 4894 | 0 |  |  |  |  | 0 | $Xi = $saveXi->copy; | 
| 4895 | 0 |  | 0 |  |  | 0 | do { | 
| 4896 | 0 |  |  |  |  | 0 | $Xi->bmul($Xi)->badd($pa)->bmod($n); | 
| 4897 | 0 |  |  |  |  | 0 | $f = Math::BigInt::bgcd($Xm-$Xi, $n); | 
| 4898 |  |  |  |  |  |  | } while ($f != 1 && $r-- != 0); | 
| 4899 | 0 | 0 | 0 |  |  | 0 | last if $f == 1 || $f == $n; | 
| 4900 |  |  |  |  |  |  | } | 
| 4901 | 21 |  |  |  |  | 1314 | return _found_factor($f, $n, "pbrent", @factors); | 
| 4902 |  |  |  |  |  |  | } | 
| 4903 |  |  |  |  |  |  |  | 
| 4904 |  |  |  |  |  |  | } elsif ($n < MPU_HALFWORD) { | 
| 4905 |  |  |  |  |  |  |  | 
| 4906 |  |  |  |  |  |  | # Doing the gcd batching as above works pretty well here, but it's a lot | 
| 4907 |  |  |  |  |  |  | # of code for not much gain for general users. | 
| 4908 | 10 |  |  |  |  | 24 | for my $i (1 .. $rounds) { | 
| 4909 | 1653 |  |  |  |  | 1757 | $Xi = ($Xi * $Xi + $pa) % $n; | 
| 4910 | 1653 | 100 |  |  |  | 2411 | my $f = _gcd_ui( ($Xi>$Xm) ? $Xi-$Xm : $Xm-$Xi, $n); | 
| 4911 | 1653 | 100 | 66 |  |  | 2506 | return _found_factor($f, $n, "pbrent", @factors) if $f != 1 && $f != $n; | 
| 4912 | 1643 | 100 |  |  |  | 2498 | $Xm = $Xi if ($i & ($i-1)) == 0;  # i is a power of 2 | 
| 4913 |  |  |  |  |  |  | } | 
| 4914 |  |  |  |  |  |  |  | 
| 4915 |  |  |  |  |  |  | } else { | 
| 4916 |  |  |  |  |  |  |  | 
| 4917 | 45 |  |  |  |  | 151 | for my $i (1 .. $rounds) { | 
| 4918 | 32881 |  |  |  |  | 52431 | $Xi = _addmod( _mulmod($Xi, $Xi, $n), $pa, $n); | 
| 4919 | 32881 | 100 |  |  |  | 68509 | my $f = _gcd_ui( ($Xi>$Xm) ? $Xi-$Xm : $Xm-$Xi, $n); | 
| 4920 | 32881 | 100 | 66 |  |  | 63180 | return _found_factor($f, $n, "pbrent", @factors) if $f != 1 && $f != $n; | 
| 4921 | 32836 | 100 |  |  |  | 66554 | $Xm = $Xi if ($i & ($i-1)) == 0;  # i is a power of 2 | 
| 4922 |  |  |  |  |  |  | } | 
| 4923 |  |  |  |  |  |  |  | 
| 4924 |  |  |  |  |  |  | } | 
| 4925 | 2 |  |  |  |  | 8 | push @factors, $n; | 
| 4926 | 2 |  |  |  |  | 23 | @factors; | 
| 4927 |  |  |  |  |  |  | } | 
| 4928 |  |  |  |  |  |  |  | 
| 4929 |  |  |  |  |  |  | sub pminus1_factor { | 
| 4930 | 7 |  |  | 7 | 0 | 7104 | my($n, $B1, $B2, $skipbasic) = @_; | 
| 4931 |  |  |  |  |  |  |  | 
| 4932 | 7 |  |  |  |  | 18 | my @factors; | 
| 4933 | 7 | 100 |  |  |  | 43 | if (!$skipbasic) { | 
| 4934 | 5 |  |  |  |  | 25 | @factors = _basic_factor($n); | 
| 4935 | 5 | 50 |  |  |  | 25 | return @factors if $n < 4; | 
| 4936 |  |  |  |  |  |  | } | 
| 4937 |  |  |  |  |  |  |  | 
| 4938 | 7 | 100 |  |  |  | 647 | if ( ref($n) ne 'Math::BigInt' ) { | 
| 4939 |  |  |  |  |  |  | # Stage 1 only | 
| 4940 | 1 | 50 |  |  |  | 5 | $B1 = 10_000_000 unless defined $B1; | 
| 4941 | 1 |  |  |  |  | 2 | my $pa = 2; | 
| 4942 | 1 |  |  |  |  | 1 | my $f = 1; | 
| 4943 | 1 |  |  |  |  | 2 | my($pc_beg, $pc_end, @bprimes); | 
| 4944 | 1 |  |  |  |  | 2 | $pc_beg = 2; | 
| 4945 | 1 |  |  |  |  | 2 | $pc_end = $pc_beg + 100_000; | 
| 4946 | 1 |  |  |  |  | 3 | my $sqrtb1 = int(sqrt($B1)); | 
| 4947 | 1 |  |  |  |  | 2 | while (1) { | 
| 4948 | 1 | 50 |  |  |  | 3 | $pc_end = $B1 if $pc_end > $B1; | 
| 4949 | 1 |  |  |  |  | 2 | @bprimes = @{ primes($pc_beg, $pc_end) }; | 
|  | 1 |  |  |  |  | 4 |  | 
| 4950 | 1 |  |  |  |  | 95 | foreach my $q (@bprimes) { | 
| 4951 | 2 |  |  |  |  | 4 | my $k = $q; | 
| 4952 | 2 | 50 |  |  |  | 8 | if ($q <= $sqrtb1) { | 
| 4953 | 2 |  |  |  |  | 8 | my $kmin = int($B1 / $q); | 
| 4954 | 2 |  |  |  |  | 6 | while ($k <= $kmin) { $k *= $q; } | 
|  | 35 |  |  |  |  | 48 |  | 
| 4955 |  |  |  |  |  |  | } | 
| 4956 | 2 |  |  |  |  | 10 | $pa = _powmod($pa, $k, $n); | 
| 4957 | 2 | 50 |  |  |  | 10 | if ($pa == 0) { push @factors, $n; return @factors; } | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 4958 | 2 |  |  |  |  | 8 | my $f = _gcd_ui( $pa-1, $n ); | 
| 4959 | 2 | 100 |  |  |  | 10 | return _found_factor($f, $n, "pminus1", @factors) if $f != 1; | 
| 4960 |  |  |  |  |  |  | } | 
| 4961 | 0 | 0 |  |  |  | 0 | last if $pc_end >= $B1; | 
| 4962 | 0 |  |  |  |  | 0 | $pc_beg = $pc_end+1; | 
| 4963 | 0 |  |  |  |  | 0 | $pc_end += 500_000; | 
| 4964 |  |  |  |  |  |  | } | 
| 4965 | 0 |  |  |  |  | 0 | push @factors, $n; | 
| 4966 | 0 |  |  |  |  | 0 | return @factors; | 
| 4967 |  |  |  |  |  |  | } | 
| 4968 |  |  |  |  |  |  |  | 
| 4969 |  |  |  |  |  |  | # Stage 2 isn't really any faster than stage 1 for the examples I've tried. | 
| 4970 |  |  |  |  |  |  | # Perl's overhead is greater than the savings of multiply vs. powmod | 
| 4971 |  |  |  |  |  |  |  | 
| 4972 | 6 | 100 |  |  |  | 29 | if (!defined $B1) { | 
| 4973 | 1 |  |  |  |  | 7 | for my $mul (1, 100, 1000, 10_000, 100_000, 1_000_000) { | 
| 4974 | 1 |  |  |  |  | 4 | $B1 = 1000 * $mul; | 
| 4975 | 1 |  |  |  |  | 3 | $B2 = 1*$B1; | 
| 4976 |  |  |  |  |  |  | #warn "Trying p-1 with $B1 / $B2\n"; | 
| 4977 | 1 |  |  |  |  | 21 | my @nf = pminus1_factor($n, $B1, $B2); | 
| 4978 | 1 | 50 |  |  |  | 5 | if (scalar @nf > 1) { | 
| 4979 | 1 |  |  |  |  | 4 | push @factors, @nf; | 
| 4980 | 1 |  |  |  |  | 11 | return @factors; | 
| 4981 |  |  |  |  |  |  | } | 
| 4982 |  |  |  |  |  |  | } | 
| 4983 | 0 |  |  |  |  | 0 | push @factors, $n; | 
| 4984 | 0 |  |  |  |  | 0 | return @factors; | 
| 4985 |  |  |  |  |  |  | } | 
| 4986 | 5 | 100 |  |  |  | 23 | $B2 = 1*$B1 unless defined $B2; | 
| 4987 |  |  |  |  |  |  |  | 
| 4988 | 5 |  |  |  |  | 22 | my $one = $n->copy->bone; | 
| 4989 | 5 |  |  |  |  | 578 | my ($j, $q, $saveq) = (32, 2, 2); | 
| 4990 | 5 |  |  |  |  | 19 | my $t = $one->copy; | 
| 4991 | 5 |  |  |  |  | 117 | my $pa = $one->copy->binc(); | 
| 4992 | 5 |  |  |  |  | 441 | my $savea = $pa->copy; | 
| 4993 | 5 |  |  |  |  | 110 | my $f = $one->copy; | 
| 4994 | 5 |  |  |  |  | 95 | my($pc_beg, $pc_end, @bprimes); | 
| 4995 |  |  |  |  |  |  |  | 
| 4996 | 5 |  |  |  |  | 10 | $pc_beg = 2; | 
| 4997 | 5 |  |  |  |  | 17 | $pc_end = $pc_beg + 100_000; | 
| 4998 | 5 |  |  |  |  | 14 | while (1) { | 
| 4999 | 5 | 100 |  |  |  | 22 | $pc_end = $B1 if $pc_end > $B1; | 
| 5000 | 5 |  |  |  |  | 15 | @bprimes = @{ primes($pc_beg, $pc_end) }; | 
|  | 5 |  |  |  |  | 32 |  | 
| 5001 | 5 |  |  |  |  | 290 | foreach my $q (@bprimes) { | 
| 5002 | 4252 |  |  |  |  | 13094 | my($k, $kmin) = ($q, int($B1 / $q)); | 
| 5003 | 4252 |  |  |  |  | 8606 | while ($k <= $kmin) { $k *= $q; } | 
|  | 593 |  |  |  |  | 1087 |  | 
| 5004 | 4252 |  |  |  |  | 9539 | $t *= $k;                         # accumulate powers for a | 
| 5005 | 4252 | 100 |  |  |  | 718797 | if ( ($j++ % 64) == 0) { | 
| 5006 | 68 | 50 | 33 |  |  | 522 | next if $pc_beg > 2 && ($j-1) % 256; | 
| 5007 | 68 |  |  |  |  | 353 | $pa->bmodpow($t, $n); | 
| 5008 | 68 |  |  |  |  | 21833104 | $t = $one->copy; | 
| 5009 | 68 | 50 |  |  |  | 2878 | if ($pa == 0) { push @factors, $n; return @factors; } | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 5010 | 68 |  |  |  |  | 21496 | $f = Math::BigInt::bgcd( $pa->copy->bdec, $n ); | 
| 5011 | 68 | 100 |  |  |  | 225155 | last if $f == $n; | 
| 5012 | 66 | 100 |  |  |  | 2914 | return _found_factor($f, $n, "pminus1", @factors) unless $f->is_one; | 
| 5013 | 65 |  |  |  |  | 1278 | $saveq = $q; | 
| 5014 | 65 |  |  |  |  | 207 | $savea = $pa->copy; | 
| 5015 |  |  |  |  |  |  | } | 
| 5016 |  |  |  |  |  |  | } | 
| 5017 | 4 |  |  |  |  | 120 | $q = $bprimes[-1]; | 
| 5018 | 4 | 50 | 66 |  |  | 24 | last if !$f->is_one || $pc_end >= $B1; | 
| 5019 | 0 |  |  |  |  | 0 | $pc_beg = $pc_end+1; | 
| 5020 | 0 |  |  |  |  | 0 | $pc_end += 500_000; | 
| 5021 |  |  |  |  |  |  | } | 
| 5022 | 4 |  |  |  |  | 718 | undef @bprimes; | 
| 5023 | 4 |  |  |  |  | 29 | $pa->bmodpow($t, $n); | 
| 5024 | 4 | 50 |  |  |  | 306229 | if ($pa == 0) { push @factors, $n; return @factors; } | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 5025 | 4 |  |  |  |  | 1024 | $f = Math::BigInt::bgcd( $pa-1, $n ); | 
| 5026 | 4 | 100 |  |  |  | 7095 | if ($f == $n) { | 
| 5027 | 2 |  |  |  |  | 100 | $q = $saveq; | 
| 5028 | 2 |  |  |  |  | 7 | $pa = $savea->copy; | 
| 5029 | 2 |  |  |  |  | 50 | while ($q <= $B1) { | 
| 5030 | 114 |  |  |  |  | 328 | my ($k, $kmin) = ($q, int($B1 / $q)); | 
| 5031 | 114 |  |  |  |  | 264 | while ($k <= $kmin) { $k *= $q; } | 
|  | 0 |  |  |  |  | 0 |  | 
| 5032 | 114 |  |  |  |  | 420 | $pa->bmodpow($k, $n); | 
| 5033 | 114 |  |  |  |  | 648639 | my $f = Math::BigInt::bgcd( $pa-1, $n ); | 
| 5034 | 114 | 100 |  |  |  | 485241 | if ($f == $n) { push @factors, $n; return @factors; } | 
|  | 2 |  |  |  |  | 96 |  | 
|  | 2 |  |  |  |  | 40 |  | 
| 5035 | 112 | 50 |  |  |  | 4443 | last if !$f->is_one; | 
| 5036 | 112 |  |  |  |  | 1628 | $q = next_prime($q); | 
| 5037 |  |  |  |  |  |  | } | 
| 5038 |  |  |  |  |  |  | } | 
| 5039 |  |  |  |  |  |  | # STAGE 2 | 
| 5040 | 2 | 50 | 33 |  |  | 92 | if ($f->is_one && $B2 > $B1) { | 
| 5041 | 2 |  |  |  |  | 60 | my $bm = $pa->copy; | 
| 5042 | 2 |  |  |  |  | 52 | my $b = $one->copy; | 
| 5043 | 2 |  |  |  |  | 49 | my @precomp_bm; | 
| 5044 | 2 |  |  |  |  | 9 | $precomp_bm[0] = ($bm * $bm) % $n; | 
| 5045 | 2 |  |  |  |  | 1019 | foreach my $j (1..19) { | 
| 5046 | 38 |  |  |  |  | 23091 | $precomp_bm[$j] = ($precomp_bm[$j-1] * $bm * $bm) % $n; | 
| 5047 |  |  |  |  |  |  | } | 
| 5048 | 2 |  |  |  |  | 1313 | $pa->bmodpow($q, $n); | 
| 5049 | 2 |  |  |  |  | 10213 | my $j = 1; | 
| 5050 | 2 |  |  |  |  | 9 | $pc_beg = $q+1; | 
| 5051 | 2 |  |  |  |  | 4 | $pc_end = $pc_beg + 100_000; | 
| 5052 | 2 |  |  |  |  | 7 | while (1) { | 
| 5053 | 2 | 50 |  |  |  | 9 | $pc_end = $B2 if $pc_end > $B2; | 
| 5054 | 2 |  |  |  |  | 6 | @bprimes = @{ primes($pc_beg, $pc_end) }; | 
|  | 2 |  |  |  |  | 15 |  | 
| 5055 | 2 |  |  |  |  | 32 | foreach my $i (0 .. $#bprimes) { | 
| 5056 | 896 |  |  |  |  | 2170 | my $diff = $bprimes[$i] - $q; | 
| 5057 | 896 |  |  |  |  | 1405 | $q = $bprimes[$i]; | 
| 5058 | 896 |  |  |  |  | 1527 | my $qdiff = ($diff >> 1) - 1; | 
| 5059 | 896 | 100 |  |  |  | 2122 | if (!defined $precomp_bm[$qdiff]) { | 
| 5060 | 3 |  |  |  |  | 18 | $precomp_bm[$qdiff] = $bm->copy->bmodpow($diff, $n); | 
| 5061 |  |  |  |  |  |  | } | 
| 5062 | 896 |  |  |  |  | 9104 | $pa->bmul($precomp_bm[$qdiff])->bmod($n); | 
| 5063 | 896 | 50 |  |  |  | 342129 | if ($pa == 0) { push @factors, $n; return @factors; } | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 5064 | 896 |  |  |  |  | 152753 | $b->bmul($pa-1); | 
| 5065 | 896 | 100 |  |  |  | 2049562 | if (($j++ % 128) == 0) { | 
| 5066 | 7 |  |  |  |  | 44 | $b->bmod($n); | 
| 5067 | 7 |  |  |  |  | 53209 | $f = Math::BigInt::bgcd( $b, $n ); | 
| 5068 | 7 | 100 |  |  |  | 21090 | last if !$f->is_one; | 
| 5069 |  |  |  |  |  |  | } | 
| 5070 |  |  |  |  |  |  | } | 
| 5071 | 2 | 50 | 33 |  |  | 45 | last if !$f->is_one || $pc_end >= $B2; | 
| 5072 | 0 |  |  |  |  | 0 | $pc_beg = $pc_end+1; | 
| 5073 | 0 |  |  |  |  | 0 | $pc_end += 500_000; | 
| 5074 |  |  |  |  |  |  | } | 
| 5075 | 2 |  |  |  |  | 39 | $f = Math::BigInt::bgcd( $b, $n ); | 
| 5076 |  |  |  |  |  |  | } | 
| 5077 | 2 |  |  |  |  | 5045 | return _found_factor($f, $n, "pminus1", @factors); | 
| 5078 |  |  |  |  |  |  | } | 
| 5079 |  |  |  |  |  |  |  | 
| 5080 |  |  |  |  |  |  | sub holf_factor { | 
| 5081 | 3 |  |  | 3 | 0 | 6073 | my($n, $rounds, $startrounds) = @_; | 
| 5082 | 3 | 50 |  |  |  | 16 | $rounds = 64*1024*1024 unless defined $rounds; | 
| 5083 | 3 | 50 |  |  |  | 13 | $startrounds = 1 unless defined $startrounds; | 
| 5084 | 3 | 50 |  |  |  | 11 | $startrounds = 1 if $startrounds < 1; | 
| 5085 |  |  |  |  |  |  |  | 
| 5086 | 3 |  |  |  |  | 12 | my @factors = _basic_factor($n); | 
| 5087 | 3 | 50 |  |  |  | 13 | return @factors if $n < 4; | 
| 5088 |  |  |  |  |  |  |  | 
| 5089 | 3 | 100 |  |  |  | 305 | if ( ref($n) eq 'Math::BigInt' ) { | 
| 5090 | 2 |  |  |  |  | 9 | for my $i ($startrounds .. $rounds) { | 
| 5091 | 2 |  |  |  |  | 10 | my $ni = $n->copy->bmul($i); | 
| 5092 | 2 |  |  |  |  | 383 | my $s = $ni->copy->bsqrt->bfloor->as_int; | 
| 5093 | 2 | 50 |  |  |  | 2495 | if ($s * $s == $ni) { | 
| 5094 |  |  |  |  |  |  | # s^2 = n*i, so m = s^2 mod n = 0.  Hence f = GCD(n, s) = GCD(n, n*i) | 
| 5095 | 0 |  |  |  |  | 0 | my $f = Math::BigInt::bgcd($ni, $n); | 
| 5096 | 0 |  |  |  |  | 0 | return _found_factor($f, $n, "HOLF", @factors); | 
| 5097 |  |  |  |  |  |  | } | 
| 5098 | 2 |  |  |  |  | 386 | $s->binc; | 
| 5099 | 2 |  |  |  |  | 91 | my $m = ($s * $s) - $ni; | 
| 5100 |  |  |  |  |  |  | # Check for perfect square | 
| 5101 | 2 |  |  |  |  | 620 | my $mc = _bigint_to_int($m & 31); | 
| 5102 | 2 | 0 | 33 |  |  | 92 | next unless $mc==0||$mc==1||$mc==4||$mc==9||$mc==16||$mc==17||$mc==25; | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
| 5103 | 2 |  |  |  |  | 10 | my $f = $m->copy->bsqrt->bfloor->as_int; | 
| 5104 | 2 | 50 |  |  |  | 216 | next unless ($f*$f) == $m; | 
| 5105 | 2 | 50 |  |  |  | 218 | $f = Math::BigInt::bgcd( ($s > $f) ? $s-$f : $f-$s,  $n); | 
| 5106 | 2 |  |  |  |  | 905 | return _found_factor($f, $n, "HOLF ($i rounds)", @factors); | 
| 5107 |  |  |  |  |  |  | } | 
| 5108 |  |  |  |  |  |  | } else { | 
| 5109 | 1 |  |  |  |  | 5 | for my $i ($startrounds .. $rounds) { | 
| 5110 | 3 |  |  |  |  | 8 | my $s = int(sqrt($n * $i)); | 
| 5111 | 3 | 50 |  |  |  | 7 | $s++ if ($s * $s) != ($n * $i); | 
| 5112 | 3 | 50 |  |  |  | 7 | my $m = ($s < MPU_HALFWORD) ? ($s*$s) % $n : _mulmod($s, $s, $n); | 
| 5113 |  |  |  |  |  |  | # Check for perfect square | 
| 5114 | 3 |  |  |  |  | 4 | my $mc = $m & 31; | 
| 5115 | 3 | 50 | 33 |  |  | 29 | next unless $mc==0||$mc==1||$mc==4||$mc==9||$mc==16||$mc==17||$mc==25; | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
| 5116 | 1 |  |  |  |  | 2 | my $f = int(sqrt($m)); | 
| 5117 | 1 | 50 |  |  |  | 67 | next unless $f*$f == $m; | 
| 5118 | 1 |  |  |  |  | 6 | $f = _gcd_ui($s - $f,  $n); | 
| 5119 | 1 |  |  |  |  | 6 | return _found_factor($f, $n, "HOLF ($i rounds)", @factors); | 
| 5120 |  |  |  |  |  |  | } | 
| 5121 |  |  |  |  |  |  | } | 
| 5122 | 0 |  |  |  |  | 0 | push @factors, $n; | 
| 5123 | 0 |  |  |  |  | 0 | @factors; | 
| 5124 |  |  |  |  |  |  | } | 
| 5125 |  |  |  |  |  |  |  | 
| 5126 |  |  |  |  |  |  | sub fermat_factor { | 
| 5127 | 2 |  |  | 2 | 0 | 2780 | my($n, $rounds) = @_; | 
| 5128 | 2 | 50 |  |  |  | 10 | $rounds = 64*1024*1024 unless defined $rounds; | 
| 5129 |  |  |  |  |  |  |  | 
| 5130 | 2 |  |  |  |  | 11 | my @factors = _basic_factor($n); | 
| 5131 | 2 | 50 |  |  |  | 8 | return @factors if $n < 4; | 
| 5132 |  |  |  |  |  |  |  | 
| 5133 | 2 | 100 |  |  |  | 126 | if ( ref($n) eq 'Math::BigInt' ) { | 
| 5134 | 1 |  |  |  |  | 6 | my $pa = $n->copy->bsqrt->bfloor->as_int; | 
| 5135 | 1 | 50 |  |  |  | 1407 | return _found_factor($pa, $n, "Fermat", @factors) if $pa*$pa == $n; | 
| 5136 | 1 |  |  |  |  | 188 | $pa++; | 
| 5137 | 1 |  |  |  |  | 55 | my $b2 = $pa*$pa - $n; | 
| 5138 | 1 |  |  |  |  | 298 | my $lasta = $pa + $rounds; | 
| 5139 | 1 |  |  |  |  | 177 | while ($pa <= $lasta) { | 
| 5140 | 1 |  |  |  |  | 48 | my $mc = _bigint_to_int($b2 & 31); | 
| 5141 | 1 | 0 | 33 |  |  | 36 | if ($mc==0||$mc==1||$mc==4||$mc==9||$mc==16||$mc==17||$mc==25) { | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
| 5142 | 1 |  |  |  |  | 4 | my $s = $b2->copy->bsqrt->bfloor->as_int; | 
| 5143 | 1 | 50 |  |  |  | 109 | if ($s*$s == $b2) { | 
| 5144 | 1 |  |  |  |  | 106 | my $i = $pa-($lasta-$rounds)+1; | 
| 5145 | 1 |  |  |  |  | 477 | return _found_factor($pa - $s, $n, "Fermat ($i rounds)", @factors); | 
| 5146 |  |  |  |  |  |  | } | 
| 5147 |  |  |  |  |  |  | } | 
| 5148 | 0 |  |  |  |  | 0 | $pa++; | 
| 5149 | 0 |  |  |  |  | 0 | $b2 = $pa*$pa-$n; | 
| 5150 |  |  |  |  |  |  | } | 
| 5151 |  |  |  |  |  |  | } else { | 
| 5152 | 1 |  |  |  |  | 3 | my $pa = int(sqrt($n)); | 
| 5153 | 1 | 50 |  |  |  | 4 | return _found_factor($pa, $n, "Fermat", @factors) if $pa*$pa == $n; | 
| 5154 | 1 |  |  |  |  | 2 | $pa++; | 
| 5155 | 1 |  |  |  |  | 4 | my $b2 = $pa*$pa - $n; | 
| 5156 | 1 |  |  |  |  | 2 | my $lasta = $pa + $rounds; | 
| 5157 | 1 |  |  |  |  | 3 | while ($pa <= $lasta) { | 
| 5158 | 2 |  |  |  |  | 6 | my $mc = $b2 & 31; | 
| 5159 | 2 | 100 | 33 |  |  | 22 | if ($mc==0||$mc==1||$mc==4||$mc==9||$mc==16||$mc==17||$mc==25) { | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
| 5160 | 1 |  |  |  |  | 2 | my $s = int(sqrt($b2)); | 
| 5161 | 1 | 50 |  |  |  | 3 | if ($s*$s == $b2) { | 
| 5162 | 1 |  |  |  |  | 3 | my $i = $pa-($lasta-$rounds)+1; | 
| 5163 | 1 |  |  |  |  | 13 | return _found_factor($pa - $s, $n, "Fermat ($i rounds)", @factors); | 
| 5164 |  |  |  |  |  |  | } | 
| 5165 |  |  |  |  |  |  | } | 
| 5166 | 1 |  |  |  |  | 2 | $pa++; | 
| 5167 | 1 |  |  |  |  | 2 | $b2 = $pa*$pa-$n; | 
| 5168 |  |  |  |  |  |  | } | 
| 5169 |  |  |  |  |  |  | } | 
| 5170 | 0 |  |  |  |  | 0 | push @factors, $n; | 
| 5171 | 0 |  |  |  |  | 0 | @factors; | 
| 5172 |  |  |  |  |  |  | } | 
| 5173 |  |  |  |  |  |  |  | 
| 5174 |  |  |  |  |  |  |  | 
| 5175 |  |  |  |  |  |  | sub ecm_factor { | 
| 5176 | 7 |  |  | 7 | 0 | 4914 | my($n, $B1, $B2, $ncurves) = @_; | 
| 5177 | 7 |  |  |  |  | 37 | _validate_positive_integer($n); | 
| 5178 |  |  |  |  |  |  |  | 
| 5179 | 7 |  |  |  |  | 38 | my @factors = _basic_factor($n); | 
| 5180 | 7 | 50 |  |  |  | 34 | return @factors if $n < 4; | 
| 5181 |  |  |  |  |  |  |  | 
| 5182 | 7 | 50 |  |  |  | 824 | if ($Math::Prime::Util::_GMPfunc{"ecm_factor"}) { | 
| 5183 | 0 | 0 |  |  |  | 0 | $B1 = 0 if !defined $B1; | 
| 5184 | 0 | 0 |  |  |  | 0 | $ncurves = 0 if !defined $ncurves; | 
| 5185 | 0 |  |  |  |  | 0 | my @ef = Math::Prime::Util::GMP::ecm_factor($n, $B1, $ncurves); | 
| 5186 | 0 | 0 |  |  |  | 0 | if (@ef > 1) { | 
| 5187 | 0 |  |  |  |  | 0 | my $ecmfac = Math::Prime::Util::_reftyped($n, $ef[-1]); | 
| 5188 | 0 |  |  |  |  | 0 | return _found_factor($ecmfac, $n, "ECM (GMP) B1=$B1 curves $ncurves", @factors); | 
| 5189 |  |  |  |  |  |  | } | 
| 5190 | 0 |  |  |  |  | 0 | push @factors, $n; | 
| 5191 | 0 |  |  |  |  | 0 | return @factors; | 
| 5192 |  |  |  |  |  |  | } | 
| 5193 |  |  |  |  |  |  |  | 
| 5194 | 7 | 100 |  |  |  | 27 | $ncurves = 10 unless defined $ncurves; | 
| 5195 |  |  |  |  |  |  |  | 
| 5196 | 7 | 100 |  |  |  | 26 | if (!defined $B1) { | 
| 5197 | 1 |  |  |  |  | 6 | for my $mul (1, 10, 100, 1000, 10_000, 100_000, 1_000_000) { | 
| 5198 | 1 |  |  |  |  | 4 | $B1 = 100 * $mul; | 
| 5199 | 1 |  |  |  |  | 2 | $B2 = 10*$B1; | 
| 5200 |  |  |  |  |  |  | #warn "Trying ecm with $B1 / $B2\n"; | 
| 5201 | 1 |  |  |  |  | 17 | my @nf = ecm_factor($n, $B1, $B2, $ncurves); | 
| 5202 | 1 | 50 |  |  |  | 5 | if (scalar @nf > 1) { | 
| 5203 | 1 |  |  |  |  | 4 | push @factors, @nf; | 
| 5204 | 1 |  |  |  |  | 10 | return @factors; | 
| 5205 |  |  |  |  |  |  | } | 
| 5206 |  |  |  |  |  |  | } | 
| 5207 | 0 |  |  |  |  | 0 | push @factors, $n; | 
| 5208 | 0 |  |  |  |  | 0 | return @factors; | 
| 5209 |  |  |  |  |  |  | } | 
| 5210 |  |  |  |  |  |  |  | 
| 5211 | 6 | 50 |  |  |  | 24 | $B2 = 10*$B1 unless defined $B2; | 
| 5212 | 6 |  |  |  |  | 30 | my $sqrt_b1 = int(sqrt($B1)+1); | 
| 5213 |  |  |  |  |  |  |  | 
| 5214 |  |  |  |  |  |  | # Affine code.  About 3x slower than the projective, and no stage 2. | 
| 5215 |  |  |  |  |  |  | # | 
| 5216 |  |  |  |  |  |  | #if (!defined $Math::Prime::Util::ECAffinePoint::VERSION) { | 
| 5217 |  |  |  |  |  |  | #  eval { require Math::Prime::Util::ECAffinePoint; 1; } | 
| 5218 |  |  |  |  |  |  | #  or do { croak "Cannot load Math::Prime::Util::ECAffinePoint"; }; | 
| 5219 |  |  |  |  |  |  | #} | 
| 5220 |  |  |  |  |  |  | #my @bprimes = @{ primes(2, $B1) }; | 
| 5221 |  |  |  |  |  |  | #my $irandf = Math::Prime::Util::_get_rand_func(); | 
| 5222 |  |  |  |  |  |  | #foreach my $curve (1 .. $ncurves) { | 
| 5223 |  |  |  |  |  |  | #  my $a = $irandf->($n-1); | 
| 5224 |  |  |  |  |  |  | #  my $b = 1; | 
| 5225 |  |  |  |  |  |  | #  my $ECP = Math::Prime::Util::ECAffinePoint->new($a, $b, $n, 0, 1); | 
| 5226 |  |  |  |  |  |  | #  foreach my $q (@bprimes) { | 
| 5227 |  |  |  |  |  |  | #    my $k = $q; | 
| 5228 |  |  |  |  |  |  | #    if ($k < $sqrt_b1) { | 
| 5229 |  |  |  |  |  |  | #      my $kmin = int($B1 / $q); | 
| 5230 |  |  |  |  |  |  | #      while ($k <= $kmin) { $k *= $q; } | 
| 5231 |  |  |  |  |  |  | #    } | 
| 5232 |  |  |  |  |  |  | #    $ECP->mul($k); | 
| 5233 |  |  |  |  |  |  | #    my $f = $ECP->f; | 
| 5234 |  |  |  |  |  |  | #    if ($f != 1) { | 
| 5235 |  |  |  |  |  |  | #      last if $f == $n; | 
| 5236 |  |  |  |  |  |  | #      warn "ECM found factors with B1 = $B1 in curve $curve\n"; | 
| 5237 |  |  |  |  |  |  | #      return _found_factor($f, $n, "ECM B1=$B1 curve $curve", @factors); | 
| 5238 |  |  |  |  |  |  | #    } | 
| 5239 |  |  |  |  |  |  | #    last if $ECP->is_infinity; | 
| 5240 |  |  |  |  |  |  | #  } | 
| 5241 |  |  |  |  |  |  | #} | 
| 5242 |  |  |  |  |  |  |  | 
| 5243 | 6 |  |  |  |  | 1914 | require Math::Prime::Util::ECProjectivePoint; | 
| 5244 | 6 |  |  |  |  | 1388 | require Math::Prime::Util::RandomPrimes; | 
| 5245 |  |  |  |  |  |  |  | 
| 5246 |  |  |  |  |  |  | # With multiple curves, it's better to get all the primes at once. | 
| 5247 |  |  |  |  |  |  | # The downside is this can kill memory with a very large B1. | 
| 5248 | 6 |  |  |  |  | 18 | my @bprimes = @{ primes(3, $B1) }; | 
|  | 6 |  |  |  |  | 32 |  | 
| 5249 | 6 |  |  |  |  | 29 | foreach my $q (@bprimes) { | 
| 5250 | 33 | 100 |  |  |  | 71 | last if $q > $sqrt_b1; | 
| 5251 | 27 |  |  |  |  | 71 | my($k,$kmin) = ($q, int($B1/$q)); | 
| 5252 | 27 |  |  |  |  | 58 | while ($k <= $kmin) { $k *= $q; } | 
|  | 40 |  |  |  |  | 76 |  | 
| 5253 | 27 |  |  |  |  | 43 | $q = $k; | 
| 5254 |  |  |  |  |  |  | } | 
| 5255 | 6 | 50 |  |  |  | 30 | my @b2primes = ($B2 > $B1) ? @{primes($B1+1, $B2)} : (); | 
|  | 6 |  |  |  |  | 21 |  | 
| 5256 |  |  |  |  |  |  |  | 
| 5257 | 6 |  |  |  |  | 143 | foreach my $curve (1 .. $ncurves) { | 
| 5258 | 24 |  |  |  |  | 2377 | my $sigma = Math::Prime::Util::urandomm($n-6) + 6; | 
| 5259 | 24 |  |  |  |  | 9028 | my ($u, $v) = ( ($sigma*$sigma - 5) % $n, (4 * $sigma) % $n ); | 
| 5260 | 24 |  |  |  |  | 23723 | my ($x, $z) = ( ($u*$u*$u) % $n,  ($v*$v*$v) % $n ); | 
| 5261 | 24 |  |  |  |  | 31034 | my $cb = (4 * $x * $v) % $n; | 
| 5262 | 24 |  |  |  |  | 13880 | my $ca = ( (($v-$u)**3) * (3*$u + $v) ) % $n; | 
| 5263 | 24 |  |  |  |  | 36946 | my $f = Math::BigInt::bgcd( $cb, $n ); | 
| 5264 | 24 | 50 |  |  |  | 80592 | $f = Math::BigInt::bgcd( $z, $n ) if $f == 1; | 
| 5265 | 24 | 50 |  |  |  | 81451 | next if $f == $n; | 
| 5266 | 24 | 50 |  |  |  | 1090 | return _found_factor($f,$n, "ECM B1=$B1 curve $curve", @factors) if $f != 1; | 
| 5267 | 24 | 100 |  |  |  | 2838 | $cb = Math::BigInt->new("$cb") unless ref($cb) eq 'Math::BigInt'; | 
| 5268 | 24 |  |  |  |  | 130 | $u = $cb->copy->bmodinv($n); | 
| 5269 | 24 |  |  |  |  | 116947 | $ca = (($ca*$u) - 2) % $n; | 
| 5270 |  |  |  |  |  |  |  | 
| 5271 | 24 |  |  |  |  | 16136 | my $ECP = Math::Prime::Util::ECProjectivePoint->new($ca, $n, $x, $z); | 
| 5272 | 24 |  |  |  |  | 82 | my $fm = $n-$n+1; | 
| 5273 | 24 |  |  |  |  | 6006 | my $i = 15; | 
| 5274 |  |  |  |  |  |  |  | 
| 5275 | 24 |  |  |  |  | 123 | for (my $q = 2; $q < $B1; $q *= 2) { $ECP->double(); } | 
|  | 174 |  |  |  |  | 546 |  | 
| 5276 | 24 |  |  |  |  | 112 | foreach my $k (@bprimes) { | 
| 5277 | 2857 |  |  |  |  | 29345 | $ECP->mul($k); | 
| 5278 | 2857 |  |  |  |  | 12159 | $fm = ($fm * $ECP->x() ) % $n; | 
| 5279 | 2857 | 100 |  |  |  | 1258380 | if ($i++ % 32 == 0) { | 
| 5280 | 86 |  |  |  |  | 521 | $f = Math::BigInt::bgcd($fm, $n); | 
| 5281 | 86 | 100 |  |  |  | 304486 | last if $f != 1; | 
| 5282 |  |  |  |  |  |  | } | 
| 5283 |  |  |  |  |  |  | } | 
| 5284 | 24 |  |  |  |  | 290 | $f = Math::BigInt::bgcd($fm, $n); | 
| 5285 | 24 | 50 |  |  |  | 81518 | next if $f == $n; | 
| 5286 |  |  |  |  |  |  |  | 
| 5287 | 24 | 100 | 66 |  |  | 1421 | if ($f == 1 && $B2 > $B1) { # BEGIN STAGE 2 | 
| 5288 | 22 | 100 |  |  |  | 3388 | my $D = int(sqrt($B2/2));  $D++ if $D % 2; | 
|  | 22 |  |  |  |  | 98 |  | 
| 5289 | 22 |  |  |  |  | 71 | my $one = $n - $n + 1; | 
| 5290 | 22 |  |  |  |  | 5986 | my $g = $one; | 
| 5291 |  |  |  |  |  |  |  | 
| 5292 | 22 |  |  |  |  | 142 | my $S2P = $ECP->copy->normalize; | 
| 5293 | 22 |  |  |  |  | 112 | $f = $S2P->f; | 
| 5294 | 22 | 50 |  |  |  | 106 | if ($f != 1) { | 
| 5295 | 0 | 0 |  |  |  | 0 | next if $f == $n; | 
| 5296 |  |  |  |  |  |  | #warn "ECM S2 normalize f=$f\n" if $f != 1; | 
| 5297 | 0 |  |  |  |  | 0 | return _found_factor($f, $n, "ECM S2 B1=$B1 curve $curve"); | 
| 5298 |  |  |  |  |  |  | } | 
| 5299 | 22 |  |  |  |  | 2597 | my $S2x = $S2P->x; | 
| 5300 | 22 |  |  |  |  | 90 | my $S2d = $S2P->d; | 
| 5301 | 22 |  |  |  |  | 78 | my @nqx = ($n-$n, $S2x); | 
| 5302 |  |  |  |  |  |  |  | 
| 5303 | 22 |  |  |  |  | 2604 | foreach my $i (2 .. 2*$D) { | 
| 5304 | 1838 |  |  |  |  | 798177 | my($x2, $z2); | 
| 5305 | 1838 | 100 |  |  |  | 5133 | if ($i % 2) { | 
| 5306 | 909 |  |  |  |  | 5312 | ($x2, $z2) = Math::Prime::Util::ECProjectivePoint::_addx($nqx[($i-1)/2], $nqx[($i+1)/2], $S2x, $n); | 
| 5307 |  |  |  |  |  |  | } else { | 
| 5308 | 929 |  |  |  |  | 4320 | ($x2, $z2) = Math::Prime::Util::ECProjectivePoint::_double($nqx[$i/2], $one, $n, $S2d); | 
| 5309 |  |  |  |  |  |  | } | 
| 5310 | 1838 |  |  |  |  | 848511 | $nqx[$i] = $x2; | 
| 5311 |  |  |  |  |  |  | #($f, $u, undef) = _extended_gcd($z2, $n); | 
| 5312 | 1838 |  |  |  |  | 5370 | $f = Math::BigInt::bgcd( $z2, $n ); | 
| 5313 | 1838 | 100 |  |  |  | 6100658 | last if $f != 1; | 
| 5314 | 1836 |  |  |  |  | 221098 | $u = $z2->copy->bmodinv($n); | 
| 5315 | 1836 |  |  |  |  | 8790206 | $nqx[$i] = ($x2 * $u) % $n; | 
| 5316 |  |  |  |  |  |  | } | 
| 5317 | 22 | 100 |  |  |  | 9000 | if ($f != 1) { | 
| 5318 | 2 | 50 |  |  |  | 191 | next if $f == $n; | 
| 5319 |  |  |  |  |  |  | #warn "ECM S2 1: B1 $B1 B2 $B2 curve $curve f=$f\n"; | 
| 5320 | 2 |  |  |  |  | 142 | return _found_factor($f, $n, "ECM S2 B1=$B1 curve $curve", @factors); | 
| 5321 |  |  |  |  |  |  | } | 
| 5322 |  |  |  |  |  |  |  | 
| 5323 | 20 |  |  |  |  | 2449 | $x = $nqx[2*$D-1]; | 
| 5324 | 20 |  |  |  |  | 119 | my $m = 1; | 
| 5325 | 20 |  |  |  |  | 110 | while ($m < ($B2+$D)) { | 
| 5326 | 882 | 100 |  |  |  | 2405 | if ($m != 1) { | 
| 5327 | 862 |  |  |  |  | 1611 | my $oldx = $S2x; | 
| 5328 | 862 |  |  |  |  | 3652 | my ($x1, $z1) = Math::Prime::Util::ECProjectivePoint::_addx($nqx[2*$D], $S2x, $x, $n); | 
| 5329 | 862 |  |  |  |  | 804102 | $f = Math::BigInt::bgcd( $z1, $n ); | 
| 5330 | 862 | 50 |  |  |  | 2880549 | last if $f != 1; | 
| 5331 | 862 |  |  |  |  | 101627 | $u = $z1->copy->bmodinv($n); | 
| 5332 | 862 |  |  |  |  | 4167315 | $S2x = ($x1 * $u) % $n; | 
| 5333 | 862 |  |  |  |  | 377818 | $x = $oldx; | 
| 5334 | 862 | 50 |  |  |  | 3394 | last if $f != 1; | 
| 5335 |  |  |  |  |  |  | } | 
| 5336 | 882 | 100 |  |  |  | 101016 | if ($m+$D > $B1) { | 
| 5337 | 722 | 100 |  |  |  | 3142 | my @p = grep { $_ >= $m-$D && $_ <= $m+$D } @b2primes; | 
|  | 337305 |  |  |  |  | 735678 |  | 
| 5338 | 722 |  |  |  |  | 1941 | foreach my $i (@p) { | 
| 5339 | 4950 | 100 |  |  |  | 2453819 | last if $i >= $m; | 
| 5340 | 4245 |  |  |  |  | 14708 | $g = ($g * ($S2x - $nqx[$m+$D-$i])) % $n; | 
| 5341 |  |  |  |  |  |  | } | 
| 5342 | 722 |  |  |  |  | 11659 | foreach my $i (@p) { | 
| 5343 | 8736 | 100 |  |  |  | 1628080 | next unless $i > $m; | 
| 5344 | 4281 | 100 | 100 |  |  | 14161 | next if $i > ($m+$m) || is_prime($m+$m-$i); | 
| 5345 | 3324 |  |  |  |  | 11117 | $g = ($g * ($S2x - $nqx[$i-$m])) % $n; | 
| 5346 |  |  |  |  |  |  | } | 
| 5347 | 722 |  |  |  |  | 314340 | $f = Math::BigInt::bgcd($g, $n); | 
| 5348 |  |  |  |  |  |  | #warn "ECM S2 3: found $f in stage 2\n" if $f != 1; | 
| 5349 | 722 | 100 |  |  |  | 2398420 | last if $f != 1; | 
| 5350 |  |  |  |  |  |  | } | 
| 5351 | 880 |  |  |  |  | 90624 | $m += 2*$D; | 
| 5352 |  |  |  |  |  |  | } | 
| 5353 |  |  |  |  |  |  | } # END STAGE 2 | 
| 5354 |  |  |  |  |  |  |  | 
| 5355 | 22 | 50 |  |  |  | 863 | next if $f == $n; | 
| 5356 | 22 | 100 |  |  |  | 987 | if ($f != 1) { | 
| 5357 |  |  |  |  |  |  | #warn "ECM found factors with B1 = $B1 in curve $curve\n"; | 
| 5358 | 4 |  |  |  |  | 500 | return _found_factor($f, $n, "ECM B1=$B1 curve $curve", @factors); | 
| 5359 |  |  |  |  |  |  | } | 
| 5360 |  |  |  |  |  |  | # end of curve loop | 
| 5361 |  |  |  |  |  |  | } | 
| 5362 | 0 |  |  |  |  | 0 | push @factors, $n; | 
| 5363 | 0 |  |  |  |  | 0 | @factors; | 
| 5364 |  |  |  |  |  |  | } | 
| 5365 |  |  |  |  |  |  |  | 
| 5366 |  |  |  |  |  |  | sub divisors { | 
| 5367 | 38 |  |  | 38 | 0 | 1785 | my($n) = @_; | 
| 5368 | 38 |  |  |  |  | 181 | _validate_positive_integer($n); | 
| 5369 | 38 |  |  |  |  | 92 | my(@factors, @d, @t); | 
| 5370 |  |  |  |  |  |  |  | 
| 5371 |  |  |  |  |  |  | # In scalar context, returns sigma_0(n).  Very fast. | 
| 5372 | 38 | 50 |  |  |  | 157 | return Math::Prime::Util::divisor_sum($n,0) unless wantarray; | 
| 5373 | 38 | 0 |  |  |  | 119 | return ($n == 0) ? (0,1) : (1)  if $n <= 1; | 
|  |  | 50 |  |  |  |  |  | 
| 5374 |  |  |  |  |  |  |  | 
| 5375 | 38 | 50 |  |  |  | 4385 | if ($Math::Prime::Util::_GMPfunc{"divisors"}) { | 
| 5376 |  |  |  |  |  |  | # This trips an erroneous compile time error without the eval. | 
| 5377 | 0 |  |  |  |  | 0 | eval ' @d = Math::Prime::Util::GMP::divisors($n); ';  ## no critic qw(ProhibitStringyEval) | 
| 5378 | 0 | 0 |  |  |  | 0 | @d = map { $_ <= ~0 ? $_ : ref($n)->new($_) } @d   if ref($n); | 
|  | 0 | 0 |  |  |  | 0 |  | 
| 5379 | 0 |  |  |  |  | 0 | return @d; | 
| 5380 |  |  |  |  |  |  | } | 
| 5381 |  |  |  |  |  |  |  | 
| 5382 | 38 |  |  |  |  | 208 | @factors = Math::Prime::Util::factor($n); | 
| 5383 | 38 | 50 |  |  |  | 192 | return (1,$n) if scalar @factors == 1; | 
| 5384 |  |  |  |  |  |  |  | 
| 5385 | 38 |  |  |  |  | 175 | my $bigint = ref($n); | 
| 5386 | 38 | 50 |  |  |  | 150 | @factors = map { $bigint->new("$_") } @factors  if $bigint; | 
|  | 225 |  |  |  |  | 9694 |  | 
| 5387 | 38 | 50 |  |  |  | 2494 | @d = $bigint ? ($bigint->new(1)) : (1); | 
| 5388 |  |  |  |  |  |  |  | 
| 5389 | 38 |  |  |  |  | 1681 | while (my $p = shift @factors) { | 
| 5390 | 191 |  |  |  |  | 6737 | my $e = 1; | 
| 5391 | 191 |  | 100 |  |  | 677 | while (@factors && $p == $factors[0]) { $e++; shift(@factors); } | 
|  | 34 |  |  |  |  | 1413 |  | 
|  | 34 |  |  |  |  | 157 |  | 
| 5392 | 191 |  |  |  |  | 5414 | push @d,  @t = map { $_ * $p } @d;               # multiply through once | 
|  | 2648 |  |  |  |  | 230570 |  | 
| 5393 | 191 |  |  |  |  | 18951 | push @d,  @t = map { $_ * $p } @t   for 2 .. $e; # repeat | 
|  | 34 |  |  |  |  | 1231 |  | 
| 5394 |  |  |  |  |  |  | } | 
| 5395 |  |  |  |  |  |  |  | 
| 5396 | 38 | 100 |  |  |  | 266 | @d = map { $_ <= INTMAX ? _bigint_to_int($_) : $_ } @d   if $bigint; | 
|  | 2720 | 50 |  |  |  | 86850 |  | 
| 5397 | 38 |  |  |  |  | 5481 | @d = sort { $a <=> $b } @d; | 
|  | 9181 |  |  |  |  | 54931 |  | 
| 5398 | 38 |  |  |  |  | 1108 | @d; | 
| 5399 |  |  |  |  |  |  | } | 
| 5400 |  |  |  |  |  |  |  | 
| 5401 |  |  |  |  |  |  |  | 
| 5402 |  |  |  |  |  |  | sub chebyshev_theta { | 
| 5403 | 2 |  |  | 2 | 0 | 8 | my($n,$low) = @_; | 
| 5404 | 2 | 100 |  |  |  | 9 | $low = 2 unless defined $low; | 
| 5405 | 2 |  |  |  |  | 7 | my($sum,$high) = (0.0, 0); | 
| 5406 | 2 |  |  |  |  | 8 | while ($low <= $n) { | 
| 5407 | 2 |  |  |  |  | 6 | $high = $low + 1e6; | 
| 5408 | 2 | 50 |  |  |  | 7 | $high = $n if $high > $n; | 
| 5409 | 2 |  |  |  |  | 5 | $sum += log($_) for @{primes($low,$high)}; | 
|  | 2 |  |  |  |  | 10 |  | 
| 5410 | 2 |  |  |  |  | 40 | $low = $high+1; | 
| 5411 |  |  |  |  |  |  | } | 
| 5412 | 2 |  |  |  |  | 10 | $sum; | 
| 5413 |  |  |  |  |  |  | } | 
| 5414 |  |  |  |  |  |  |  | 
| 5415 |  |  |  |  |  |  | sub chebyshev_psi { | 
| 5416 | 1 |  |  | 1 | 0 | 4 | my($n) = @_; | 
| 5417 | 1 | 50 |  |  |  | 5 | return 0 if $n <= 1; | 
| 5418 | 1 |  |  |  |  | 6 | my ($sum, $logn, $sqrtn) = (0.0, log($n), int(sqrt($n))); | 
| 5419 |  |  |  |  |  |  |  | 
| 5420 |  |  |  |  |  |  | # Sum the log of prime powers first | 
| 5421 | 1 |  |  |  |  | 2 | for my $p (@{primes($sqrtn)}) { | 
|  | 1 |  |  |  |  | 3 |  | 
| 5422 | 22 |  |  |  |  | 40 | my $logp = log($p); | 
| 5423 | 22 |  |  |  |  | 37 | $sum += $logp * int($logn/$logp+1e-15); | 
| 5424 |  |  |  |  |  |  | } | 
| 5425 |  |  |  |  |  |  | # The rest all have exponent 1: add them in using the segmenting theta code | 
| 5426 | 1 |  |  |  |  | 9 | $sum += chebyshev_theta($n, $sqrtn+1); | 
| 5427 |  |  |  |  |  |  |  | 
| 5428 | 1 |  |  |  |  | 15 | $sum; | 
| 5429 |  |  |  |  |  |  | } | 
| 5430 |  |  |  |  |  |  |  | 
| 5431 |  |  |  |  |  |  | sub hclassno { | 
| 5432 | 0 |  |  | 0 | 0 | 0 | my $n = shift; | 
| 5433 |  |  |  |  |  |  |  | 
| 5434 | 0 | 0 |  |  |  | 0 | return -1 if $n == 0; | 
| 5435 | 0 | 0 | 0 |  |  | 0 | return 0 if $n < 0 || ($n % 4) == 1 || ($n % 4) == 2; | 
|  |  |  | 0 |  |  |  |  | 
| 5436 | 0 | 0 |  |  |  | 0 | return 2 * (2,3,6,6,6,8,12,9,6,12,18,12,8,12,18,18,12,15,24,12,6,24,30,20,12,12,24,24,18,24)[($n>>1)-1] if $n <= 60; | 
| 5437 |  |  |  |  |  |  |  | 
| 5438 | 0 |  |  |  |  | 0 | my ($h, $square, $b, $b2) = (0, 0, $n & 1, ($n+1) >> 2); | 
| 5439 |  |  |  |  |  |  |  | 
| 5440 | 0 | 0 |  |  |  | 0 | if ($b == 0) { | 
| 5441 | 0 |  |  |  |  | 0 | my $lim = int(sqrt($b2)); | 
| 5442 | 0 | 0 |  |  |  | 0 | if (_is_perfect_square($b2)) { | 
| 5443 | 0 |  |  |  |  | 0 | $square = 1; | 
| 5444 | 0 |  |  |  |  | 0 | $lim--; | 
| 5445 |  |  |  |  |  |  | } | 
| 5446 |  |  |  |  |  |  | #$h += scalar(grep { $_ <= $lim } divisors($b2)); | 
| 5447 | 0 | 0 |  |  |  | 0 | for my $i (1 .. $lim) { $h++ unless $b2 % $i; } | 
|  | 0 |  |  |  |  | 0 |  | 
| 5448 | 0 |  |  |  |  | 0 | ($b,$b2) = (2, ($n+4) >> 2); | 
| 5449 |  |  |  |  |  |  | } | 
| 5450 | 0 |  |  |  |  | 0 | while ($b2 * 3 < $n) { | 
| 5451 | 0 | 0 |  |  |  | 0 | $h++ unless $b2 % $b; | 
| 5452 | 0 |  |  |  |  | 0 | my $lim = int(sqrt($b2)); | 
| 5453 | 0 | 0 |  |  |  | 0 | if (_is_perfect_square($b2)) { | 
| 5454 | 0 |  |  |  |  | 0 | $h++; | 
| 5455 | 0 |  |  |  |  | 0 | $lim--; | 
| 5456 |  |  |  |  |  |  | } | 
| 5457 |  |  |  |  |  |  | #$h += 2 * scalar(grep { $_ > $b && $_ <= $lim } divisors($b2)); | 
| 5458 | 0 | 0 |  |  |  | 0 | for my $i ($b+1 .. $lim) { $h += 2 unless $b2 % $i; } | 
|  | 0 |  |  |  |  | 0 |  | 
| 5459 | 0 |  |  |  |  | 0 | $b += 2; | 
| 5460 | 0 |  |  |  |  | 0 | $b2 = ($n+$b*$b) >> 2; | 
| 5461 |  |  |  |  |  |  | } | 
| 5462 | 0 | 0 |  |  |  | 0 | return (($b2*3 == $n) ? 2*(3*$h+1) : $square ? 3*(2*$h+1) : 6*$h) << 1; | 
|  |  | 0 |  |  |  |  |  | 
| 5463 |  |  |  |  |  |  | } | 
| 5464 |  |  |  |  |  |  |  | 
| 5465 |  |  |  |  |  |  | # Sigma method for prime powers | 
| 5466 |  |  |  |  |  |  | sub _taup { | 
| 5467 | 0 |  |  | 0 |  | 0 | my($p, $e, $n) = @_; | 
| 5468 | 0 |  |  |  |  | 0 | my($bp) = Math::BigInt->new("".$p); | 
| 5469 | 0 | 0 |  |  |  | 0 | if ($e == 1) { | 
| 5470 | 0 | 0 |  |  |  | 0 | return (0,1,-24,252,-1472,4830,-6048,-16744,84480)[$p] if $p <= 8; | 
| 5471 | 0 |  |  |  |  | 0 | my $ds5  = $bp->copy->bpow( 5)->binc();  # divisor_sum(p,5) | 
| 5472 | 0 |  |  |  |  | 0 | my $ds11 = $bp->copy->bpow(11)->binc();  # divisor_sum(p,11) | 
| 5473 | 0 |  |  |  |  | 0 | my $s    = Math::BigInt->new("".vecsum(map { vecprod(BTWO,Math::Prime::Util::divisor_sum($_,5), Math::Prime::Util::divisor_sum($p-$_,5)) } 1..($p-1)>>1)); | 
|  | 0 |  |  |  |  | 0 |  | 
| 5474 | 0 |  |  |  |  | 0 | $n = ( 65*$ds11 + 691*$ds5 - (691*252)*$s ) / 756; | 
| 5475 |  |  |  |  |  |  | } else { | 
| 5476 | 0 |  |  |  |  | 0 | my $t = Math::BigInt->new(""._taup($p,1)); | 
| 5477 | 0 |  |  |  |  | 0 | $n = $t->copy->bpow($e); | 
| 5478 | 0 | 0 |  |  |  | 0 | if ($e == 2) { | 
|  |  | 0 |  |  |  |  |  | 
| 5479 | 0 |  |  |  |  | 0 | $n -= $bp->copy->bpow(11); | 
| 5480 |  |  |  |  |  |  | } elsif ($e == 3) { | 
| 5481 | 0 |  |  |  |  | 0 | $n -= BTWO * $t * $bp->copy->bpow(11); | 
| 5482 |  |  |  |  |  |  | } else { | 
| 5483 | 0 | 0 |  |  |  | 0 | $n += vecsum( map { vecprod( ($_&1) ? - BONE : BONE, | 
|  | 0 |  |  |  |  | 0 |  | 
| 5484 |  |  |  |  |  |  | $bp->copy->bpow(11*$_), | 
| 5485 |  |  |  |  |  |  | binomial($e-$_, $e-2*$_), | 
| 5486 |  |  |  |  |  |  | $t ** ($e-2*$_) ) } 1 .. ($e>>1) ); | 
| 5487 |  |  |  |  |  |  | } | 
| 5488 |  |  |  |  |  |  | } | 
| 5489 | 0 | 0 | 0 |  |  | 0 | $n = _bigint_to_int($n) if ref($n) && $n->bacmp(BMAX) <= 0; | 
| 5490 | 0 |  |  |  |  | 0 | $n; | 
| 5491 |  |  |  |  |  |  | } | 
| 5492 |  |  |  |  |  |  |  | 
| 5493 |  |  |  |  |  |  | # Cohen's method using Hurwitz class numbers | 
| 5494 |  |  |  |  |  |  | # The two hclassno calls could be collapsed with some work | 
| 5495 |  |  |  |  |  |  | sub _tauprime { | 
| 5496 | 9 |  |  | 9 |  | 11 | my $p = shift; | 
| 5497 | 9 | 100 |  |  |  | 22 | return -24 if $p == 2; | 
| 5498 | 8 |  |  |  |  | 298 | my $sum = Math::BigInt->new(0); | 
| 5499 | 8 | 50 |  |  |  | 1080 | if ($p < (MPU_32BIT ?  300  :  1600)) { | 
| 5500 | 8 |  |  |  |  | 267 | my($p9,$pp7) = (9*$p, 7*$p*$p); | 
| 5501 | 8 |  |  |  |  | 904 | for my $t (1 .. Math::Prime::Util::sqrtint($p)) { | 
| 5502 | 36 |  |  |  |  | 3428 | my $t2 = $t * $t; | 
| 5503 | 36 |  |  |  |  | 55 | my $v = $p - $t2; | 
| 5504 | 36 |  |  |  |  | 650 | $sum += $t2**3 * (4*$t2*$t2 - $p9*$t2 + $pp7) * (Math::Prime::Util::hclassno(4*$v) + 2 * Math::Prime::Util::hclassno($v)); | 
| 5505 |  |  |  |  |  |  | } | 
| 5506 | 8 |  |  |  |  | 3076 | $p = Math::BigInt->new("$p"); | 
| 5507 |  |  |  |  |  |  | } else { | 
| 5508 | 0 |  |  |  |  | 0 | $p = Math::BigInt->new("$p"); | 
| 5509 | 0 |  |  |  |  | 0 | my($p9,$pp7) = (9*$p, 7*$p*$p); | 
| 5510 | 0 |  |  |  |  | 0 | for my $t (1 .. Math::Prime::Util::sqrtint($p)) { | 
| 5511 | 0 |  |  |  |  | 0 | my $t2 = Math::BigInt->new("$t") ** 2; | 
| 5512 | 0 |  |  |  |  | 0 | my $v = $p - $t2; | 
| 5513 | 0 |  |  |  |  | 0 | $sum += $t2**3 * (4*$t2*$t2 - $p9*$t2 + $pp7) * (Math::Prime::Util::hclassno(4*$v) + 2 * Math::Prime::Util::hclassno($v)); | 
| 5514 |  |  |  |  |  |  | } | 
| 5515 |  |  |  |  |  |  | } | 
| 5516 | 8 |  |  |  |  | 295 | 28*$p**6 - 28*$p**5 - 90*$p**4 - 35*$p**3 - 1 - 32 * ($sum/3); | 
| 5517 |  |  |  |  |  |  | } | 
| 5518 |  |  |  |  |  |  |  | 
| 5519 |  |  |  |  |  |  | # Recursive method for handling prime powers | 
| 5520 |  |  |  |  |  |  | sub _taupower { | 
| 5521 | 9 |  |  | 9 |  | 1160 | my($p, $e) = @_; | 
| 5522 | 9 | 50 |  |  |  | 18 | return 1 if $e <= 0; | 
| 5523 | 9 | 100 |  |  |  | 21 | return _tauprime($p) if $e == 1; | 
| 5524 | 2 |  |  |  |  | 7 | $p = Math::BigInt->new("$p"); | 
| 5525 | 2 |  |  |  |  | 86 | my($tp, $p11) = ( _tauprime($p), $p**11 ); | 
| 5526 | 2 | 100 |  |  |  | 5108 | return $tp ** 2 - $p11 if $e == 2; | 
| 5527 | 1 | 50 |  |  |  | 5 | return $tp ** 3 - 2 * $tp * $p11 if $e == 3; | 
| 5528 | 1 | 50 |  |  |  | 4 | return $tp ** 4 - 3 * $tp**2 * $p11 + $p11**2 if $e == 4; | 
| 5529 |  |  |  |  |  |  | # Recurse -3 | 
| 5530 | 1 |  |  |  |  | 4 | ($tp**3 - 2*$tp*$p11) * _taupower($p,$e-3) + ($p11*$p11 - $tp*$tp*$p11) * _taupower($p,$e-4); | 
| 5531 |  |  |  |  |  |  | } | 
| 5532 |  |  |  |  |  |  |  | 
| 5533 |  |  |  |  |  |  | sub ramanujan_tau { | 
| 5534 | 4 |  |  | 4 | 0 | 4999 | my $n = shift; | 
| 5535 | 4 | 50 |  |  |  | 12 | return 0 if $n <= 0; | 
| 5536 |  |  |  |  |  |  |  | 
| 5537 |  |  |  |  |  |  | # Use GMP if we have no XS or if size is small | 
| 5538 | 4 | 50 | 33 |  |  | 18 | if ($n < 100000 || !Math::Prime::Util::prime_get_config()->{'xs'}) { | 
| 5539 | 4 | 50 |  |  |  | 11 | if ($Math::Prime::Util::_GMPfunc{"ramanujan_tau"}) { | 
| 5540 | 0 |  |  |  |  | 0 | return Math::Prime::Util::_reftyped($_[0], Math::Prime::Util::GMP::ramanujan_tau($n)); | 
| 5541 |  |  |  |  |  |  | } | 
| 5542 |  |  |  |  |  |  | } | 
| 5543 |  |  |  |  |  |  |  | 
| 5544 |  |  |  |  |  |  | # _taup is faster for small numbers, but gets very slow.  It's not a huge | 
| 5545 |  |  |  |  |  |  | # deal, and the GMP code will probably get run for small inputs anyway. | 
| 5546 | 4 |  |  |  |  | 28 | vecprod(map { _taupower($_->[0],$_->[1]) } Math::Prime::Util::factor_exp($n)); | 
|  | 7 |  |  |  |  | 4822 |  | 
| 5547 |  |  |  |  |  |  | } | 
| 5548 |  |  |  |  |  |  |  | 
| 5549 |  |  |  |  |  |  | sub _Euler { | 
| 5550 | 79 |  |  | 79 |  | 149 | my($dig) = @_; | 
| 5551 |  |  |  |  |  |  | return Math::Prime::Util::GMP::Euler($dig) | 
| 5552 | 79 | 0 | 33 |  |  | 170 | if $dig > 70 && $Math::Prime::Util::_GMPfunc{"Euler"}; | 
| 5553 | 79 |  |  |  |  | 498 | '0.57721566490153286060651209008240243104215933593992359880576723488486772677766467'; | 
| 5554 |  |  |  |  |  |  | } | 
| 5555 |  |  |  |  |  |  | sub _Li2 { | 
| 5556 | 1 |  |  | 1 |  | 3 | my($dig) = @_; | 
| 5557 |  |  |  |  |  |  | return Math::Prime::Util::GMP::li(2,$dig) | 
| 5558 | 1 | 0 | 33 |  |  | 4 | if $dig > 70 && $Math::Prime::Util::_GMPfunc{"li"}; | 
| 5559 | 1 |  |  |  |  | 5 | '1.04516378011749278484458888919461313652261557815120157583290914407501320521'; | 
| 5560 |  |  |  |  |  |  | } | 
| 5561 |  |  |  |  |  |  |  | 
| 5562 |  |  |  |  |  |  | sub ExponentialIntegral { | 
| 5563 | 18 |  |  | 18 | 0 | 7685 | my($x) = @_; | 
| 5564 | 18 | 50 |  |  |  | 68 | return - MPU_INFINITY if $x == 0; | 
| 5565 | 18 | 50 |  |  |  | 45 | return 0              if $x == - MPU_INFINITY; | 
| 5566 | 18 | 50 |  |  |  | 45 | return MPU_INFINITY   if $x == MPU_INFINITY; | 
| 5567 |  |  |  |  |  |  |  | 
| 5568 | 18 | 50 |  |  |  | 44 | if ($Math::Prime::Util::_GMPfunc{"ei"}) { | 
| 5569 | 0 | 0 | 0 |  |  | 0 | $x = Math::BigFloat->new("$x") if defined $bignum::VERSION && ref($x) ne 'Math::BigFloat'; | 
| 5570 | 0 | 0 |  |  |  | 0 | return 0.0 + Math::Prime::Util::GMP::ei($x,40) if !ref($x); | 
| 5571 | 0 |  |  |  |  | 0 | my $str = Math::Prime::Util::GMP::ei($x, _find_big_acc($x)); | 
| 5572 | 0 |  |  |  |  | 0 | return $x->copy->bzero->badd($str); | 
| 5573 |  |  |  |  |  |  | } | 
| 5574 |  |  |  |  |  |  |  | 
| 5575 | 18 | 50 | 33 |  |  | 49 | $x = Math::BigFloat->new("$x") if defined $bignum::VERSION && ref($x) ne 'Math::BigFloat'; | 
| 5576 |  |  |  |  |  |  |  | 
| 5577 | 18 |  |  |  |  | 26 | my $tol = 1e-16; | 
| 5578 | 18 |  |  |  |  | 23 | my $sum = 0.0; | 
| 5579 | 18 |  |  |  |  | 31 | my($y, $t); | 
| 5580 | 18 |  |  |  |  | 25 | my $c = 0.0; | 
| 5581 | 18 |  |  |  |  | 29 | my $val; # The result from one of the four methods | 
| 5582 |  |  |  |  |  |  |  | 
| 5583 | 18 | 100 |  |  |  | 108 | if ($x < -1) { | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 5584 |  |  |  |  |  |  | # Continued fraction | 
| 5585 | 1 |  |  |  |  | 3 | my $lc = 0; | 
| 5586 | 1 |  |  |  |  | 5 | my $ld = 1 / (1 - $x); | 
| 5587 | 1 |  |  |  |  | 3 | $val = $ld * (-exp($x)); | 
| 5588 | 1 |  |  |  |  | 4 | for my $n (1 .. 100000) { | 
| 5589 | 15 |  |  |  |  | 28 | $lc = 1 / (2*$n + 1 - $x - $n*$n*$lc); | 
| 5590 | 15 |  |  |  |  | 29 | $ld = 1 / (2*$n + 1 - $x - $n*$n*$ld); | 
| 5591 | 15 |  |  |  |  | 19 | my $old = $val; | 
| 5592 | 15 |  |  |  |  | 21 | $val *= $ld/$lc; | 
| 5593 | 15 | 100 |  |  |  | 33 | last if abs($val - $old) <= ($tol * abs($val)); | 
| 5594 |  |  |  |  |  |  | } | 
| 5595 |  |  |  |  |  |  | } elsif ($x < 0) { | 
| 5596 |  |  |  |  |  |  | # Rational Chebyshev approximation | 
| 5597 | 5 |  |  |  |  | 12 | my @C6p = ( -148151.02102575750838086, | 
| 5598 |  |  |  |  |  |  | 150260.59476436982420737, | 
| 5599 |  |  |  |  |  |  | 89904.972007457256553251, | 
| 5600 |  |  |  |  |  |  | 15924.175980637303639884, | 
| 5601 |  |  |  |  |  |  | 2150.0672908092918123209, | 
| 5602 |  |  |  |  |  |  | 116.69552669734461083368, | 
| 5603 |  |  |  |  |  |  | 5.0196785185439843791020); | 
| 5604 | 5 |  |  |  |  | 12 | my @C6q = (  256664.93484897117319268, | 
| 5605 |  |  |  |  |  |  | 184340.70063353677359298, | 
| 5606 |  |  |  |  |  |  | 52440.529172056355429883, | 
| 5607 |  |  |  |  |  |  | 8125.8035174768735759866, | 
| 5608 |  |  |  |  |  |  | 750.43163907103936624165, | 
| 5609 |  |  |  |  |  |  | 40.205465640027706061433, | 
| 5610 |  |  |  |  |  |  | 1.0000000000000000000000); | 
| 5611 | 5 |  |  |  |  | 13 | my $sumn = $C6p[0]-$x*($C6p[1]-$x*($C6p[2]-$x*($C6p[3]-$x*($C6p[4]-$x*($C6p[5]-$x*$C6p[6]))))); | 
| 5612 | 5 |  |  |  |  | 11 | my $sumd = $C6q[0]-$x*($C6q[1]-$x*($C6q[2]-$x*($C6q[3]-$x*($C6q[4]-$x*($C6q[5]-$x*$C6q[6]))))); | 
| 5613 | 5 |  |  |  |  | 16 | $val = log(-$x) - ($sumn / $sumd); | 
| 5614 |  |  |  |  |  |  | } elsif ($x < -log($tol)) { | 
| 5615 |  |  |  |  |  |  | # Convergent series | 
| 5616 | 9 |  |  |  |  | 14 | my $fact_n = 1; | 
| 5617 | 9 |  |  |  |  | 23 | $y = _Euler(18)-$c; $t = $sum+$y; $c = ($t-$sum)-$y; $sum = $t; | 
|  | 9 |  |  |  |  | 15 |  | 
|  | 9 |  |  |  |  | 17 |  | 
|  | 9 |  |  |  |  | 13 |  | 
| 5618 | 9 |  |  |  |  | 18 | $y = log($x)-$c; $t = $sum+$y; $c = ($t-$sum)-$y; $sum = $t; | 
|  | 9 |  |  |  |  | 12 |  | 
|  | 9 |  |  |  |  | 12 |  | 
|  | 9 |  |  |  |  | 15 |  | 
| 5619 | 9 |  |  |  |  | 19 | for my $n (1 .. 200) { | 
| 5620 | 401 |  |  |  |  | 515 | $fact_n *= $x/$n; | 
| 5621 | 401 |  |  |  |  | 513 | my $term = $fact_n / $n; | 
| 5622 | 401 |  |  |  |  | 494 | $y = $term-$c; $t = $sum+$y; $c = ($t-$sum)-$y; $sum = $t; | 
|  | 401 |  |  |  |  | 501 |  | 
|  | 401 |  |  |  |  | 539 |  | 
|  | 401 |  |  |  |  | 475 |  | 
| 5623 | 401 | 100 |  |  |  | 692 | last if $term < $tol; | 
| 5624 |  |  |  |  |  |  | } | 
| 5625 | 9 |  |  |  |  | 18 | $val = $sum; | 
| 5626 |  |  |  |  |  |  | } else { | 
| 5627 |  |  |  |  |  |  | # Asymptotic divergent series | 
| 5628 | 3 |  |  |  |  | 8 | my $invx = 1.0 / $x; | 
| 5629 | 3 |  |  |  |  | 6 | my $term = $invx; | 
| 5630 | 3 |  |  |  |  | 7 | $sum = 1.0 + $term; | 
| 5631 | 3 |  |  |  |  | 9 | for my $n (2 .. 200) { | 
| 5632 | 81 |  |  |  |  | 100 | my $last_term = $term; | 
| 5633 | 81 |  |  |  |  | 132 | $term *= $n * $invx; | 
| 5634 | 81 | 100 |  |  |  | 136 | last if $term < $tol; | 
| 5635 | 78 | 50 |  |  |  | 123 | if ($term < $last_term) { | 
| 5636 | 78 |  |  |  |  | 96 | $y = $term-$c; $t = $sum+$y; $c = ($t-$sum)-$y; $sum = $t; | 
|  | 78 |  |  |  |  | 99 |  | 
|  | 78 |  |  |  |  | 99 |  | 
|  | 78 |  |  |  |  | 110 |  | 
| 5637 |  |  |  |  |  |  | } else { | 
| 5638 | 0 |  |  |  |  | 0 | $y = (-$last_term/3)-$c; $t = $sum+$y; $c = ($t-$sum)-$y; $sum = $t; | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 5639 | 0 |  |  |  |  | 0 | last; | 
| 5640 |  |  |  |  |  |  | } | 
| 5641 |  |  |  |  |  |  | } | 
| 5642 | 3 |  |  |  |  | 22 | $val = exp($x) * $invx * $sum; | 
| 5643 |  |  |  |  |  |  | } | 
| 5644 | 18 |  |  |  |  | 158 | $val; | 
| 5645 |  |  |  |  |  |  | } | 
| 5646 |  |  |  |  |  |  |  | 
| 5647 |  |  |  |  |  |  | sub LogarithmicIntegral { | 
| 5648 | 91 |  |  | 91 | 0 | 21859 | my($x,$opt) = @_; | 
| 5649 | 91 | 100 |  |  |  | 304 | return 0              if $x == 0; | 
| 5650 | 90 | 50 |  |  |  | 14350 | return - MPU_INFINITY if $x == 1; | 
| 5651 | 90 | 50 |  |  |  | 11974 | return MPU_INFINITY   if $x == MPU_INFINITY; | 
| 5652 | 90 | 50 |  |  |  | 11363 | croak "Invalid input to LogarithmicIntegral:  x must be > 0" if $x <= 0; | 
| 5653 | 90 | 50 |  |  |  | 13616 | $opt = 0 unless defined $opt; | 
| 5654 |  |  |  |  |  |  |  | 
| 5655 | 90 | 50 |  |  |  | 293 | if ($Math::Prime::Util::_GMPfunc{"li"}) { | 
| 5656 | 0 | 0 | 0 |  |  | 0 | $x = Math::BigFloat->new("$x") if defined $bignum::VERSION && ref($x) ne 'Math::BigFloat'; | 
| 5657 | 0 | 0 |  |  |  | 0 | return 0.0 + Math::Prime::Util::GMP::li($x,40) if !ref($x); | 
| 5658 | 0 |  |  |  |  | 0 | my $str = Math::Prime::Util::GMP::li($x, _find_big_acc($x)); | 
| 5659 | 0 |  |  |  |  | 0 | return $x->copy->bzero->badd($str); | 
| 5660 |  |  |  |  |  |  | } | 
| 5661 |  |  |  |  |  |  |  | 
| 5662 | 90 | 100 |  |  |  | 228 | if ($x == 2) { | 
| 5663 | 1 | 50 |  |  |  | 7 | my $li2const = (ref($x) eq 'Math::BigFloat') ? Math::BigFloat->new(_Li2(_find_big_acc($x))) : 0.0+_Li2(30); | 
| 5664 | 1 |  |  |  |  | 9 | return $li2const; | 
| 5665 |  |  |  |  |  |  | } | 
| 5666 |  |  |  |  |  |  |  | 
| 5667 | 89 | 50 |  |  |  | 11608 | if (defined $bignum::VERSION) { | 
|  |  | 100 |  |  |  |  |  | 
| 5668 |  |  |  |  |  |  | # If bignum is on, always use Math::BigFloat. | 
| 5669 | 0 | 0 |  |  |  | 0 | $x = Math::BigFloat->new("$x") if ref($x) ne 'Math::BigFloat'; | 
| 5670 |  |  |  |  |  |  | } elsif (ref($x)) { | 
| 5671 |  |  |  |  |  |  | # bignum is off, use native if small, BigFloat otherwise. | 
| 5672 | 79 | 100 |  |  |  | 239 | if ($x <= 1e16) { | 
| 5673 | 60 |  |  |  |  | 14395 | $x = _bigint_to_int($x); | 
| 5674 |  |  |  |  |  |  | } else { | 
| 5675 | 19 | 50 |  |  |  | 5931 | $x = _upgrade_to_float($x) if ref($x) ne 'Math::BigFloat'; | 
| 5676 |  |  |  |  |  |  | } | 
| 5677 |  |  |  |  |  |  | } | 
| 5678 |  |  |  |  |  |  | # Make sure we preserve whatever accuracy setting the input was using. | 
| 5679 | 89 | 100 | 66 |  |  | 1901 | $x->accuracy($_[0]->accuracy) if ref($x) && ref($_[0]) =~ /^Math::Big/ && $_[0]->accuracy; | 
|  |  |  | 100 |  |  |  |  | 
| 5680 |  |  |  |  |  |  |  | 
| 5681 |  |  |  |  |  |  | # Do divergent series here for big inputs.  Common for big pc approximations. | 
| 5682 |  |  |  |  |  |  | # Why is this here? | 
| 5683 |  |  |  |  |  |  | #   1) exp(log(x)) results in a lot of lost precision | 
| 5684 |  |  |  |  |  |  | #   2) exp(x) with lots of precision turns out to be really slow, and in | 
| 5685 |  |  |  |  |  |  | #      this case it was unnecessary. | 
| 5686 | 89 |  |  |  |  | 782 | my $tol = 1e-16; | 
| 5687 | 89 |  |  |  |  | 161 | my $xdigits = 0; | 
| 5688 | 89 |  |  |  |  | 149 | my $finalacc = 0; | 
| 5689 | 89 | 100 |  |  |  | 250 | if (ref($x) =~ /^Math::Big/) { | 
| 5690 | 19 |  |  |  |  | 80 | $xdigits = _find_big_acc($x); | 
| 5691 | 19 |  |  |  |  | 64 | my $xlen = length($x->copy->bfloor->bstr()); | 
| 5692 | 19 | 100 |  |  |  | 2553 | $xdigits = $xlen if $xdigits < $xlen; | 
| 5693 | 19 |  |  |  |  | 64 | $finalacc = $xdigits; | 
| 5694 | 19 |  |  |  |  | 85 | $xdigits += length(int(log(0.0+"$x"))) + 1; | 
| 5695 | 19 |  |  |  |  | 1093 | $tol = Math::BigFloat->new(10)->bpow(-$xdigits); | 
| 5696 | 19 |  |  |  |  | 27375 | $x->accuracy($xdigits); | 
| 5697 |  |  |  |  |  |  | } | 
| 5698 | 89 | 100 |  |  |  | 1562 | my $logx = $xdigits ? $x->copy->blog(undef,$xdigits) : log($x); | 
| 5699 |  |  |  |  |  |  |  | 
| 5700 |  |  |  |  |  |  | # TODO: See if we can tune this | 
| 5701 | 89 |  |  |  |  | 1741288 | if (0 && $x >= 1) { | 
| 5702 |  |  |  |  |  |  | _upgrade_to_float(); | 
| 5703 |  |  |  |  |  |  | my $sum = Math::BigFloat->new(0); | 
| 5704 |  |  |  |  |  |  | my $inner_sum = Math::BigFloat->new(0); | 
| 5705 |  |  |  |  |  |  | my $p = Math::BigFloat->new(-1); | 
| 5706 |  |  |  |  |  |  | my $factorial = 1; | 
| 5707 |  |  |  |  |  |  | my $power2 = 1; | 
| 5708 |  |  |  |  |  |  | my $q; | 
| 5709 |  |  |  |  |  |  | my $k = 0; | 
| 5710 |  |  |  |  |  |  | my $neglogx = -$logx; | 
| 5711 |  |  |  |  |  |  | for my $n (1 .. 1000) { | 
| 5712 |  |  |  |  |  |  | $factorial = vecprod($factorial, $n); | 
| 5713 |  |  |  |  |  |  | $q = vecprod($factorial, $power2); | 
| 5714 |  |  |  |  |  |  | $power2 = vecprod(2, $power2); | 
| 5715 |  |  |  |  |  |  | while ($k <= ($n-1)>>1) { | 
| 5716 |  |  |  |  |  |  | $inner_sum += Math::BigFloat->new(1) / (2*$k+1); | 
| 5717 |  |  |  |  |  |  | $k++; | 
| 5718 |  |  |  |  |  |  | } | 
| 5719 |  |  |  |  |  |  | $p *= $neglogx; | 
| 5720 |  |  |  |  |  |  | my $term = ($p / $q) * $inner_sum; | 
| 5721 |  |  |  |  |  |  | $sum += $term; | 
| 5722 |  |  |  |  |  |  | last if abs($term) < $tol; | 
| 5723 |  |  |  |  |  |  | } | 
| 5724 |  |  |  |  |  |  | $sum *= sqrt($x); | 
| 5725 |  |  |  |  |  |  | return 0.0+_Euler(18) + log($logx) + $sum unless ref($x)=~/^Math::Big/; | 
| 5726 |  |  |  |  |  |  | my $val = Math::BigFloat->new(_Euler(40))->badd("".log($logx))->badd("$sum"); | 
| 5727 |  |  |  |  |  |  | $val->accuracy($finalacc) if $xdigits; | 
| 5728 |  |  |  |  |  |  | return $val; | 
| 5729 |  |  |  |  |  |  | } | 
| 5730 |  |  |  |  |  |  |  | 
| 5731 | 89 | 100 |  |  |  | 259 | if ($x > 1e16) { | 
| 5732 | 19 | 50 |  |  |  | 8260 | my $invx = ref($logx) ? Math::BigFloat->bone / $logx : 1.0/$logx; | 
| 5733 |  |  |  |  |  |  | # n = 0  =>  0!/(logx)^0 = 1/1 = 1 | 
| 5734 |  |  |  |  |  |  | # n = 1  =>  1!/(logx)^1 = 1/logx | 
| 5735 | 19 |  |  |  |  | 20542 | my $term = $invx; | 
| 5736 | 19 |  |  |  |  | 114 | my $sum = 1.0 + $term; | 
| 5737 | 19 |  |  |  |  | 14619 | for my $n (2 .. 1000) { | 
| 5738 | 947 |  |  |  |  | 46144 | my $last_term = $term; | 
| 5739 | 947 |  |  |  |  | 2513 | $term *= $n * $invx; | 
| 5740 | 947 | 50 |  |  |  | 1080833 | last if $term < $tol; | 
| 5741 | 947 | 100 |  |  |  | 125697 | if ($term < $last_term) { | 
| 5742 | 928 |  |  |  |  | 130210 | $sum += $term; | 
| 5743 |  |  |  |  |  |  | } else { | 
| 5744 | 19 |  |  |  |  | 4048 | $sum -= ($last_term/3); | 
| 5745 | 19 |  |  |  |  | 32473 | last; | 
| 5746 |  |  |  |  |  |  | } | 
| 5747 | 928 | 50 |  |  |  | 598917 | $term->bround($xdigits) if $xdigits; | 
| 5748 |  |  |  |  |  |  | } | 
| 5749 | 19 |  |  |  |  | 97 | $invx *= $sum; | 
| 5750 | 19 |  |  |  |  | 12196 | $invx *= $x; | 
| 5751 | 19 | 50 | 33 |  |  | 8847 | $invx->accuracy($finalacc) if ref($invx) && $xdigits; | 
| 5752 | 19 |  |  |  |  | 6943 | return $invx; | 
| 5753 |  |  |  |  |  |  | } | 
| 5754 |  |  |  |  |  |  | # Convergent series. | 
| 5755 | 70 | 50 |  |  |  | 168 | if ($x >= 1) { | 
| 5756 | 70 |  |  |  |  | 100 | my $fact_n = 1.0; | 
| 5757 | 70 |  |  |  |  | 98 | my $nfac = 1.0; | 
| 5758 | 70 |  |  |  |  | 117 | my $sum  = 0.0; | 
| 5759 | 70 |  |  |  |  | 149 | for my $n (1 .. 200) { | 
| 5760 | 2909 |  |  |  |  | 3774 | $fact_n *= $logx/$n; | 
| 5761 | 2909 |  |  |  |  | 3840 | my $term = $fact_n / $n; | 
| 5762 | 2909 |  |  |  |  | 3519 | $sum += $term; | 
| 5763 | 2909 | 100 |  |  |  | 4614 | last if $term < $tol; | 
| 5764 | 2839 | 50 |  |  |  | 4729 | $term->bround($xdigits) if $xdigits; | 
| 5765 |  |  |  |  |  |  | } | 
| 5766 |  |  |  |  |  |  |  | 
| 5767 | 70 | 50 |  |  |  | 248 | return 0.0+_Euler(18) + log($logx) + $sum unless ref($x) =~ /^Math::Big/; | 
| 5768 |  |  |  |  |  |  |  | 
| 5769 | 0 |  |  |  |  | 0 | my $val = Math::BigFloat->new(_Euler(40))->badd("".log($logx))->badd("$sum"); | 
| 5770 | 0 | 0 |  |  |  | 0 | $val->accuracy($finalacc) if $xdigits; | 
| 5771 | 0 |  |  |  |  | 0 | return $val; | 
| 5772 |  |  |  |  |  |  | } | 
| 5773 |  |  |  |  |  |  |  | 
| 5774 | 0 |  |  |  |  | 0 | ExponentialIntegral($logx); | 
| 5775 |  |  |  |  |  |  | } | 
| 5776 |  |  |  |  |  |  |  | 
| 5777 |  |  |  |  |  |  | # Riemann Zeta function for native integers. | 
| 5778 |  |  |  |  |  |  | my @_Riemann_Zeta_Table = ( | 
| 5779 |  |  |  |  |  |  | 0.6449340668482264364724151666460251892,  # zeta(2) - 1 | 
| 5780 |  |  |  |  |  |  | 0.2020569031595942853997381615114499908, | 
| 5781 |  |  |  |  |  |  | 0.0823232337111381915160036965411679028, | 
| 5782 |  |  |  |  |  |  | 0.0369277551433699263313654864570341681, | 
| 5783 |  |  |  |  |  |  | 0.0173430619844491397145179297909205279, | 
| 5784 |  |  |  |  |  |  | 0.0083492773819228268397975498497967596, | 
| 5785 |  |  |  |  |  |  | 0.0040773561979443393786852385086524653, | 
| 5786 |  |  |  |  |  |  | 0.0020083928260822144178527692324120605, | 
| 5787 |  |  |  |  |  |  | 0.0009945751278180853371459589003190170, | 
| 5788 |  |  |  |  |  |  | 0.0004941886041194645587022825264699365, | 
| 5789 |  |  |  |  |  |  | 0.0002460865533080482986379980477396710, | 
| 5790 |  |  |  |  |  |  | 0.0001227133475784891467518365263573957, | 
| 5791 |  |  |  |  |  |  | 0.0000612481350587048292585451051353337, | 
| 5792 |  |  |  |  |  |  | 0.0000305882363070204935517285106450626, | 
| 5793 |  |  |  |  |  |  | 0.0000152822594086518717325714876367220, | 
| 5794 |  |  |  |  |  |  | 0.0000076371976378997622736002935630292, | 
| 5795 |  |  |  |  |  |  | 0.0000038172932649998398564616446219397, | 
| 5796 |  |  |  |  |  |  | 0.0000019082127165539389256569577951013, | 
| 5797 |  |  |  |  |  |  | 0.0000009539620338727961131520386834493, | 
| 5798 |  |  |  |  |  |  | 0.0000004769329867878064631167196043730, | 
| 5799 |  |  |  |  |  |  | 0.0000002384505027277329900036481867530, | 
| 5800 |  |  |  |  |  |  | 0.0000001192199259653110730677887188823, | 
| 5801 |  |  |  |  |  |  | 0.0000000596081890512594796124402079358, | 
| 5802 |  |  |  |  |  |  | 0.0000000298035035146522801860637050694, | 
| 5803 |  |  |  |  |  |  | 0.0000000149015548283650412346585066307, | 
| 5804 |  |  |  |  |  |  | 0.0000000074507117898354294919810041706, | 
| 5805 |  |  |  |  |  |  | 0.0000000037253340247884570548192040184, | 
| 5806 |  |  |  |  |  |  | 0.0000000018626597235130490064039099454, | 
| 5807 |  |  |  |  |  |  | 0.0000000009313274324196681828717647350, | 
| 5808 |  |  |  |  |  |  | 0.0000000004656629065033784072989233251, | 
| 5809 |  |  |  |  |  |  | 0.0000000002328311833676505492001455976, | 
| 5810 |  |  |  |  |  |  | 0.0000000001164155017270051977592973835, | 
| 5811 |  |  |  |  |  |  | 0.0000000000582077208790270088924368599, | 
| 5812 |  |  |  |  |  |  | 0.0000000000291038504449709968692942523, | 
| 5813 |  |  |  |  |  |  | 0.0000000000145519218910419842359296322, | 
| 5814 |  |  |  |  |  |  | 0.0000000000072759598350574810145208690, | 
| 5815 |  |  |  |  |  |  | 0.0000000000036379795473786511902372363, | 
| 5816 |  |  |  |  |  |  | 0.0000000000018189896503070659475848321, | 
| 5817 |  |  |  |  |  |  | 0.0000000000009094947840263889282533118, | 
| 5818 |  |  |  |  |  |  | ); | 
| 5819 |  |  |  |  |  |  |  | 
| 5820 |  |  |  |  |  |  |  | 
| 5821 |  |  |  |  |  |  | sub RiemannZeta { | 
| 5822 | 160 |  |  | 160 | 0 | 4940 | my($x) = @_; | 
| 5823 |  |  |  |  |  |  |  | 
| 5824 | 160 | 100 |  |  |  | 467 | my $ix = ($x == int($x))  ?  "" . Math::BigInt->new($x)  :  0; | 
| 5825 |  |  |  |  |  |  |  | 
| 5826 |  |  |  |  |  |  | # Try our GMP code if possible. | 
| 5827 | 160 | 50 |  |  |  | 10527 | if ($Math::Prime::Util::_GMPfunc{"zeta"}) { | 
| 5828 | 0 |  |  |  |  | 0 | my($wantbf,$xdigits) = _bfdigits($x); | 
| 5829 |  |  |  |  |  |  | # If we knew the *exact* number of zero digits, we could let GMP zeta | 
| 5830 |  |  |  |  |  |  | # handle the correct rounding.  But we don't, so we have to go over. | 
| 5831 | 0 |  |  |  |  | 0 | my $zero_dig = "".int($x / 3) - 1; | 
| 5832 | 0 |  |  |  |  | 0 | my $strval = Math::Prime::Util::GMP::zeta($x, $xdigits + 8 + $zero_dig); | 
| 5833 | 0 | 0 |  |  |  | 0 | if ($strval =~ s/^(1\.0*)/./) { | 
| 5834 | 0 | 0 |  |  |  | 0 | $strval .= "e-".(length($1)-2) if length($1) > 2; | 
| 5835 |  |  |  |  |  |  | } else { | 
| 5836 | 0 |  |  |  |  | 0 | $strval =~ s/^(\d+)/$1-1/e; | 
|  | 0 |  |  |  |  | 0 |  | 
| 5837 |  |  |  |  |  |  | } | 
| 5838 |  |  |  |  |  |  |  | 
| 5839 | 0 | 0 |  |  |  | 0 | return ($wantbf)  ?  Math::BigFloat->new($strval,$wantbf)  : 0.0 + $strval; | 
| 5840 |  |  |  |  |  |  | } | 
| 5841 |  |  |  |  |  |  |  | 
| 5842 |  |  |  |  |  |  | # If we need a bigfloat result, then call our PP routine. | 
| 5843 | 160 | 100 | 66 |  |  | 569 | if (defined $bignum::VERSION || ref($x) =~ /^Math::Big/) { | 
| 5844 | 4 |  |  |  |  | 1379 | require Math::Prime::Util::ZetaBigFloat; | 
| 5845 | 4 |  |  |  |  | 18 | return Math::Prime::Util::ZetaBigFloat::RiemannZeta($x); | 
| 5846 |  |  |  |  |  |  | } | 
| 5847 |  |  |  |  |  |  |  | 
| 5848 |  |  |  |  |  |  | # Native float results | 
| 5849 | 156 | 100 | 100 |  |  | 505 | return 0.0 + $_Riemann_Zeta_Table[int($x)-2] | 
| 5850 |  |  |  |  |  |  | if $x == int($x) && defined $_Riemann_Zeta_Table[int($x)-2]; | 
| 5851 | 148 |  |  |  |  | 225 | my $tol = 1.11e-16; | 
| 5852 |  |  |  |  |  |  |  | 
| 5853 |  |  |  |  |  |  | # Series based on (2n)! / B_2n. | 
| 5854 |  |  |  |  |  |  | # This is a simplification of the Cephes zeta function. | 
| 5855 | 148 |  |  |  |  | 329 | my @A = ( | 
| 5856 |  |  |  |  |  |  | 12.0, | 
| 5857 |  |  |  |  |  |  | -720.0, | 
| 5858 |  |  |  |  |  |  | 30240.0, | 
| 5859 |  |  |  |  |  |  | -1209600.0, | 
| 5860 |  |  |  |  |  |  | 47900160.0, | 
| 5861 |  |  |  |  |  |  | -1892437580.3183791606367583212735166426, | 
| 5862 |  |  |  |  |  |  | 74724249600.0, | 
| 5863 |  |  |  |  |  |  | -2950130727918.1642244954382084600497650, | 
| 5864 |  |  |  |  |  |  | 116467828143500.67248729113000661089202, | 
| 5865 |  |  |  |  |  |  | -4597978722407472.6105457273596737891657, | 
| 5866 |  |  |  |  |  |  | 181521054019435467.73425331153534235290, | 
| 5867 |  |  |  |  |  |  | -7166165256175667011.3346447367083352776, | 
| 5868 |  |  |  |  |  |  | 282908877253042996618.18640556532523927, | 
| 5869 |  |  |  |  |  |  | ); | 
| 5870 | 148 |  |  |  |  | 196 | my $s = 0.0; | 
| 5871 | 148 |  |  |  |  | 201 | my $rb = 0.0; | 
| 5872 | 148 |  |  |  |  | 247 | foreach my $i (2 .. 10) { | 
| 5873 | 533 |  |  |  |  | 875 | $rb = $i ** -$x; | 
| 5874 | 533 |  |  |  |  | 689 | $s += $rb; | 
| 5875 | 533 | 100 |  |  |  | 1193 | return $s if abs($rb/$s) < $tol; | 
| 5876 |  |  |  |  |  |  | } | 
| 5877 | 4 |  |  |  |  | 7 | my $w = 10.0; | 
| 5878 | 4 |  |  |  |  | 12 | $s = $s  +  $rb*$w/($x-1.0)  -  0.5*$rb; | 
| 5879 | 4 |  |  |  |  | 8 | my $ra = 1.0; | 
| 5880 | 4 |  |  |  |  | 9 | foreach my $i (0 .. 12) { | 
| 5881 | 29 |  |  |  |  | 39 | my $k = 2*$i; | 
| 5882 | 29 |  |  |  |  | 41 | $ra *= $x + $k; | 
| 5883 | 29 |  |  |  |  | 35 | $rb /= $w; | 
| 5884 | 29 |  |  |  |  | 49 | my $t = $ra*$rb/$A[$i]; | 
| 5885 | 29 |  |  |  |  | 37 | $s += $t; | 
| 5886 | 29 |  |  |  |  | 37 | $t = abs($t/$s); | 
| 5887 | 29 | 100 |  |  |  | 52 | last if $t < $tol; | 
| 5888 | 25 |  |  |  |  | 34 | $ra *= $x + $k + 1.0; | 
| 5889 | 25 |  |  |  |  | 38 | $rb /= $w; | 
| 5890 |  |  |  |  |  |  | } | 
| 5891 | 4 |  |  |  |  | 35 | return $s; | 
| 5892 |  |  |  |  |  |  | } | 
| 5893 |  |  |  |  |  |  |  | 
| 5894 |  |  |  |  |  |  | # Riemann R function | 
| 5895 |  |  |  |  |  |  | sub RiemannR { | 
| 5896 | 10 |  |  | 10 | 0 | 4449 | my($x) = @_; | 
| 5897 |  |  |  |  |  |  |  | 
| 5898 | 10 | 50 |  |  |  | 39 | croak "Invalid input to ReimannR:  x must be > 0" if $x <= 0; | 
| 5899 |  |  |  |  |  |  |  | 
| 5900 |  |  |  |  |  |  | # With MPU::GMP v0.49 this is fast. | 
| 5901 | 10 | 50 |  |  |  | 28 | if ($Math::Prime::Util::_GMPfunc{"riemannr"}) { | 
| 5902 | 0 |  |  |  |  | 0 | my($wantbf,$xdigits) = _bfdigits($x); | 
| 5903 | 0 |  |  |  |  | 0 | my $strval = Math::Prime::Util::GMP::riemannr($x, $xdigits); | 
| 5904 | 0 | 0 |  |  |  | 0 | return ($wantbf)  ?  Math::BigFloat->new($strval,$wantbf)  :  0.0 + $strval; | 
| 5905 |  |  |  |  |  |  | } | 
| 5906 |  |  |  |  |  |  |  | 
| 5907 |  |  |  |  |  |  |  | 
| 5908 |  |  |  |  |  |  | # TODO: look into this as a generic solution | 
| 5909 | 10 |  |  |  |  | 16 | if (0 && $Math::Prime::Util::_GMPfunc{"zeta"}) { | 
| 5910 |  |  |  |  |  |  | my($wantbf,$xdigits) = _bfdigits($x); | 
| 5911 |  |  |  |  |  |  | $x = _upgrade_to_float($x); | 
| 5912 |  |  |  |  |  |  |  | 
| 5913 |  |  |  |  |  |  | my $extra_acc = 4; | 
| 5914 |  |  |  |  |  |  | $xdigits += $extra_acc; | 
| 5915 |  |  |  |  |  |  | $x->accuracy($xdigits); | 
| 5916 |  |  |  |  |  |  |  | 
| 5917 |  |  |  |  |  |  | my $logx = log($x); | 
| 5918 |  |  |  |  |  |  | my $part_term = $x->copy->bone; | 
| 5919 |  |  |  |  |  |  | my $sum = $x->copy->bone; | 
| 5920 |  |  |  |  |  |  | my $tol = $x->copy->bone->brsft($xdigits-1, 10); | 
| 5921 |  |  |  |  |  |  | my $bigk = $x->copy->bone; | 
| 5922 |  |  |  |  |  |  | my $term; | 
| 5923 |  |  |  |  |  |  | for my $k (1 .. 10000) { | 
| 5924 |  |  |  |  |  |  | $part_term *= $logx / $bigk; | 
| 5925 |  |  |  |  |  |  | my $zarg = $bigk->copy->binc; | 
| 5926 |  |  |  |  |  |  | my $zeta = (RiemannZeta($zarg) * $bigk) + $bigk; | 
| 5927 |  |  |  |  |  |  | #my $strval = Math::Prime::Util::GMP::zeta($k+1, $xdigits + int(($k+1) / 3)); | 
| 5928 |  |  |  |  |  |  | #my $zeta = Math::BigFloat->new($strval)->bdec->bmul($bigk)->badd($bigk); | 
| 5929 |  |  |  |  |  |  | $term = $part_term / $zeta; | 
| 5930 |  |  |  |  |  |  | $sum += $term; | 
| 5931 |  |  |  |  |  |  | last if $term < ($tol * $sum); | 
| 5932 |  |  |  |  |  |  | $bigk->binc; | 
| 5933 |  |  |  |  |  |  | } | 
| 5934 |  |  |  |  |  |  | $sum->bround($xdigits-$extra_acc); | 
| 5935 |  |  |  |  |  |  | my $strval = "$sum"; | 
| 5936 |  |  |  |  |  |  | return ($wantbf)  ?  Math::BigFloat->new($strval,$wantbf)  :  0.0 + $strval; | 
| 5937 |  |  |  |  |  |  | } | 
| 5938 |  |  |  |  |  |  |  | 
| 5939 | 10 | 50 | 33 |  |  | 50 | if (defined $bignum::VERSION || ref($x) =~ /^Math::Big/) { | 
| 5940 | 0 |  |  |  |  | 0 | require Math::Prime::Util::ZetaBigFloat; | 
| 5941 | 0 |  |  |  |  | 0 | return Math::Prime::Util::ZetaBigFloat::RiemannR($x); | 
| 5942 |  |  |  |  |  |  | } | 
| 5943 |  |  |  |  |  |  |  | 
| 5944 | 10 |  |  |  |  | 15 | my $sum = 0.0; | 
| 5945 | 10 |  |  |  |  | 18 | my $tol = 1e-18; | 
| 5946 | 10 |  |  |  |  | 21 | my($c, $y, $t) = (0.0); | 
| 5947 | 10 | 100 |  |  |  | 26 | if ($x > 10**17) { | 
| 5948 | 1 |  |  |  |  | 63 | my @mob = Math::Prime::Util::moebius(0,300); | 
| 5949 | 1 |  |  |  |  | 6 | for my $k (1 .. 300) { | 
| 5950 | 19 | 100 |  |  |  | 38 | next if $mob[$k] == 0; | 
| 5951 | 13 |  |  |  |  | 70 | my $term = $mob[$k] / $k * | 
| 5952 |  |  |  |  |  |  | Math::Prime::Util::LogarithmicIntegral($x**(1.0/$k)); | 
| 5953 | 13 |  |  |  |  | 19 | $y = $term-$c; $t = $sum+$y; $c = ($t-$sum)-$y; $sum = $t; | 
|  | 13 |  |  |  |  | 21 |  | 
|  | 13 |  |  |  |  | 19 |  | 
|  | 13 |  |  |  |  | 18 |  | 
| 5954 | 13 | 100 |  |  |  | 42 | last if abs($term) < ($tol * abs($sum)); | 
| 5955 |  |  |  |  |  |  | } | 
| 5956 |  |  |  |  |  |  | } else { | 
| 5957 | 9 |  |  |  |  | 16 | $y = 1.0-$c; $t = $sum+$y; $c = ($t-$sum)-$y; $sum = $t; | 
|  | 9 |  |  |  |  | 17 |  | 
|  | 9 |  |  |  |  | 19 |  | 
|  | 9 |  |  |  |  | 13 |  | 
| 5958 | 9 |  |  |  |  | 24 | my $flogx = log($x); | 
| 5959 | 9 |  |  |  |  | 15 | my $part_term = 1.0; | 
| 5960 | 9 |  |  |  |  | 23 | for my $k (1 .. 10000) { | 
| 5961 | 425 | 100 |  |  |  | 823 | my $zeta = ($k <= $#_Riemann_Zeta_Table) | 
| 5962 |  |  |  |  |  |  | ? $_Riemann_Zeta_Table[$k+1-2]    # Small k from table | 
| 5963 |  |  |  |  |  |  | : RiemannZeta($k+1);              # Large k from function | 
| 5964 | 425 |  |  |  |  | 596 | $part_term *= $flogx / $k; | 
| 5965 | 425 |  |  |  |  | 644 | my $term = $part_term / ($k + $k * $zeta); | 
| 5966 | 425 |  |  |  |  | 579 | $y = $term-$c; $t = $sum+$y; $c = ($t-$sum)-$y; $sum = $t; | 
|  | 425 |  |  |  |  | 508 |  | 
|  | 425 |  |  |  |  | 552 |  | 
|  | 425 |  |  |  |  | 555 |  | 
| 5967 | 425 | 100 |  |  |  | 772 | last if $term < ($tol * $sum); | 
| 5968 |  |  |  |  |  |  | } | 
| 5969 |  |  |  |  |  |  | } | 
| 5970 | 10 |  |  |  |  | 89 | return $sum; | 
| 5971 |  |  |  |  |  |  | } | 
| 5972 |  |  |  |  |  |  |  | 
| 5973 |  |  |  |  |  |  | sub LambertW { | 
| 5974 | 1 |  |  | 1 | 0 | 457 | my $x = shift; | 
| 5975 | 1 | 50 |  |  |  | 6 | croak "Invalid input to LambertW:  x must be >= -1/e" if $x < -0.36787944118; | 
| 5976 | 1 | 50 |  |  |  | 4 | $x = _upgrade_to_float($x) if ref($x) eq 'Math::BigInt'; | 
| 5977 | 1 | 50 |  |  |  | 4 | my $xacc = ref($x) ? _find_big_acc($x) : 0; | 
| 5978 | 1 |  |  |  |  | 3 | my $w; | 
| 5979 |  |  |  |  |  |  |  | 
| 5980 | 1 | 50 |  |  |  | 5 | if ($Math::Prime::Util::_GMPfunc{"lambertw"}) { | 
| 5981 | 0 | 0 |  |  |  | 0 | my $w = (!$xacc) | 
| 5982 |  |  |  |  |  |  | ? 0.0 + Math::Prime::Util::GMP::lambertw($x) | 
| 5983 |  |  |  |  |  |  | : $x->copy->bzero->badd(Math::Prime::Util::GMP::lambertw($x, $xacc)); | 
| 5984 | 0 |  |  |  |  | 0 | return $w; | 
| 5985 |  |  |  |  |  |  | } | 
| 5986 |  |  |  |  |  |  |  | 
| 5987 |  |  |  |  |  |  | # Approximation | 
| 5988 | 1 | 50 |  |  |  | 8 | if ($x < -0.06) { | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 5989 | 0 |  |  |  |  | 0 | my $ti = $x * 2 * exp($x-$x+1) + 2; | 
| 5990 | 0 | 0 |  |  |  | 0 | return -1 if $ti <= 0; | 
| 5991 | 0 |  |  |  |  | 0 | my $t  = sqrt($ti); | 
| 5992 | 0 |  |  |  |  | 0 | $w = (-1 + 1/6*$t + (257/720)*$t*$t + (13/720)*$t*$t*$t) / (1 + (5/6)*$t + (103/720)*$t*$t); | 
| 5993 |  |  |  |  |  |  | } elsif ($x < 1.363) { | 
| 5994 | 0 |  |  |  |  | 0 | my $l1 = log($x + 1); | 
| 5995 | 0 |  |  |  |  | 0 | $w = $l1 * (1 - log(1+$l1) / (2+$l1)); | 
| 5996 |  |  |  |  |  |  | } elsif ($x < 3.7) { | 
| 5997 | 0 |  |  |  |  | 0 | my $l1 = log($x); | 
| 5998 | 0 |  |  |  |  | 0 | my $l2 = log($l1); | 
| 5999 | 0 |  |  |  |  | 0 | $w = $l1 - $l2 - log(1 - $l2/$l1)/2.0; | 
| 6000 |  |  |  |  |  |  | } else { | 
| 6001 | 1 |  |  |  |  | 3 | my $l1 = log($x); | 
| 6002 | 1 |  |  |  |  | 3 | my $l2 = log($l1); | 
| 6003 | 1 |  |  |  |  | 4 | my $d1 = 2 * $l1 * $l1; | 
| 6004 | 1 |  |  |  |  | 4 | my $d2 = 3 * $l1 * $d1; | 
| 6005 | 1 |  |  |  |  | 3 | my $d3 = 2 * $l1 * $d2; | 
| 6006 | 1 |  |  |  |  | 2 | my $d4 = 5 * $l1 * $d3; | 
| 6007 | 1 |  |  |  |  | 10 | $w = $l1 - $l2 + $l2/$l1 + $l2*($l2-2)/$d1 | 
| 6008 |  |  |  |  |  |  | + $l2*(6+$l2*(-9+2*$l2))/$d2 | 
| 6009 |  |  |  |  |  |  | + $l2*(-12+$l2*(36+$l2*(-22+3*$l2)))/$d3 | 
| 6010 |  |  |  |  |  |  | + $l2*(60+$l2*(-300+$l2*(350+$l2*(-125+12*$l2))))/$d4; | 
| 6011 |  |  |  |  |  |  | } | 
| 6012 |  |  |  |  |  |  |  | 
| 6013 |  |  |  |  |  |  | # Now iterate to get the answer | 
| 6014 |  |  |  |  |  |  | # | 
| 6015 |  |  |  |  |  |  | # Newton: | 
| 6016 |  |  |  |  |  |  | #   $w = $w*(log($x) - log($w) + 1) / ($w+1); | 
| 6017 |  |  |  |  |  |  | # Halley: | 
| 6018 |  |  |  |  |  |  | #   my $e = exp($w); | 
| 6019 |  |  |  |  |  |  | #   my $f = $w * $e - $x; | 
| 6020 |  |  |  |  |  |  | #   $w -= $f / ($w*$e+$e - ($w+2)*$f/(2*$w+2)); | 
| 6021 |  |  |  |  |  |  |  | 
| 6022 |  |  |  |  |  |  | # Fritsch converges quadratically, so tolerance could be 4x smaller.  Use 2x. | 
| 6023 | 1 | 50 |  |  |  | 4 | my $tol = ($xacc) ? 10**(-int(1+$xacc/2)) : 1e-16; | 
| 6024 | 1 | 50 |  |  |  | 3 | $w->accuracy($xacc+10) if $xacc; | 
| 6025 | 1 |  |  |  |  | 4 | for (1 .. 200) { | 
| 6026 | 200 | 50 |  |  |  | 311 | last if $w == 0; | 
| 6027 | 200 |  |  |  |  | 267 | my $w1 = $w + 1; | 
| 6028 | 200 |  |  |  |  | 278 | my $zn = log($x/$w) - $w; | 
| 6029 | 200 |  |  |  |  | 297 | my $qn = $w1 * 2 * ($w1+(2*$zn/3)); | 
| 6030 | 200 |  |  |  |  | 296 | my $en = ($zn/$w1) * ($qn-$zn)/($qn-$zn*2); | 
| 6031 | 200 |  |  |  |  | 261 | my $wen = $w * $en; | 
| 6032 | 200 |  |  |  |  | 244 | $w += $wen; | 
| 6033 | 200 | 50 |  |  |  | 353 | last if abs($wen) < $tol; | 
| 6034 |  |  |  |  |  |  | } | 
| 6035 | 1 | 50 |  |  |  | 5 | $w->accuracy($xacc) if $xacc; | 
| 6036 |  |  |  |  |  |  |  | 
| 6037 | 1 |  |  |  |  | 5 | $w; | 
| 6038 |  |  |  |  |  |  | } | 
| 6039 |  |  |  |  |  |  |  | 
| 6040 |  |  |  |  |  |  | my $_Pi = "3.141592653589793238462643383279503"; | 
| 6041 |  |  |  |  |  |  | sub Pi { | 
| 6042 | 986 |  |  | 986 | 0 | 776882 | my $digits = shift; | 
| 6043 | 986 | 50 |  |  |  | 2700 | return 0.0+$_Pi unless $digits; | 
| 6044 | 986 | 50 |  |  |  | 2076 | return 0.0+sprintf("%.*lf", $digits-1, $_Pi) if $digits < 15; | 
| 6045 | 986 | 100 |  |  |  | 2046 | return _upgrade_to_float($_Pi, $digits) if $digits < 30; | 
| 6046 |  |  |  |  |  |  |  | 
| 6047 |  |  |  |  |  |  | # Performance ranking: | 
| 6048 |  |  |  |  |  |  | #   MPU::GMP         Uses AGM or Ramanujan/Chudnosky with binary splitting | 
| 6049 |  |  |  |  |  |  | #   MPFR             Uses AGM, from 1x to 1/4x the above | 
| 6050 |  |  |  |  |  |  | #   Perl AGM w/GMP   also AGM, nice growth rate, but slower than above | 
| 6051 |  |  |  |  |  |  | #   C pidigits       much worse than above, but faster than the others | 
| 6052 |  |  |  |  |  |  | #   Perl AGM         without Math::BigInt::GMP, it's sluggish | 
| 6053 |  |  |  |  |  |  | #   Math::BigFloat   new versions use AGM, old ones are *very* slow | 
| 6054 |  |  |  |  |  |  | # | 
| 6055 |  |  |  |  |  |  | # With a few thousand digits, any of the top 4 are fine. | 
| 6056 |  |  |  |  |  |  | # At 10k digits, the first two are pulling away. | 
| 6057 |  |  |  |  |  |  | # At 50k digits, the first three are 5-20x faster than C pidigits, and | 
| 6058 |  |  |  |  |  |  | #   pray you're not having to the Perl BigFloat methods without GMP. | 
| 6059 |  |  |  |  |  |  | # At 100k digits, the first two are 15x faster than the third, C pidigits | 
| 6060 |  |  |  |  |  |  | #   is 200x slower, and the rest thousands of times slower. | 
| 6061 |  |  |  |  |  |  | # At 1M digits, the first is under 1 second, MPFR under 2 seconds, | 
| 6062 |  |  |  |  |  |  | #   Perl AGM (Math::BigInt::GMP) is over a minute, and C piigits at 1.5 hours. | 
| 6063 |  |  |  |  |  |  | # | 
| 6064 |  |  |  |  |  |  | # Interestingly, Math::BigInt::Pari, while greatly faster than Calc, is | 
| 6065 |  |  |  |  |  |  | # *much* slower than GMP for these operations (both AGM and Machin).  While | 
| 6066 |  |  |  |  |  |  | # Perl AGM with the Math::BigInt::GMP backend will pull away from C pidigits, | 
| 6067 |  |  |  |  |  |  | # using it with the other backends doesn't do so. | 
| 6068 |  |  |  |  |  |  | # | 
| 6069 |  |  |  |  |  |  | # The GMP program at https://gmplib.org/download/misc/gmp-chudnovsky.c | 
| 6070 |  |  |  |  |  |  | # will run ~4x faster than MPFR and ~1.5x faster than MPU::GMP. | 
| 6071 |  |  |  |  |  |  |  | 
| 6072 | 972 |  |  |  |  | 3575 | my $have_bigint_gmp = Math::BigInt->config()->{lib} =~ /GMP/; | 
| 6073 | 972 |  |  |  |  | 46154 | my $have_xdigits    = Math::Prime::Util::prime_get_config()->{'xs'}; | 
| 6074 | 972 |  |  |  |  | 2829 | my $_verbose = Math::Prime::Util::prime_get_config()->{'verbose'}; | 
| 6075 |  |  |  |  |  |  |  | 
| 6076 | 972 | 50 |  |  |  | 3021 | if ($Math::Prime::Util::_GMPfunc{"Pi"}) { | 
| 6077 | 0 | 0 |  |  |  | 0 | print "  using MPUGMP for Pi($digits)\n" if $_verbose; | 
| 6078 | 0 |  |  |  |  | 0 | return _upgrade_to_float( Math::Prime::Util::GMP::Pi($digits) ); | 
| 6079 |  |  |  |  |  |  | } | 
| 6080 |  |  |  |  |  |  |  | 
| 6081 |  |  |  |  |  |  | # We could consider looking for Math::MPFR or Math::Pari | 
| 6082 |  |  |  |  |  |  |  | 
| 6083 |  |  |  |  |  |  | # This has a *much* better growth rate than the later solutions. | 
| 6084 | 972 | 100 | 33 |  |  | 3420 | if ( !$have_xdigits || ($have_bigint_gmp && $digits > 100) ) { | 
|  |  |  | 66 |  |  |  |  | 
| 6085 | 1 | 50 |  |  |  | 3 | print "  using Perl AGM for Pi($digits)\n" if $_verbose; | 
| 6086 |  |  |  |  |  |  | # Brent-Salamin (aka AGM or Gauss-Legendre) | 
| 6087 | 1 |  |  |  |  | 2 | $digits += 8; | 
| 6088 | 1 |  |  |  |  | 13 | my $HALF = _upgrade_to_float(0.5); | 
| 6089 | 1 |  |  |  |  | 315 | my ($an, $bn, $tn, $pn) = ($HALF->copy->bone, $HALF->copy->bsqrt($digits), | 
| 6090 |  |  |  |  |  |  | $HALF->copy->bmul($HALF), $HALF->copy->bone); | 
| 6091 | 1 |  |  |  |  | 7891 | while ($pn < $digits) { | 
| 6092 | 7 |  |  |  |  | 3788 | my $prev_an = $an->copy; | 
| 6093 | 7 |  |  |  |  | 221 | $an->badd($bn)->bmul($HALF, $digits); | 
| 6094 | 7 |  |  |  |  | 5717 | $bn->bmul($prev_an)->bsqrt($digits); | 
| 6095 | 7 |  |  |  |  | 83726 | $prev_an->bsub($an); | 
| 6096 | 7 |  |  |  |  | 3114 | $tn->bsub($pn * $prev_an * $prev_an); | 
| 6097 | 7 |  |  |  |  | 13605 | $pn->badd($pn); | 
| 6098 |  |  |  |  |  |  | } | 
| 6099 | 1 |  |  |  |  | 521 | $an->badd($bn); | 
| 6100 | 1 |  |  |  |  | 399 | $an->bmul($an,$digits)->bdiv(4*$tn, $digits-8); | 
| 6101 | 1 |  |  |  |  | 2779 | return $an; | 
| 6102 |  |  |  |  |  |  | } | 
| 6103 |  |  |  |  |  |  |  | 
| 6104 |  |  |  |  |  |  | # Spigot method in C.  Low overhead but not good growth rate. | 
| 6105 | 971 | 50 |  |  |  | 1908 | if ($have_xdigits) { | 
| 6106 | 971 | 50 |  |  |  | 1708 | print "  using XS spigot for Pi($digits)\n" if $_verbose; | 
| 6107 | 971 |  |  |  |  | 3595377 | return _upgrade_to_float(Math::Prime::Util::_pidigits($digits)); | 
| 6108 |  |  |  |  |  |  | } | 
| 6109 |  |  |  |  |  |  |  | 
| 6110 |  |  |  |  |  |  | # We're going to have to use the Math::BigFloat code. | 
| 6111 |  |  |  |  |  |  | # 1) it rounds incorrectly (e.g. 761, 1372, 1509,...). | 
| 6112 |  |  |  |  |  |  | #    Fix by adding some digits and rounding. | 
| 6113 |  |  |  |  |  |  | # 2) AGM is *much* faster once past ~2000 digits | 
| 6114 |  |  |  |  |  |  | # 3) It is very slow without the GMP backend.  The Pari backend helps | 
| 6115 |  |  |  |  |  |  | #    but it still pretty bad.  With Calc it's glacial for large inputs. | 
| 6116 |  |  |  |  |  |  |  | 
| 6117 |  |  |  |  |  |  | #           Math::BigFloat                AGM              spigot   AGM | 
| 6118 |  |  |  |  |  |  | # Size     GMP    Pari  Calc        GMP    Pari  Calc        C      C+GMP | 
| 6119 |  |  |  |  |  |  | #   500   0.04    0.60   0.30      0.08    0.10   0.47      0.09    0.06 | 
| 6120 |  |  |  |  |  |  | #  1000   0.04    0.11   1.82      0.09    0.14   1.82      0.09    0.06 | 
| 6121 |  |  |  |  |  |  | #  2000   0.07    0.37  13.5       0.09    0.34   9.16      0.10    0.06 | 
| 6122 |  |  |  |  |  |  | #  4000   0.14    2.17 107.8       0.12    1.14  39.7       0.20    0.06 | 
| 6123 |  |  |  |  |  |  | #  8000   0.52   15.7              0.22    4.63 186.2       0.56    0.08 | 
| 6124 |  |  |  |  |  |  | # 16000   2.73  121.8              0.52   19.2              2.00    0.08 | 
| 6125 |  |  |  |  |  |  | # 32000  15.4                      1.42                     7.78    0.12 | 
| 6126 |  |  |  |  |  |  | #                                   ^                        ^       ^ | 
| 6127 |  |  |  |  |  |  | #                                   |      use this THIRD ---+       | | 
| 6128 |  |  |  |  |  |  | #                use this SECOND ---+                                | | 
| 6129 |  |  |  |  |  |  | #                                                  use this FIRST ---+ | 
| 6130 |  |  |  |  |  |  | # approx | 
| 6131 |  |  |  |  |  |  | # growth  5.6x    7.6x   8.0x      2.7x    4.1x   4.7x      3.9x    2.0x | 
| 6132 |  |  |  |  |  |  |  | 
| 6133 | 0 | 0 |  |  |  | 0 | print "  using BigFloat for Pi($digits)\n" if $_verbose; | 
| 6134 | 0 |  |  |  |  | 0 | _upgrade_to_float(0); | 
| 6135 | 0 |  |  |  |  | 0 | return Math::BigFloat::bpi($digits+10)->round($digits); | 
| 6136 |  |  |  |  |  |  | } | 
| 6137 |  |  |  |  |  |  |  | 
| 6138 |  |  |  |  |  |  | sub forpart { | 
| 6139 | 1 |  |  | 1 | 0 | 1579 | my($sub, $n, $rhash) = @_; | 
| 6140 | 1 |  |  |  |  | 6 | _forcompositions(1, $sub, $n, $rhash); | 
| 6141 |  |  |  |  |  |  | } | 
| 6142 |  |  |  |  |  |  | sub forcomp { | 
| 6143 | 0 |  |  | 0 | 0 | 0 | my($sub, $n, $rhash) = @_; | 
| 6144 | 0 |  |  |  |  | 0 | _forcompositions(0, $sub, $n, $rhash); | 
| 6145 |  |  |  |  |  |  | } | 
| 6146 |  |  |  |  |  |  | sub _forcompositions { | 
| 6147 | 1 |  |  | 1 |  | 4 | my($ispart, $sub, $n, $rhash) = @_; | 
| 6148 | 1 |  |  |  |  | 4 | _validate_positive_integer($n); | 
| 6149 | 1 |  |  |  |  | 6 | my($mina, $maxa, $minn, $maxn, $primeq) = (1,$n,1,$n,-1); | 
| 6150 | 1 | 50 |  |  |  | 3 | if (defined $rhash) { | 
| 6151 | 0 | 0 |  |  |  | 0 | croak "forpart second argument must be a hash reference" | 
| 6152 |  |  |  |  |  |  | unless ref($rhash) eq 'HASH'; | 
| 6153 | 0 | 0 |  |  |  | 0 | if (defined $rhash->{amin}) { | 
| 6154 | 0 |  |  |  |  | 0 | $mina = $rhash->{amin}; | 
| 6155 | 0 |  |  |  |  | 0 | _validate_positive_integer($mina); | 
| 6156 |  |  |  |  |  |  | } | 
| 6157 | 0 | 0 |  |  |  | 0 | if (defined $rhash->{amax}) { | 
| 6158 | 0 |  |  |  |  | 0 | $maxa = $rhash->{amax}; | 
| 6159 | 0 |  |  |  |  | 0 | _validate_positive_integer($maxa); | 
| 6160 |  |  |  |  |  |  | } | 
| 6161 | 0 | 0 |  |  |  | 0 | $minn = $maxn = $rhash->{n} if defined $rhash->{n}; | 
| 6162 | 0 | 0 |  |  |  | 0 | $minn = $rhash->{nmin} if defined $rhash->{nmin}; | 
| 6163 | 0 | 0 |  |  |  | 0 | $maxn = $rhash->{nmax} if defined $rhash->{nmax}; | 
| 6164 | 0 |  |  |  |  | 0 | _validate_positive_integer($minn); | 
| 6165 | 0 |  |  |  |  | 0 | _validate_positive_integer($maxn); | 
| 6166 | 0 | 0 |  |  |  | 0 | if (defined $rhash->{prime}) { | 
| 6167 | 0 |  |  |  |  | 0 | $primeq = $rhash->{prime}; | 
| 6168 | 0 |  |  |  |  | 0 | _validate_positive_integer($primeq); | 
| 6169 |  |  |  |  |  |  | } | 
| 6170 | 0 | 0 |  |  |  | 0 | $mina = 1 if $mina < 1; | 
| 6171 | 0 | 0 |  |  |  | 0 | $maxa = $n if $maxa > $n; | 
| 6172 | 0 | 0 |  |  |  | 0 | $minn = 1 if $minn < 1; | 
| 6173 | 0 | 0 |  |  |  | 0 | $maxn = $n if $maxn > $n; | 
| 6174 | 0 | 0 | 0 |  |  | 0 | $primeq = 2 if $primeq != -1 && $primeq != 0; | 
| 6175 |  |  |  |  |  |  | } | 
| 6176 |  |  |  |  |  |  |  | 
| 6177 | 1 | 50 | 33 |  |  | 5 | $sub->() if $n == 0 && $minn <= 1; | 
| 6178 | 1 | 50 | 33 |  |  | 14 | return if $n < $minn || $minn > $maxn || $mina > $maxa || $maxn <= 0 || $maxa <= 0; | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
| 6179 |  |  |  |  |  |  |  | 
| 6180 | 1 |  |  |  |  | 4 | my $oldforexit = Math::Prime::Util::_start_for_loop(); | 
| 6181 | 1 |  |  |  |  | 3 | my ($x, $y, $r, $k); | 
| 6182 | 1 |  |  |  |  | 14 | my @a = (0) x ($n); | 
| 6183 | 1 |  |  |  |  | 3 | $k = 1; | 
| 6184 | 1 |  |  |  |  | 3 | $a[0] = $mina - 1; | 
| 6185 | 1 |  |  |  |  | 4 | $a[1] = $n - $mina + 1; | 
| 6186 | 1 |  |  |  |  | 4 | while ($k != 0) { | 
| 6187 | 5 |  |  |  |  | 24 | $x = $a[$k-1]+1; | 
| 6188 | 5 |  |  |  |  | 14 | $y = $a[$k]-1; | 
| 6189 | 5 |  |  |  |  | 9 | $k--; | 
| 6190 | 5 | 50 |  |  |  | 11 | $r = $ispart ? $x : 1; | 
| 6191 | 5 |  |  |  |  | 11 | while ($r <= $y) { | 
| 6192 | 4 |  |  |  |  | 6 | $a[$k] = $x; | 
| 6193 | 4 |  |  |  |  | 6 | $x = $r; | 
| 6194 | 4 |  |  |  |  | 5 | $y -= $x; | 
| 6195 | 4 |  |  |  |  | 9 | $k++; | 
| 6196 |  |  |  |  |  |  | } | 
| 6197 | 5 |  |  |  |  | 7 | $a[$k] = $x + $y; | 
| 6198 |  |  |  |  |  |  | # Restrict size | 
| 6199 | 5 |  |  |  |  | 11 | while ($k+1 > $maxn) { | 
| 6200 | 0 |  |  |  |  | 0 | $a[$k-1] += $a[$k]; | 
| 6201 | 0 |  |  |  |  | 0 | $k--; | 
| 6202 |  |  |  |  |  |  | } | 
| 6203 | 5 | 50 |  |  |  | 10 | next if $k+1 < $minn; | 
| 6204 |  |  |  |  |  |  | # Restrict values | 
| 6205 | 5 | 50 | 33 |  |  | 29 | if ($mina > 1 || $maxa < $n) { | 
| 6206 | 0 | 0 |  |  |  | 0 | last if $a[0] > $maxa; | 
| 6207 | 0 | 0 |  |  |  | 0 | if ($ispart) { | 
| 6208 | 0 | 0 |  |  |  | 0 | next if $a[$k] > $maxa; | 
| 6209 |  |  |  |  |  |  | } else { | 
| 6210 | 0 | 0 |  | 0 |  | 0 | next if Math::Prime::Util::vecany(sub{ $_ < $mina || $_ > $maxa }, @a[0..$k]); | 
|  | 0 | 0 |  |  |  | 0 |  | 
| 6211 |  |  |  |  |  |  | } | 
| 6212 |  |  |  |  |  |  | } | 
| 6213 | 5 | 50 | 33 | 0 |  | 12 | next if $primeq == 0 && Math::Prime::Util::vecany(sub{ is_prime($_) }, @a[0..$k]); | 
|  | 0 |  |  |  |  | 0 |  | 
| 6214 | 5 | 50 | 33 | 0 |  | 13 | next if $primeq == 2 && Math::Prime::Util::vecany(sub{ !is_prime($_) }, @a[0..$k]); | 
|  | 0 |  |  |  |  | 0 |  | 
| 6215 | 5 | 50 |  |  |  | 14 | last if Math::Prime::Util::_get_forexit(); | 
| 6216 | 5 |  |  |  |  | 17 | $sub->(@a[0 .. $k]); | 
| 6217 |  |  |  |  |  |  | } | 
| 6218 | 1 |  |  |  |  | 7 | Math::Prime::Util::_end_for_loop($oldforexit); | 
| 6219 |  |  |  |  |  |  | } | 
| 6220 |  |  |  |  |  |  | sub forcomb { | 
| 6221 | 1 |  |  | 1 | 0 | 609 | my($sub, $n, $k) = @_; | 
| 6222 | 1 |  |  |  |  | 5 | _validate_positive_integer($n); | 
| 6223 |  |  |  |  |  |  |  | 
| 6224 | 1 |  |  |  |  | 3 | my($begk, $endk); | 
| 6225 | 1 | 50 |  |  |  | 13 | if (defined $k) { | 
| 6226 | 1 |  |  |  |  | 6 | _validate_positive_integer($k); | 
| 6227 | 1 | 50 |  |  |  | 3 | return if $k > $n; | 
| 6228 | 1 |  |  |  |  | 4 | $begk = $endk = $k; | 
| 6229 |  |  |  |  |  |  | } else { | 
| 6230 | 0 |  |  |  |  | 0 | $begk = 0; | 
| 6231 | 0 |  |  |  |  | 0 | $endk = $n; | 
| 6232 |  |  |  |  |  |  | } | 
| 6233 |  |  |  |  |  |  |  | 
| 6234 | 1 |  |  |  |  | 5 | my $oldforexit = Math::Prime::Util::_start_for_loop(); | 
| 6235 | 1 |  |  |  |  | 4 | for my $k ($begk .. $endk) { | 
| 6236 | 1 | 50 |  |  |  | 4 | if ($k == 0) { | 
| 6237 | 0 |  |  |  |  | 0 | $sub->(); | 
| 6238 |  |  |  |  |  |  | } else { | 
| 6239 | 1 |  |  |  |  | 5 | my @c = 0 .. $k-1; | 
| 6240 | 1 |  |  |  |  | 2 | while (1) { | 
| 6241 | 3 |  |  |  |  | 10 | $sub->(@c); | 
| 6242 | 3 | 50 |  |  |  | 15 | last if Math::Prime::Util::_get_forexit(); | 
| 6243 | 3 | 100 |  |  |  | 18 | next if $c[-1]++ < $n-1; | 
| 6244 | 2 |  |  |  |  | 7 | my $i = $k-2; | 
| 6245 | 2 |  | 100 |  |  | 20 | $i-- while $i >= 0 && $c[$i] >= $n-($k-$i); | 
| 6246 | 2 | 100 |  |  |  | 11 | last if $i < 0; | 
| 6247 | 1 |  |  |  |  | 3 | $c[$i]++; | 
| 6248 | 1 |  |  |  |  | 4 | while (++$i < $k) { $c[$i] = $c[$i-1] + 1; } | 
|  | 1 |  |  |  |  | 4 |  | 
| 6249 |  |  |  |  |  |  | } | 
| 6250 |  |  |  |  |  |  | } | 
| 6251 | 1 | 50 |  |  |  | 14 | last if Math::Prime::Util::_get_forexit(); | 
| 6252 |  |  |  |  |  |  | } | 
| 6253 | 1 |  |  |  |  | 4 | Math::Prime::Util::_end_for_loop($oldforexit); | 
| 6254 |  |  |  |  |  |  | } | 
| 6255 |  |  |  |  |  |  | sub _forperm { | 
| 6256 | 1 |  |  | 1 |  | 2 | my($sub, $n, $all_perm) = @_; | 
| 6257 | 1 |  |  |  |  | 3 | my $k = $n; | 
| 6258 | 1 |  |  |  |  | 3 | my @c = reverse 0 .. $k-1; | 
| 6259 | 1 |  |  |  |  | 14 | my $inc = 0; | 
| 6260 | 1 |  |  |  |  | 4 | my $send = 1; | 
| 6261 | 1 |  |  |  |  | 5 | my $oldforexit = Math::Prime::Util::_start_for_loop(); | 
| 6262 | 1 |  |  |  |  | 3 | while (1) { | 
| 6263 | 6 | 50 |  |  |  | 15 | if (!$all_perm) {   # Derangements via simple filtering. | 
| 6264 | 0 |  |  |  |  | 0 | $send = 1; | 
| 6265 | 0 |  |  |  |  | 0 | for my $p (0 .. $#c) { | 
| 6266 | 0 | 0 |  |  |  | 0 | if ($c[$p] == $k-$p-1) { | 
| 6267 | 0 |  |  |  |  | 0 | $send = 0; | 
| 6268 | 0 |  |  |  |  | 0 | last; | 
| 6269 |  |  |  |  |  |  | } | 
| 6270 |  |  |  |  |  |  | } | 
| 6271 |  |  |  |  |  |  | } | 
| 6272 | 6 | 50 |  |  |  | 11 | if ($send) { | 
| 6273 | 6 |  |  |  |  | 19 | $sub->(reverse @c); | 
| 6274 | 6 | 50 |  |  |  | 27 | last if Math::Prime::Util::_get_forexit(); | 
| 6275 |  |  |  |  |  |  | } | 
| 6276 | 6 | 100 |  |  |  | 20 | if (++$inc & 1) { | 
| 6277 | 3 |  |  |  |  | 9 | @c[0,1] = @c[1,0]; | 
| 6278 | 3 |  |  |  |  | 5 | next; | 
| 6279 |  |  |  |  |  |  | } | 
| 6280 | 3 |  |  |  |  | 4 | my $j = 2; | 
| 6281 | 3 |  | 100 |  |  | 22 | $j++ while $j < $k && $c[$j] > $c[$j-1]; | 
| 6282 | 3 | 100 |  |  |  | 9 | last if $j >= $k; | 
| 6283 | 2 |  |  |  |  | 4 | my $m = 0; | 
| 6284 | 2 |  |  |  |  | 5 | $m++ while $c[$j] > $c[$m]; | 
| 6285 | 2 |  |  |  |  | 5 | @c[$j,$m] = @c[$m,$j]; | 
| 6286 | 2 |  |  |  |  | 18 | @c[0..$j-1] = reverse @c[0..$j-1]; | 
| 6287 |  |  |  |  |  |  | } | 
| 6288 | 1 |  |  |  |  | 8 | Math::Prime::Util::_end_for_loop($oldforexit); | 
| 6289 |  |  |  |  |  |  | } | 
| 6290 |  |  |  |  |  |  | sub forperm { | 
| 6291 | 1 |  |  | 1 | 0 | 1114 | my($sub, $n, $k) = @_; | 
| 6292 | 1 |  |  |  |  | 14 | _validate_positive_integer($n); | 
| 6293 | 1 | 50 |  |  |  | 7 | croak "Too many arguments for forperm" if defined $k; | 
| 6294 | 1 | 50 |  |  |  | 4 | return $sub->() if $n == 0; | 
| 6295 | 1 | 50 |  |  |  | 4 | return $sub->(0) if $n == 1; | 
| 6296 | 1 |  |  |  |  | 6 | _forperm($sub, $n, 1); | 
| 6297 |  |  |  |  |  |  | } | 
| 6298 |  |  |  |  |  |  | sub forderange { | 
| 6299 | 0 |  |  | 0 | 0 | 0 | my($sub, $n, $k) = @_; | 
| 6300 | 0 |  |  |  |  | 0 | _validate_positive_integer($n); | 
| 6301 | 0 | 0 |  |  |  | 0 | croak "Too many arguments for forderange" if defined $k; | 
| 6302 | 0 | 0 |  |  |  | 0 | return $sub->() if $n == 0; | 
| 6303 | 0 | 0 |  |  |  | 0 | return if $n == 1; | 
| 6304 | 0 |  |  |  |  | 0 | _forperm($sub, $n, 0); | 
| 6305 |  |  |  |  |  |  | } | 
| 6306 |  |  |  |  |  |  |  | 
| 6307 |  |  |  |  |  |  | sub _multiset_permutations { | 
| 6308 | 78 |  |  | 78 |  | 127 | my($sub, $prefix, $ar, $sum) = @_; | 
| 6309 |  |  |  |  |  |  |  | 
| 6310 | 78 | 100 |  |  |  | 129 | return if $sum == 0; | 
| 6311 |  |  |  |  |  |  |  | 
| 6312 |  |  |  |  |  |  | # Remove any values with 0 occurances | 
| 6313 | 77 |  |  |  |  | 120 | my @n = grep { $_->[1] > 0 } @$ar; | 
|  | 238 |  |  |  |  | 454 |  | 
| 6314 |  |  |  |  |  |  |  | 
| 6315 | 77 | 50 |  |  |  | 162 | if ($sum == 1) {                       # A single value | 
|  |  | 100 |  |  |  |  |  | 
| 6316 | 0 |  |  |  |  | 0 | $sub->(@$prefix, $n[0]->[0]); | 
| 6317 |  |  |  |  |  |  | } elsif ($sum == 2) {                  # Optimize the leaf case | 
| 6318 | 51 |  |  |  |  | 73 | my($n0,$n1) = map { $_->[0] } @n; | 
|  | 97 |  |  |  |  | 169 |  | 
| 6319 | 51 | 100 |  |  |  | 96 | if (@n == 1) { | 
| 6320 | 5 |  |  |  |  | 13 | $sub->(@$prefix, $n0, $n0); | 
| 6321 |  |  |  |  |  |  | } else { | 
| 6322 | 46 |  |  |  |  | 111 | $sub->(@$prefix, $n0, $n1); | 
| 6323 | 46 | 100 |  |  |  | 235 | $sub->(@$prefix, $n1, $n0) unless Math::Prime::Util::_get_forexit(); | 
| 6324 |  |  |  |  |  |  | } | 
| 6325 |  |  |  |  |  |  | } elsif (0 && $sum == scalar(@n)) {         # All entries have 1 occurance | 
| 6326 |  |  |  |  |  |  | # TODO:  Figure out a way to use this safely.  We need to capture any | 
| 6327 |  |  |  |  |  |  | #        lastfor that was seen in the forperm. | 
| 6328 |  |  |  |  |  |  | my @i = map { $_->[0] } @n; | 
| 6329 | 0 |  |  | 0 |  | 0 | Math::Prime::Util::forperm(sub { $sub->(@$prefix, @i[@_]) }, 1+$#i); | 
| 6330 |  |  |  |  |  |  | } else {                               # Recurse over each leading value | 
| 6331 | 26 |  |  |  |  | 46 | for my $v (@n) { | 
| 6332 | 73 |  |  |  |  | 90 | $v->[1]--; | 
| 6333 | 73 |  |  |  |  | 113 | push @$prefix, $v->[0]; | 
| 6334 | 40 |  |  | 40 |  | 1149864 | no warnings 'recursion'; | 
|  | 40 |  |  |  |  | 109 |  | 
|  | 40 |  |  |  |  | 113802 |  | 
| 6335 | 73 |  |  |  |  | 193 | _multiset_permutations($sub, $prefix, \@n, $sum-1); | 
| 6336 | 73 |  |  |  |  | 249 | pop @$prefix; | 
| 6337 | 73 |  |  |  |  | 93 | $v->[1]++; | 
| 6338 | 73 | 100 |  |  |  | 169 | last if Math::Prime::Util::_get_forexit(); | 
| 6339 |  |  |  |  |  |  | } | 
| 6340 |  |  |  |  |  |  | } | 
| 6341 |  |  |  |  |  |  | } | 
| 6342 |  |  |  |  |  |  |  | 
| 6343 |  |  |  |  |  |  | sub numtoperm { | 
| 6344 | 0 |  |  | 0 | 0 | 0 | my($n,$k) = @_; | 
| 6345 | 0 |  |  |  |  | 0 | _validate_positive_integer($n); | 
| 6346 | 0 |  |  |  |  | 0 | _validate_integer($k); | 
| 6347 | 0 | 0 |  |  |  | 0 | return () if $n == 0; | 
| 6348 | 0 | 0 |  |  |  | 0 | return (0) if $n == 1; | 
| 6349 | 0 |  |  |  |  | 0 | my $f = factorial($n-1); | 
| 6350 | 0 | 0 | 0 |  |  | 0 | $k %= vecprod($f,$n) if $k < 0 || int($k/$f) >= $n; | 
| 6351 | 0 |  |  |  |  | 0 | my @S = map { $_ } 0 .. $n-1; | 
|  | 0 |  |  |  |  | 0 |  | 
| 6352 | 0 |  |  |  |  | 0 | my @V; | 
| 6353 | 0 |  |  |  |  | 0 | while ($n-- > 0) { | 
| 6354 | 0 |  |  |  |  | 0 | my $i = int($k/$f); | 
| 6355 | 0 |  |  |  |  | 0 | push @V, splice(@S,$i,1); | 
| 6356 | 0 | 0 |  |  |  | 0 | last if $n == 0; | 
| 6357 | 0 |  |  |  |  | 0 | $k -= $i*$f; | 
| 6358 | 0 |  |  |  |  | 0 | $f /= $n; | 
| 6359 |  |  |  |  |  |  | } | 
| 6360 | 0 |  |  |  |  | 0 | @V; | 
| 6361 |  |  |  |  |  |  | } | 
| 6362 |  |  |  |  |  |  |  | 
| 6363 |  |  |  |  |  |  | sub permtonum { | 
| 6364 | 2 |  |  | 2 | 0 | 10533 | my $A = shift; | 
| 6365 | 2 | 50 |  |  |  | 11 | croak "permtonum argument must be an array reference" | 
| 6366 |  |  |  |  |  |  | unless ref($A) eq 'ARRAY'; | 
| 6367 | 2 |  |  |  |  | 5 | my $n = scalar(@$A); | 
| 6368 | 2 | 100 |  |  |  | 12 | return 0 if $n == 0; | 
| 6369 |  |  |  |  |  |  | { | 
| 6370 | 1 |  |  |  |  | 8 | my %S; | 
|  | 1 |  |  |  |  | 2 |  | 
| 6371 | 1 |  |  |  |  | 4 | for my $v (@$A) { | 
| 6372 |  |  |  |  |  |  | croak "permtonum invalid permutation array" | 
| 6373 | 26 | 50 | 33 |  |  | 165 | if !defined $v || $v < 0 || $v >= $n || $S{$v}++; | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
| 6374 |  |  |  |  |  |  | } | 
| 6375 |  |  |  |  |  |  | } | 
| 6376 | 1 |  |  |  |  | 7 | my $f = factorial($n-1); | 
| 6377 | 1 |  |  |  |  | 3 | my $rank = 0; | 
| 6378 | 1 |  |  |  |  | 7 | for my $i (0 .. $n-2) { | 
| 6379 | 25 |  |  |  |  | 6218 | my $k = 0; | 
| 6380 | 25 |  |  |  |  | 70 | for my $j ($i+1 .. $n-1) { | 
| 6381 | 325 | 100 |  |  |  | 587 | $k++ if $A->[$j] < $A->[$i]; | 
| 6382 |  |  |  |  |  |  | } | 
| 6383 | 25 |  |  |  |  | 152 | $rank = Math::Prime::Util::vecsum($rank, Math::Prime::Util::vecprod($k,$f)); | 
| 6384 | 25 |  |  |  |  | 123 | $f /= $n-$i-1; | 
| 6385 |  |  |  |  |  |  | } | 
| 6386 | 1 |  |  |  |  | 222 | $rank; | 
| 6387 |  |  |  |  |  |  | } | 
| 6388 |  |  |  |  |  |  |  | 
| 6389 |  |  |  |  |  |  | sub randperm { | 
| 6390 | 0 |  |  | 0 | 0 | 0 | my($n,$k) = @_; | 
| 6391 | 0 |  |  |  |  | 0 | _validate_positive_integer($n); | 
| 6392 | 0 | 0 |  |  |  | 0 | if (defined $k) { | 
| 6393 | 0 |  |  |  |  | 0 | _validate_positive_integer($k); | 
| 6394 |  |  |  |  |  |  | } | 
| 6395 | 0 | 0 | 0 |  |  | 0 | $k = $n if !defined($k) || $k > $n; | 
| 6396 | 0 | 0 |  |  |  | 0 | return () if $k == 0; | 
| 6397 |  |  |  |  |  |  |  | 
| 6398 | 0 |  |  |  |  | 0 | my @S; | 
| 6399 | 0 | 0 |  |  |  | 0 | if ("$k"/"$n" <= 0.30) { | 
| 6400 | 0 |  |  |  |  | 0 | my %seen; | 
| 6401 |  |  |  |  |  |  | my $v; | 
| 6402 | 0 |  |  |  |  | 0 | for my $i (1 .. $k) { | 
| 6403 | 0 |  |  |  |  | 0 | do { $v = Math::Prime::Util::urandomm($n); } while $seen{$v}++; | 
|  | 0 |  |  |  |  | 0 |  | 
| 6404 | 0 |  |  |  |  | 0 | push @S,$v; | 
| 6405 |  |  |  |  |  |  | } | 
| 6406 |  |  |  |  |  |  | } else { | 
| 6407 | 0 |  |  |  |  | 0 | @S = map { $_ } 0..$n-1; | 
|  | 0 |  |  |  |  | 0 |  | 
| 6408 | 0 |  |  |  |  | 0 | for my $i (0 .. $n-2) { | 
| 6409 | 0 | 0 |  |  |  | 0 | last if $i >= $k; | 
| 6410 | 0 |  |  |  |  | 0 | my $j = Math::Prime::Util::urandomm($n-$i); | 
| 6411 | 0 |  |  |  |  | 0 | @S[$i,$i+$j] = @S[$i+$j,$i]; | 
| 6412 |  |  |  |  |  |  | } | 
| 6413 | 0 |  |  |  |  | 0 | $#S = $k-1; | 
| 6414 |  |  |  |  |  |  | } | 
| 6415 | 0 |  |  |  |  | 0 | return @S; | 
| 6416 |  |  |  |  |  |  | } | 
| 6417 |  |  |  |  |  |  |  | 
| 6418 |  |  |  |  |  |  | sub shuffle { | 
| 6419 | 0 |  |  | 0 | 0 | 0 | my @S=@_; | 
| 6420 |  |  |  |  |  |  | # Note: almost all the time is spent in urandomm. | 
| 6421 | 0 |  |  |  |  | 0 | for (my $i = $#S; $i >= 1; $i--) { | 
| 6422 | 0 |  |  |  |  | 0 | my $j = Math::Prime::Util::urandomm($i+1); | 
| 6423 | 0 |  |  |  |  | 0 | @S[$i,$j] = @S[$j,$i]; | 
| 6424 |  |  |  |  |  |  | } | 
| 6425 | 0 |  |  |  |  | 0 | @S; | 
| 6426 |  |  |  |  |  |  | } | 
| 6427 |  |  |  |  |  |  |  | 
| 6428 |  |  |  |  |  |  | ############################################################################### | 
| 6429 |  |  |  |  |  |  | #       Random numbers | 
| 6430 |  |  |  |  |  |  | ############################################################################### | 
| 6431 |  |  |  |  |  |  |  | 
| 6432 |  |  |  |  |  |  | # PPFE:  irand irand64 drand random_bytes csrand srand _is_csprng_well_seeded | 
| 6433 |  |  |  |  |  |  | sub urandomb { | 
| 6434 | 46 |  |  | 46 | 0 | 175 | my($n) = @_; | 
| 6435 | 46 | 50 |  |  |  | 162 | return 0 if $n <= 0; | 
| 6436 | 46 | 50 |  |  |  | 139 | return ( Math::Prime::Util::irand() >> (32-$n) ) if $n <= 32; | 
| 6437 | 46 | 50 |  |  |  | 125 | return ( Math::Prime::Util::irand64() >> (64-$n) ) if MPU_MAXBITS >= 64 && $n <= 64; | 
| 6438 | 46 |  |  |  |  | 874 | my $bytes = Math::Prime::Util::random_bytes(($n+7)>>3); | 
| 6439 | 46 |  |  |  |  | 244 | my $binary = substr(unpack("B*",$bytes),0,$n); | 
| 6440 | 46 |  |  |  |  | 294 | return Math::BigInt->new("0b$binary"); | 
| 6441 |  |  |  |  |  |  | } | 
| 6442 |  |  |  |  |  |  | sub urandomm { | 
| 6443 | 46 |  |  | 46 | 0 | 163 | my($n) = @_; | 
| 6444 |  |  |  |  |  |  | # _validate_positive_integer($n); | 
| 6445 |  |  |  |  |  |  | return Math::Prime::Util::_reftyped($_[0], Math::Prime::Util::GMP::urandomm($n)) | 
| 6446 | 46 | 50 |  |  |  | 192 | if $Math::Prime::Util::_GMPfunc{"urandomm"}; | 
| 6447 | 46 | 50 |  |  |  | 182 | return 0 if $n <= 1; | 
| 6448 | 46 |  |  |  |  | 5815 | my $r; | 
| 6449 | 46 | 50 |  |  |  | 143 | if ($n <= 4294967295) { | 
|  |  | 50 |  |  |  |  |  | 
| 6450 | 0 |  |  |  |  | 0 | my $rmax = int(4294967295 / $n) * $n; | 
| 6451 | 0 |  |  |  |  | 0 | do { $r = Math::Prime::Util::irand() } while $r >= $rmax; | 
|  | 0 |  |  |  |  | 0 |  | 
| 6452 |  |  |  |  |  |  | } elsif (!ref($n)) { | 
| 6453 | 0 |  |  |  |  | 0 | my $rmax = int(~0 / $n) * $n; | 
| 6454 | 0 |  |  |  |  | 0 | do { $r = Math::Prime::Util::irand64() } while $r >= $rmax; | 
|  | 0 |  |  |  |  | 0 |  | 
| 6455 |  |  |  |  |  |  | } else { | 
| 6456 |  |  |  |  |  |  | # TODO: verify and try to optimize this | 
| 6457 | 46 |  |  |  |  | 6209 | my $bits = length($n->as_bin) - 2; | 
| 6458 | 46 |  |  |  |  | 12656 | my $bytes = 1 + (($bits+7)>>3); | 
| 6459 | 46 |  |  |  |  | 229 | my $rmax = Math::BigInt->bone->blsft($bytes*8)->bdec; | 
| 6460 | 46 |  |  |  |  | 24614 | my $overflow = $rmax - ($rmax % $n); | 
| 6461 | 46 |  |  |  |  | 16926 | do { $r = Math::Prime::Util::urandomb($bytes*8); } while $r >= $overflow; | 
|  | 46 |  |  |  |  | 3004 |  | 
| 6462 |  |  |  |  |  |  | } | 
| 6463 | 46 |  |  |  |  | 23013 | return $r % $n; | 
| 6464 |  |  |  |  |  |  | } | 
| 6465 |  |  |  |  |  |  |  | 
| 6466 |  |  |  |  |  |  | sub random_prime { | 
| 6467 | 2 |  |  | 2 | 0 | 133963 | my($low, $high) = @_; | 
| 6468 | 2 | 50 |  |  |  | 12 | if (scalar(@_) == 1) { ($low,$high) = (2,$low);          } | 
|  | 0 |  |  |  |  | 0 |  | 
| 6469 | 2 |  |  |  |  | 10 | else                 { _validate_positive_integer($low); } | 
| 6470 | 2 |  |  |  |  | 11 | _validate_positive_integer($high); | 
| 6471 |  |  |  |  |  |  |  | 
| 6472 |  |  |  |  |  |  | return Math::Prime::Util::_reftyped($_[0], Math::Prime::Util::GMP::random_prime($low, $high)) | 
| 6473 | 2 | 50 |  |  |  | 20 | if $Math::Prime::Util::_GMPfunc{"random_prime"}; | 
| 6474 |  |  |  |  |  |  |  | 
| 6475 | 2 |  |  |  |  | 1079 | require Math::Prime::Util::RandomPrimes; | 
| 6476 | 2 |  |  |  |  | 13 | return Math::Prime::Util::RandomPrimes::random_prime($low,$high); | 
| 6477 |  |  |  |  |  |  | } | 
| 6478 |  |  |  |  |  |  |  | 
| 6479 |  |  |  |  |  |  | sub random_ndigit_prime { | 
| 6480 | 3 |  |  | 3 | 0 | 2719 | my($digits) = @_; | 
| 6481 | 3 |  |  |  |  | 20 | _validate_positive_integer($digits, 1); | 
| 6482 |  |  |  |  |  |  | return Math::Prime::Util::_reftyped($_[0], Math::Prime::Util::GMP::random_ndigit_prime($digits)) | 
| 6483 | 3 | 50 |  |  |  | 13 | if $Math::Prime::Util::_GMPfunc{"random_ndigit_prime"}; | 
| 6484 | 3 |  |  |  |  | 957 | require Math::Prime::Util::RandomPrimes; | 
| 6485 | 3 |  |  |  |  | 18 | return Math::Prime::Util::RandomPrimes::random_ndigit_prime($digits); | 
| 6486 |  |  |  |  |  |  | } | 
| 6487 |  |  |  |  |  |  | sub random_nbit_prime { | 
| 6488 | 6 |  |  | 6 | 0 | 79294 | my($bits) = @_; | 
| 6489 | 6 |  |  |  |  | 33 | _validate_positive_integer($bits, 2); | 
| 6490 |  |  |  |  |  |  | return Math::Prime::Util::_reftyped($_[0], Math::Prime::Util::GMP::random_nbit_prime($bits)) | 
| 6491 | 6 | 50 |  |  |  | 29 | if $Math::Prime::Util::_GMPfunc{"random_nbit_prime"}; | 
| 6492 | 6 |  |  |  |  | 53 | require Math::Prime::Util::RandomPrimes; | 
| 6493 | 6 |  |  |  |  | 36 | return Math::Prime::Util::RandomPrimes::random_nbit_prime($bits); | 
| 6494 |  |  |  |  |  |  | } | 
| 6495 |  |  |  |  |  |  | sub random_strong_prime { | 
| 6496 | 1 |  |  | 1 | 0 | 212 | my($bits) = @_; | 
| 6497 | 1 |  |  |  |  | 7 | _validate_positive_integer($bits, 128); | 
| 6498 |  |  |  |  |  |  | return Math::Prime::Util::_reftyped($_[0], Math::Prime::Util::GMP::random_strong_prime($bits)) | 
| 6499 | 1 | 50 |  |  |  | 6 | if $Math::Prime::Util::_GMPfunc{"random_strong_prime"}; | 
| 6500 | 1 |  |  |  |  | 10 | require Math::Prime::Util::RandomPrimes; | 
| 6501 | 1 |  |  |  |  | 8 | return Math::Prime::Util::RandomPrimes::random_strong_prime($bits); | 
| 6502 |  |  |  |  |  |  | } | 
| 6503 |  |  |  |  |  |  |  | 
| 6504 |  |  |  |  |  |  | sub random_maurer_prime { | 
| 6505 | 3 |  |  | 3 | 0 | 1122 | my($bits) = @_; | 
| 6506 | 3 |  |  |  |  | 19 | _validate_positive_integer($bits, 2); | 
| 6507 |  |  |  |  |  |  |  | 
| 6508 |  |  |  |  |  |  | return Math::Prime::Util::_reftyped($_[0], Math::Prime::Util::GMP::random_maurer_prime($bits)) | 
| 6509 | 3 | 50 |  |  |  | 15 | if $Math::Prime::Util::_GMPfunc{"random_maurer_prime"}; | 
| 6510 |  |  |  |  |  |  |  | 
| 6511 | 3 |  |  |  |  | 29 | require Math::Prime::Util::RandomPrimes; | 
| 6512 | 3 |  |  |  |  | 22 | my ($n, $cert) = Math::Prime::Util::RandomPrimes::random_maurer_prime_with_cert($bits); | 
| 6513 | 3 | 50 |  |  |  | 24 | croak "maurer prime $n failed certificate verification!" | 
| 6514 |  |  |  |  |  |  | unless Math::Prime::Util::verify_prime($cert); | 
| 6515 |  |  |  |  |  |  |  | 
| 6516 | 3 |  |  |  |  | 36 | return $n; | 
| 6517 |  |  |  |  |  |  | } | 
| 6518 |  |  |  |  |  |  |  | 
| 6519 |  |  |  |  |  |  | sub random_shawe_taylor_prime { | 
| 6520 | 1 |  |  | 1 | 0 | 57 | my($bits) = @_; | 
| 6521 | 1 |  |  |  |  | 7 | _validate_positive_integer($bits, 2); | 
| 6522 |  |  |  |  |  |  |  | 
| 6523 |  |  |  |  |  |  | return Math::Prime::Util::_reftyped($_[0], Math::Prime::Util::GMP::random_shawe_taylor_prime($bits)) | 
| 6524 | 1 | 50 |  |  |  | 7 | if $Math::Prime::Util::_GMPfunc{"random_shawe_taylor_prime"}; | 
| 6525 |  |  |  |  |  |  |  | 
| 6526 | 1 |  |  |  |  | 11 | require Math::Prime::Util::RandomPrimes; | 
| 6527 | 1 |  |  |  |  | 7 | my ($n, $cert) = Math::Prime::Util::RandomPrimes::random_shawe_taylor_prime_with_cert($bits); | 
| 6528 | 1 | 50 |  |  |  | 7 | croak "shawe-taylor prime $n failed certificate verification!" | 
| 6529 |  |  |  |  |  |  | unless Math::Prime::Util::verify_prime($cert); | 
| 6530 |  |  |  |  |  |  |  | 
| 6531 | 1 |  |  |  |  | 13 | return $n; | 
| 6532 |  |  |  |  |  |  | } | 
| 6533 |  |  |  |  |  |  |  | 
| 6534 |  |  |  |  |  |  | sub miller_rabin_random { | 
| 6535 | 2 |  |  | 2 | 0 | 579 | my($n, $k, $seed) = @_; | 
| 6536 | 2 |  |  |  |  | 10 | _validate_positive_integer($n); | 
| 6537 | 2 | 50 |  |  |  | 11 | if (scalar(@_) == 1 ) { $k = 1; } else { _validate_positive_integer($k); } | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 2 |  |  |  |  | 7 |  | 
| 6538 |  |  |  |  |  |  |  | 
| 6539 | 2 | 50 |  |  |  | 9 | return 1 if $k <= 0; | 
| 6540 |  |  |  |  |  |  |  | 
| 6541 | 2 | 50 |  |  |  | 11 | if ($Math::Prime::Util::_GMPfunc{"miller_rabin_random"}) { | 
| 6542 | 0 | 0 |  |  |  | 0 | return Math::Prime::Util::GMP::miller_rabin_random($n, $k, $seed) if defined $seed; | 
| 6543 | 0 |  |  |  |  | 0 | return Math::Prime::Util::GMP::miller_rabin_random($n, $k); | 
| 6544 |  |  |  |  |  |  | } | 
| 6545 |  |  |  |  |  |  |  | 
| 6546 |  |  |  |  |  |  | # Math::Prime::Util::prime_get_config()->{'assume_rh'})  ==>  2*log(n)^2 | 
| 6547 | 2 | 50 |  |  |  | 9 | if ($k >= int(3*$n/4) ) { | 
| 6548 | 0 |  |  |  |  | 0 | for (2 .. int(3*$n/4)+2) { | 
| 6549 | 0 | 0 |  |  |  | 0 | return 0 unless Math::Prime::Util::is_strong_pseudoprime($n, $_); | 
| 6550 |  |  |  |  |  |  | } | 
| 6551 | 0 |  |  |  |  | 0 | return 1; | 
| 6552 |  |  |  |  |  |  | } | 
| 6553 | 2 |  |  |  |  | 1344 | my $brange = $n-2; | 
| 6554 | 2 | 100 |  |  |  | 457 | return 0 unless Math::Prime::Util::is_strong_pseudoprime($n, Math::Prime::Util::urandomm($brange)+2 ); | 
| 6555 | 1 |  |  |  |  | 4 | $k--; | 
| 6556 | 1 |  |  |  |  | 7 | while ($k > 0) { | 
| 6557 | 1 | 50 |  |  |  | 6 | my $nbases = ($k >= 20) ? 20 : $k; | 
| 6558 | 1 | 50 |  |  |  | 5 | return 0 unless is_strong_pseudoprime($n, map { urandomm($brange)+2 } 1 .. $nbases); | 
|  | 19 |  |  |  |  | 6935 |  | 
| 6559 | 1 |  |  |  |  | 31 | $k -= $nbases; | 
| 6560 |  |  |  |  |  |  | } | 
| 6561 | 1 |  |  |  |  | 18 | 1; | 
| 6562 |  |  |  |  |  |  | } | 
| 6563 |  |  |  |  |  |  |  | 
| 6564 |  |  |  |  |  |  | sub random_semiprime { | 
| 6565 | 1 |  |  | 1 | 0 | 5027 | my($b) = @_; | 
| 6566 | 1 | 50 | 33 |  |  | 12 | return 0 if defined $b && int($b) < 0; | 
| 6567 | 1 |  |  |  |  | 7 | _validate_positive_integer($b,4); | 
| 6568 |  |  |  |  |  |  |  | 
| 6569 | 1 |  |  |  |  | 2 | my $n; | 
| 6570 | 1 | 50 |  |  |  | 7 | my $min = ($b <= MPU_MAXBITS)  ?  (1 << ($b-1))  :  BTWO->copy->bpow($b-1); | 
| 6571 | 1 |  |  |  |  | 501 | my $max = $min + ($min - 1); | 
| 6572 | 1 |  |  |  |  | 313 | my $L = $b >> 1; | 
| 6573 | 1 |  |  |  |  | 4 | my $N = $b - $L; | 
| 6574 | 1 | 50 |  |  |  | 5 | my $one = ($b <= MPU_MAXBITS) ? 1 : BONE; | 
| 6575 | 1 |  | 33 |  |  | 3 | do { | 
| 6576 | 1 |  |  |  |  | 5 | $n = $one * random_nbit_prime($L) * random_nbit_prime($N); | 
| 6577 |  |  |  |  |  |  | } while $n < $min || $n > $max; | 
| 6578 | 1 | 50 | 33 |  |  | 329 | $n = _bigint_to_int($n) if ref($n) && $n->bacmp(BMAX) <= 0; | 
| 6579 | 1 |  |  |  |  | 33 | $n; | 
| 6580 |  |  |  |  |  |  | } | 
| 6581 |  |  |  |  |  |  |  | 
| 6582 |  |  |  |  |  |  | sub random_unrestricted_semiprime { | 
| 6583 | 1 |  |  | 1 | 0 | 453 | my($b) = @_; | 
| 6584 | 1 | 50 | 33 |  |  | 10 | return 0 if defined $b && int($b) < 0; | 
| 6585 | 1 |  |  |  |  | 6 | _validate_positive_integer($b,3); | 
| 6586 |  |  |  |  |  |  |  | 
| 6587 | 1 |  |  |  |  | 2 | my $n; | 
| 6588 | 1 | 50 |  |  |  | 7 | my $min = ($b <= MPU_MAXBITS)  ?  (1 << ($b-1))  :  BTWO->copy->bpow($b-1); | 
| 6589 | 1 |  |  |  |  | 480 | my $max = $min + ($min - 1); | 
| 6590 |  |  |  |  |  |  |  | 
| 6591 | 1 | 50 |  |  |  | 301 | if ($b <= 64) { | 
| 6592 | 0 |  |  |  |  | 0 | do { | 
| 6593 | 0 |  |  |  |  | 0 | $n = $min + urandomb($b-1); | 
| 6594 |  |  |  |  |  |  | } while !Math::Prime::Util::is_semiprime($n); | 
| 6595 |  |  |  |  |  |  | } else { | 
| 6596 |  |  |  |  |  |  | # Try to get probabilities right for small divisors | 
| 6597 | 1 |  |  |  |  | 39 | my %M = ( | 
| 6598 |  |  |  |  |  |  | 2 => 1.91218397452243, | 
| 6599 |  |  |  |  |  |  | 3 => 1.33954826555021, | 
| 6600 |  |  |  |  |  |  | 5 => 0.854756717114822, | 
| 6601 |  |  |  |  |  |  | 7 => 0.635492301836862, | 
| 6602 |  |  |  |  |  |  | 11 => 0.426616792046787, | 
| 6603 |  |  |  |  |  |  | 13 => 0.368193843118344, | 
| 6604 |  |  |  |  |  |  | 17 => 0.290512701603111, | 
| 6605 |  |  |  |  |  |  | 19 => 0.263359264658156, | 
| 6606 |  |  |  |  |  |  | 23 => 0.222406328935102, | 
| 6607 |  |  |  |  |  |  | 29 => 0.181229250520242, | 
| 6608 |  |  |  |  |  |  | 31 => 0.170874199059434, | 
| 6609 |  |  |  |  |  |  | 37 => 0.146112155735473, | 
| 6610 |  |  |  |  |  |  | 41 => 0.133427839963585, | 
| 6611 |  |  |  |  |  |  | 43 => 0.127929010905662, | 
| 6612 |  |  |  |  |  |  | 47 => 0.118254609086782, | 
| 6613 |  |  |  |  |  |  | 53 => 0.106316418106489, | 
| 6614 |  |  |  |  |  |  | 59 => 0.0966989675438643, | 
| 6615 |  |  |  |  |  |  | 61 => 0.0938833658008547, | 
| 6616 |  |  |  |  |  |  | 67 => 0.0864151823151671, | 
| 6617 |  |  |  |  |  |  | 71 => 0.0820822953188297, | 
| 6618 |  |  |  |  |  |  | 73 => 0.0800964416340746, | 
| 6619 |  |  |  |  |  |  | 79 => 0.0747060914833344, | 
| 6620 |  |  |  |  |  |  | 83 => 0.0714973706654851, | 
| 6621 |  |  |  |  |  |  | 89 => 0.0672115468436284, | 
| 6622 |  |  |  |  |  |  | 97 => 0.0622818892486191, | 
| 6623 |  |  |  |  |  |  | 101 => 0.0600855891549939, | 
| 6624 |  |  |  |  |  |  | 103 => 0.0590613570015407, | 
| 6625 |  |  |  |  |  |  | 107 => 0.0570921135626976, | 
| 6626 |  |  |  |  |  |  | 109 => 0.0561691667641485, | 
| 6627 |  |  |  |  |  |  | 113 => 0.0544330141081874, | 
| 6628 |  |  |  |  |  |  | 127 => 0.0490620204315701, | 
| 6629 |  |  |  |  |  |  | ); | 
| 6630 | 1 |  |  |  |  | 3 | my ($p,$r); | 
| 6631 | 1 |  |  |  |  | 120 | $r = Math::Prime::Util::drand(); | 
| 6632 | 1 |  |  |  |  | 7 | for my $prime (2..127) { | 
| 6633 | 126 | 100 |  |  |  | 222 | next unless defined $M{$prime}; | 
| 6634 | 31 |  |  |  |  | 53 | my $PR = $M{$prime} / $b  +  0.19556 / $prime; | 
| 6635 | 31 | 50 |  |  |  | 57 | if ($r <= $PR) { | 
| 6636 | 0 |  |  |  |  | 0 | $p = $prime; | 
| 6637 | 0 |  |  |  |  | 0 | last; | 
| 6638 |  |  |  |  |  |  | } | 
| 6639 | 31 |  |  |  |  | 111 | $r -= $PR; | 
| 6640 |  |  |  |  |  |  | } | 
| 6641 | 1 | 50 |  |  |  | 4 | if (!defined $p) { | 
| 6642 |  |  |  |  |  |  | # Idea from Charles Greathouse IV, 2010.  The distribution is right | 
| 6643 |  |  |  |  |  |  | # at the high level (small primes weighted more and not far off what | 
| 6644 |  |  |  |  |  |  | # we get with the uniform selection), but there is a noticeable skew | 
| 6645 |  |  |  |  |  |  | # toward primes with a large gap after them.  For instance 3 ends up | 
| 6646 |  |  |  |  |  |  | # being weighted as much as 2, and 7 more than 5. | 
| 6647 |  |  |  |  |  |  | # | 
| 6648 |  |  |  |  |  |  | # Since we handled small divisors earlier, this is less bothersome. | 
| 6649 | 1 |  |  |  |  | 3 | my $M = 0.26149721284764278375542683860869585905; | 
| 6650 | 1 |  |  |  |  | 8 | my $weight = $M + log($b * log(2)/2); | 
| 6651 | 1 |  |  |  |  | 2 | my $minr = log(log(131)); | 
| 6652 | 1 |  |  |  |  | 2 | do { | 
| 6653 | 2 |  |  |  |  | 8 | $r  = Math::Prime::Util::drand($weight) - $M; | 
| 6654 |  |  |  |  |  |  | } while $r < $minr; | 
| 6655 |  |  |  |  |  |  | # Using Math::BigFloat::bexp is ungodly slow, so avoid at all costs. | 
| 6656 | 1 |  |  |  |  | 11 | my $re = exp($r); | 
| 6657 | 1 | 50 |  |  |  | 7 | my $a = ($re < log(~0)) ? int(exp($re)+0.5) | 
| 6658 |  |  |  |  |  |  | : _upgrade_to_float($re)->bexp->bround->as_int; | 
| 6659 | 1 | 50 |  |  |  | 16 | $p = $a < 2 ? 2 : Math::Prime::Util::prev_prime($a+1); | 
| 6660 |  |  |  |  |  |  | } | 
| 6661 | 1 | 50 |  |  |  | 11 | my $ranmin = ref($min) ? $min->badd($p-1)->bdiv($p)->as_int : int(($min+$p-1)/$p); | 
| 6662 | 1 | 50 |  |  |  | 588 | my $ranmax = ref($max) ? $max->bdiv($p)->as_int : int($max/$p); | 
| 6663 | 1 |  |  |  |  | 384 | my $q = random_prime($ranmin, $ranmax); | 
| 6664 | 1 |  |  |  |  | 85 | $n = Math::Prime::Util::vecprod($p,$q); | 
| 6665 |  |  |  |  |  |  | } | 
| 6666 | 1 | 50 | 33 |  |  | 8 | $n = _bigint_to_int($n) if ref($n) && $n->bacmp(BMAX) <= 0; | 
| 6667 | 1 |  |  |  |  | 26 | $n; | 
| 6668 |  |  |  |  |  |  | } | 
| 6669 |  |  |  |  |  |  |  | 
| 6670 |  |  |  |  |  |  | sub random_factored_integer { | 
| 6671 | 0 |  |  | 0 | 0 |  | my($n) = @_; | 
| 6672 | 0 | 0 | 0 |  |  |  | return (0,[]) if defined $n && int($n) < 0; | 
| 6673 | 0 |  |  |  |  |  | _validate_positive_integer($n,1); | 
| 6674 |  |  |  |  |  |  |  | 
| 6675 | 0 |  |  |  |  |  | while (1) { | 
| 6676 | 0 |  |  |  |  |  | my @S = ($n); | 
| 6677 |  |  |  |  |  |  | # make s_i chain | 
| 6678 | 0 |  |  |  |  |  | push @S, 1 + Math::Prime::Util::urandomm($S[-1])  while $S[-1] > 1; | 
| 6679 |  |  |  |  |  |  | # first is n, last is 1 | 
| 6680 | 0 |  |  |  |  |  | @S = grep { is_prime($_) } @S[1 .. $#S-1]; | 
|  | 0 |  |  |  |  |  |  | 
| 6681 | 0 |  |  |  |  |  | my $r = Math::Prime::Util::vecprod(@S); | 
| 6682 | 0 | 0 | 0 |  |  |  | return ($r, [@S]) if $r <= $n && (1+urandomm($n)) <= $r; | 
| 6683 |  |  |  |  |  |  | } | 
| 6684 |  |  |  |  |  |  | } | 
| 6685 |  |  |  |  |  |  |  | 
| 6686 |  |  |  |  |  |  |  | 
| 6687 |  |  |  |  |  |  |  | 
| 6688 |  |  |  |  |  |  | 1; | 
| 6689 |  |  |  |  |  |  |  | 
| 6690 |  |  |  |  |  |  | __END__ |