| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Math::Prime::Util::PP; |
|
2
|
77
|
|
|
77
|
|
19763057
|
use strict; |
|
|
77
|
|
|
|
|
207
|
|
|
|
77
|
|
|
|
|
3858
|
|
|
3
|
77
|
|
|
77
|
|
438
|
use warnings; |
|
|
77
|
|
|
|
|
161
|
|
|
|
77
|
|
|
|
|
7003
|
|
|
4
|
77
|
|
|
77
|
|
531
|
use Carp qw/carp croak confess/; |
|
|
77
|
|
|
|
|
187
|
|
|
|
77
|
|
|
|
|
10058
|
|
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
BEGIN { |
|
7
|
77
|
|
|
77
|
|
378
|
$Math::Prime::Util::PP::AUTHORITY = 'cpan:DANAJ'; |
|
8
|
77
|
|
|
|
|
14560
|
$Math::Prime::Util::PP::VERSION = '0.74'; |
|
9
|
|
|
|
|
|
|
} |
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
our $BIGINTVERSION = 0.0; |
|
12
|
|
|
|
|
|
|
BEGIN { |
|
13
|
77
|
100
|
|
77
|
|
554
|
do { require Math::BigInt; Math::BigInt->import(try=>"GMP,GMPz,LTM,Pari"); } |
|
|
64
|
|
|
|
|
105606
|
|
|
|
64
|
|
|
|
|
3281381
|
|
|
14
|
|
|
|
|
|
|
unless defined $Math::BigInt::VERSION; |
|
15
|
77
|
|
|
|
|
2179932
|
$BIGINTVERSION = $Math::BigInt::VERSION; |
|
16
|
77
|
|
|
|
|
5568
|
$BIGINTVERSION =~ s/^(\d+)\.(\d+).*/$1.$2/; |
|
17
|
|
|
|
|
|
|
} |
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
# The Pure Perl versions of all the Math::Prime::Util routines. |
|
20
|
|
|
|
|
|
|
# |
|
21
|
|
|
|
|
|
|
# Some of these will be relatively similar in performance, some will be |
|
22
|
|
|
|
|
|
|
# very slow in comparison. |
|
23
|
|
|
|
|
|
|
# |
|
24
|
|
|
|
|
|
|
# Most of these are pretty simple. Also, you really should look at the C |
|
25
|
|
|
|
|
|
|
# code for more detailed comments, including references to papers. |
|
26
|
|
|
|
|
|
|
|
|
27
|
0
|
|
|
|
|
0
|
BEGIN { |
|
28
|
77
|
|
|
77
|
|
726
|
use constant OLD_PERL_VERSION=> $] < 5.008; |
|
|
77
|
|
|
|
|
185
|
|
|
|
77
|
|
|
|
|
7154
|
|
|
29
|
77
|
|
|
77
|
|
505
|
use constant MPU_MAXBITS => (~0 == 4294967295) ? 32 : 64; |
|
|
77
|
|
|
|
|
162
|
|
|
|
77
|
|
|
|
|
4664
|
|
|
30
|
77
|
|
|
77
|
|
513
|
use constant MPU_64BIT => MPU_MAXBITS == 64; |
|
|
77
|
|
|
|
|
210
|
|
|
|
77
|
|
|
|
|
4506
|
|
|
31
|
77
|
|
|
77
|
|
656
|
use constant MPU_32BIT => MPU_MAXBITS == 32; |
|
|
77
|
|
|
|
|
341
|
|
|
|
77
|
|
|
|
|
4743
|
|
|
32
|
|
|
|
|
|
|
#use constant MPU_MAXPARAM => MPU_32BIT ? 4294967295 : 18446744073709551615; |
|
33
|
|
|
|
|
|
|
#use constant MPU_MAXDIGITS => MPU_32BIT ? 10 : 20; |
|
34
|
77
|
|
|
77
|
|
743
|
use constant MPU_MAXPRIME => MPU_32BIT ? 4294967291 : 18446744073709551557; |
|
|
77
|
|
|
|
|
252
|
|
|
|
77
|
|
|
|
|
4040
|
|
|
35
|
77
|
|
|
77
|
|
517
|
use constant MPU_MAXPRIMEIDX => MPU_32BIT ? 203280221 : 425656284035217743; |
|
|
77
|
|
|
|
|
198
|
|
|
|
77
|
|
|
|
|
4613
|
|
|
36
|
77
|
|
|
77
|
|
530
|
use constant MPU_HALFWORD => MPU_32BIT ? 65536 : OLD_PERL_VERSION ? 33554432 : 4294967296; |
|
|
77
|
|
|
|
|
145
|
|
|
|
77
|
|
|
|
|
4506
|
|
|
37
|
77
|
|
|
77
|
|
434
|
use constant UVPACKLET => MPU_32BIT ? 'L' : 'Q'; |
|
|
77
|
|
|
|
|
202
|
|
|
|
77
|
|
|
|
|
6193
|
|
|
38
|
77
|
|
|
77
|
|
473
|
use constant MPU_INFINITY => (65535 > 0+'inf') ? 20**20**20 : 0+'inf'; |
|
|
77
|
|
|
|
|
164
|
|
|
|
77
|
|
|
|
|
6995
|
|
|
39
|
77
|
|
|
77
|
|
470
|
use constant INTMAX => (!OLD_PERL_VERSION || MPU_32BIT) ? ~0 : 562949953421312; |
|
|
77
|
|
|
|
|
218
|
|
|
|
77
|
|
|
|
|
5562
|
|
|
40
|
77
|
|
|
77
|
|
512
|
use constant INTMIN => (MPU_32BIT ? -2147483648 : !OLD_PERL_VERSION ? -9223372036854775808 : -562949953421312); |
|
|
77
|
|
|
|
|
221
|
|
|
|
77
|
|
|
|
|
4832
|
|
|
41
|
77
|
|
|
77
|
|
471
|
use constant SINTMAX => (INTMAX >> 1); |
|
|
77
|
|
|
|
|
186
|
|
|
|
77
|
|
|
|
|
5112
|
|
|
42
|
77
|
|
|
77
|
|
466
|
use constant B_PRIM235 => Math::BigInt->new("30"); |
|
|
77
|
|
|
|
|
158
|
|
|
|
77
|
|
|
|
|
563
|
|
|
43
|
77
|
|
|
77
|
|
21254
|
use constant PI_TIMES_8 => 25.13274122871834590770114707; |
|
|
77
|
|
|
0
|
|
231
|
|
|
|
77
|
|
|
|
|
138976
|
|
|
44
|
|
|
|
|
|
|
} |
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
# TODO: Change this whole file to use this / tobigint |
|
47
|
|
|
|
|
|
|
our $_BIGINT; |
|
48
|
|
|
|
|
|
|
*_BIGINT = \$Math::Prime::Util::_BIGINT; |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# By using these aliases, we call into the main code instead of |
|
52
|
|
|
|
|
|
|
# to the PP function. |
|
53
|
|
|
|
|
|
|
# |
|
54
|
|
|
|
|
|
|
# If we have turned off XS, then this will call the PPFE or direct function. |
|
55
|
|
|
|
|
|
|
# This might be the same, but if the PPFE does input validation it will |
|
56
|
|
|
|
|
|
|
# be slower (albeit every call will be validated). |
|
57
|
|
|
|
|
|
|
# |
|
58
|
|
|
|
|
|
|
# Otherwise, we'll go to the XS function, which will either handle it |
|
59
|
|
|
|
|
|
|
# directly (e.g. we've broken down the input into smaller values which |
|
60
|
|
|
|
|
|
|
# the XS code can handle), or call the GMP backend, otherwise call here. |
|
61
|
|
|
|
|
|
|
# |
|
62
|
|
|
|
|
|
|
# For the usual case where we have XS, this is significantly faster. The |
|
63
|
|
|
|
|
|
|
# aliases make the code here much easier to read. An alternate |
|
64
|
|
|
|
|
|
|
# implementation would be to make the perl subs here use a pp_{...} prefix. |
|
65
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
*validate_integer = \&Math::Prime::Util::_validate_integer; |
|
68
|
|
|
|
|
|
|
*validate_integer_nonneg = \&Math::Prime::Util::_validate_integer_nonneg; |
|
69
|
|
|
|
|
|
|
*validate_integer_positive = \&Math::Prime::Util::_validate_integer_positive; |
|
70
|
|
|
|
|
|
|
*validate_integer_abs = \&Math::Prime::Util::_validate_integer_abs; |
|
71
|
|
|
|
|
|
|
*_bigint_to_int = \&Math::Prime::Util::_bigint_to_int; |
|
72
|
|
|
|
|
|
|
*reftyped = \&Math::Prime::Util::_reftyped; |
|
73
|
|
|
|
|
|
|
#*load_bigint = \&Math::Prime::Util::_load_bigint; |
|
74
|
|
|
|
|
|
|
*tobigint = \&Math::Prime::Util::_to_bigint; |
|
75
|
|
|
|
|
|
|
*maybetobigint = \&Math::Prime::Util::_to_bigint_if_needed; |
|
76
|
|
|
|
|
|
|
*maybetobigintall = \&Math::Prime::Util::_maybe_bigint_allargs; |
|
77
|
|
|
|
|
|
|
*getconfig = \&Math::Prime::Util::prime_get_config; |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
*Maddint = \&Math::Prime::Util::addint; |
|
80
|
|
|
|
|
|
|
*Msubint = \&Math::Prime::Util::subint; |
|
81
|
|
|
|
|
|
|
*Madd1int = \&Math::Prime::Util::add1int; |
|
82
|
|
|
|
|
|
|
*Msub1int = \&Math::Prime::Util::sub1int; |
|
83
|
|
|
|
|
|
|
*Mmulint = \&Math::Prime::Util::mulint; |
|
84
|
|
|
|
|
|
|
*Mdivint = \&Math::Prime::Util::divint; |
|
85
|
|
|
|
|
|
|
*Mpowint = \&Math::Prime::Util::powint; |
|
86
|
|
|
|
|
|
|
*Mmodint = \&Math::Prime::Util::modint; |
|
87
|
|
|
|
|
|
|
*Mcdivint = \&Math::Prime::Util::cdivint; |
|
88
|
|
|
|
|
|
|
*Mabsint = \&Math::Prime::Util::absint; |
|
89
|
|
|
|
|
|
|
*Msqrtint = \&Math::Prime::Util::sqrtint; |
|
90
|
|
|
|
|
|
|
*Mrootint = \&Math::Prime::Util::rootint; |
|
91
|
|
|
|
|
|
|
*Mlogint = \&Math::Prime::Util::logint; |
|
92
|
|
|
|
|
|
|
*Mnegint = \&Math::Prime::Util::negint; |
|
93
|
|
|
|
|
|
|
*Mcmpint = \&Math::Prime::Util::cmpint; |
|
94
|
|
|
|
|
|
|
*Mlshiftint = \&Math::Prime::Util::lshiftint; |
|
95
|
|
|
|
|
|
|
*Mrshiftint = \&Math::Prime::Util::rshiftint; |
|
96
|
|
|
|
|
|
|
*Mdivrem = \&Math::Prime::Util::divrem; |
|
97
|
|
|
|
|
|
|
*Mtdivrem = \&Math::Prime::Util::tdivrem; |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
*Maddmod = \&Math::Prime::Util::addmod; |
|
100
|
|
|
|
|
|
|
*Msubmod = \&Math::Prime::Util::submod; |
|
101
|
|
|
|
|
|
|
*Mmulmod = \&Math::Prime::Util::mulmod; |
|
102
|
|
|
|
|
|
|
*Mdivmod = \&Math::Prime::Util::divmod; |
|
103
|
|
|
|
|
|
|
*Mpowmod = \&Math::Prime::Util::powmod; |
|
104
|
|
|
|
|
|
|
*Minvmod = \&Math::Prime::Util::invmod; |
|
105
|
|
|
|
|
|
|
*Mrootmod = \&Math::Prime::Util::rootmod; |
|
106
|
|
|
|
|
|
|
*Mmuladdmod = \&Math::Prime::Util::muladdmod; |
|
107
|
|
|
|
|
|
|
*Mmulsubmod = \&Math::Prime::Util::mulsubmod; |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
*Mgcd = \&Math::Prime::Util::gcd; |
|
110
|
|
|
|
|
|
|
*Mlcm = \&Math::Prime::Util::lcm; |
|
111
|
|
|
|
|
|
|
*Mgcdext = \&Math::Prime::Util::gcdext; |
|
112
|
|
|
|
|
|
|
*Mfactor = \&Math::Prime::Util::factor; |
|
113
|
|
|
|
|
|
|
*Mfactor_exp = \&Math::Prime::Util::factor_exp; |
|
114
|
|
|
|
|
|
|
*Mtrial_factor = \&Math::Prime::Util::trial_factor; |
|
115
|
|
|
|
|
|
|
*Mdivisors = \&Math::Prime::Util::divisors; |
|
116
|
|
|
|
|
|
|
*Mdivisor_sum = \&Math::Prime::Util::divisor_sum; |
|
117
|
|
|
|
|
|
|
*Mis_prime = \&Math::Prime::Util::is_prime; |
|
118
|
|
|
|
|
|
|
*Mis_semiprime = \&Math::Prime::Util::is_semiprime; |
|
119
|
|
|
|
|
|
|
*Mis_prime_power = \&Math::Prime::Util::is_prime_power; |
|
120
|
|
|
|
|
|
|
*Mis_power = \&Math::Prime::Util::is_power; |
|
121
|
|
|
|
|
|
|
*Mis_square_free = \&Math::Prime::Util::is_square_free; |
|
122
|
|
|
|
|
|
|
*Mis_odd = \&Math::Prime::Util::is_odd; |
|
123
|
|
|
|
|
|
|
*Mis_even = \&Math::Prime::Util::is_even; |
|
124
|
|
|
|
|
|
|
*Mis_congruent = \&Math::Prime::Util::is_congruent; |
|
125
|
|
|
|
|
|
|
*Mis_divisible = \&Math::Prime::Util::is_divisible; |
|
126
|
|
|
|
|
|
|
*Mchinese = \&Math::Prime::Util::chinese; |
|
127
|
|
|
|
|
|
|
*Mvaluation = \&Math::Prime::Util::valuation; |
|
128
|
|
|
|
|
|
|
*Mkronecker = \&Math::Prime::Util::kronecker; |
|
129
|
|
|
|
|
|
|
*Mmoebius = \&Math::Prime::Util::moebius; |
|
130
|
|
|
|
|
|
|
*Mtotient = \&Math::Prime::Util::euler_phi; |
|
131
|
|
|
|
|
|
|
*Mfactorial = \&Math::Prime::Util::factorial; |
|
132
|
|
|
|
|
|
|
*Mfalling_factorial = \&Math::Prime::Util::falling_factorial; |
|
133
|
|
|
|
|
|
|
*Mprimorial = \&Math::Prime::Util::primorial; |
|
134
|
|
|
|
|
|
|
*Mpn_primorial = \&Math::Prime::Util::pn_primorial; |
|
135
|
|
|
|
|
|
|
*Mbinomial = \&Math::Prime::Util::binomial; |
|
136
|
|
|
|
|
|
|
*Mstirling = \&Math::Prime::Util::stirling; |
|
137
|
|
|
|
|
|
|
*Mpowersum = \&Math::Prime::Util::powersum; |
|
138
|
|
|
|
|
|
|
*Murandomm = \&Math::Prime::Util::urandomm; |
|
139
|
|
|
|
|
|
|
*Murandomb = \&Math::Prime::Util::urandomb; |
|
140
|
|
|
|
|
|
|
*Mnext_prime = \&Math::Prime::Util::next_prime; |
|
141
|
|
|
|
|
|
|
*Mprev_prime = \&Math::Prime::Util::prev_prime; |
|
142
|
|
|
|
|
|
|
*Mprime_count = \&Math::Prime::Util::prime_count; |
|
143
|
|
|
|
|
|
|
*Mlucasumod = \&Math::Prime::Util::lucasumod; |
|
144
|
|
|
|
|
|
|
*Mznorder = \&Math::Prime::Util::znorder; |
|
145
|
|
|
|
|
|
|
*Mhclassno = \&Math::Prime::Util::hclassno; |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
*Mvecall = \&Math::Prime::Util::vecall; |
|
148
|
|
|
|
|
|
|
*Mvecany = \&Math::Prime::Util::vecany; |
|
149
|
|
|
|
|
|
|
*Mvecnone = \&Math::Prime::Util::vecnone; |
|
150
|
|
|
|
|
|
|
*Mvecsum = \&Math::Prime::Util::vecsum; |
|
151
|
|
|
|
|
|
|
*Mvecprod = \&Math::Prime::Util::vecprod; |
|
152
|
|
|
|
|
|
|
*Mvecmin = \&Math::Prime::Util::vecmin; |
|
153
|
|
|
|
|
|
|
*Mvecmax = \&Math::Prime::Util::vecmax; |
|
154
|
|
|
|
|
|
|
*Mvecfirst = \&Math::Prime::Util::vecfirst; |
|
155
|
|
|
|
|
|
|
*Mvecsort = \&Math::Prime::Util::vecsort; |
|
156
|
|
|
|
|
|
|
*Mvecsorti = \&Math::Prime::Util::vecsorti; |
|
157
|
|
|
|
|
|
|
*Mvecslide = \&Math::Prime::Util::vecslide; |
|
158
|
|
|
|
|
|
|
*Mtoset = \&Math::Prime::Util::toset; |
|
159
|
|
|
|
|
|
|
*Msetinsert = \&Math::Prime::Util::setinsert; |
|
160
|
|
|
|
|
|
|
*Msetcontains = \&Math::Prime::Util::setcontains; |
|
161
|
|
|
|
|
|
|
*Msetunion = \&Math::Prime::Util::setunion; |
|
162
|
|
|
|
|
|
|
*Msetintersect = \&Math::Prime::Util::setintersect; |
|
163
|
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
*Mfromdigits = \&Math::Prime::Util::fromdigits; |
|
165
|
|
|
|
|
|
|
*Mtodigits = \&Math::Prime::Util::todigits; |
|
166
|
|
|
|
|
|
|
*Mtodigitstring = \&Math::Prime::Util::todigitstring; |
|
167
|
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
*Mprimes = \&Math::Prime::Util::primes; |
|
169
|
|
|
|
|
|
|
*Mfordivisors = \&Math::Prime::Util::fordivisors; |
|
170
|
|
|
|
|
|
|
*Mforprimes = \&Math::Prime::Util::forprimes; |
|
171
|
|
|
|
|
|
|
*MLi = \&Math::Prime::Util::LogarithmicIntegral; |
|
172
|
|
|
|
|
|
|
*Mprime_omega = \&Math::Prime::Util::prime_omega; |
|
173
|
|
|
|
|
|
|
*Mnth_prime_upper = \&Math::Prime::Util::nth_prime_upper; |
|
174
|
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
if (defined $Math::Prime::Util::GMP::VERSION && $Math::Prime::Util::GMP::VERSION >= 0.53) { |
|
176
|
|
|
|
|
|
|
*Saddint = \&Math::Prime::Util::GMP::addint; |
|
177
|
|
|
|
|
|
|
*Ssubint = \&Math::Prime::Util::GMP::subint; |
|
178
|
|
|
|
|
|
|
*Smulint = \&Math::Prime::Util::GMP::mulint; |
|
179
|
|
|
|
|
|
|
*Sdivint = \&Math::Prime::Util::GMP::divint; |
|
180
|
|
|
|
|
|
|
*Spowint = \&Math::Prime::Util::GMP::powint; |
|
181
|
|
|
|
|
|
|
} else { |
|
182
|
|
|
|
|
|
|
*Saddint = \&Math::Prime::Util::addint; |
|
183
|
|
|
|
|
|
|
*Ssubint = \&Math::Prime::Util::subint; |
|
184
|
|
|
|
|
|
|
*Smulint = \&Math::Prime::Util::mulint; |
|
185
|
|
|
|
|
|
|
*Sdivint = \&Math::Prime::Util::divint; |
|
186
|
|
|
|
|
|
|
*Spowint = \&Math::Prime::Util::powint; |
|
187
|
|
|
|
|
|
|
} |
|
188
|
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
# We don't have this function yet. Use a simple version for now. |
|
190
|
|
|
|
|
|
|
*Mtoint = \&_toint_simple; |
|
191
|
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
sub _is_nonneg_int { |
|
194
|
2
|
50
|
33
|
2
|
|
25
|
((defined $_[0]) && $_[0] ne '' && ($_[0] !~ tr/0123456789//c)); |
|
195
|
|
|
|
|
|
|
} |
|
196
|
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
sub _upgrade_to_float { |
|
198
|
1037
|
100
|
|
1037
|
|
12808
|
do { require Math::BigFloat; Math::BigFloat->import(); } |
|
|
2
|
|
|
|
|
4059
|
|
|
|
2
|
|
|
|
|
79750
|
|
|
199
|
|
|
|
|
|
|
if !defined $Math::BigFloat::VERSION; |
|
200
|
1037
|
|
|
|
|
10182
|
Math::BigFloat->new(@_); |
|
201
|
|
|
|
|
|
|
} |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
# Get the accuracy of variable x, or the max default from BigInt/BigFloat |
|
204
|
|
|
|
|
|
|
# One might think to use ref($x)->accuracy() but numbers get upgraded and |
|
205
|
|
|
|
|
|
|
# downgraded willy-nilly, and it will do the wrong thing from the user's |
|
206
|
|
|
|
|
|
|
# perspective. |
|
207
|
|
|
|
|
|
|
sub _find_big_acc { |
|
208
|
40
|
|
|
40
|
|
131
|
my($x) = @_; |
|
209
|
40
|
|
|
|
|
83
|
my $b; |
|
210
|
|
|
|
|
|
|
|
|
211
|
40
|
50
|
|
|
|
259
|
$b = $x->accuracy() if ref($x) =~ /^Math::Big/; |
|
212
|
40
|
100
|
|
|
|
545
|
return $b if defined $b; |
|
213
|
|
|
|
|
|
|
|
|
214
|
16
|
|
|
|
|
39
|
my($i,$f); |
|
215
|
16
|
|
|
|
|
79
|
$i = Math::BigInt->accuracy(); |
|
216
|
16
|
50
|
|
|
|
262
|
$f = defined $Math::BigFloat::VERSION ? Math::BigFloat->accuracy() : undef; |
|
217
|
16
|
0
|
33
|
|
|
235
|
return (($i > $f) ? $i : $f) if defined $i && defined $f; |
|
|
|
50
|
|
|
|
|
|
|
218
|
16
|
50
|
|
|
|
56
|
return $i if defined $i; |
|
219
|
16
|
50
|
|
|
|
53
|
return $f if defined $f; |
|
220
|
|
|
|
|
|
|
|
|
221
|
16
|
|
|
|
|
85
|
$i = Math::BigInt->div_scale(); |
|
222
|
16
|
50
|
|
|
|
367
|
$f = defined $Math::BigFloat::VERSION ? Math::BigFloat->div_scale() : undef; |
|
223
|
16
|
50
|
33
|
|
|
346
|
return (($i > $f) ? $i : $f) if defined $i && defined $f; |
|
|
|
50
|
|
|
|
|
|
|
224
|
16
|
0
|
|
|
|
0
|
return $i if defined $i; |
|
225
|
16
|
0
|
|
|
|
0
|
return $f if defined $f; |
|
226
|
16
|
|
|
|
|
0
|
return 18; |
|
227
|
|
|
|
|
|
|
} |
|
228
|
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
# Only used by RiemannZeta. TODO: refactor to remove this. |
|
230
|
|
|
|
|
|
|
sub _bfdigits { |
|
231
|
0
|
|
|
0
|
|
0
|
my($wantbf, $xdigits) = (0, 17); |
|
232
|
0
|
0
|
0
|
|
|
0
|
if (defined $bignum::VERSION || ref($_[0]) =~ /^Math::Big/) { |
|
233
|
0
|
0
|
|
|
|
0
|
do { require Math::BigFloat; Math::BigFloat->import(); } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
234
|
|
|
|
|
|
|
if !defined $Math::BigFloat::VERSION; |
|
235
|
0
|
0
|
|
|
|
0
|
if (ref($_[0]) eq 'Math::BigInt') { |
|
236
|
0
|
|
|
|
|
0
|
my $xacc = ($_[0])->accuracy(); |
|
237
|
0
|
|
|
|
|
0
|
$_[0] = Math::BigFloat->new($_[0]); |
|
238
|
0
|
0
|
|
|
|
0
|
($_[0])->accuracy($xacc) if $xacc; |
|
239
|
|
|
|
|
|
|
} |
|
240
|
0
|
0
|
|
|
|
0
|
$_[0] = Math::BigFloat->new("$_[0]") if ref($_[0]) ne 'Math::BigFloat'; |
|
241
|
0
|
|
|
|
|
0
|
$wantbf = _find_big_acc($_[0]); |
|
242
|
0
|
|
|
|
|
0
|
$xdigits = $wantbf; |
|
243
|
|
|
|
|
|
|
} |
|
244
|
0
|
|
|
|
|
0
|
($wantbf, $xdigits); |
|
245
|
|
|
|
|
|
|
} |
|
246
|
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
sub _validate_integer { |
|
249
|
456323
|
|
|
456323
|
|
582852
|
if (OLD_PERL_VERSION && defined $_[0] && !ref($_[0])) { |
|
250
|
77
|
|
|
77
|
|
704
|
no warnings 'numeric'; |
|
|
77
|
|
|
|
|
192
|
|
|
|
77
|
|
|
|
|
53148
|
|
|
251
|
|
|
|
|
|
|
$_[0] = "$_[0]" if "$_[0]" > 1e15 || "$_[0]" < -1e15; |
|
252
|
|
|
|
|
|
|
} |
|
253
|
456323
|
|
|
|
|
738474
|
my($n) = @_; |
|
254
|
456323
|
50
|
|
|
|
870527
|
croak "Parameter must be defined" if !defined $n; |
|
255
|
|
|
|
|
|
|
|
|
256
|
456323
|
|
|
|
|
639846
|
my $refn = ref($n); |
|
257
|
|
|
|
|
|
|
|
|
258
|
456323
|
100
|
0
|
|
|
737591
|
if (!$refn) { # Typical case, an integer or string |
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
259
|
453867
|
50
|
66
|
|
|
1657206
|
croak "Parameter '$n' must be an integer" |
|
|
|
|
33
|
|
|
|
|
|
260
|
|
|
|
|
|
|
if $n eq '' || ($n =~ tr/0123456789//c && $n !~ /^([+-]?)\d+\z/); |
|
261
|
453867
|
50
|
33
|
|
|
1038478
|
substr($_[0],0,1,'') if $1 && (substr($n,0,1) eq '+' || $n eq '-0'); |
|
|
|
|
66
|
|
|
|
|
|
262
|
453867
|
100
|
66
|
|
|
1361036
|
$_[0] = maybetobigint($n) if $n >= INTMAX || $n <= INTMIN; |
|
263
|
|
|
|
|
|
|
} elsif ($refn eq 'Math::BigInt') { |
|
264
|
2456
|
50
|
|
|
|
7820
|
croak "Parameter '$n' must be an integer" unless $n->is_int; |
|
265
|
2456
|
0
|
|
|
|
29519
|
if ($n->is_negative) { $_[0]=_bigint_to_int($_[0]) if $n >= INTMIN; } |
|
|
0
|
50
|
|
|
|
0
|
|
|
266
|
2456
|
100
|
|
|
|
21114
|
else { $_[0]=_bigint_to_int($_[0]) if $n <= INTMAX; } |
|
267
|
|
|
|
|
|
|
} elsif ($refn =~ /^Math::/ && $refn ne 'Math::BigFloat') { |
|
268
|
0
|
0
|
0
|
|
|
0
|
$_[0] = _bigint_to_int($_[0]) if $n <= INTMAX && $n >= INTMIN; |
|
269
|
|
|
|
|
|
|
} elsif ($refn eq 'CODE') { |
|
270
|
0
|
|
|
|
|
0
|
$_[0] = $_[0]->(); |
|
271
|
0
|
|
|
|
|
0
|
return _validate_integer($_[0]); |
|
272
|
|
|
|
|
|
|
} else { |
|
273
|
0
|
|
|
|
|
0
|
$_[0] = "$_[0]"; |
|
274
|
0
|
|
|
|
|
0
|
return _validate_integer($_[0]); |
|
275
|
|
|
|
|
|
|
} |
|
276
|
456323
|
50
|
66
|
|
|
1430052
|
$_[0]->upgrade(undef) if ref($_[0]) eq 'Math::BigInt' && $_[0]->upgrade(); |
|
277
|
456323
|
|
|
|
|
740378
|
1; |
|
278
|
|
|
|
|
|
|
} |
|
279
|
|
|
|
|
|
|
sub _validate_integer_nonneg { |
|
280
|
53551
|
|
|
53551
|
|
75538
|
if (OLD_PERL_VERSION && defined $_[0] && !ref($_[0])) { |
|
281
|
77
|
|
|
77
|
|
689
|
no warnings 'numeric'; |
|
|
77
|
|
|
|
|
173
|
|
|
|
77
|
|
|
|
|
1521282
|
|
|
282
|
|
|
|
|
|
|
$_[0] = "$_[0]" if "$_[0]" > 1e15; |
|
283
|
|
|
|
|
|
|
} |
|
284
|
53551
|
|
|
|
|
82599
|
my($n) = @_; |
|
285
|
53551
|
50
|
|
|
|
102200
|
croak "Parameter must be defined" if !defined $n; |
|
286
|
|
|
|
|
|
|
|
|
287
|
53551
|
|
|
|
|
82200
|
my $refn = ref($n); |
|
288
|
|
|
|
|
|
|
|
|
289
|
53551
|
100
|
0
|
|
|
92699
|
if (!$refn) { # Typical case, an integer or string |
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
290
|
53356
|
50
|
33
|
|
|
270450
|
croak "Parameter '$n' must be a non-negative integer" |
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
291
|
|
|
|
|
|
|
if $n eq '' || ($n =~ tr/0123456789//c && $n !~ /^(\+?)\d+\z/) || $n < 0; |
|
292
|
53356
|
50
|
66
|
|
|
131628
|
substr($_[0],0,1,'') if $1 && substr($n,0,1) eq '+'; |
|
293
|
|
|
|
|
|
|
# If probably a bigint, do the upgrade, then verify for edge cases. |
|
294
|
53356
|
100
|
|
|
|
100996
|
$_[0] = maybetobigint($n) if $n >= INTMAX; |
|
295
|
|
|
|
|
|
|
} elsif ($refn eq 'Math::BigInt') { |
|
296
|
195
|
50
|
33
|
|
|
751
|
croak "Parameter '$n' must be a non-negative integer" |
|
297
|
|
|
|
|
|
|
if !$n->is_int || $n->is_negative; |
|
298
|
195
|
100
|
|
|
|
3771
|
$_[0] = _bigint_to_int($_[0]) if $n <= INTMAX; |
|
299
|
|
|
|
|
|
|
} elsif ($refn =~ /^Math::/ && $refn ne 'Math::BigFloat') { |
|
300
|
0
|
0
|
|
|
|
0
|
croak "Parameter '$n' must be a non-negative integer" if $n < 0; |
|
301
|
0
|
0
|
|
|
|
0
|
$_[0] = _bigint_to_int($_[0]) if $n <= INTMAX; |
|
302
|
|
|
|
|
|
|
} elsif ($refn eq 'CODE') { |
|
303
|
0
|
|
|
|
|
0
|
$_[0] = $_[0]->(); |
|
304
|
0
|
|
|
|
|
0
|
return _validate_integer_nonneg($_[0]); |
|
305
|
|
|
|
|
|
|
} else { |
|
306
|
0
|
|
|
|
|
0
|
$_[0] = "$_[0]"; |
|
307
|
0
|
|
|
|
|
0
|
return _validate_integer_nonneg($_[0]); |
|
308
|
|
|
|
|
|
|
} |
|
309
|
53551
|
50
|
66
|
|
|
148520
|
$_[0]->upgrade(undef) if ref($_[0]) eq 'Math::BigInt' && $_[0]->upgrade(); |
|
310
|
53551
|
|
|
|
|
86792
|
1; |
|
311
|
|
|
|
|
|
|
} |
|
312
|
|
|
|
|
|
|
sub _validate_integer_positive { |
|
313
|
10677
|
|
|
10677
|
|
24598
|
_validate_integer($_[0]); |
|
314
|
10677
|
50
|
|
|
|
36307
|
croak "Parameter '$_[0]' must be a positive integer" |
|
315
|
|
|
|
|
|
|
if "$_[0]" < 1; |
|
316
|
10677
|
|
|
|
|
13723
|
1; |
|
317
|
|
|
|
|
|
|
} |
|
318
|
|
|
|
|
|
|
sub _validate_integer_abs { |
|
319
|
4537
|
100
|
|
4537
|
|
9291
|
if (ref($_[0])) { |
|
320
|
21
|
50
|
|
|
|
81
|
$_[0] = -$_[0] if $_[0] < 0; |
|
321
|
|
|
|
|
|
|
} else { |
|
322
|
4516
|
100
|
|
|
|
14348
|
$_[0] =~ s/^-// if "$_[0]" < 0; |
|
323
|
|
|
|
|
|
|
} |
|
324
|
4537
|
|
|
|
|
13933
|
_validate_integer($_[0]); |
|
325
|
|
|
|
|
|
|
} |
|
326
|
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
sub _try_real_gmp_func { |
|
328
|
0
|
|
|
0
|
|
0
|
my($fref, $ver, $x) = @_; |
|
329
|
0
|
0
|
0
|
|
|
0
|
return undef unless defined $Math::Prime::Util::GMP::VERSION && |
|
330
|
|
|
|
|
|
|
$Math::Prime::Util::GMP::VERSION >= $ver; |
|
331
|
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
# For Math::BigInt input we could return Mtoint($str), FP, or full BigFloat. |
|
333
|
|
|
|
|
|
|
|
|
334
|
0
|
0
|
0
|
|
|
0
|
if (!ref($x) || ref($x) eq 'Math::BigInt') { |
|
335
|
0
|
|
|
|
|
0
|
my $fr = 0.0 + $fref->($x, 40); # enough for full long double |
|
336
|
0
|
0
|
0
|
|
|
0
|
return $fr if !ref($x) || ($fr < 1e15 && $fr > -1e15); |
|
|
|
|
0
|
|
|
|
|
|
337
|
|
|
|
|
|
|
} |
|
338
|
0
|
|
|
|
|
0
|
my $dig = _find_big_acc($x); |
|
339
|
0
|
|
|
|
|
0
|
my $str = $fref->($x, $dig); |
|
340
|
0
|
|
|
|
|
0
|
return _upgrade_to_float($str); |
|
341
|
|
|
|
|
|
|
} |
|
342
|
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
sub _binary_search { |
|
344
|
16
|
|
|
16
|
|
63
|
my($n, $lo, $hi, $sub, $exitsub) = @_; |
|
345
|
16
|
|
|
|
|
46
|
while ($lo < $hi) { |
|
346
|
183
|
|
|
|
|
478
|
my $mid = $lo + int(($hi-$lo) >> 1); |
|
347
|
183
|
50
|
66
|
|
|
577
|
return $mid if defined $exitsub && $exitsub->($n,$lo,$hi); |
|
348
|
183
|
100
|
|
|
|
409
|
if ($sub->($mid) < $n) { $lo = $mid+1; } |
|
|
99
|
|
|
|
|
348
|
|
|
349
|
84
|
|
|
|
|
284
|
else { $hi = $mid; } |
|
350
|
|
|
|
|
|
|
} |
|
351
|
16
|
|
|
|
|
110
|
return $lo-1; |
|
352
|
|
|
|
|
|
|
} |
|
353
|
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
################################################################################ |
|
355
|
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
# TODO: this is in progress. |
|
357
|
|
|
|
|
|
|
# It's TBD what should be done on failures (undef? croak?) |
|
358
|
|
|
|
|
|
|
# Handling of trivial floats is terrible. |
|
359
|
|
|
|
|
|
|
# A single native int should be as fast as possible |
|
360
|
|
|
|
|
|
|
sub _toint { |
|
361
|
0
|
|
|
0
|
|
0
|
my @v = @_; # copy them all |
|
362
|
0
|
|
|
|
|
0
|
my @out; |
|
363
|
0
|
|
|
|
|
0
|
for my $v (@v) { |
|
364
|
0
|
0
|
|
|
|
0
|
if (!defined $v) { push @out, 0; next; } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
365
|
0
|
0
|
0
|
|
|
0
|
if (ref($v)) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
366
|
0
|
0
|
|
|
|
0
|
$v = $v->as_int() if ref($v) eq 'Math::BigFloat'; |
|
367
|
|
|
|
|
|
|
} elsif ($v =~ /^[+-]?\d+\z/) { |
|
368
|
|
|
|
|
|
|
# Good as-is |
|
369
|
|
|
|
|
|
|
} elsif ($v =~ /e/i || $v =~ /\./) { |
|
370
|
0
|
|
|
|
|
0
|
$v = _upgrade_to_float($v)->as_int(); |
|
371
|
|
|
|
|
|
|
} else { |
|
372
|
0
|
|
|
|
|
0
|
$v = int($v); |
|
373
|
|
|
|
|
|
|
} |
|
374
|
0
|
0
|
|
|
|
0
|
if ($v =~ /^nan\z/i) { push @out, undef; next; } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
375
|
|
|
|
|
|
|
|
|
376
|
0
|
|
|
|
|
0
|
validate_integer($v); |
|
377
|
0
|
|
|
|
|
0
|
push @out, $v; |
|
378
|
|
|
|
|
|
|
} |
|
379
|
0
|
|
|
|
|
0
|
@out; |
|
380
|
|
|
|
|
|
|
} |
|
381
|
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
sub _toint_simple { |
|
383
|
461
|
|
|
461
|
|
5866
|
my($n) = @_; |
|
384
|
461
|
50
|
|
|
|
1066
|
if ($n >= 0) { |
|
385
|
461
|
|
|
|
|
11830
|
my $max = MPU_32BIT ? 4294967295 : 70368744177664; # 2^46 |
|
386
|
461
|
100
|
|
|
|
4717
|
if ($n =~ /^[+]?\d+\z/) { |
|
|
|
100
|
|
|
|
|
|
|
387
|
4
|
100
|
|
|
|
80
|
return int("$n") if $n < $max; |
|
388
|
|
|
|
|
|
|
} elsif ($n < $max) { |
|
389
|
428
|
|
|
|
|
4000
|
return int("$n"); |
|
390
|
|
|
|
|
|
|
} else { |
|
391
|
29
|
|
|
|
|
13400
|
$n = "" . _upgrade_to_float("$n")->bfloor; |
|
392
|
|
|
|
|
|
|
} |
|
393
|
|
|
|
|
|
|
} else { |
|
394
|
0
|
|
|
|
|
0
|
my $min = MPU_32BIT ? -2147483648 : -35184372088832; # -2^45 |
|
395
|
0
|
0
|
|
|
|
0
|
if ($n =~ /^[-]\d+\z/) { |
|
|
|
0
|
|
|
|
|
|
|
396
|
0
|
0
|
|
|
|
0
|
return int($n) if $n > $min; |
|
397
|
|
|
|
|
|
|
} elsif ($n > $min) { |
|
398
|
0
|
|
|
|
|
0
|
return int($n); |
|
399
|
|
|
|
|
|
|
} else { |
|
400
|
0
|
|
|
|
|
0
|
$n = "" . _upgrade_to_float("$n")->bceil; |
|
401
|
|
|
|
|
|
|
} |
|
402
|
|
|
|
|
|
|
} |
|
403
|
30
|
|
|
|
|
18547
|
validate_integer($n); |
|
404
|
30
|
50
|
66
|
|
|
277
|
$n = tobigint($n) if ref($n) && defined $_BIGINT && ref($n) ne $_BIGINT; |
|
|
|
|
66
|
|
|
|
|
|
405
|
30
|
|
|
|
|
552
|
$n; |
|
406
|
|
|
|
|
|
|
} |
|
407
|
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
sub _frombinary { |
|
409
|
27
|
|
|
27
|
|
121
|
my($bstr) = @_; |
|
410
|
27
|
|
|
|
|
181
|
$bstr =~ s/^0//; |
|
411
|
27
|
50
|
|
|
|
98
|
return oct('0b' . $bstr) if length($bstr) <= 32; |
|
412
|
|
|
|
|
|
|
# Avoid the useless portable warning that can't be silenced. |
|
413
|
27
|
100
|
|
|
|
89
|
if (MPU_MAXBITS >= 64 && length($bstr) <= 64) { # 64-bit Perl, 33-64 bit str |
|
414
|
1
|
|
|
|
|
4
|
my $low = substr($bstr,-32,32,''); |
|
415
|
1
|
|
|
|
|
32
|
return (oct('0b'.$bstr) << 32) + oct('0b'.$low); |
|
416
|
|
|
|
|
|
|
} |
|
417
|
|
|
|
|
|
|
# Length is bigger than word size, so must be a bigint |
|
418
|
26
|
50
|
|
|
|
207
|
if (!defined $_BIGINT) { |
|
|
|
50
|
|
|
|
|
|
|
419
|
0
|
|
|
|
|
0
|
return Math::BigInt->new("0b$bstr"); |
|
420
|
|
|
|
|
|
|
} elsif ($_BIGINT =~ /^Math::(BigInt|GMPz|GMP)$/) { |
|
421
|
26
|
|
|
|
|
203
|
return $_BIGINT->new("0b$bstr"); |
|
422
|
|
|
|
|
|
|
} else { |
|
423
|
0
|
|
|
|
|
0
|
return tobigint( Math::BigInt->new("0b$bstr") ); |
|
424
|
|
|
|
|
|
|
} |
|
425
|
|
|
|
|
|
|
} |
|
426
|
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
################################################################################ |
|
428
|
|
|
|
|
|
|
################################################################################ |
|
429
|
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
my($_precalc_size, @_primes_small) = (2,undef,2); |
|
431
|
|
|
|
|
|
|
{ |
|
432
|
|
|
|
|
|
|
my $_init_precalc_size = 5003; |
|
433
|
|
|
|
|
|
|
_register_free_sub(sub { |
|
434
|
|
|
|
|
|
|
if ($_precalc_size > $_init_precalc_size) { |
|
435
|
|
|
|
|
|
|
($_precalc_size, @_primes_small) = (2,undef,2); |
|
436
|
|
|
|
|
|
|
_expand_prime_cache($_init_precalc_size); |
|
437
|
|
|
|
|
|
|
} |
|
438
|
|
|
|
|
|
|
}); |
|
439
|
|
|
|
|
|
|
_expand_prime_cache($_init_precalc_size); |
|
440
|
|
|
|
|
|
|
} |
|
441
|
|
|
|
|
|
|
sub _expand_prime_cache { |
|
442
|
81
|
|
|
81
|
|
252
|
my($N) = @_; |
|
443
|
81
|
100
|
|
|
|
366
|
if ($N > $_precalc_size) { |
|
444
|
80
|
100
|
|
|
|
322
|
if ($_primes_small[-1] < 7) { |
|
445
|
78
|
|
|
|
|
228
|
@_primes_small = (0,2); |
|
446
|
78
|
|
|
|
|
433
|
my $sieveref = _sieve_erat_string($N); |
|
447
|
78
|
|
|
|
|
54624
|
push @_primes_small, 2*pos($$sieveref)-1 while $$sieveref =~ m/0/g; |
|
448
|
|
|
|
|
|
|
} else { |
|
449
|
2
|
|
|
|
|
10
|
my($lo,$hi) = ($_primes_small[-1] + 2, $N | 0x1); |
|
450
|
2
|
|
|
|
|
20
|
my($BASE, $sieveref) = ($lo-2, _sieve_segment($lo, $hi)); |
|
451
|
2
|
|
|
|
|
8384
|
push @_primes_small, $BASE+2*pos($$sieveref) while $$sieveref =~ m/0/g; |
|
452
|
|
|
|
|
|
|
} |
|
453
|
80
|
|
|
|
|
433
|
$_precalc_size = $N; |
|
454
|
|
|
|
|
|
|
} |
|
455
|
81
|
|
|
|
|
314
|
return $_primes_small[-1]; |
|
456
|
|
|
|
|
|
|
} |
|
457
|
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
my @_prime_next_small = ( |
|
460
|
|
|
|
|
|
|
2,2,3,5,5,7,7,11,11,11,11,13,13,17,17,17,17,19,19,23,23,23,23, |
|
461
|
|
|
|
|
|
|
29,29,29,29,29,29,31,31,37,37,37,37,37,37,41,41,41,41,43,43,47, |
|
462
|
|
|
|
|
|
|
47,47,47,53,53,53,53,53,53,59,59,59,59,59,59,61,61,67,67,67,67,67,67,71); |
|
463
|
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
# For wheel-30 |
|
465
|
|
|
|
|
|
|
my @_prime_indices = (1, 7, 11, 13, 17, 19, 23, 29); |
|
466
|
|
|
|
|
|
|
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); |
|
467
|
|
|
|
|
|
|
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); |
|
468
|
|
|
|
|
|
|
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); |
|
469
|
|
|
|
|
|
|
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); |
|
470
|
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
sub _tiny_prime_count { |
|
472
|
1288
|
|
|
1288
|
|
2248
|
my($n) = @_; |
|
473
|
1288
|
50
|
|
|
|
2887
|
return if $n >= $_primes_small[-1]; |
|
474
|
1288
|
|
|
|
|
1999
|
my $j = $#_primes_small; |
|
475
|
1288
|
|
|
|
|
2171
|
my $i = 1 + ($n >> 4); |
|
476
|
1288
|
|
|
|
|
2810
|
while ($i < $j) { |
|
477
|
12356
|
|
|
|
|
17494
|
my $mid = ($i+$j)>>1; |
|
478
|
12356
|
100
|
|
|
|
21169
|
if ($_primes_small[$mid] <= $n) { $i = $mid+1; } |
|
|
1991
|
|
|
|
|
4467
|
|
|
479
|
10365
|
|
|
|
|
19690
|
else { $j = $mid; } |
|
480
|
|
|
|
|
|
|
} |
|
481
|
1288
|
|
|
|
|
4094
|
return $i-1; |
|
482
|
|
|
|
|
|
|
} |
|
483
|
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
sub _is_prime7 { # n must not be divisible by 2, 3, or 5 |
|
485
|
16199
|
|
|
16199
|
|
184379
|
my($n) = @_; |
|
486
|
|
|
|
|
|
|
|
|
487
|
16199
|
100
|
100
|
|
|
37986
|
$n = _bigint_to_int($n) if ref($n) && $n <= INTMAX; |
|
488
|
|
|
|
|
|
|
|
|
489
|
16199
|
100
|
|
|
|
190155
|
if (ref($n)) { |
|
490
|
|
|
|
|
|
|
# Check div by 7,11,13,17,19,23,29; then by 31,37,...,109,113 |
|
491
|
661
|
100
|
|
|
|
5405
|
return 0 unless Mgcd($n,215656441) == 1; |
|
492
|
438
|
100
|
|
|
|
2617
|
return 0 unless Mgcd($n,'4885866070719029716366506343847722513') == 1; |
|
493
|
345
|
100
|
|
|
|
2366
|
return 0 unless _miller_rabin_2($n); |
|
494
|
90
|
50
|
|
|
|
21911
|
if (Mcmpint($n,"18446744073709551615") <= 0) { |
|
495
|
0
|
0
|
|
|
|
0
|
return is_almost_extra_strong_lucas_pseudoprime($n) ? 2 : 0; |
|
496
|
|
|
|
|
|
|
} |
|
497
|
90
|
100
|
|
|
|
10601
|
return is_extra_strong_lucas_pseudoprime($n) ? 1 : 0; |
|
498
|
|
|
|
|
|
|
} |
|
499
|
|
|
|
|
|
|
|
|
500
|
15538
|
100
|
|
|
|
33344
|
if ($n < 61*61) { |
|
501
|
5865
|
|
|
|
|
14358
|
foreach my $i (qw/7 11 13 17 19 23 29 31 37 41 43 47 53 59/) { |
|
502
|
36135
|
100
|
|
|
|
76706
|
return 2 if $i*$i > $n; |
|
503
|
32598
|
100
|
|
|
|
73770
|
return 0 if !($n % $i); |
|
504
|
|
|
|
|
|
|
} |
|
505
|
151
|
|
|
|
|
665
|
return 2; |
|
506
|
|
|
|
|
|
|
} |
|
507
|
|
|
|
|
|
|
|
|
508
|
9673
|
100
|
100
|
|
|
152990
|
return 0 if !($n % 7) || !($n % 11) || !($n % 13) || !($n % 17) || |
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
509
|
|
|
|
|
|
|
!($n % 19) || !($n % 23) || !($n % 29) || !($n % 31) || |
|
510
|
|
|
|
|
|
|
!($n % 37) || !($n % 41) || !($n % 43) || !($n % 47) || |
|
511
|
|
|
|
|
|
|
!($n % 53) || !($n % 59); |
|
512
|
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
# We could do: |
|
514
|
|
|
|
|
|
|
# return is_strong_pseudoprime($n, (2,299417)) if $n < 19471033; |
|
515
|
|
|
|
|
|
|
# or: |
|
516
|
|
|
|
|
|
|
# foreach my $p (@_primes_small[18..168]) { |
|
517
|
|
|
|
|
|
|
# last if $p > $limit; |
|
518
|
|
|
|
|
|
|
# return 0 unless $n % $p; |
|
519
|
|
|
|
|
|
|
# } |
|
520
|
|
|
|
|
|
|
# return 2; |
|
521
|
|
|
|
|
|
|
|
|
522
|
5821
|
100
|
|
|
|
17744
|
if ($n <= 1_500_000) { |
|
523
|
2530
|
|
|
|
|
6538
|
my $limit = int(sqrt($n)); |
|
524
|
2530
|
|
|
|
|
4270
|
my $i = 61; |
|
525
|
2530
|
|
|
|
|
6589
|
while (($i+30) <= $limit) { |
|
526
|
2347
|
100
|
100
|
|
|
27145
|
return 0 unless ($n% $i ) && ($n%($i+ 6)) && |
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
527
|
|
|
|
|
|
|
($n%($i+10)) && ($n%($i+12)) && |
|
528
|
|
|
|
|
|
|
($n%($i+16)) && ($n%($i+18)) && |
|
529
|
|
|
|
|
|
|
($n%($i+22)) && ($n%($i+28)); |
|
530
|
2224
|
|
|
|
|
4814
|
$i += 30; |
|
531
|
|
|
|
|
|
|
} |
|
532
|
2407
|
|
|
|
|
5189
|
for my $inc (6,4,2,4,2,4,6,2) { |
|
533
|
10229
|
100
|
|
|
|
20626
|
last if $i > $limit; |
|
534
|
8027
|
100
|
|
|
|
16321
|
return 0 if !($n % $i); |
|
535
|
7912
|
|
|
|
|
15007
|
$i += $inc; |
|
536
|
|
|
|
|
|
|
} |
|
537
|
2292
|
|
|
|
|
8970
|
return 2; |
|
538
|
|
|
|
|
|
|
} |
|
539
|
|
|
|
|
|
|
|
|
540
|
3291
|
100
|
|
|
|
6068
|
if ($n < 154639673381) { # BPSW seems to be faster after this |
|
541
|
|
|
|
|
|
|
# Deterministic set of Miller-Rabin tests. If the MR routines can handle |
|
542
|
|
|
|
|
|
|
# bases greater than n, this can be simplified. This covers all 64-bit |
|
543
|
|
|
|
|
|
|
# inputs, even though we restrict it to smaller inputs for performance. |
|
544
|
3239
|
|
|
|
|
4349
|
my @b; |
|
545
|
|
|
|
|
|
|
# n > 1_000_000 because of the previous block. |
|
546
|
3239
|
100
|
|
|
|
5562
|
if ($n < 19471033) {@b=(2,299417)} |
|
|
3198
|
100
|
|
|
|
7376
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
547
|
6
|
|
|
|
|
17
|
elsif ($n < 38010307) {@b=(2,9332593)} |
|
548
|
14
|
|
|
|
|
45
|
elsif ($n < 316349281) {@b=(11000544,31481107)} # 2 bases |
|
549
|
8
|
|
|
|
|
93
|
elsif ($n < 4759123141) {@b=(2,7,61)} |
|
550
|
13
|
|
|
|
|
42
|
elsif ($n < 154639673381) {@b=(15,176006322,4221622697)} # 3 bases |
|
551
|
0
|
|
|
|
|
0
|
elsif ($n < 47636622961201) {@b=(2,2570940,211991001,3749873356)}# 4 bases |
|
552
|
0
|
|
|
|
|
0
|
elsif ($n < 3770579582154547) {@b=(2,2570940,880937,610386380,4130785767)} |
|
553
|
0
|
|
|
|
|
0
|
else {@b=(2,325,9375,28178,450775,9780504,1795265022)} |
|
554
|
3239
|
100
|
|
|
|
6385
|
return is_strong_pseudoprime($n, @b) ? 2 : 0; |
|
555
|
|
|
|
|
|
|
} |
|
556
|
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
# Inlined BPSW |
|
558
|
52
|
100
|
|
|
|
283
|
return 0 unless _miller_rabin_2($n); |
|
559
|
38
|
50
|
|
|
|
380
|
return is_almost_extra_strong_lucas_pseudoprime($n) ? 2 : 0; |
|
560
|
|
|
|
|
|
|
} |
|
561
|
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
sub is_prime { |
|
563
|
14490
|
|
|
14490
|
0
|
94558
|
my($n) = @_; |
|
564
|
14490
|
|
|
|
|
41077
|
validate_integer($n); |
|
565
|
14490
|
100
|
|
|
|
75816
|
return 0 if $n < 2; |
|
566
|
|
|
|
|
|
|
|
|
567
|
14487
|
100
|
|
|
|
273426
|
if (ref($n) eq 'Math::BigInt') { |
|
568
|
1065
|
100
|
|
|
|
4067
|
return 0 unless Math::BigInt::bgcd($n, B_PRIM235)->is_one; |
|
569
|
|
|
|
|
|
|
} else { |
|
570
|
13422
|
100
|
100
|
|
|
25008
|
if ($n < 7) { return ($n == 2) || ($n == 3) || ($n == 5) ? 2 : 0; } |
|
|
99
|
100
|
|
|
|
609
|
|
|
571
|
13323
|
100
|
100
|
|
|
63052
|
return 0 if !($n % 2) || !($n % 3) || !($n % 5); |
|
|
|
|
100
|
|
|
|
|
|
572
|
|
|
|
|
|
|
} |
|
573
|
7821
|
|
|
|
|
213109
|
return _is_prime7($n); |
|
574
|
|
|
|
|
|
|
} |
|
575
|
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
# is_prob_prime is the same thing for us. |
|
577
|
|
|
|
|
|
|
*is_prob_prime = \&is_prime; |
|
578
|
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
# BPSW probable prime. No composites are known to have passed this test |
|
580
|
|
|
|
|
|
|
# since it was published in 1980, though we know infinitely many exist. |
|
581
|
|
|
|
|
|
|
# It has also been verified that no 64-bit composite will return true. |
|
582
|
|
|
|
|
|
|
# Slow since it's all in PP and uses bigints. |
|
583
|
|
|
|
|
|
|
sub _is_bpsw_prime { |
|
584
|
29
|
|
|
29
|
|
90
|
my($n) = @_; |
|
585
|
29
|
0
|
0
|
|
|
117
|
return ($n==2 || $n==3 || $n==5) ? 2 : 0 if $n < 7; |
|
|
|
50
|
|
|
|
|
|
|
586
|
29
|
50
|
|
|
|
5360
|
return 0 unless $n % 2; |
|
587
|
29
|
100
|
|
|
|
8848
|
return 0 unless _miller_rabin_2($n); |
|
588
|
8
|
100
|
|
|
|
1478
|
if ($n <= 18446744073709551615) { |
|
589
|
3
|
50
|
|
|
|
12
|
return is_almost_extra_strong_lucas_pseudoprime($n) ? 2 : 0; |
|
590
|
|
|
|
|
|
|
} |
|
591
|
5
|
50
|
|
|
|
1410
|
return is_extra_strong_lucas_pseudoprime($n) ? 1 : 0; |
|
592
|
|
|
|
|
|
|
} |
|
593
|
|
|
|
|
|
|
sub is_bpsw_prime { |
|
594
|
29
|
|
|
29
|
0
|
123
|
my($n) = @_; |
|
595
|
29
|
|
|
|
|
148
|
validate_integer($n); |
|
596
|
29
|
|
|
|
|
1189
|
return _is_bpsw_prime($n); |
|
597
|
|
|
|
|
|
|
} |
|
598
|
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
sub is_provable_prime { |
|
600
|
0
|
|
|
0
|
0
|
0
|
my($n) = @_; |
|
601
|
0
|
|
|
|
|
0
|
validate_integer($n); |
|
602
|
0
|
0
|
|
|
|
0
|
return _is_bpsw_prime($n) if $n <= 18446744073709551615; |
|
603
|
0
|
|
|
|
|
0
|
my($is_prime, $cert) = Math::Prime::Util::is_provable_prime_with_cert($n); |
|
604
|
0
|
|
|
|
|
0
|
$is_prime; |
|
605
|
|
|
|
|
|
|
} |
|
606
|
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
# Possible sieve storage: |
|
608
|
|
|
|
|
|
|
# 1) vec with mod-30 wheel: 8 bits / 30 |
|
609
|
|
|
|
|
|
|
# 2) vec with mod-2 wheel : 15 bits / 30 |
|
610
|
|
|
|
|
|
|
# 3) str with mod-30 wheel: 8 bytes / 30 |
|
611
|
|
|
|
|
|
|
# 4) str with mod-2 wheel : 15 bytes / 30 |
|
612
|
|
|
|
|
|
|
# |
|
613
|
|
|
|
|
|
|
# It looks like using vecs is about 2x slower than strs, and the strings also |
|
614
|
|
|
|
|
|
|
# let us do some fast operations on the results. E.g. |
|
615
|
|
|
|
|
|
|
# Count all primes: |
|
616
|
|
|
|
|
|
|
# $count += $$sieveref =~ tr/0//; |
|
617
|
|
|
|
|
|
|
# Loop over primes: |
|
618
|
|
|
|
|
|
|
# foreach my $s (split("0", $$sieveref, -1)) { |
|
619
|
|
|
|
|
|
|
# $n += 2 + 2 * length($s); |
|
620
|
|
|
|
|
|
|
# .. do something with the prime $n |
|
621
|
|
|
|
|
|
|
# } |
|
622
|
|
|
|
|
|
|
# |
|
623
|
|
|
|
|
|
|
# We're using method 4, though sadly it is memory intensive relative to the |
|
624
|
|
|
|
|
|
|
# other methods. I will point out that it is 30-60x less memory than sieves |
|
625
|
|
|
|
|
|
|
# using an array, and the performance of this function is over 10x that |
|
626
|
|
|
|
|
|
|
# of naive sieves. |
|
627
|
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
sub _sieve_erat_string { |
|
629
|
112
|
|
|
112
|
|
311
|
my($end) = @_; |
|
630
|
112
|
100
|
|
|
|
606
|
$end-- if ($end & 1) == 0; |
|
631
|
112
|
|
|
|
|
307
|
my $s_end = $end >> 1; |
|
632
|
|
|
|
|
|
|
|
|
633
|
112
|
|
|
|
|
489
|
my $whole = int( $s_end / 15); # Prefill with 3 and 5 already marked. |
|
634
|
112
|
50
|
|
|
|
468
|
croak "Sieve too large" if $whole > 1_145_324_612; # ~32 GB string |
|
635
|
112
|
|
|
|
|
6020
|
my $sieve = '100010010010110' . '011010010010110' x $whole; |
|
636
|
112
|
|
|
|
|
465
|
substr($sieve, $s_end+1) = ''; # Ensure we don't make too many entries |
|
637
|
112
|
|
|
|
|
429
|
my ($n, $limit) = ( 7, int(sqrt($end)) ); |
|
638
|
112
|
|
|
|
|
465
|
while ( $n <= $limit ) { |
|
639
|
2873
|
|
|
|
|
6882
|
for (my $s = ($n*$n) >> 1; $s <= $s_end; $s += $n) { |
|
640
|
2738328
|
|
|
|
|
5398455
|
substr($sieve, $s, 1) = '1'; |
|
641
|
|
|
|
|
|
|
} |
|
642
|
2873
|
|
|
|
|
4450
|
do { $n += 2 } while substr($sieve, $n>>1, 1); |
|
|
6642
|
|
|
|
|
20372
|
|
|
643
|
|
|
|
|
|
|
} |
|
644
|
112
|
|
|
|
|
4092
|
return \$sieve; |
|
645
|
|
|
|
|
|
|
} |
|
646
|
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
# TODO: this should be integrated with prime_precalc |
|
648
|
|
|
|
|
|
|
{ |
|
649
|
|
|
|
|
|
|
my $primary_size_limit = 15000; |
|
650
|
|
|
|
|
|
|
my $primary_sieve_size = 0; |
|
651
|
|
|
|
|
|
|
my $primary_sieve_ref; |
|
652
|
|
|
|
|
|
|
sub _sieve_erat { |
|
653
|
2326
|
|
|
2326
|
|
3645
|
my($end) = @_; |
|
654
|
|
|
|
|
|
|
|
|
655
|
2326
|
100
|
|
|
|
6565
|
return _sieve_erat_string($end) if $end > $primary_size_limit; |
|
656
|
|
|
|
|
|
|
|
|
657
|
2294
|
100
|
|
|
|
4045
|
if ($primary_sieve_size == 0) { |
|
658
|
2
|
|
|
|
|
5
|
$primary_sieve_size = $primary_size_limit; |
|
659
|
2
|
|
|
|
|
9
|
$primary_sieve_ref = _sieve_erat_string($primary_sieve_size); |
|
660
|
|
|
|
|
|
|
} |
|
661
|
2294
|
|
|
|
|
6768
|
my $sieve = substr($$primary_sieve_ref, 0, ($end+1)>>1); |
|
662
|
2294
|
|
|
|
|
8639
|
return \$sieve; |
|
663
|
|
|
|
|
|
|
} |
|
664
|
|
|
|
|
|
|
_register_free_sub(sub { |
|
665
|
|
|
|
|
|
|
($primary_sieve_size, $primary_sieve_ref) = (0,''); |
|
666
|
|
|
|
|
|
|
}); |
|
667
|
|
|
|
|
|
|
} |
|
668
|
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
sub _sieve_segment { |
|
671
|
634
|
|
|
634
|
|
1553
|
my($beg,$end,$limit) = @_; |
|
672
|
634
|
50
|
33
|
|
|
1557
|
($beg, $end) = map { _bigint_to_int($_) } ($beg, $end) |
|
|
0
|
|
|
|
|
0
|
|
|
673
|
|
|
|
|
|
|
if ref($end) && $end <= INTMAX; |
|
674
|
634
|
50
|
|
|
|
1598
|
croak "Internal error: segment beg is even" if ($beg % 2) == 0; |
|
675
|
634
|
50
|
|
|
|
1339
|
croak "Internal error: segment end is even" if ($end % 2) == 0; |
|
676
|
634
|
50
|
|
|
|
1404
|
croak "Internal error: segment end < beg" if $end < $beg; |
|
677
|
634
|
50
|
|
|
|
1449
|
croak "Internal error: segment beg should be >= 3" if $beg < 3; |
|
678
|
634
|
|
|
|
|
1489
|
my $range = int( ($end - $beg) / 2 ) + 1; |
|
679
|
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
# Prefill with 3 and 5 already marked, and offset to the segment start. |
|
681
|
634
|
|
|
|
|
1238
|
my $whole = int( ($range+14) / 15); |
|
682
|
634
|
|
|
|
|
1124
|
my $startp = ($beg % 30) >> 1; |
|
683
|
634
|
|
|
|
|
4123
|
my $sieve = substr('011010010010110', $startp) . '011010010010110' x $whole; |
|
684
|
|
|
|
|
|
|
# Set 3 and 5 to prime if we're sieving them. |
|
685
|
634
|
100
|
|
|
|
1356
|
substr($sieve,0,2) = '00' if $beg == 3; |
|
686
|
634
|
100
|
|
|
|
1506
|
substr($sieve,0,1) = '0' if $beg == 5; |
|
687
|
|
|
|
|
|
|
# Get rid of any extra we added. |
|
688
|
634
|
|
|
|
|
1022
|
substr($sieve, $range) = ''; |
|
689
|
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
# If the end value is below 7^2, then the pre-sieve is all we needed. |
|
691
|
634
|
100
|
|
|
|
1382
|
return \$sieve if $end < 49; |
|
692
|
|
|
|
|
|
|
|
|
693
|
624
|
|
|
|
|
2485
|
my $sqlimit = Msqrtint($end); |
|
694
|
624
|
50
|
33
|
|
|
1692
|
$limit = $sqlimit if !defined $limit || $sqlimit < $limit; |
|
695
|
|
|
|
|
|
|
# For large value of end, it's a huge win to just walk primes. |
|
696
|
|
|
|
|
|
|
|
|
697
|
624
|
|
|
|
|
1487
|
my($p, $s, $primesieveref) = (7-2, 3, _sieve_erat($limit)); |
|
698
|
624
|
|
|
|
|
1256
|
my $sieve_end = ($end - $beg) >> 1; |
|
699
|
624
|
|
|
|
|
1701
|
while ( (my $nexts = 1 + index($$primesieveref, '0', $s)) > 0 ) { |
|
700
|
40830
|
|
|
|
|
49999
|
$p += 2 * ($nexts - $s); |
|
701
|
40830
|
|
|
|
|
49375
|
$s = $nexts; |
|
702
|
40830
|
|
|
|
|
47591
|
my $p2 = $p*$p; |
|
703
|
|
|
|
|
|
|
|
|
704
|
40830
|
100
|
|
|
|
60802
|
if ($p2 < $beg) { # Make p2 the next odd multiple of p >= beg |
|
705
|
40207
|
50
|
|
|
|
55861
|
if ($beg < 2**49) { |
|
706
|
40207
|
|
|
|
|
60153
|
my $f = int(($beg+$p-1)/$p); |
|
707
|
40207
|
|
|
|
|
54630
|
$p2 = $p * ($f + (1-($f&1))); |
|
708
|
|
|
|
|
|
|
} else { |
|
709
|
0
|
|
|
|
|
0
|
my $f = Mcdivint($beg,$p); |
|
710
|
0
|
|
|
|
|
0
|
$p2 = Mmulint($p, $f + (1-($f&1))); |
|
711
|
|
|
|
|
|
|
} |
|
712
|
|
|
|
|
|
|
} |
|
713
|
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
# Large bases and small segments often don't hit the segment at all. |
|
715
|
40830
|
100
|
|
|
|
82301
|
next if $p2 > $end; |
|
716
|
|
|
|
|
|
|
|
|
717
|
|
|
|
|
|
|
# Inner loop marking multiples of p, divide by 2 to keep loop simpler. |
|
718
|
20939
|
|
|
|
|
32783
|
for ($p2 = ($p2 - $beg) >> 1; $p2 <= $sieve_end; $p2 += $p) { |
|
719
|
676511
|
|
|
|
|
1067804
|
substr($sieve, $p2, 1) = '1'; |
|
720
|
|
|
|
|
|
|
} |
|
721
|
|
|
|
|
|
|
} |
|
722
|
624
|
|
|
|
|
2761
|
\$sieve; |
|
723
|
|
|
|
|
|
|
} |
|
724
|
|
|
|
|
|
|
|
|
725
|
|
|
|
|
|
|
sub trial_primes { |
|
726
|
2
|
|
|
2
|
0
|
3394
|
my($low,$high) = @_; |
|
727
|
2
|
100
|
|
|
|
8
|
if (!defined $high) { |
|
728
|
1
|
|
|
|
|
2
|
$high = $low; |
|
729
|
1
|
|
|
|
|
3
|
$low = 2; |
|
730
|
|
|
|
|
|
|
} |
|
731
|
2
|
|
|
|
|
13
|
validate_integer_nonneg($low); |
|
732
|
2
|
|
|
|
|
40
|
validate_integer_nonneg($high); |
|
733
|
2
|
50
|
|
|
|
27
|
return if $low > $high; |
|
734
|
2
|
|
|
|
|
39
|
my @primes; |
|
735
|
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
# For a tiny range, just use next_prime calls |
|
737
|
2
|
50
|
|
|
|
7
|
if (($high-$low) < 1000) { |
|
738
|
2
|
50
|
|
|
|
323
|
$low-- if $low >= 2; |
|
739
|
2
|
|
|
|
|
241
|
my $curprime = Mnext_prime($low); |
|
740
|
2
|
|
|
|
|
7
|
while ($curprime <= $high) { |
|
741
|
24
|
|
|
|
|
135
|
push @primes, $curprime; |
|
742
|
24
|
|
|
|
|
37
|
$curprime = Mnext_prime($curprime); |
|
743
|
|
|
|
|
|
|
} |
|
744
|
2
|
|
|
|
|
58
|
return \@primes; |
|
745
|
|
|
|
|
|
|
} |
|
746
|
|
|
|
|
|
|
|
|
747
|
|
|
|
|
|
|
# Sieve to 10k then BPSW test |
|
748
|
0
|
0
|
0
|
|
|
0
|
push @primes, 2 if ($low <= 2) && ($high >= 2); |
|
749
|
0
|
0
|
0
|
|
|
0
|
push @primes, 3 if ($low <= 3) && ($high >= 3); |
|
750
|
0
|
0
|
0
|
|
|
0
|
push @primes, 5 if ($low <= 5) && ($high >= 5); |
|
751
|
0
|
0
|
|
|
|
0
|
$low = 7 if $low < 7; |
|
752
|
0
|
0
|
|
|
|
0
|
$low++ if ($low % 2) == 0; |
|
753
|
0
|
0
|
|
|
|
0
|
$high-- if ($high % 2) == 0; |
|
754
|
0
|
|
|
|
|
0
|
my $sieveref = _sieve_segment($low, $high, 10000); |
|
755
|
0
|
|
|
|
|
0
|
my $n = $low-2; |
|
756
|
0
|
|
|
|
|
0
|
while ($$sieveref =~ m/0/g) { |
|
757
|
0
|
|
|
|
|
0
|
my $p = $n+2*pos($$sieveref); |
|
758
|
0
|
0
|
0
|
|
|
0
|
push @primes, $p if _miller_rabin_2($p) && is_extra_strong_lucas_pseudoprime($p); |
|
759
|
|
|
|
|
|
|
} |
|
760
|
0
|
|
|
|
|
0
|
return \@primes; |
|
761
|
|
|
|
|
|
|
} |
|
762
|
|
|
|
|
|
|
|
|
763
|
|
|
|
|
|
|
sub primes { |
|
764
|
2720
|
|
|
2720
|
0
|
45608
|
my($low,$high) = @_; |
|
765
|
2720
|
100
|
|
|
|
7193
|
if (scalar @_ > 1) { |
|
766
|
2670
|
|
|
|
|
7055
|
validate_integer_nonneg($low); |
|
767
|
2670
|
100
|
|
|
|
6132
|
$low = 2 if $low < 2; |
|
768
|
|
|
|
|
|
|
} else { |
|
769
|
50
|
|
|
|
|
147
|
($low,$high) = (2, $low); |
|
770
|
|
|
|
|
|
|
} |
|
771
|
2720
|
|
|
|
|
6350
|
validate_integer_nonneg($high); |
|
772
|
2720
|
|
|
|
|
4785
|
my $sref = []; |
|
773
|
2720
|
100
|
66
|
|
|
14923
|
return $sref if ($low > $high) || ($high < 2); |
|
774
|
801
|
100
|
|
|
|
6194
|
return [grep { $_ >= $low && $_ <= $high } @_primes_small] |
|
|
646760
|
100
|
|
|
|
1706917
|
|
|
775
|
|
|
|
|
|
|
if $high <= $_primes_small[-1]; |
|
776
|
|
|
|
|
|
|
|
|
777
|
10
|
50
|
33
|
|
|
254
|
if ($Math::Prime::Util::_GMPfunc{"sieve_primes"} && $Math::Prime::Util::GMP::VERSION >= 0.34) { |
|
778
|
0
|
|
|
|
|
0
|
my @pr = Math::Prime::Util::GMP::sieve_primes($low, $high, 0); |
|
779
|
0
|
0
|
|
|
|
0
|
return ref($high) ? [maybetobigintall(@pr)] : \@pr; |
|
780
|
|
|
|
|
|
|
} |
|
781
|
|
|
|
|
|
|
|
|
782
|
|
|
|
|
|
|
# At some point even the pretty-fast pure perl sieve is going to be a |
|
783
|
|
|
|
|
|
|
# dog, and we should move to trials. This is typical with a small range |
|
784
|
|
|
|
|
|
|
# on a large base. More thought on the switchover should be done. |
|
785
|
10
|
50
|
66
|
|
|
134
|
return trial_primes($low, $high) if ref($low) eq 'Math::BigInt' |
|
|
|
|
33
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
786
|
|
|
|
|
|
|
|| ref($high) eq 'Math::BigInt' |
|
787
|
|
|
|
|
|
|
|| ($low > 1_000_000_000_000 && ($high-$low) < int($low/1_000_000)); |
|
788
|
|
|
|
|
|
|
|
|
789
|
9
|
100
|
66
|
|
|
49
|
push @$sref, 2 if ($low <= 2) && ($high >= 2); |
|
790
|
9
|
100
|
66
|
|
|
42
|
push @$sref, 3 if ($low <= 3) && ($high >= 3); |
|
791
|
9
|
100
|
66
|
|
|
41
|
push @$sref, 5 if ($low <= 5) && ($high >= 5); |
|
792
|
9
|
100
|
|
|
|
62
|
$low = 7 if $low < 7; |
|
793
|
9
|
100
|
|
|
|
37
|
$low++ if ($low % 2) == 0; |
|
794
|
9
|
100
|
|
|
|
62
|
$high-- if ($high % 2) == 0; |
|
795
|
9
|
50
|
|
|
|
72
|
return $sref if $low > $high; |
|
796
|
|
|
|
|
|
|
|
|
797
|
9
|
|
|
|
|
20
|
my($n,$sieveref); |
|
798
|
9
|
100
|
|
|
|
37
|
if ($low == 7) { |
|
799
|
2
|
|
|
|
|
6
|
$n = 0; |
|
800
|
2
|
|
|
|
|
10
|
$sieveref = _sieve_erat($high); |
|
801
|
2
|
|
|
|
|
15
|
substr($$sieveref,0,3,'111'); |
|
802
|
|
|
|
|
|
|
} else { |
|
803
|
7
|
|
|
|
|
30
|
$n = $low-1; |
|
804
|
7
|
|
|
|
|
111
|
$sieveref = _sieve_segment($low,$high); |
|
805
|
|
|
|
|
|
|
} |
|
806
|
9
|
|
|
|
|
14798
|
push @$sref, $n+2*pos($$sieveref)-1 while $$sieveref =~ m/0/g; |
|
807
|
9
|
|
|
|
|
1293
|
$sref; |
|
808
|
|
|
|
|
|
|
} |
|
809
|
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
sub sieve_range { |
|
811
|
4
|
|
|
4
|
0
|
1706
|
my($n, $width, $depth) = @_; |
|
812
|
4
|
|
|
|
|
17
|
validate_integer_nonneg($n); |
|
813
|
4
|
|
|
|
|
11
|
validate_integer_nonneg($width); |
|
814
|
4
|
|
|
|
|
8
|
validate_integer_nonneg($depth); |
|
815
|
|
|
|
|
|
|
|
|
816
|
4
|
|
|
|
|
4
|
my @candidates; |
|
817
|
4
|
|
|
|
|
6
|
my $start = $n; |
|
818
|
|
|
|
|
|
|
|
|
819
|
4
|
100
|
|
|
|
10
|
if ($n < 5) { |
|
820
|
1
|
50
|
33
|
|
|
4
|
push @candidates, (2-$n) if $n <= 2 && $n+$width-1 >= 2; |
|
821
|
1
|
50
|
33
|
|
|
4
|
push @candidates, (3-$n) if $n <= 3 && $n+$width-1 >= 3; |
|
822
|
1
|
50
|
33
|
|
|
11
|
push @candidates, (4-$n) if $n <= 4 && $n+$width-1 >= 4 && $depth < 2; |
|
|
|
|
33
|
|
|
|
|
|
823
|
1
|
|
|
|
|
3
|
$start = 5; |
|
824
|
1
|
|
|
|
|
3
|
$width -= ($start - $n); |
|
825
|
|
|
|
|
|
|
} |
|
826
|
|
|
|
|
|
|
|
|
827
|
4
|
100
|
|
|
|
11
|
return @candidates, map {$start+$_-$n } 0 .. $width-1 if $depth < 2; |
|
|
3
|
|
|
|
|
7
|
|
|
828
|
17
|
|
|
|
|
39
|
return @candidates, map { $_ - $n } |
|
829
|
40
|
100
|
100
|
|
|
101
|
grep { ($_ & 1) && ($depth < 3 || ($_ % 3)) } |
|
830
|
3
|
100
|
|
|
|
17
|
map { $start+$_ } |
|
|
40
|
|
|
|
|
57
|
|
|
831
|
|
|
|
|
|
|
0 .. $width-1 if $depth < 5; |
|
832
|
|
|
|
|
|
|
|
|
833
|
1
|
50
|
|
|
|
9
|
if (!($start & 1)) { $start++; $width--; } |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
2
|
|
|
834
|
1
|
50
|
|
|
|
4
|
$width-- if !($width&1); |
|
835
|
1
|
50
|
|
|
|
6
|
return @candidates if $width < 1; |
|
836
|
|
|
|
|
|
|
|
|
837
|
1
|
|
|
|
|
8
|
my $sieveref = _sieve_segment($start, $start+$width-1, $depth); |
|
838
|
1
|
|
|
|
|
4
|
my $offset = $start - $n - 2; |
|
839
|
1
|
|
|
|
|
9
|
while ($$sieveref =~ m/0/g) { |
|
840
|
6
|
|
|
|
|
12
|
push @candidates, $offset + (pos($$sieveref) << 1); |
|
841
|
|
|
|
|
|
|
} |
|
842
|
1
|
|
|
|
|
9
|
return @candidates; |
|
843
|
|
|
|
|
|
|
} |
|
844
|
|
|
|
|
|
|
|
|
845
|
|
|
|
|
|
|
sub sieve_prime_cluster { |
|
846
|
19
|
|
|
19
|
0
|
5523322
|
my($lo,$hi,@cl) = @_; |
|
847
|
19
|
|
|
|
|
114
|
my $_verbose = getconfig()->{'verbose'}; |
|
848
|
19
|
|
|
|
|
141
|
validate_integer_nonneg($lo); |
|
849
|
19
|
|
|
|
|
913
|
validate_integer_nonneg($hi); |
|
850
|
|
|
|
|
|
|
|
|
851
|
19
|
50
|
|
|
|
479
|
if ($Math::Prime::Util::_GMPfunc{"sieve_prime_cluster"}) { |
|
852
|
0
|
|
|
|
|
0
|
return maybetobigintall( |
|
853
|
|
|
|
|
|
|
Math::Prime::Util::GMP::sieve_prime_cluster($lo,$hi,@cl) |
|
854
|
|
|
|
|
|
|
); |
|
855
|
|
|
|
|
|
|
} |
|
856
|
|
|
|
|
|
|
|
|
857
|
19
|
50
|
|
|
|
85
|
return @{Mprimes($lo,$hi)} if scalar(@cl) == 0; |
|
|
0
|
|
|
|
|
0
|
|
|
858
|
|
|
|
|
|
|
|
|
859
|
19
|
|
|
|
|
68
|
unshift @cl, 0; |
|
860
|
19
|
|
|
|
|
84
|
for my $i (1 .. $#cl) { |
|
861
|
48
|
|
|
|
|
202
|
validate_integer_nonneg($cl[$i]); |
|
862
|
48
|
50
|
|
|
|
169
|
croak "sieve_prime_cluster: values must be even" if $cl[$i] & 1; |
|
863
|
48
|
50
|
|
|
|
153
|
croak "sieve_prime_cluster: values must be increasing" if $cl[$i] <= $cl[$i-1]; |
|
864
|
|
|
|
|
|
|
} |
|
865
|
19
|
|
|
|
|
68
|
my($p,$sievelim,@p) = (17, 3000); |
|
866
|
19
|
100
|
66
|
|
|
205
|
if (defined $_BIGINT && (ref($lo) || ref($hi))) { |
|
|
|
|
33
|
|
|
|
|
|
867
|
10
|
50
|
33
|
|
|
95
|
($lo,$hi) = map {tobigint($_)} ($lo,$hi) if ref($lo) ne $_BIGINT || ref($hi) ne $_BIGINT; |
|
|
0
|
|
|
|
|
0
|
|
|
868
|
|
|
|
|
|
|
} |
|
869
|
19
|
50
|
|
|
|
91
|
$p = 13 if ($hi-$lo) < 50_000_000; |
|
870
|
19
|
50
|
|
|
|
4841
|
$p = 11 if ($hi-$lo) < 1_000_000; |
|
871
|
19
|
100
|
100
|
|
|
4240
|
$p = 7 if ($hi-$lo) < 20_000 && $lo < INTMAX; |
|
872
|
|
|
|
|
|
|
|
|
873
|
|
|
|
|
|
|
# Add any cases under our sieving point. |
|
874
|
19
|
100
|
|
|
|
6362
|
if ($lo <= $sievelim) { |
|
875
|
7
|
100
|
|
|
|
23
|
$sievelim = $hi if $sievelim > $hi; |
|
876
|
7
|
|
|
|
|
18
|
for my $n (@{Mprimes($lo,$sievelim)}) { |
|
|
7
|
|
|
|
|
31
|
|
|
877
|
1063
|
|
|
|
|
1625
|
my $ac = 1; |
|
878
|
1063
|
|
|
|
|
2445
|
for my $ci (1 .. $#cl) { |
|
879
|
1119
|
100
|
|
|
|
2545
|
if (!Mis_prime($n+$cl[$ci])) { $ac = 0; last; } |
|
|
882
|
|
|
|
|
1383
|
|
|
|
882
|
|
|
|
|
1620
|
|
|
880
|
|
|
|
|
|
|
} |
|
881
|
1063
|
100
|
|
|
|
2687
|
push @p, $n if $ac; |
|
882
|
|
|
|
|
|
|
} |
|
883
|
7
|
|
|
|
|
60
|
$lo = Mnext_prime($sievelim); |
|
884
|
|
|
|
|
|
|
} |
|
885
|
19
|
100
|
|
|
|
2297
|
return @p if $lo > $hi; |
|
886
|
|
|
|
|
|
|
|
|
887
|
|
|
|
|
|
|
# Compute acceptable residues. |
|
888
|
14
|
|
|
|
|
728
|
my $pr = Mprimorial($p); |
|
889
|
14
|
|
|
|
|
88
|
my $startpr = _bigint_to_int($lo % $pr); |
|
890
|
|
|
|
|
|
|
|
|
891
|
14
|
100
|
|
|
|
4161
|
my @acc = grep { ($_ & 1) && $_%3 } ($startpr .. $startpr + $pr - 1); |
|
|
26040
|
|
|
|
|
60779
|
|
|
892
|
14
|
|
|
|
|
1469
|
for my $c (@cl) { |
|
893
|
52
|
50
|
|
|
|
185
|
if ($p >= 7) { |
|
894
|
52
|
100
|
100
|
|
|
206
|
@acc = grep { (($_+$c)%3) && (($_+$c)%5) && (($_+$c)%7) } @acc; |
|
|
16854
|
|
|
|
|
57646
|
|
|
895
|
|
|
|
|
|
|
} else { |
|
896
|
0
|
0
|
|
|
|
0
|
@acc = grep { (($_+$c)%3) && (($_+$c)%5) } @acc; |
|
|
0
|
|
|
|
|
0
|
|
|
897
|
|
|
|
|
|
|
} |
|
898
|
|
|
|
|
|
|
} |
|
899
|
14
|
|
|
|
|
57
|
for my $c (@cl) { |
|
900
|
52
|
|
|
|
|
113
|
@acc = grep { Mgcd($_+$c,$pr) == 1 } @acc; |
|
|
1972
|
|
|
|
|
4680
|
|
|
901
|
|
|
|
|
|
|
} |
|
902
|
14
|
|
|
|
|
51
|
@acc = map { $_-$startpr } @acc; |
|
|
636
|
|
|
|
|
1026
|
|
|
903
|
|
|
|
|
|
|
|
|
904
|
14
|
50
|
|
|
|
87
|
print "cluster sieve using ",scalar(@acc)," residues mod $pr\n" if $_verbose; |
|
905
|
14
|
50
|
|
|
|
61
|
return @p if scalar(@acc) == 0; |
|
906
|
|
|
|
|
|
|
|
|
907
|
|
|
|
|
|
|
# Prepare table for more sieving. |
|
908
|
14
|
|
|
|
|
35
|
my @mprimes = @{Mprimes( $p+1, $sievelim)}; |
|
|
14
|
|
|
|
|
1494
|
|
|
909
|
14
|
|
|
|
|
169
|
my(@lorem,@vprem); |
|
910
|
14
|
|
|
|
|
81
|
for my $pidx (0..$#mprimes) { |
|
911
|
5953
|
|
|
|
|
13195
|
my $p = $mprimes[$pidx]; |
|
912
|
5953
|
|
|
|
|
15651
|
$lorem[$pidx] = _bigint_to_int($lo % $p); |
|
913
|
5953
|
|
|
|
|
169287
|
for my $c (@cl) { |
|
914
|
22106
|
|
|
|
|
130285
|
$vprem[$pidx]->[ ($p-($c%$p)) % $p ] = 1; |
|
915
|
|
|
|
|
|
|
} |
|
916
|
|
|
|
|
|
|
} |
|
917
|
|
|
|
|
|
|
|
|
918
|
|
|
|
|
|
|
# Walk the range in primorial chunks, doing primality tests. |
|
919
|
14
|
|
|
|
|
60
|
my($nummr, $numlucas) = (0,0); |
|
920
|
14
|
|
|
|
|
93
|
while ($lo <= $hi) { |
|
921
|
|
|
|
|
|
|
|
|
922
|
54
|
|
|
|
|
3211
|
my @racc = @acc; |
|
923
|
|
|
|
|
|
|
|
|
924
|
|
|
|
|
|
|
# Make sure we don't do anything past the limit |
|
925
|
54
|
100
|
|
|
|
255
|
if (($lo+$acc[-1]) > $hi) { |
|
926
|
14
|
|
|
|
|
4088
|
my $max = _bigint_to_int($hi-$lo); |
|
927
|
14
|
|
|
|
|
497
|
@racc = grep { $_ <= $max } @racc; |
|
|
636
|
|
|
|
|
1137
|
|
|
928
|
|
|
|
|
|
|
} |
|
929
|
|
|
|
|
|
|
|
|
930
|
|
|
|
|
|
|
# Sieve more values using native math |
|
931
|
54
|
|
|
|
|
7554
|
for my $pidx (0 .. $#mprimes) { |
|
932
|
16108
|
|
|
|
|
24109
|
my $p = $mprimes[$pidx]; |
|
933
|
16108
|
|
|
|
|
31993
|
my $rem = $lorem[$pidx]; |
|
934
|
16108
|
|
|
|
|
24216
|
@racc = grep { !$vprem[$pidx]->[ ($rem+$_) % $p ] } @racc; |
|
|
217789
|
|
|
|
|
451076
|
|
|
935
|
16108
|
100
|
|
|
|
33965
|
last unless scalar(@racc); |
|
936
|
|
|
|
|
|
|
} |
|
937
|
|
|
|
|
|
|
|
|
938
|
|
|
|
|
|
|
# Do final primality tests. |
|
939
|
54
|
100
|
|
|
|
322
|
if ($lo < 1e13) { |
|
940
|
26
|
|
|
|
|
61
|
for my $r (@racc) { |
|
941
|
415
|
|
|
|
|
968
|
my($good, $p) = (1, $lo + $r); |
|
942
|
415
|
|
|
|
|
901
|
for my $c (@cl) { |
|
943
|
830
|
|
|
|
|
1551
|
$nummr++; |
|
944
|
830
|
50
|
|
|
|
2266
|
if (!Mis_prime($p+$c)) { $good = 0; last; } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
945
|
|
|
|
|
|
|
} |
|
946
|
415
|
50
|
|
|
|
1369
|
push @p, $p if $good; |
|
947
|
|
|
|
|
|
|
} |
|
948
|
|
|
|
|
|
|
} else { |
|
949
|
28
|
|
|
|
|
8246
|
for my $r (@racc) { |
|
950
|
50
|
|
|
|
|
332
|
my($good, $p) = (1, $lo + $r); |
|
951
|
50
|
|
|
|
|
14989
|
for my $c (@cl) { |
|
952
|
66
|
|
|
|
|
3436
|
$nummr++; |
|
953
|
66
|
100
|
|
|
|
278
|
if (!_miller_rabin_2($p+$c)) { $good = 0; last; } |
|
|
46
|
|
|
|
|
154
|
|
|
|
46
|
|
|
|
|
140
|
|
|
954
|
|
|
|
|
|
|
} |
|
955
|
50
|
100
|
|
|
|
1688
|
next unless $good; |
|
956
|
4
|
|
|
|
|
16
|
for my $c (@cl) { |
|
957
|
8
|
|
|
|
|
1124
|
$numlucas++; |
|
958
|
8
|
50
|
|
|
|
42
|
if (!Math::Prime::Util::is_extra_strong_lucas_pseudoprime($p+$c)) { $good = 0; last; } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
959
|
|
|
|
|
|
|
} |
|
960
|
4
|
50
|
|
|
|
428
|
push @p, $p if $good; |
|
961
|
|
|
|
|
|
|
} |
|
962
|
|
|
|
|
|
|
} |
|
963
|
|
|
|
|
|
|
|
|
964
|
54
|
|
|
|
|
229
|
$lo += $pr; |
|
965
|
54
|
100
|
|
|
|
10071
|
if ($lo <= $hi) { # update native remainders |
|
966
|
40
|
|
|
|
|
10572
|
$lorem[$_] = ($lorem[$_] + $pr) % $mprimes[$_] for 0..$#mprimes; |
|
967
|
|
|
|
|
|
|
} |
|
968
|
|
|
|
|
|
|
} |
|
969
|
14
|
50
|
|
|
|
1236
|
print "cluster sieve ran $nummr MR and $numlucas Lucas tests\n" if $_verbose; |
|
970
|
14
|
|
|
|
|
39910
|
@p; |
|
971
|
|
|
|
|
|
|
} |
|
972
|
|
|
|
|
|
|
|
|
973
|
|
|
|
|
|
|
sub prime_powers { |
|
974
|
2
|
|
|
2
|
0
|
1108
|
my($low,$high) = @_; |
|
975
|
2
|
50
|
|
|
|
10
|
if (scalar @_ > 1) { |
|
976
|
2
|
|
|
|
|
9
|
validate_integer_nonneg($low); |
|
977
|
2
|
100
|
|
|
|
7
|
$low = 2 if $low < 2; |
|
978
|
|
|
|
|
|
|
} else { |
|
979
|
0
|
|
|
|
|
0
|
($low,$high) = (2, $low); |
|
980
|
|
|
|
|
|
|
} |
|
981
|
2
|
|
|
|
|
8
|
validate_integer_nonneg($high); |
|
982
|
|
|
|
|
|
|
|
|
983
|
2
|
50
|
33
|
|
|
13
|
if ($high > 1e18 || ($high-$low) < 10) { |
|
984
|
0
|
|
|
|
|
0
|
my $sref = []; |
|
985
|
0
|
|
|
|
|
0
|
while ($low <= $high) { |
|
986
|
0
|
0
|
|
|
|
0
|
push @$sref, $low if Mis_prime_power($low); |
|
987
|
0
|
|
|
|
|
0
|
$low = Madd1int($low); |
|
988
|
|
|
|
|
|
|
} |
|
989
|
0
|
|
|
|
|
0
|
return $sref; |
|
990
|
|
|
|
|
|
|
} else { |
|
991
|
2
|
|
|
|
|
5
|
my @powers; |
|
992
|
2
|
|
|
|
|
15
|
for my $k (2 .. Mlogint($high,2)) { |
|
993
|
18
|
|
|
|
|
39
|
my $P = Mpowint(2,$k); |
|
994
|
18
|
100
|
|
|
|
41
|
push @powers, $P if $P >= $low; |
|
995
|
|
|
|
|
|
|
} |
|
996
|
2
|
|
|
|
|
9
|
for my $k (2 .. Mlogint($high,3)) { |
|
997
|
10
|
|
|
|
|
22
|
my $P = Mpowint(3,$k); |
|
998
|
10
|
100
|
|
|
|
31
|
push @powers, $P if $P >= $low; |
|
999
|
|
|
|
|
|
|
} |
|
1000
|
2
|
|
|
|
|
10
|
for my $k (2 .. Mlogint($high,5)) { |
|
1001
|
6
|
|
|
|
|
17
|
my $rootn = Mrootint($high, $k); |
|
1002
|
|
|
|
|
|
|
Mforprimes( sub { |
|
1003
|
85
|
|
|
85
|
|
145
|
my $P = Mpowint($_,$k); |
|
1004
|
85
|
50
|
|
|
|
697
|
push @powers, $P if $P >= $low; |
|
1005
|
6
|
|
|
|
|
58
|
}, 5, $rootn); |
|
1006
|
|
|
|
|
|
|
} |
|
1007
|
2
|
|
|
|
|
6
|
push @powers, @{Mprimes($low,$high)}; |
|
|
2
|
|
|
|
|
11
|
|
|
1008
|
2
|
|
|
|
|
17
|
return Mvecsorti(\@powers); |
|
1009
|
|
|
|
|
|
|
} |
|
1010
|
|
|
|
|
|
|
} |
|
1011
|
|
|
|
|
|
|
|
|
1012
|
|
|
|
|
|
|
sub twin_primes { |
|
1013
|
5
|
|
|
5
|
0
|
2518
|
my($low,$high) = @_; |
|
1014
|
5
|
100
|
|
|
|
25
|
if (scalar @_ > 1) { |
|
1015
|
4
|
|
|
|
|
18
|
validate_integer_nonneg($low); |
|
1016
|
4
|
50
|
|
|
|
44
|
$low = 2 if $low < 2; |
|
1017
|
|
|
|
|
|
|
} else { |
|
1018
|
1
|
|
|
|
|
4
|
($low,$high) = (2, $low); |
|
1019
|
|
|
|
|
|
|
} |
|
1020
|
5
|
|
|
|
|
172
|
validate_integer_nonneg($high); |
|
1021
|
5
|
|
|
|
|
34
|
my @tp; |
|
1022
|
5
|
50
|
|
|
|
19
|
if ($Math::Prime::Util::_GMPfunc{"twin_twin_primes"}) { |
|
1023
|
0
|
|
|
|
|
0
|
@tp = Math::Prime::Util::GMP::sieve_twin_primes($low, $high); |
|
1024
|
|
|
|
|
|
|
} else { |
|
1025
|
5
|
|
|
|
|
19
|
@tp = sieve_prime_cluster($low, $high, 2); |
|
1026
|
|
|
|
|
|
|
} |
|
1027
|
5
|
100
|
|
|
|
62
|
return ref($high) ? [maybetobigintall(@tp)] : \@tp; |
|
1028
|
|
|
|
|
|
|
} |
|
1029
|
|
|
|
|
|
|
|
|
1030
|
|
|
|
|
|
|
sub semi_primes { |
|
1031
|
1
|
|
|
1
|
0
|
2263
|
my($low,$high) = @_; |
|
1032
|
1
|
50
|
|
|
|
79
|
if (scalar @_ > 1) { |
|
1033
|
1
|
|
|
|
|
7
|
validate_integer_nonneg($low); |
|
1034
|
1
|
50
|
|
|
|
5
|
$low = 4 if $low < 4; |
|
1035
|
|
|
|
|
|
|
} else { |
|
1036
|
0
|
|
|
|
|
0
|
($low,$high) = (4, $low); |
|
1037
|
|
|
|
|
|
|
} |
|
1038
|
1
|
|
|
|
|
4
|
validate_integer_nonneg($high); |
|
1039
|
1
|
|
|
|
|
3
|
my @sp; |
|
1040
|
1
|
|
|
17
|
|
12
|
Math::Prime::Util::forsemiprimes(sub { push @sp,$_; }, $low, $high); |
|
|
17
|
|
|
|
|
47
|
|
|
1041
|
1
|
|
|
|
|
9
|
\@sp; |
|
1042
|
|
|
|
|
|
|
} |
|
1043
|
|
|
|
|
|
|
|
|
1044
|
|
|
|
|
|
|
# TODO: Port n_range_ramanujan_primes to replace this. |
|
1045
|
|
|
|
|
|
|
# export it as a function |
|
1046
|
|
|
|
|
|
|
# |
|
1047
|
|
|
|
|
|
|
# For now, let's ignore it, this is only used for the PP. |
|
1048
|
|
|
|
|
|
|
|
|
1049
|
|
|
|
|
|
|
sub _n_ramanujan_primes { |
|
1050
|
5
|
|
|
5
|
|
16
|
my($n) = @_; |
|
1051
|
5
|
50
|
|
|
|
52
|
return [] if $n <= 0; |
|
1052
|
5
|
|
|
|
|
55
|
my $max = Mnth_prime_upper(int(48/19*$n)+1); |
|
1053
|
5
|
|
|
|
|
34
|
my @L = (2, (0) x $n-1); |
|
1054
|
5
|
|
|
|
|
12
|
my $s = 1; |
|
1055
|
5
|
|
|
|
|
31
|
for (my $k = 7; $k <= $max; $k += 2) { |
|
1056
|
6178
|
100
|
|
|
|
13508
|
$s++ if Mis_prime($k); |
|
1057
|
6178
|
100
|
|
|
|
16907
|
$L[$s] = $k+1 if $s < $n; |
|
1058
|
6178
|
100
|
100
|
|
|
20086
|
$s-- if ($k&3) == 1 && Mis_prime(($k+1)>>1); |
|
1059
|
6178
|
100
|
|
|
|
21458
|
$L[$s] = $k+2 if $s < $n; |
|
1060
|
|
|
|
|
|
|
} |
|
1061
|
5
|
|
|
|
|
22
|
\@L; |
|
1062
|
|
|
|
|
|
|
} |
|
1063
|
|
|
|
|
|
|
|
|
1064
|
|
|
|
|
|
|
sub ramanujan_primes { |
|
1065
|
4
|
|
|
4
|
0
|
1471
|
my($low,$high) = @_; |
|
1066
|
4
|
50
|
|
|
|
20
|
if (scalar @_ > 1) { |
|
1067
|
4
|
|
|
|
|
19
|
validate_integer_nonneg($low); |
|
1068
|
4
|
100
|
|
|
|
19
|
$low = 2 if $low < 2; |
|
1069
|
|
|
|
|
|
|
} else { |
|
1070
|
0
|
|
|
|
|
0
|
($low,$high) = (2, $low); |
|
1071
|
|
|
|
|
|
|
} |
|
1072
|
4
|
|
|
|
|
15
|
validate_integer_nonneg($high); |
|
1073
|
4
|
50
|
33
|
|
|
39
|
return [] if ($low > $high) || ($high < 2); |
|
1074
|
4
|
|
|
|
|
78
|
my $nn = Math::Prime::Util::prime_count_upper($high) >> 1; |
|
1075
|
4
|
|
|
|
|
18
|
my $L = _n_ramanujan_primes($nn); |
|
1076
|
4
|
|
66
|
|
|
50
|
shift @$L while @$L && $L->[0] < $low; |
|
1077
|
4
|
|
100
|
|
|
89
|
pop @$L while @$L && $L->[-1] > $high; |
|
1078
|
4
|
|
|
|
|
19
|
$L; |
|
1079
|
|
|
|
|
|
|
} |
|
1080
|
|
|
|
|
|
|
|
|
1081
|
|
|
|
|
|
|
sub is_ramanujan_prime { |
|
1082
|
2
|
|
|
2
|
0
|
6
|
my($n) = @_; |
|
1083
|
2
|
50
|
|
|
|
6
|
return 1 if $n == 2; |
|
1084
|
2
|
50
|
|
|
|
7
|
return 0 if $n < 11; |
|
1085
|
2
|
|
|
|
|
29
|
my $L = Math::Prime::Util::ramanujan_primes($n,$n); |
|
1086
|
2
|
100
|
|
|
|
25
|
return (scalar(@$L) > 0) ? 1 : 0; |
|
1087
|
|
|
|
|
|
|
} |
|
1088
|
|
|
|
|
|
|
|
|
1089
|
|
|
|
|
|
|
sub nth_ramanujan_prime { |
|
1090
|
1
|
|
|
1
|
0
|
996
|
my($n) = @_; |
|
1091
|
1
|
|
|
|
|
8
|
validate_integer_nonneg($n); |
|
1092
|
1
|
50
|
|
|
|
5
|
return undef if $n <= 0; ## no critic qw(ProhibitExplicitReturnUndef) |
|
1093
|
1
|
|
|
|
|
6
|
my $L = _n_ramanujan_primes($n); |
|
1094
|
1
|
|
|
|
|
24
|
return $L->[$n-1]; |
|
1095
|
|
|
|
|
|
|
} |
|
1096
|
|
|
|
|
|
|
|
|
1097
|
|
|
|
|
|
|
sub next_prime { |
|
1098
|
9761
|
|
|
9761
|
0
|
37841
|
my($n) = @_; |
|
1099
|
9761
|
|
|
|
|
23751
|
validate_integer_nonneg($n); |
|
1100
|
9760
|
100
|
|
|
|
33707
|
return $_prime_next_small[$n] if $n <= 0+$#_prime_next_small; |
|
1101
|
|
|
|
|
|
|
# This turns out not to be faster. |
|
1102
|
|
|
|
|
|
|
# return $_primes_small[1+_tiny_prime_count($n)] if $n < $_primes_small[-1]; |
|
1103
|
|
|
|
|
|
|
|
|
1104
|
2041
|
100
|
100
|
|
|
12244
|
return tobigint(MPU_32BIT ? "4294967311" : "18446744073709551629") if !ref($n) && $n >= MPU_MAXPRIME; |
|
1105
|
|
|
|
|
|
|
# n is now either 1) not bigint and < maxprime, or (2) bigint and >= uvmax |
|
1106
|
|
|
|
|
|
|
|
|
1107
|
2036
|
50
|
66
|
|
|
4999
|
if ($n > 4294967295 && getconfig()->{'gmp'}) { |
|
1108
|
0
|
|
|
|
|
0
|
return reftyped($_[0], Math::Prime::Util::GMP::next_prime($n)); |
|
1109
|
|
|
|
|
|
|
} |
|
1110
|
|
|
|
|
|
|
|
|
1111
|
2036
|
|
100
|
|
|
3134
|
do { |
|
1112
|
6600
|
|
|
|
|
35058
|
$n += $_wheeladvance30[$n%30]; |
|
1113
|
|
|
|
|
|
|
} while !($n%7) || !_is_prime7($n); |
|
1114
|
|
|
|
|
|
|
|
|
1115
|
2036
|
|
|
|
|
11190
|
$n; |
|
1116
|
|
|
|
|
|
|
} |
|
1117
|
|
|
|
|
|
|
|
|
1118
|
|
|
|
|
|
|
sub prev_prime { |
|
1119
|
157
|
|
|
157
|
0
|
4694
|
my($n) = @_; |
|
1120
|
157
|
|
|
|
|
609
|
validate_integer_nonneg($n); |
|
1121
|
157
|
100
|
|
|
|
631
|
return (undef,undef,undef,2,3,3,5,5,7,7,7,7)[$n] if $n <= 11; |
|
1122
|
156
|
50
|
66
|
|
|
1013
|
if ($n > 4294967295 && getconfig()->{'gmp'}) { |
|
1123
|
0
|
|
|
|
|
0
|
return reftyped($_[0], Math::Prime::Util::GMP::prev_prime($n)); |
|
1124
|
|
|
|
|
|
|
} |
|
1125
|
|
|
|
|
|
|
|
|
1126
|
156
|
|
100
|
|
|
270
|
do { |
|
1127
|
3104
|
|
|
|
|
9423
|
$n -= $_wheelretreat30[$n%30]; |
|
1128
|
|
|
|
|
|
|
} while !($n%7) || !_is_prime7($n); |
|
1129
|
|
|
|
|
|
|
|
|
1130
|
156
|
100
|
100
|
|
|
526
|
$n = _bigint_to_int($n) if ref($n) && $n <= INTMAX; |
|
1131
|
156
|
|
|
|
|
1286
|
$n; |
|
1132
|
|
|
|
|
|
|
} |
|
1133
|
|
|
|
|
|
|
|
|
1134
|
|
|
|
|
|
|
sub next_prime_power { |
|
1135
|
2
|
|
|
2
|
0
|
1170
|
my($n) = @_; |
|
1136
|
2
|
|
|
|
|
9
|
validate_integer_nonneg($n); |
|
1137
|
2
|
50
|
|
|
|
7
|
return (2,2,3,4,5,7,7,8,9)[$n] if $n <= 8; |
|
1138
|
2
|
|
|
|
|
3
|
while (1) { |
|
1139
|
18
|
|
|
|
|
54
|
$n = Madd1int($n); |
|
1140
|
18
|
100
|
|
|
|
39
|
return $n if Mis_prime_power($n); |
|
1141
|
|
|
|
|
|
|
} |
|
1142
|
|
|
|
|
|
|
} |
|
1143
|
|
|
|
|
|
|
sub prev_prime_power { |
|
1144
|
2
|
|
|
2
|
0
|
5
|
my($n) = @_; |
|
1145
|
2
|
|
|
|
|
7
|
validate_integer_nonneg($n); |
|
1146
|
2
|
50
|
|
|
|
4
|
return (undef,undef,undef,2,3,4,5,5,7)[$n] if $n <= 8; |
|
1147
|
2
|
|
|
|
|
3
|
while (1) { |
|
1148
|
12
|
|
|
|
|
24
|
$n = Msub1int($n); |
|
1149
|
12
|
100
|
|
|
|
24
|
return $n if Mis_prime_power($n); |
|
1150
|
|
|
|
|
|
|
} |
|
1151
|
|
|
|
|
|
|
} |
|
1152
|
|
|
|
|
|
|
|
|
1153
|
|
|
|
|
|
|
sub partitions { |
|
1154
|
5
|
|
|
5
|
0
|
4146
|
my($n) = @_; |
|
1155
|
5
|
|
|
|
|
38
|
validate_integer_nonneg($n); |
|
1156
|
|
|
|
|
|
|
|
|
1157
|
5
|
|
|
|
|
105
|
my $d = Msqrtint(Madd1int($n)); |
|
1158
|
5
|
|
|
|
|
29
|
my @pent = (1, map { (($_*(3*$_+1))>>1, (($_+1)*(3*$_+2))>>1) } 1 .. $d); |
|
|
173
|
|
|
|
|
316
|
|
|
1159
|
5
|
|
|
|
|
19
|
my $bigpn = (~0 > 4294967295) ? 400 : 270; |
|
1160
|
5
|
100
|
|
|
|
11
|
my($ZERO,$ONE) = map { $n >= $bigpn ? tobigint($_) : $_ } (0,1); |
|
|
10
|
|
|
|
|
70
|
|
|
1161
|
5
|
|
|
|
|
26
|
my @part = ($ONE); |
|
1162
|
5
|
|
|
|
|
21
|
foreach my $j (scalar @part .. $n) { |
|
1163
|
8051
|
|
|
|
|
1657315
|
my ($psum1, $psum2) = ($ZERO, $ZERO); |
|
1164
|
8051
|
|
|
|
|
16565
|
my $k = 1; |
|
1165
|
8051
|
|
|
|
|
19079
|
foreach my $p (@pent) { |
|
1166
|
460204
|
100
|
|
|
|
51917290
|
last if $p > $j; |
|
1167
|
452153
|
100
|
|
|
|
938672
|
if ((++$k) & 2) { $psum1 += $part[ $j - $p ] } |
|
|
230126
|
|
|
|
|
609017
|
|
|
1168
|
222027
|
|
|
|
|
623123
|
else { $psum2 += $part[ $j - $p ] } |
|
1169
|
|
|
|
|
|
|
} |
|
1170
|
8051
|
|
|
|
|
28889
|
$part[$j] = $psum1 - $psum2; |
|
1171
|
|
|
|
|
|
|
} |
|
1172
|
5
|
|
|
|
|
4743
|
return $part[$n]; |
|
1173
|
|
|
|
|
|
|
} |
|
1174
|
|
|
|
|
|
|
|
|
1175
|
|
|
|
|
|
|
my @_lf63 = (0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0); |
|
1176
|
|
|
|
|
|
|
my @_small_lucky = (undef,1,3,7,9,13,15,21,25,31,33,37,43,49,51,63,67,69,73,75,79,87,93,99,105,111,115,127,129,133,135,141,151,159,163,169,171,189,193,195); |
|
1177
|
|
|
|
|
|
|
|
|
1178
|
|
|
|
|
|
|
sub lucky_numbers { |
|
1179
|
3
|
|
|
3
|
0
|
14
|
my($lo,$hi) = @_; |
|
1180
|
3
|
100
|
|
|
|
6
|
if (defined $hi) { validate_integer_nonneg($lo); } |
|
|
1
|
|
|
|
|
4
|
|
|
1181
|
2
|
|
|
|
|
4
|
else { ($lo,$hi) = (1, $lo); } |
|
1182
|
3
|
|
|
|
|
10
|
validate_integer_nonneg($hi); |
|
1183
|
3
|
50
|
33
|
|
|
21
|
return [] if $hi < $lo || $hi == 0; |
|
1184
|
|
|
|
|
|
|
|
|
1185
|
3
|
|
|
|
|
4
|
my @lucky; |
|
1186
|
|
|
|
|
|
|
# This wheel handles the evens and every 3rd by a mod 6 wheel, |
|
1187
|
|
|
|
|
|
|
# then uses the mask to skip every 7th and 9th remaining value. |
|
1188
|
3
|
|
|
|
|
7
|
for (my $k = 1; $k <= $hi; $k += 6) { |
|
1189
|
358
|
|
|
|
|
345
|
my $m63 = $k % 63; |
|
1190
|
358
|
100
|
|
|
|
573
|
push @lucky, $k unless $_lf63[$m63]; |
|
1191
|
358
|
100
|
|
|
|
556
|
push @lucky, $k+2 unless $_lf63[$m63+2]; |
|
1192
|
|
|
|
|
|
|
} |
|
1193
|
3
|
50
|
|
|
|
14
|
delete $lucky[-1] if $lucky[-1] > $hi; |
|
1194
|
|
|
|
|
|
|
|
|
1195
|
|
|
|
|
|
|
# Do the standard lucky sieve. |
|
1196
|
3
|
|
66
|
|
|
19
|
for (my $k = 4; $k <= $#lucky && $lucky[$k]-1 <= $#lucky; $k++) { |
|
1197
|
64
|
|
|
|
|
84
|
for (my $skip = my $index = $lucky[$k]-1; $index <= $#lucky; $index += $skip) { |
|
1198
|
203
|
|
|
|
|
315
|
splice(@lucky, $index, 1); |
|
1199
|
|
|
|
|
|
|
} |
|
1200
|
|
|
|
|
|
|
} |
|
1201
|
|
|
|
|
|
|
|
|
1202
|
3
|
100
|
|
|
|
6
|
if ($lo > 1) { @lucky = grep { $_ >= $lo } @lucky; } |
|
|
1
|
|
|
|
|
4
|
|
|
|
114
|
|
|
|
|
115
|
|
|
1203
|
|
|
|
|
|
|
|
|
1204
|
3
|
|
|
|
|
7
|
\@lucky; |
|
1205
|
|
|
|
|
|
|
} |
|
1206
|
|
|
|
|
|
|
|
|
1207
|
|
|
|
|
|
|
sub lucky_count { |
|
1208
|
1
|
|
|
1
|
0
|
15
|
my($lo,$hi) = @_; |
|
1209
|
1
|
50
|
|
|
|
4
|
if (defined $hi) { validate_integer_nonneg($lo); } |
|
|
0
|
|
|
|
|
0
|
|
|
1210
|
1
|
|
|
|
|
2
|
else { ($lo,$hi) = (1, $lo); } |
|
1211
|
1
|
|
|
|
|
3
|
validate_integer_nonneg($hi); |
|
1212
|
1
|
50
|
33
|
|
|
7
|
return 0 if $hi < $lo || $hi == 0; |
|
1213
|
|
|
|
|
|
|
|
|
1214
|
|
|
|
|
|
|
# Return from our static data if very small. |
|
1215
|
1
|
0
|
0
|
|
|
4
|
return scalar(grep { defined $_ && $_ >= $lo && $_ <= $hi } @_small_lucky) if $hi <= $_small_lucky[-1]; |
|
|
0
|
50
|
|
|
|
0
|
|
|
1216
|
|
|
|
|
|
|
|
|
1217
|
|
|
|
|
|
|
# Trivial but slow way: |
|
1218
|
|
|
|
|
|
|
# return scalar(@{Math::Prime::Util::lucky_numbers($lo, $hi)}); |
|
1219
|
|
|
|
|
|
|
|
|
1220
|
1
|
50
|
|
|
|
4
|
$lo-- if $lo & 1; |
|
1221
|
1
|
50
|
|
|
|
4
|
$hi++ if $hi & 1; |
|
1222
|
1
|
|
|
|
|
4
|
my $lsize = 1 + lucky_count_upper($hi); |
|
1223
|
1
|
|
|
|
|
4
|
my ($locount, $hicount) = ($lo >> 1, $hi >> 1); |
|
1224
|
1
|
|
|
|
|
3
|
my $ln = Math::Prime::Util::lucky_numbers($lsize); |
|
1225
|
1
|
|
|
|
|
3
|
shift @$ln; |
|
1226
|
1
|
50
|
|
|
|
3
|
if ($lo <= 1) { |
|
1227
|
1
|
|
|
|
|
40
|
$hicount -= int($hicount / $_) for @$ln; |
|
1228
|
|
|
|
|
|
|
} else { |
|
1229
|
0
|
|
|
|
|
0
|
for my $l (@$ln) { |
|
1230
|
0
|
0
|
|
|
|
0
|
last if $l > $hicount; |
|
1231
|
0
|
0
|
|
|
|
0
|
$locount -= int($locount / $l) if $l <= $lo; |
|
1232
|
0
|
|
|
|
|
0
|
$hicount -= int($hicount / $l); |
|
1233
|
|
|
|
|
|
|
} |
|
1234
|
|
|
|
|
|
|
} |
|
1235
|
1
|
|
|
|
|
19
|
return $hicount - $locount; |
|
1236
|
|
|
|
|
|
|
} |
|
1237
|
|
|
|
|
|
|
sub _simple_lucky_count_approx { |
|
1238
|
4
|
|
|
4
|
|
5
|
my($n) = @_; |
|
1239
|
4
|
50
|
|
|
|
9
|
$n = "$n" if ref($n); |
|
1240
|
4
|
50
|
|
|
|
8
|
return 0 + ($n > 0) + ($n > 2) if $n < 7; |
|
1241
|
4
|
50
|
|
|
|
12
|
return 0.9957 * $n/log($n) if $n <= 1000000; |
|
1242
|
0
|
|
|
|
|
0
|
return (1.03670 - log($n)/299) * $n/log($n); |
|
1243
|
|
|
|
|
|
|
} |
|
1244
|
|
|
|
|
|
|
sub _simple_lucky_count_upper { |
|
1245
|
4
|
|
|
4
|
|
5
|
my($n) = @_; |
|
1246
|
4
|
50
|
|
|
|
12
|
$n = "$n" if ref($n); |
|
1247
|
4
|
50
|
|
|
|
8
|
return 0 + ($n > 0) + ($n > 2) if $n < 7; |
|
1248
|
4
|
50
|
|
|
|
7
|
return int(5 + 1.039 * $n/log($n)) if $n <= 7000; |
|
1249
|
4
|
50
|
|
|
|
10
|
my $a = ($n < 10017000) ? 0.58003 - 3.00e-9 * ($n-7000) : 0.55; |
|
1250
|
4
|
|
|
|
|
10
|
return int($n/(1.065*log($n) - $a - 3.1/log($n) - 2.85/(log($n)*log($n)))); |
|
1251
|
|
|
|
|
|
|
} |
|
1252
|
|
|
|
|
|
|
sub _simple_lucky_count_lower { |
|
1253
|
4
|
|
|
4
|
|
6
|
my($n) = @_; |
|
1254
|
4
|
|
|
|
|
14
|
my $approx = _simple_lucky_count_approx($n); |
|
1255
|
4
|
50
|
|
|
|
6
|
my $est = $approx * (($n <= 10000) ? 0.9 : 0.99); |
|
1256
|
4
|
|
|
|
|
13
|
int($est); |
|
1257
|
|
|
|
|
|
|
} |
|
1258
|
|
|
|
|
|
|
sub lucky_count_approx { |
|
1259
|
1
|
|
|
1
|
0
|
12
|
my($n) = @_; |
|
1260
|
1
|
|
|
|
|
3
|
validate_integer_nonneg($n); |
|
1261
|
1
|
0
|
|
|
|
3
|
return scalar(grep { defined $_ && $_ <= $n } @_small_lucky) if $n <= $_small_lucky[-1]; |
|
|
0
|
50
|
|
|
|
0
|
|
|
1262
|
1
|
|
|
|
|
4
|
my($lo,$hi) = (_simple_lucky_count_lower($n), _simple_lucky_count_upper($n)); |
|
1263
|
|
|
|
|
|
|
_binary_search($n, $lo, $hi, |
|
1264
|
1
|
|
|
7
|
|
5
|
sub{Math::Prime::Util::nth_lucky_approx(shift)}); |
|
|
7
|
|
|
|
|
9
|
|
|
1265
|
|
|
|
|
|
|
} |
|
1266
|
|
|
|
|
|
|
sub lucky_count_upper { |
|
1267
|
2
|
|
|
2
|
0
|
9
|
my($n) = @_; |
|
1268
|
2
|
|
|
|
|
3
|
validate_integer_nonneg($n); |
|
1269
|
2
|
0
|
|
|
|
3
|
return scalar(grep { defined $_ && $_ <= $n } @_small_lucky) if $n <= $_small_lucky[-1]; |
|
|
0
|
50
|
|
|
|
0
|
|
|
1270
|
2
|
|
|
|
|
4
|
my($lo,$hi) = (_simple_lucky_count_lower($n), _simple_lucky_count_upper($n)); |
|
1271
|
|
|
|
|
|
|
1+_binary_search($n, $lo, $hi, |
|
1272
|
2
|
|
|
14
|
|
16
|
sub{Math::Prime::Util::nth_lucky_lower(shift)}); |
|
|
14
|
|
|
|
|
22
|
|
|
1273
|
|
|
|
|
|
|
} |
|
1274
|
|
|
|
|
|
|
sub lucky_count_lower { |
|
1275
|
1
|
|
|
1
|
0
|
907
|
my($n) = @_; |
|
1276
|
1
|
|
|
|
|
5
|
validate_integer_nonneg($n); |
|
1277
|
1
|
0
|
|
|
|
5
|
return scalar(grep { defined $_ && $_ <= $n } @_small_lucky) if $n <= $_small_lucky[-1]; |
|
|
0
|
50
|
|
|
|
0
|
|
|
1278
|
1
|
|
|
|
|
4
|
my($lo,$hi) = (_simple_lucky_count_lower($n), _simple_lucky_count_upper($n)); |
|
1279
|
|
|
|
|
|
|
_binary_search($n, $lo, $hi, |
|
1280
|
1
|
|
|
7
|
|
19
|
sub{Math::Prime::Util::nth_lucky_upper(shift)}); |
|
|
7
|
|
|
|
|
28
|
|
|
1281
|
|
|
|
|
|
|
} |
|
1282
|
|
|
|
|
|
|
|
|
1283
|
|
|
|
|
|
|
sub nth_lucky { |
|
1284
|
1
|
|
|
1
|
0
|
565
|
my($n) = @_; |
|
1285
|
1
|
|
|
|
|
4
|
validate_integer_nonneg($n); |
|
1286
|
1
|
50
|
|
|
|
5
|
return $_small_lucky[$n] if $n <= 0+$#_small_lucky; |
|
1287
|
0
|
|
|
|
|
0
|
my $k = $n-1; |
|
1288
|
0
|
|
|
|
|
0
|
my $ln = lucky_numbers($n); |
|
1289
|
0
|
|
|
|
|
0
|
shift @$ln; |
|
1290
|
0
|
|
|
|
|
0
|
$k += int($k / ($_-1)) for reverse @$ln; |
|
1291
|
0
|
|
|
|
|
0
|
2*$k+1; |
|
1292
|
|
|
|
|
|
|
} |
|
1293
|
|
|
|
|
|
|
sub nth_lucky_approx { |
|
1294
|
31
|
|
|
31
|
0
|
33
|
my($n) = @_; |
|
1295
|
31
|
|
|
|
|
43
|
validate_integer_nonneg($n); |
|
1296
|
31
|
50
|
|
|
|
45
|
return $_small_lucky[$n] if $n <= 0+$#_small_lucky; |
|
1297
|
31
|
50
|
|
|
|
55
|
$n = "$n" if ref($n); |
|
1298
|
31
|
|
|
|
|
39
|
my($logn, $loglogn, $mult) = (log($n), log(log($n)), 1); |
|
1299
|
31
|
100
|
|
|
|
41
|
if ($n <= 80000) { |
|
1300
|
28
|
50
|
|
|
|
32
|
my $c = ($n <= 10000) ? 0.2502 : 0.2581; |
|
1301
|
28
|
|
|
|
|
29
|
$mult = $logn + 0.5 * $loglogn + $c * $loglogn * $loglogn; |
|
1302
|
|
|
|
|
|
|
} else { |
|
1303
|
3
|
50
|
|
|
|
9
|
my $c = ($n <= 10000) ? -0.0173 : ($n <= 100000) ? -0.0318 : |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
1304
|
|
|
|
|
|
|
($n <= 1000000) ? -0.0384 : ($n <= 10000000) ? -0.0422 : -0.0440; |
|
1305
|
3
|
|
|
|
|
5
|
$mult = $logn + (0.5 + $c) * $loglogn *$loglogn; |
|
1306
|
|
|
|
|
|
|
} |
|
1307
|
31
|
|
|
|
|
56
|
return int( $n * $mult + 0.5); |
|
1308
|
|
|
|
|
|
|
} |
|
1309
|
|
|
|
|
|
|
sub nth_lucky_upper { |
|
1310
|
8
|
|
|
8
|
0
|
12
|
my($n) = @_; |
|
1311
|
8
|
|
|
|
|
12
|
validate_integer_nonneg($n); |
|
1312
|
8
|
50
|
|
|
|
20
|
return $_small_lucky[$n] if $n <= 0+$#_small_lucky; |
|
1313
|
8
|
50
|
|
|
|
19
|
my $c = ($n <= 100) ? 1.05 : ($n <= 300) ? 1.03 : ($n <= 800) ? 1.01 : 1.0033; |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
1314
|
8
|
|
|
|
|
17
|
return 1 + int( $c * nth_lucky_approx($n) + 0.5 ); |
|
1315
|
|
|
|
|
|
|
} |
|
1316
|
|
|
|
|
|
|
sub nth_lucky_lower { |
|
1317
|
15
|
|
|
15
|
0
|
18
|
my($n) = @_; |
|
1318
|
15
|
|
|
|
|
27
|
validate_integer_nonneg($n); |
|
1319
|
15
|
50
|
|
|
|
20
|
return $_small_lucky[$n] if $n <= 0+$#_small_lucky; |
|
1320
|
15
|
100
|
|
|
|
25
|
my $c = ($n <= 130) ? 0.985 : ($n <= 1000) ? 0.992 : 0.996; |
|
|
|
50
|
|
|
|
|
|
|
1321
|
15
|
|
|
|
|
29
|
return int( $c * nth_lucky_approx($n) ); |
|
1322
|
|
|
|
|
|
|
} |
|
1323
|
|
|
|
|
|
|
|
|
1324
|
|
|
|
|
|
|
sub is_lucky { |
|
1325
|
2
|
|
|
2
|
0
|
1152
|
my($n) = @_; |
|
1326
|
|
|
|
|
|
|
|
|
1327
|
|
|
|
|
|
|
# Pretests |
|
1328
|
2
|
50
|
66
|
|
|
35
|
return 0 if $n <= 0 || !($n % 2) || ($n % 6) == 5 || $_lf63[$n % 63]; |
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
1329
|
1
|
50
|
|
|
|
4
|
return 1 if $n < 45; |
|
1330
|
|
|
|
|
|
|
|
|
1331
|
|
|
|
|
|
|
# Really simple but slow: |
|
1332
|
|
|
|
|
|
|
# return lucky_numbers($n)->[-1] == $n; |
|
1333
|
|
|
|
|
|
|
|
|
1334
|
1
|
|
|
|
|
7
|
my $upper = int(200 + 0.994 * $n / log($n)); |
|
1335
|
1
|
|
|
|
|
27
|
my $lucky = lucky_numbers($upper); |
|
1336
|
1
|
|
|
|
|
3
|
my $pos = ($n+1) >> 1; |
|
1337
|
1
|
|
|
|
|
9
|
my $i = 1; |
|
1338
|
1
|
|
|
|
|
1
|
while (1) { |
|
1339
|
48
|
50
|
|
|
|
66
|
my $l = ($i <= $#$lucky) ? $lucky->[$i++] : nth_lucky($i++); |
|
1340
|
48
|
100
|
|
|
|
61
|
return 1 if $pos < $l; |
|
1341
|
47
|
|
|
|
|
44
|
my $quo = int($pos / $l); |
|
1342
|
47
|
50
|
|
|
|
58
|
return 0 if $pos == $quo * $l; |
|
1343
|
47
|
|
|
|
|
38
|
$pos -= $quo; |
|
1344
|
|
|
|
|
|
|
} |
|
1345
|
|
|
|
|
|
|
} |
|
1346
|
|
|
|
|
|
|
|
|
1347
|
|
|
|
|
|
|
sub minimal_goldbach_pair { |
|
1348
|
2
|
|
|
2
|
0
|
1068
|
my($n) = @_; |
|
1349
|
2
|
|
|
|
|
41
|
validate_integer_nonneg($n); |
|
1350
|
2
|
50
|
|
|
|
9
|
return undef if $n < 4; |
|
1351
|
2
|
0
|
33
|
|
|
262
|
return Mis_prime($n-2) ? 2 : undef if $n == 4 || Mis_odd($n); |
|
|
|
50
|
|
|
|
|
|
|
1352
|
2
|
|
|
|
|
446
|
my($p,$H)=(3,Mrshiftint($n)); |
|
1353
|
2
|
|
|
|
|
263
|
while ($p <= $H) { |
|
1354
|
721
|
100
|
|
|
|
106712
|
return $p if Mis_prime($n-$p); |
|
1355
|
719
|
|
|
|
|
146361
|
$p = next_prime($p); |
|
1356
|
|
|
|
|
|
|
} |
|
1357
|
0
|
|
|
|
|
0
|
undef; |
|
1358
|
|
|
|
|
|
|
} |
|
1359
|
|
|
|
|
|
|
sub goldbach_pair_count { |
|
1360
|
4
|
|
|
4
|
0
|
14
|
my($n) = @_; |
|
1361
|
4
|
|
|
|
|
18
|
validate_integer_nonneg($n); |
|
1362
|
4
|
50
|
|
|
|
15
|
return 0 if $n < 4; |
|
1363
|
4
|
100
|
66
|
|
|
26
|
return Mis_prime($n-2) ? 1 : 0 if $n == 4 || Mis_odd($n); |
|
|
|
100
|
|
|
|
|
|
|
1364
|
2
|
|
|
|
|
22
|
my $s = 0; |
|
1365
|
|
|
|
|
|
|
Mforprimes( sub { |
|
1366
|
296
|
100
|
|
296
|
|
897
|
$s++ if Mis_prime($n-$_); |
|
1367
|
2
|
|
|
|
|
26
|
}, Mrshiftint($n), $n-3); |
|
1368
|
2
|
|
|
|
|
24
|
$s; |
|
1369
|
|
|
|
|
|
|
} |
|
1370
|
|
|
|
|
|
|
sub goldbach_pairs { |
|
1371
|
6
|
|
|
6
|
0
|
20
|
my($n) = @_; |
|
1372
|
6
|
100
|
|
|
|
20
|
return goldbach_pair_count($n) unless wantarray; |
|
1373
|
3
|
|
|
|
|
9
|
validate_integer_nonneg($n); |
|
1374
|
3
|
50
|
|
|
|
6
|
return () if $n < 4; |
|
1375
|
3
|
100
|
66
|
|
|
16
|
return Mis_prime($n-2) ? (2) : () if $n & 1 || $n == 4; |
|
|
|
100
|
|
|
|
|
|
|
1376
|
1
|
|
|
|
|
1
|
my @L; |
|
1377
|
|
|
|
|
|
|
Mforprimes( sub { |
|
1378
|
16
|
100
|
|
16
|
|
49
|
push @L,$n-$_ if Mis_prime($n-$_); |
|
1379
|
1
|
|
|
|
|
10
|
}, Mrshiftint($n,1), $n-3); |
|
1380
|
1
|
|
|
|
|
24
|
reverse @L; |
|
1381
|
|
|
|
|
|
|
} |
|
1382
|
|
|
|
|
|
|
|
|
1383
|
|
|
|
|
|
|
|
|
1384
|
|
|
|
|
|
|
sub primorial { |
|
1385
|
43
|
|
|
43
|
0
|
50991
|
my($n) = @_; |
|
1386
|
|
|
|
|
|
|
|
|
1387
|
43
|
|
|
|
|
119
|
my @plist = @{Mprimes($n)}; |
|
|
43
|
|
|
|
|
1109
|
|
|
1388
|
43
|
|
|
|
|
173
|
my $max = (MPU_32BIT) ? 29 : (OLD_PERL_VERSION) ? 43 : 53; |
|
1389
|
|
|
|
|
|
|
|
|
1390
|
|
|
|
|
|
|
# If small enough, multiply the small primes. |
|
1391
|
43
|
100
|
|
|
|
198
|
if ($n < $max) { |
|
1392
|
6
|
|
|
|
|
28
|
my $pn = 1; |
|
1393
|
6
|
|
|
|
|
28
|
$pn *= $_ for @plist; |
|
1394
|
6
|
|
|
|
|
39
|
return $pn; |
|
1395
|
|
|
|
|
|
|
} |
|
1396
|
|
|
|
|
|
|
|
|
1397
|
|
|
|
|
|
|
# Otherwise, combine them as UVs, then combine using product tree. |
|
1398
|
37
|
|
|
|
|
93
|
my $i = 0; |
|
1399
|
37
|
|
|
|
|
135
|
while ($i < $#plist) { |
|
1400
|
960
|
|
|
|
|
2052
|
my $m = $plist[$i] * $plist[$i+1]; |
|
1401
|
960
|
100
|
|
|
|
1730
|
if ($m <= INTMAX) { splice(@plist, $i, 2, $m); } |
|
|
893
|
|
|
|
|
2993
|
|
|
1402
|
67
|
|
|
|
|
153
|
else { $i++; } |
|
1403
|
|
|
|
|
|
|
} |
|
1404
|
37
|
|
|
|
|
5453
|
Mvecprod(@plist); |
|
1405
|
|
|
|
|
|
|
} |
|
1406
|
|
|
|
|
|
|
|
|
1407
|
|
|
|
|
|
|
sub pn_primorial { |
|
1408
|
29
|
|
|
29
|
0
|
47152
|
my($n) = @_; |
|
1409
|
29
|
100
|
|
|
|
181
|
return (1,2,6,30,210,2310,30030,510510,9699690,223092870)[$n] if $n < 10; |
|
1410
|
20
|
|
|
|
|
910
|
Mprimorial(nth_prime($n)); |
|
1411
|
|
|
|
|
|
|
} |
|
1412
|
|
|
|
|
|
|
|
|
1413
|
|
|
|
|
|
|
sub consecutive_integer_lcm { |
|
1414
|
57
|
|
|
57
|
0
|
67463
|
my($n) = @_; |
|
1415
|
57
|
|
|
|
|
250
|
validate_integer_nonneg($n); |
|
1416
|
|
|
|
|
|
|
|
|
1417
|
57
|
50
|
|
|
|
199
|
return (1,1,2)[$n] if $n <= 2; |
|
1418
|
57
|
|
|
|
|
105
|
my @powers; |
|
1419
|
57
|
|
|
|
|
196
|
for (my $p = 2; $p <= $n; $p = Mnext_prime($p)) { |
|
1420
|
1412
|
|
|
|
|
2661
|
my($p_power, $pmin) = ($p, int($n/$p)); |
|
1421
|
1412
|
|
|
|
|
3350
|
$p_power = Mmulint($p_power,$p) while $p_power <= $pmin; |
|
1422
|
1412
|
|
|
|
|
3863
|
push @powers, $p_power; |
|
1423
|
|
|
|
|
|
|
} |
|
1424
|
57
|
|
|
|
|
4342
|
my $pn = Mvecprod(@powers); |
|
1425
|
57
|
100
|
|
|
|
811
|
$pn = _bigint_to_int($pn) if $pn <= INTMAX; |
|
1426
|
57
|
|
|
|
|
13133
|
return $pn; |
|
1427
|
|
|
|
|
|
|
} |
|
1428
|
|
|
|
|
|
|
|
|
1429
|
|
|
|
|
|
|
sub frobenius_number { |
|
1430
|
3
|
|
|
3
|
0
|
1418
|
my(@A) = @_; |
|
1431
|
3
|
50
|
|
|
|
34
|
return undef if scalar(@A) == 0; |
|
1432
|
3
|
|
|
|
|
24
|
validate_integer_positive($_) for @A; |
|
1433
|
3
|
|
|
|
|
75
|
Mvecsorti(\@A); |
|
1434
|
3
|
50
|
|
|
|
16
|
return -1 if $A[0] == 1; |
|
1435
|
3
|
50
|
33
|
|
|
23
|
return undef if $A[0] <= 1 || scalar(@A) <= 1; |
|
1436
|
3
|
50
|
|
|
|
23
|
croak "Frobenius number set must be coprime" unless Mgcd(@A) == 1; |
|
1437
|
|
|
|
|
|
|
|
|
1438
|
3
|
100
|
|
|
|
251
|
return Msubint(Msubint(Mmulint($A[0],$A[1]),$A[0]),$A[1]) if scalar(@A) == 2; |
|
1439
|
|
|
|
|
|
|
|
|
1440
|
|
|
|
|
|
|
# Basic Round Robin algorithm from Böcker and Lipták |
|
1441
|
|
|
|
|
|
|
# https://bio.informatik.uni-jena.de/wp/wp-content/uploads/2024/01/BoeckerLiptak_FastSimpleAlgorithm_reprint_2007.pdf |
|
1442
|
|
|
|
|
|
|
|
|
1443
|
1
|
|
|
|
|
4
|
my $nlen = $A[0]; |
|
1444
|
1
|
|
|
|
|
19
|
my @N = (0, (undef) x ($nlen-1)); |
|
1445
|
1
|
|
|
|
|
15
|
for my $i (1 .. $#A) { |
|
1446
|
|
|
|
|
|
|
{ # Optimization 3, skip redundant bases |
|
1447
|
2
|
|
|
|
|
6
|
my $ai = $A[$i]; |
|
|
2
|
|
|
|
|
13
|
|
|
1448
|
2
|
|
|
|
|
9
|
my $np = $N[Mmodint($ai,$nlen)]; |
|
1449
|
2
|
50
|
66
|
|
|
36
|
next if defined $np && $np <= $ai; |
|
1450
|
|
|
|
|
|
|
} |
|
1451
|
2
|
|
|
|
|
11
|
my $d = Mgcd($A[0], $A[$i]); |
|
1452
|
2
|
|
|
|
|
24
|
my $nlend = Mdivint($nlen,$d); |
|
1453
|
2
|
|
|
|
|
18
|
for my $r (0 .. $d-1) { |
|
1454
|
|
|
|
|
|
|
my $n = ($r == 0) ? 0 |
|
1455
|
2
|
50
|
|
|
|
17
|
: Mvecmin(grep {defined} @N[map { $r+$_*$d } 0..$nlend]); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
1456
|
2
|
50
|
|
|
|
8
|
if (defined $n) { |
|
1457
|
2
|
50
|
|
|
|
11
|
if (Maddint($n,Mmulint($A[$i],$nlend-1)) <= INTMAX) { |
|
1458
|
2
|
|
|
|
|
17
|
for (1 .. $nlend-1) { |
|
1459
|
8
|
|
|
|
|
14
|
$n += $A[$i]; |
|
1460
|
8
|
|
|
|
|
32
|
my $p = $n % $nlen; |
|
1461
|
8
|
100
|
100
|
|
|
28
|
if (!defined $N[$p] || $N[$p] >= $n) {$N[$p]=$n;} else {$n=$N[$p];} |
|
|
6
|
|
|
|
|
15
|
|
|
|
2
|
|
|
|
|
7
|
|
|
1462
|
|
|
|
|
|
|
} |
|
1463
|
|
|
|
|
|
|
} else { |
|
1464
|
0
|
|
|
|
|
0
|
for (1 .. $nlend-1) { |
|
1465
|
0
|
|
|
|
|
0
|
$n = Maddint($n,$A[$i]); |
|
1466
|
0
|
|
|
|
|
0
|
my $p = Mmodint($n,$nlen); |
|
1467
|
0
|
0
|
0
|
|
|
0
|
if (!defined $N[$p] || $N[$p] >= $n) {$N[$p]=$n;} else {$n=$N[$p];} |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
1468
|
|
|
|
|
|
|
} |
|
1469
|
|
|
|
|
|
|
} |
|
1470
|
|
|
|
|
|
|
} |
|
1471
|
|
|
|
|
|
|
} |
|
1472
|
|
|
|
|
|
|
} |
|
1473
|
1
|
|
|
|
|
5
|
my $max = Mvecmax(grep { defined } @N); |
|
|
5
|
|
|
|
|
17
|
|
|
1474
|
1
|
50
|
|
|
|
6
|
$max -= $nlen if defined $max; |
|
1475
|
1
|
|
|
|
|
9
|
$max; |
|
1476
|
|
|
|
|
|
|
} |
|
1477
|
|
|
|
|
|
|
|
|
1478
|
|
|
|
|
|
|
sub jordan_totient { |
|
1479
|
25
|
|
|
25
|
0
|
3841
|
my($k, $n) = @_; |
|
1480
|
25
|
|
|
|
|
59
|
validate_integer_nonneg($k); |
|
1481
|
25
|
|
|
|
|
204
|
validate_integer_nonneg($n); |
|
1482
|
25
|
0
|
|
|
|
114
|
return ($n == 1) ? 1 : 0 if $k == 0; |
|
|
|
50
|
|
|
|
|
|
|
1483
|
25
|
50
|
|
|
|
47
|
return Mtotient($n) if $k == 1; |
|
1484
|
25
|
0
|
|
|
|
41
|
return ($n == 1) ? 1 : 0 if $n <= 1; |
|
|
|
50
|
|
|
|
|
|
|
1485
|
|
|
|
|
|
|
|
|
1486
|
|
|
|
|
|
|
return reftyped($_[0], Math::Prime::Util::GMP::jordan_totient($k, $n)) |
|
1487
|
25
|
50
|
|
|
|
523
|
if $Math::Prime::Util::_GMPfunc{"jordan_totient"}; |
|
1488
|
|
|
|
|
|
|
|
|
1489
|
25
|
|
|
|
|
30
|
my $totient = 1; |
|
1490
|
25
|
|
|
|
|
122
|
foreach my $f (Mfactor_exp($n)) { |
|
1491
|
42
|
|
|
|
|
75
|
my ($p, $e) = @$f; |
|
1492
|
42
|
|
|
|
|
503
|
$p = Mpowint($p,$k); |
|
1493
|
42
|
|
|
|
|
1351
|
$totient = Mmulint($totient, $p-1); |
|
1494
|
42
|
|
|
|
|
1557
|
$totient = Mmulint($totient, $p) for 2 .. $e; |
|
1495
|
|
|
|
|
|
|
} |
|
1496
|
25
|
|
|
|
|
90
|
$totient; |
|
1497
|
|
|
|
|
|
|
} |
|
1498
|
|
|
|
|
|
|
|
|
1499
|
|
|
|
|
|
|
sub euler_phi { |
|
1500
|
57
|
100
|
|
57
|
0
|
2974
|
return _euler_phi_range(@_) if scalar @_ > 1; |
|
1501
|
49
|
|
|
|
|
102
|
my($n) = @_; |
|
1502
|
49
|
50
|
33
|
|
|
224
|
return 0 if defined $n && $n < 0; |
|
1503
|
|
|
|
|
|
|
|
|
1504
|
|
|
|
|
|
|
return reftyped($_[0],Math::Prime::Util::GMP::totient($n)) |
|
1505
|
49
|
50
|
|
|
|
1781
|
if $Math::Prime::Util::_GMPfunc{"totient"}; |
|
1506
|
|
|
|
|
|
|
|
|
1507
|
49
|
|
|
|
|
195
|
validate_integer_nonneg($n); |
|
1508
|
49
|
100
|
|
|
|
804
|
return $n if $n <= 1; |
|
1509
|
|
|
|
|
|
|
|
|
1510
|
45
|
|
|
|
|
850
|
my ($t2, $tot) = (1,1); |
|
1511
|
|
|
|
|
|
|
|
|
1512
|
45
|
100
|
|
|
|
147
|
if ($n % 2 == 0) { |
|
1513
|
23
|
|
|
|
|
1550
|
my $totk = 0; |
|
1514
|
23
|
|
|
|
|
124
|
while (($n % 4) == 0) { $n >>= 1; $totk++; } |
|
|
145
|
|
|
|
|
46745
|
|
|
|
145
|
|
|
|
|
28779
|
|
|
1515
|
23
|
|
|
|
|
1233
|
$n >>= 1; |
|
1516
|
23
|
100
|
|
|
|
941
|
$t2 = $totk < 32 ? 1 << $totk : Mlshiftint(1,$totk) if $totk > 0; |
|
|
|
100
|
|
|
|
|
|
|
1517
|
|
|
|
|
|
|
} |
|
1518
|
|
|
|
|
|
|
|
|
1519
|
45
|
100
|
|
|
|
541
|
if ($n < INTMAX) { |
|
1520
|
41
|
|
|
|
|
720
|
foreach my $f (Mfactor_exp($n)) { |
|
1521
|
65
|
|
|
|
|
193
|
my ($p, $e) = @$f; |
|
1522
|
65
|
|
|
|
|
111
|
$tot *= $p-1; |
|
1523
|
65
|
|
|
|
|
11380
|
$tot *= $p for 2 .. $e; |
|
1524
|
|
|
|
|
|
|
} |
|
1525
|
|
|
|
|
|
|
} else { |
|
1526
|
4
|
|
|
|
|
521
|
foreach my $f (Mfactor_exp($n)) { |
|
1527
|
26
|
|
|
|
|
43
|
my ($p, $e) = @$f; |
|
1528
|
26
|
|
|
|
|
107
|
$tot = Mmulint($tot, $p-1); |
|
1529
|
26
|
|
|
|
|
185
|
$tot = Mmulint($tot, $p) for 2 .. $e; |
|
1530
|
|
|
|
|
|
|
} |
|
1531
|
|
|
|
|
|
|
} |
|
1532
|
45
|
|
|
|
|
465
|
Mmulint($t2, $tot); |
|
1533
|
|
|
|
|
|
|
} |
|
1534
|
|
|
|
|
|
|
|
|
1535
|
|
|
|
|
|
|
sub inverse_totient { |
|
1536
|
2
|
|
|
2
|
0
|
7
|
my($n) = @_; |
|
1537
|
2
|
|
|
|
|
12
|
validate_integer_nonneg($n); |
|
1538
|
|
|
|
|
|
|
|
|
1539
|
2
|
0
|
|
|
|
8
|
return wantarray ? (1,2) : 2 if $n == 1; |
|
|
|
50
|
|
|
|
|
|
|
1540
|
2
|
0
|
33
|
|
|
15
|
return wantarray ? () : 0 if $n < 1 || ($n & 1); |
|
|
|
50
|
|
|
|
|
|
|
1541
|
|
|
|
|
|
|
|
|
1542
|
2
|
50
|
|
|
|
14
|
if (Mis_prime($n >> 1)) { # Coleman Remark 3.3 (Thm 3.1) and Prop 6.2 |
|
1543
|
0
|
|
|
|
|
0
|
my $np1 = Madd1int($n); |
|
1544
|
0
|
0
|
|
|
|
0
|
return wantarray ? () : 0 if !Mis_prime($np1); |
|
|
|
0
|
|
|
|
|
|
|
1545
|
0
|
0
|
|
|
|
0
|
return wantarray ? ($np1, Mmulint($np1,2)) : 2 if $n >= 10; |
|
|
|
0
|
|
|
|
|
|
|
1546
|
|
|
|
|
|
|
} |
|
1547
|
|
|
|
|
|
|
|
|
1548
|
2
|
100
|
|
|
|
10
|
if (!wantarray) { |
|
1549
|
1
|
|
|
|
|
5
|
my %r = ( 1 => 1 ); |
|
1550
|
8
|
|
|
8
|
|
14
|
Mfordivisors(sub { my $d = $_; |
|
1551
|
8
|
|
|
|
|
23
|
my $p = Madd1int($d); |
|
1552
|
8
|
100
|
|
|
|
22
|
if (Mis_prime($p)) { |
|
1553
|
4
|
|
|
|
|
27
|
my($dp,@sumi,@sumv) = ($d); |
|
1554
|
4
|
|
|
|
|
18
|
for my $v (0 .. Mvaluation($n, $p)) { |
|
1555
|
22
|
|
|
|
|
39
|
Mfordivisors(sub { my $d2 = $_; |
|
1556
|
22
|
100
|
|
|
|
67
|
if (defined $r{$d2}) { push @sumi, Mmulint($d2,$dp); push @sumv, $r{$d2}; } |
|
|
7
|
|
|
|
|
26
|
|
|
|
7
|
|
|
|
|
22
|
|
|
1557
|
7
|
|
|
|
|
60
|
}, Mdivint($n,$dp)); |
|
1558
|
7
|
|
|
|
|
48
|
$dp = Mmulint($dp,$p); |
|
1559
|
|
|
|
|
|
|
} |
|
1560
|
4
|
|
|
|
|
37
|
$r{ $sumi[$_] } += $sumv[$_] for 0 .. $#sumi; |
|
1561
|
|
|
|
|
|
|
} |
|
1562
|
1
|
|
|
|
|
89
|
}, $n); |
|
1563
|
1
|
50
|
|
|
|
972
|
return (defined $r{$n}) ? $r{$n} : 0; |
|
1564
|
|
|
|
|
|
|
|
|
1565
|
|
|
|
|
|
|
} else { |
|
1566
|
|
|
|
|
|
|
|
|
1567
|
|
|
|
|
|
|
# To save memory, we split this into two steps. |
|
1568
|
|
|
|
|
|
|
|
|
1569
|
1
|
|
|
|
|
24
|
my $_verbose = getconfig()->{'verbose'}; |
|
1570
|
1
|
|
|
|
|
8
|
my %r = ( 1 => [1] ); |
|
1571
|
1
|
|
|
|
|
6
|
my %needed = ( $n => 0 ); |
|
1572
|
1
|
|
|
|
|
4
|
my @DIVINFO; |
|
1573
|
|
|
|
|
|
|
|
|
1574
|
|
|
|
|
|
|
# 1. For each divisor from 1 .. n, track which values are needed. |
|
1575
|
1
|
|
|
|
|
5
|
for my $d (divisors($n)) { |
|
1576
|
8
|
|
|
|
|
44
|
my $p = Madd1int($d); |
|
1577
|
8
|
100
|
|
|
|
23
|
next unless Mis_prime($p); |
|
1578
|
4
|
|
|
|
|
8
|
my @L; |
|
1579
|
4
|
|
|
|
|
34
|
for my $v (0 .. Mvaluation($n, $p)) { |
|
1580
|
7
|
|
|
|
|
29
|
my $pv = Mpowint($p, $v); |
|
1581
|
7
|
|
|
|
|
18
|
my($dp,$pp) = map { Mmulint($_,$pv) } ($d,$p); |
|
|
14
|
|
|
|
|
37
|
|
|
1582
|
22
|
|
|
22
|
|
40
|
Mfordivisors(sub { my $d2 = $_; |
|
1583
|
22
|
|
|
|
|
56
|
my $F = Mmulint($d2,$dp); |
|
1584
|
|
|
|
|
|
|
# In phase 2, we will look at the list in d2 to add to list in F. |
|
1585
|
|
|
|
|
|
|
# If F isn't needed later then we ignore it completely. |
|
1586
|
22
|
100
|
66
|
|
|
95
|
if (defined $needed{$F} && $needed{$F} < $d) { |
|
1587
|
7
|
100
|
|
|
|
24
|
$needed{$d2} = $d unless defined $needed{$d2}; |
|
1588
|
7
|
|
|
|
|
48
|
push @L, [$d2,$pp,$F]; |
|
1589
|
|
|
|
|
|
|
} |
|
1590
|
7
|
|
|
|
|
90
|
}, Mdivint($n, $dp)); |
|
1591
|
|
|
|
|
|
|
} |
|
1592
|
4
|
|
|
|
|
18
|
push @DIVINFO, [$d, @L]; |
|
1593
|
|
|
|
|
|
|
} |
|
1594
|
|
|
|
|
|
|
|
|
1595
|
1
|
50
|
|
|
|
6
|
print " ... inverse_totient phase 1 complete ...\n" if $_verbose; |
|
1596
|
|
|
|
|
|
|
|
|
1597
|
|
|
|
|
|
|
# 2. Process the divisors in reverse order. |
|
1598
|
1
|
|
|
|
|
18
|
for my $dinfo (reverse @DIVINFO) { |
|
1599
|
4
|
|
|
|
|
12
|
my($d,@L) = @$dinfo; |
|
1600
|
4
|
|
|
|
|
16
|
my %todelete; |
|
1601
|
|
|
|
|
|
|
my @T; |
|
1602
|
|
|
|
|
|
|
# Multiply through by $pp |
|
1603
|
4
|
|
|
|
|
8
|
for my $dset (@L) { |
|
1604
|
7
|
100
|
|
|
|
19
|
if (defined $r{$dset->[0]}) { |
|
1605
|
3
|
|
|
|
|
8
|
my($d2,$pp,$F) = @$dset; |
|
1606
|
3
|
|
|
|
|
6
|
push @T, [$F, [map { Mmulint($pp,$_) } @{$r{$d2}}]]; |
|
|
4
|
|
|
|
|
11
|
|
|
|
3
|
|
|
|
|
7
|
|
|
1607
|
3
|
100
|
|
|
|
15
|
$todelete{$d2} = 1 if $needed{$d2} >= $d; |
|
1608
|
|
|
|
|
|
|
} |
|
1609
|
|
|
|
|
|
|
} |
|
1610
|
|
|
|
|
|
|
# Delete intermediate data that isn't needed any more |
|
1611
|
4
|
|
|
|
|
13
|
delete $r{$_} for keys %todelete; |
|
1612
|
|
|
|
|
|
|
# Append the multiplied lists. |
|
1613
|
4
|
|
|
|
|
9
|
push @{$r{$_->[0]}}, @{$_->[1]} for @T; |
|
|
3
|
|
|
|
|
9
|
|
|
|
3
|
|
|
|
|
13
|
|
|
1614
|
|
|
|
|
|
|
} |
|
1615
|
1
|
|
|
|
|
21
|
undef %needed; |
|
1616
|
1
|
50
|
|
|
|
6
|
print " ... inverse_totient phase 2 complete ...\n" if $_verbose; |
|
1617
|
|
|
|
|
|
|
|
|
1618
|
1
|
50
|
|
|
|
5
|
return (defined $r{$n}) ? @{Mvecsorti($r{$n})} : (); |
|
|
1
|
|
|
|
|
52
|
|
|
1619
|
|
|
|
|
|
|
} |
|
1620
|
|
|
|
|
|
|
} |
|
1621
|
|
|
|
|
|
|
|
|
1622
|
|
|
|
|
|
|
sub _euler_phi_range { |
|
1623
|
8
|
|
|
8
|
|
49
|
my($lo, $hi) = @_; |
|
1624
|
8
|
|
|
|
|
46
|
validate_integer($lo); |
|
1625
|
8
|
|
|
|
|
60
|
validate_integer($hi); |
|
1626
|
|
|
|
|
|
|
|
|
1627
|
8
|
|
|
|
|
17
|
my @totients; |
|
1628
|
8
|
|
66
|
|
|
57
|
while ($lo < 0 && $lo <= $hi) { |
|
1629
|
5
|
|
|
|
|
9
|
push @totients, 0; |
|
1630
|
5
|
|
|
|
|
16
|
$lo++; |
|
1631
|
|
|
|
|
|
|
} |
|
1632
|
8
|
50
|
|
|
|
44
|
return @totients if $hi < $lo; |
|
1633
|
|
|
|
|
|
|
|
|
1634
|
8
|
100
|
100
|
|
|
628
|
if ($hi > 2**30 || $hi-$lo < 100) { |
|
1635
|
5
|
100
|
|
|
|
427
|
($lo,$hi) = (tobigint($lo),tobigint($hi)) if $hi > 2**49; |
|
1636
|
5
|
|
|
|
|
48
|
push @totients, euler_phi($lo++) while $lo <= $hi; |
|
1637
|
|
|
|
|
|
|
} else { |
|
1638
|
3
|
|
|
|
|
360
|
my @tot = (0 .. $hi); |
|
1639
|
3
|
|
|
|
|
32
|
foreach my $i (2 .. $hi) { |
|
1640
|
1781
|
100
|
|
|
|
3621
|
next unless $tot[$i] == $i; |
|
1641
|
317
|
|
|
|
|
502
|
$tot[$i] = $i-1; |
|
1642
|
317
|
|
|
|
|
656
|
foreach my $j (2 .. int($hi / $i)) { |
|
1643
|
3397
|
|
|
|
|
6356
|
$tot[$i*$j] -= $tot[$i*$j]/$i; |
|
1644
|
|
|
|
|
|
|
} |
|
1645
|
|
|
|
|
|
|
} |
|
1646
|
3
|
100
|
|
|
|
30
|
splice(@tot, 0, $lo) if $lo > 0; |
|
1647
|
3
|
|
|
|
|
562
|
push @totients, @tot; |
|
1648
|
|
|
|
|
|
|
} |
|
1649
|
8
|
|
|
|
|
650
|
@totients; |
|
1650
|
|
|
|
|
|
|
} |
|
1651
|
|
|
|
|
|
|
|
|
1652
|
|
|
|
|
|
|
sub _sumtot { |
|
1653
|
7
|
|
|
7
|
|
21
|
my($n, $cdata, $ecache) = @_; |
|
1654
|
7
|
50
|
|
|
|
24
|
return $cdata->[$n] if $n <= 0+$#$cdata; |
|
1655
|
7
|
100
|
|
|
|
27
|
return $ecache->{$n} if defined $ecache->{$n}; |
|
1656
|
|
|
|
|
|
|
|
|
1657
|
6
|
|
|
|
|
34
|
my $sum = Mmulint($n, $n+1) >> 1; |
|
1658
|
6
|
|
|
|
|
36
|
my $s = sqrtint($n); |
|
1659
|
6
|
|
|
|
|
49
|
my $lim = Mdivint($n, $s+1); |
|
1660
|
|
|
|
|
|
|
|
|
1661
|
6
|
|
|
|
|
34
|
my($x, $nextx) = ($n, Mdivint($n,2)); |
|
1662
|
6
|
|
|
|
|
27
|
$sum -= Mmulint($x - $nextx, $cdata->[1]); |
|
1663
|
6
|
|
|
|
|
19
|
for my $k (2 .. $lim) { |
|
1664
|
259
|
|
|
|
|
607
|
($x,$nextx) = ($nextx, Mdivint($n,$k+1)); |
|
1665
|
259
|
100
|
|
|
|
687
|
$sum -= ($x <= 0+$#$cdata) ? $cdata->[$x] : _sumtot($x, $cdata, $ecache); |
|
1666
|
259
|
50
|
|
|
|
783
|
$sum -= Mmulint($x - $nextx, |
|
1667
|
|
|
|
|
|
|
($k <= $#$cdata) ? $cdata->[$k] : _sumtot($k, $cdata, $ecache)); |
|
1668
|
|
|
|
|
|
|
} |
|
1669
|
6
|
100
|
|
|
|
65
|
if ($s > $lim) { |
|
1670
|
2
|
|
|
|
|
34
|
($x,$nextx) = ($nextx, Mdivint($n,$s+1)); |
|
1671
|
2
|
50
|
|
|
|
35
|
$sum -= Mmulint($x - $nextx, |
|
1672
|
|
|
|
|
|
|
($s <= 0+$#$cdata) ? $cdata->[$s] : _sumtot($s, $cdata, $ecache)); |
|
1673
|
|
|
|
|
|
|
} |
|
1674
|
6
|
|
|
|
|
43
|
$ecache->{$n} = $sum; |
|
1675
|
6
|
|
|
|
|
35
|
$sum; |
|
1676
|
|
|
|
|
|
|
} |
|
1677
|
|
|
|
|
|
|
|
|
1678
|
|
|
|
|
|
|
sub sumtotient { |
|
1679
|
4
|
|
|
4
|
0
|
16
|
my($n) = @_; |
|
1680
|
4
|
|
|
|
|
29
|
validate_integer_nonneg($n); |
|
1681
|
4
|
50
|
|
|
|
16
|
return $n if $n <= 2; |
|
1682
|
|
|
|
|
|
|
|
|
1683
|
4
|
100
|
|
|
|
30
|
if ($n < 900) { # Simple linear sum for small values. |
|
1684
|
2
|
|
|
|
|
6
|
my $sum = 0; |
|
1685
|
2
|
|
|
|
|
11
|
$sum += $_ for Mtotient(1,$n); |
|
1686
|
2
|
|
|
|
|
45
|
return $sum; |
|
1687
|
|
|
|
|
|
|
} |
|
1688
|
|
|
|
|
|
|
|
|
1689
|
2
|
|
|
|
|
14
|
my $cbrt = Mrootint($n,3); |
|
1690
|
2
|
|
|
|
|
34
|
my $csize = Mvecprod(4, $cbrt, $cbrt); |
|
1691
|
2
|
50
|
|
|
|
30
|
$csize = 50_000_000 if $csize > 50_000_000; # Limit memory use to ~2.5GB |
|
1692
|
2
|
|
|
|
|
21
|
my @sumcache = Mtotient(0,$csize); |
|
1693
|
2
|
|
|
|
|
545
|
$sumcache[$_] += $sumcache[$_-1] for 2 .. $csize; |
|
1694
|
2
|
|
|
|
|
35
|
_sumtot($n, \@sumcache, {}); |
|
1695
|
|
|
|
|
|
|
} |
|
1696
|
|
|
|
|
|
|
|
|
1697
|
|
|
|
|
|
|
|
|
1698
|
|
|
|
|
|
|
sub prime_bigomega { |
|
1699
|
12
|
|
|
12
|
0
|
80
|
my($n) = @_; |
|
1700
|
12
|
|
|
|
|
52
|
validate_integer_abs($n); |
|
1701
|
12
|
|
|
|
|
561
|
return scalar(Mfactor($n)); |
|
1702
|
|
|
|
|
|
|
} |
|
1703
|
|
|
|
|
|
|
sub prime_omega { |
|
1704
|
3092
|
|
|
3092
|
0
|
10694
|
my($n) = @_; |
|
1705
|
3092
|
|
|
|
|
7638
|
validate_integer_abs($n); |
|
1706
|
3092
|
|
|
|
|
9368
|
return scalar(Mfactor_exp($n)); |
|
1707
|
|
|
|
|
|
|
} |
|
1708
|
|
|
|
|
|
|
|
|
1709
|
|
|
|
|
|
|
sub moebius { |
|
1710
|
1031
|
100
|
|
1031
|
0
|
14260
|
return _moebius_range(@_) if scalar @_ > 1; |
|
1711
|
663
|
|
|
|
|
1270
|
my($n) = @_; |
|
1712
|
663
|
|
|
|
|
1757
|
validate_integer_abs($n); |
|
1713
|
663
|
50
|
|
|
|
6994
|
return ($n == 1) ? 1 : 0 if $n <= 1; |
|
|
|
100
|
|
|
|
|
|
|
1714
|
641
|
100
|
100
|
|
|
6546
|
return 0 if ($n >= 49) && (!($n % 4) || !($n % 9) || !($n % 25) || !($n%49) ); |
|
|
|
|
100
|
|
|
|
|
|
1715
|
580
|
|
|
|
|
28509
|
my @factors = Mfactor($n); |
|
1716
|
580
|
|
|
|
|
1440
|
foreach my $i (1 .. $#factors) { |
|
1717
|
445
|
100
|
|
|
|
1534
|
return 0 if $factors[$i] == $factors[$i-1]; |
|
1718
|
|
|
|
|
|
|
} |
|
1719
|
428
|
100
|
|
|
|
2192
|
return ((scalar @factors) % 2) ? -1 : 1; |
|
1720
|
|
|
|
|
|
|
} |
|
1721
|
|
|
|
|
|
|
sub is_square_free { |
|
1722
|
317
|
100
|
|
317
|
0
|
1095
|
return (Mmoebius($_[0]) != 0) ? 1 : 0; |
|
1723
|
|
|
|
|
|
|
} |
|
1724
|
|
|
|
|
|
|
|
|
1725
|
|
|
|
|
|
|
sub is_odd { |
|
1726
|
343
|
|
|
343
|
0
|
593
|
my($n) = @_; |
|
1727
|
343
|
|
|
|
|
885
|
validate_integer($n); |
|
1728
|
|
|
|
|
|
|
# Note: If n is a Math::BigInt (Calc), then performance: |
|
1729
|
|
|
|
|
|
|
# 0.25x $n->is_odd() # method is fastest |
|
1730
|
|
|
|
|
|
|
# 0.34x (substr($n,-1,1) =~ tr/13579/13579/) # Perl look at string |
|
1731
|
|
|
|
|
|
|
# 0.46x is_odd($n) # XS looks at the string |
|
1732
|
|
|
|
|
|
|
# 1.0x $n % 2 ? 1 : 0 |
|
1733
|
|
|
|
|
|
|
# 1.6x $n & 1 : 1 : 0 |
|
1734
|
|
|
|
|
|
|
# Using LTM backend: |
|
1735
|
|
|
|
|
|
|
# 0.21 $n->is_odd |
|
1736
|
|
|
|
|
|
|
# 0.41 (substr($n,-1,1) =~ tr/13579/13579/) |
|
1737
|
|
|
|
|
|
|
# 0.64 is_odd($n) |
|
1738
|
|
|
|
|
|
|
# 0.9 $n & 1 ? 1 : 0 |
|
1739
|
|
|
|
|
|
|
# 1.0 $n % 2 ? 1 : 0 |
|
1740
|
|
|
|
|
|
|
# |
|
1741
|
|
|
|
|
|
|
# Math::GMPz (30x faster baseline) |
|
1742
|
|
|
|
|
|
|
# 0.23 Math::GMPz::Rmpz_odd_p($n) |
|
1743
|
|
|
|
|
|
|
# 0.73 (substr($n,-1,1) =~ tr/13579/13579/) |
|
1744
|
|
|
|
|
|
|
# 0.95 $n & 1 ? 1 : 0 |
|
1745
|
|
|
|
|
|
|
# 1.0 $n % 2 ? 1 : 0 |
|
1746
|
|
|
|
|
|
|
# 1.5 is_odd($n) |
|
1747
|
343
|
|
|
|
|
501
|
my $R = ref($n); |
|
1748
|
343
|
50
|
|
|
|
713
|
return $n->is_odd() ? 1 : 0 if $R eq 'Math::BigInt'; |
|
|
|
100
|
|
|
|
|
|
|
1749
|
342
|
0
|
|
|
|
739
|
return Math::GMPz::Rmpz_odd_p($n) ? 1 : 0 if $R eq 'Math::GMPz'; |
|
|
|
50
|
|
|
|
|
|
|
1750
|
342
|
|
|
|
|
455
|
return (my $k = substr("$n",-1,1)) =~ tr/13579/13579/ if OLD_PERL_VERSION; |
|
1751
|
342
|
100
|
|
|
|
1279
|
return $n % 2 ? 1 : 0; |
|
1752
|
|
|
|
|
|
|
} |
|
1753
|
|
|
|
|
|
|
sub is_even { |
|
1754
|
113
|
|
|
113
|
0
|
911
|
my($n) = @_; |
|
1755
|
113
|
|
|
|
|
271
|
validate_integer($n); |
|
1756
|
113
|
|
|
|
|
159
|
my $R = ref($n); |
|
1757
|
113
|
50
|
|
|
|
289
|
return $n->is_even() ? 1 : 0 if $R eq 'Math::BigInt'; |
|
|
|
100
|
|
|
|
|
|
|
1758
|
109
|
0
|
|
|
|
225
|
return Math::GMPz::Rmpz_even_p($n) ? 1 : 0 if $R eq 'Math::GMPz'; |
|
|
|
50
|
|
|
|
|
|
|
1759
|
109
|
|
|
|
|
142
|
return (my $k = substr("$n",-1,1)) =~ tr/02468/02468/ if OLD_PERL_VERSION; |
|
1760
|
109
|
100
|
|
|
|
507
|
return $n % 2 ? 0 : 1; |
|
1761
|
|
|
|
|
|
|
} |
|
1762
|
|
|
|
|
|
|
|
|
1763
|
|
|
|
|
|
|
sub is_divisible { |
|
1764
|
857
|
|
|
857
|
0
|
20079
|
my($n,@d) = @_; |
|
1765
|
857
|
|
|
|
|
5010
|
validate_integer_abs($n); |
|
1766
|
857
|
|
|
|
|
189803
|
for my $d (@d) { |
|
1767
|
875
|
|
|
|
|
3132
|
validate_integer_abs($d); |
|
1768
|
875
|
0
|
|
|
|
2961
|
if ($d == 0) { return 1 if $n == 0; } |
|
|
0
|
50
|
|
|
|
0
|
|
|
1769
|
875
|
100
|
|
|
|
3638
|
else { return 1 if $n % $d == 0; } |
|
1770
|
|
|
|
|
|
|
} |
|
1771
|
327
|
|
|
|
|
181138
|
0; |
|
1772
|
|
|
|
|
|
|
} |
|
1773
|
|
|
|
|
|
|
sub is_congruent { |
|
1774
|
8
|
|
|
8
|
0
|
417061
|
my($n,$c,$d) = @_; |
|
1775
|
8
|
|
|
|
|
82
|
validate_integer($n); |
|
1776
|
8
|
|
|
|
|
198
|
validate_integer($c); |
|
1777
|
8
|
|
|
|
|
154
|
validate_integer_abs($d); |
|
1778
|
8
|
50
|
|
|
|
1492
|
if ($d != 0) { |
|
1779
|
8
|
50
|
33
|
|
|
909
|
$n = Mmodint($n,$d) if $n < 0 || $n >= $d; |
|
1780
|
8
|
100
|
100
|
|
|
66
|
$c = Mmodint($c,$d) if $c < 0 || $c >= $d; |
|
1781
|
|
|
|
|
|
|
} |
|
1782
|
8
|
|
|
|
|
247
|
return 0+($n == $c); |
|
1783
|
|
|
|
|
|
|
} |
|
1784
|
|
|
|
|
|
|
|
|
1785
|
|
|
|
|
|
|
sub is_smooth { |
|
1786
|
8
|
|
|
8
|
0
|
1956
|
my($n, $k) = @_; |
|
1787
|
8
|
|
|
|
|
88
|
validate_integer_abs($n); |
|
1788
|
8
|
|
|
|
|
1178
|
validate_integer_nonneg($k); |
|
1789
|
|
|
|
|
|
|
|
|
1790
|
8
|
50
|
|
|
|
27
|
return 1 if $n <= 1; |
|
1791
|
8
|
50
|
|
|
|
1126
|
return 0 if $k <= 1; |
|
1792
|
8
|
50
|
|
|
|
39
|
return 1 if $n <= $k; |
|
1793
|
|
|
|
|
|
|
|
|
1794
|
|
|
|
|
|
|
return Math::Prime::Util::GMP::is_smooth($n,$k) |
|
1795
|
8
|
50
|
|
|
|
1018
|
if $Math::Prime::Util::_GMPfunc{"is_smooth"}; |
|
1796
|
|
|
|
|
|
|
|
|
1797
|
8
|
50
|
|
|
|
25
|
if ($k <= 10000000) { |
|
1798
|
8
|
|
|
|
|
18
|
my @f; |
|
1799
|
8
|
|
|
|
|
12
|
while (1) { |
|
1800
|
16
|
|
|
|
|
112
|
@f = Mtrial_factor($n, $k); |
|
1801
|
16
|
100
|
|
|
|
54
|
last if scalar(@f) <= 1; |
|
1802
|
8
|
50
|
|
|
|
25
|
return 0 if $f[-2] > $k; |
|
1803
|
8
|
|
|
|
|
51
|
$n = $f[-1]; |
|
1804
|
|
|
|
|
|
|
} |
|
1805
|
8
|
|
|
|
|
135
|
return 0 + ($f[0] <= $k); |
|
1806
|
|
|
|
|
|
|
} |
|
1807
|
|
|
|
|
|
|
|
|
1808
|
0
|
0
|
|
0
|
|
0
|
return (Mvecnone(sub { $_ > $k }, Mfactor($n))) ? 1 : 0; |
|
|
0
|
|
|
|
|
0
|
|
|
1809
|
|
|
|
|
|
|
} |
|
1810
|
|
|
|
|
|
|
sub is_rough { |
|
1811
|
5
|
|
|
5
|
0
|
2811
|
my($n, $k) = @_; |
|
1812
|
5
|
|
|
|
|
55
|
validate_integer_abs($n); |
|
1813
|
5
|
|
|
|
|
605
|
validate_integer_nonneg($k); |
|
1814
|
|
|
|
|
|
|
|
|
1815
|
5
|
50
|
|
|
|
21
|
return 0+($k == 0) if $n == 0; |
|
1816
|
5
|
50
|
33
|
|
|
546
|
return 1 if $n == 1 || $k <= 1; |
|
1817
|
5
|
50
|
|
|
|
504
|
return 0 if $k > $n; |
|
1818
|
5
|
50
|
|
|
|
330
|
return 0+($n >= 1) if $k == 2; |
|
1819
|
|
|
|
|
|
|
|
|
1820
|
|
|
|
|
|
|
return Math::Prime::Util::GMP::is_rough($n,$k) |
|
1821
|
5
|
50
|
|
|
|
20727
|
if $Math::Prime::Util::_GMPfunc{"is_rough"}; |
|
1822
|
|
|
|
|
|
|
|
|
1823
|
5
|
50
|
|
|
|
19
|
if ($k < 50000) { |
|
1824
|
5
|
|
|
|
|
33
|
my @f = Mtrial_factor($n, $k-1); |
|
1825
|
5
|
|
|
|
|
48
|
return 0 + ($f[0] >= $k); |
|
1826
|
|
|
|
|
|
|
} |
|
1827
|
|
|
|
|
|
|
|
|
1828
|
0
|
0
|
|
0
|
|
0
|
return (Mvecnone(sub { $_ < $k }, Mfactor($n))) ? 1 : 0; |
|
|
0
|
|
|
|
|
0
|
|
|
1829
|
|
|
|
|
|
|
} |
|
1830
|
|
|
|
|
|
|
sub is_powerful { |
|
1831
|
6
|
|
|
6
|
0
|
1587
|
my($n, $k) = @_; |
|
1832
|
6
|
|
|
|
|
55
|
validate_integer($n); |
|
1833
|
6
|
100
|
|
|
|
40
|
if (defined $k) { validate_integer_nonneg($k); } else { $k = 2; } |
|
|
2
|
|
|
|
|
8
|
|
|
|
4
|
|
|
|
|
8
|
|
|
1834
|
|
|
|
|
|
|
|
|
1835
|
6
|
50
|
|
|
|
34
|
return 0 if $n < 1; |
|
1836
|
6
|
50
|
33
|
|
|
678
|
return 1 if $n == 1 || $k <= 1; |
|
1837
|
|
|
|
|
|
|
|
|
1838
|
|
|
|
|
|
|
return Math::Prime::Util::GMP::is_powerful($n,$k) |
|
1839
|
6
|
50
|
|
|
|
575
|
if $Math::Prime::Util::_GMPfunc{"is_powerful"}; |
|
1840
|
|
|
|
|
|
|
|
|
1841
|
|
|
|
|
|
|
# First quick checks for inadmissibility. |
|
1842
|
6
|
100
|
|
|
|
35
|
if ($k == 2) { |
|
1843
|
4
|
50
|
66
|
|
|
16
|
return 0 if ($n%3) == 0 && ($n%9) != 0; |
|
1844
|
4
|
100
|
100
|
|
|
1931
|
return 0 if ($n%5) == 0 && ($n%25) != 0; |
|
1845
|
3
|
50
|
66
|
|
|
1744
|
return 0 if ($n%7) == 0 && ($n%49) != 0; |
|
1846
|
3
|
50
|
66
|
|
|
1920
|
return 0 if ($n%11) == 0 && ($n%121) != 0; |
|
1847
|
|
|
|
|
|
|
} else { |
|
1848
|
2
|
50
|
33
|
|
|
13
|
return 0 if ($n%3) == 0 && ($n%27) != 0; |
|
1849
|
2
|
50
|
33
|
|
|
342
|
return 0 if ($n%5) == 0 && ($n%125) != 0; |
|
1850
|
2
|
50
|
33
|
|
|
314
|
return 0 if ($n%7) == 0 && ($n%343) != 0; |
|
1851
|
2
|
50
|
33
|
|
|
325
|
return 0 if ($n%11) == 0 && ($n%1331) != 0; |
|
1852
|
|
|
|
|
|
|
} |
|
1853
|
|
|
|
|
|
|
|
|
1854
|
|
|
|
|
|
|
# Next, check and remove all primes under 149 with three 64-bit gcds. |
|
1855
|
5
|
|
|
|
|
3139
|
for my $GCD ("614889782588491410","3749562977351496827","4343678784233766587") { |
|
1856
|
10
|
|
|
|
|
100
|
my $g = Mgcd($n, $GCD); |
|
1857
|
10
|
100
|
|
|
|
41
|
if ($g != 1) { |
|
1858
|
|
|
|
|
|
|
# Check anything that divides n also divides k times (and remove). |
|
1859
|
4
|
|
|
|
|
88
|
my $gk = Mpowint($g, $k); |
|
1860
|
4
|
100
|
|
|
|
145
|
return 0 if ($n % $gk) != 0; |
|
1861
|
3
|
|
|
|
|
569
|
$n = Mdivint($n, $gk); |
|
1862
|
|
|
|
|
|
|
# Now remove any possible further amounts of these divisors. |
|
1863
|
3
|
|
|
|
|
14
|
$g = Mgcd($n, $g); |
|
1864
|
3
|
|
100
|
|
|
16
|
while ($n > 1 && $g > 1) { |
|
1865
|
37
|
|
|
|
|
1083
|
$n = Mdivint($n, $g); |
|
1866
|
37
|
|
|
|
|
106
|
$g = Mgcd($n, $g); |
|
1867
|
|
|
|
|
|
|
} |
|
1868
|
3
|
100
|
|
|
|
22
|
return 1 if $n == 1; |
|
1869
|
|
|
|
|
|
|
} |
|
1870
|
|
|
|
|
|
|
} |
|
1871
|
|
|
|
|
|
|
|
|
1872
|
|
|
|
|
|
|
# For small primes, check for perfect powers and thereby limit the search |
|
1873
|
|
|
|
|
|
|
# to divisibiilty conditions on primes less than n^(1/(2k)). This is |
|
1874
|
|
|
|
|
|
|
# usually faster than full factoring. |
|
1875
|
|
|
|
|
|
|
# |
|
1876
|
|
|
|
|
|
|
# But ... it's possible this will take far too long (e.g. n=2^256+1). So |
|
1877
|
|
|
|
|
|
|
# limit to something reasonable. |
|
1878
|
|
|
|
|
|
|
|
|
1879
|
2
|
50
|
33
|
|
|
19
|
return 1 if $n == 1 || Mis_power($n) >= $k; |
|
1880
|
2
|
100
|
|
|
|
85
|
return 0 if $n < Mpowint(149, 2*$k); |
|
1881
|
|
|
|
|
|
|
|
|
1882
|
1
|
|
|
|
|
5
|
my $lim_actual = Mrootint($n, 2*$k); |
|
1883
|
1
|
50
|
|
|
|
23
|
my $lim_effect = ($lim_actual > 10000) ? 10000 : $lim_actual; |
|
1884
|
|
|
|
|
|
|
|
|
1885
|
1
|
50
|
|
|
|
8
|
if ($Math::Prime::Util::_GMPfunc{"trial_factor"}) { |
|
1886
|
0
|
|
|
|
|
0
|
while (1) { |
|
1887
|
0
|
|
|
|
|
0
|
my @fac = Math::Prime::Util::GMP::trial_factor($n, $lim_effect); |
|
1888
|
0
|
0
|
|
|
|
0
|
last if scalar(@fac) <= 1; |
|
1889
|
0
|
|
|
|
|
0
|
my $f = $fac[0]; |
|
1890
|
0
|
0
|
|
|
|
0
|
my $fk = ($k==2) ? $f*$f : Mpowint($f,$k); |
|
1891
|
0
|
0
|
|
|
|
0
|
return 0 if ($n % $fk) != 0; |
|
1892
|
0
|
|
|
|
|
0
|
$n = Mdivint($n, $fk); |
|
1893
|
0
|
|
|
|
|
0
|
$n = Mdivint($n, $f) while !($n % $f); |
|
1894
|
0
|
0
|
0
|
|
|
0
|
return 1 if $n == 1 || Mis_power($n) >= $k; |
|
1895
|
0
|
0
|
|
|
|
0
|
return 0 if $n < $fk*$fk; |
|
1896
|
|
|
|
|
|
|
} |
|
1897
|
|
|
|
|
|
|
} else { |
|
1898
|
|
|
|
|
|
|
Mforprimes( sub { |
|
1899
|
2
|
50
|
|
2
|
|
11
|
my $pk = ($k==2) ? $_*$_ : Mpowint($_,$k); |
|
1900
|
2
|
50
|
|
|
|
8
|
Math::Prime::Util::lastfor(),return if $n < $pk*$pk; |
|
1901
|
2
|
100
|
|
|
|
21
|
if (($n%$_) == 0) { |
|
1902
|
1
|
50
|
|
|
|
23
|
Math::Prime::Util::lastfor(),return if ($n % $pk) != 0; |
|
1903
|
1
|
|
|
|
|
5
|
$n = Mdivint($n, $pk); |
|
1904
|
1
|
|
|
|
|
6
|
$n = Mdivint($n, $_) while ($n % $_) == 0; |
|
1905
|
1
|
50
|
33
|
|
|
10
|
Math::Prime::Util::lastfor(),return if $n == 1 || Mis_power($n) >= $k; |
|
1906
|
|
|
|
|
|
|
} |
|
1907
|
1
|
|
|
|
|
26
|
}, 149, $lim_effect); |
|
1908
|
|
|
|
|
|
|
} |
|
1909
|
1
|
50
|
33
|
|
|
16
|
return 1 if $n == 1 || Mis_power($n) >= $k; |
|
1910
|
0
|
0
|
|
|
|
0
|
return 0 if $n <= Mpowint($lim_effect, 2*$k); |
|
1911
|
|
|
|
|
|
|
|
|
1912
|
|
|
|
|
|
|
# Taking too long. Factor what is left. |
|
1913
|
0
|
0
|
|
0
|
|
0
|
return (Mvecall(sub { $_->[1] >= $k }, Mfactor_exp($n))) ? 1 : 0; |
|
|
0
|
|
|
|
|
0
|
|
|
1914
|
|
|
|
|
|
|
} |
|
1915
|
|
|
|
|
|
|
|
|
1916
|
|
|
|
|
|
|
sub _powerful_count_recurse { |
|
1917
|
19158
|
|
|
19158
|
|
2001324
|
my($n, $k, $m, $r) = @_; |
|
1918
|
19158
|
|
|
|
|
92263
|
my $lim = Mrootint(Mdivint($n, $m), $r); |
|
1919
|
|
|
|
|
|
|
|
|
1920
|
19158
|
100
|
|
|
|
112006
|
return $lim if $r <= $k; |
|
1921
|
|
|
|
|
|
|
|
|
1922
|
7766
|
|
|
|
|
14579
|
my $sum = 0; |
|
1923
|
7766
|
|
|
|
|
22992
|
for my $i (1 .. $lim) { |
|
1924
|
35872
|
100
|
100
|
|
|
221886
|
if (Mgcd($m,$i) == 1 && Mis_square_free($i)) { |
|
1925
|
19154
|
|
|
|
|
566424
|
$sum += _powerful_count_recurse($n, $k, Mmulint($m,Mpowint($i,$r)), $r-1); |
|
1926
|
|
|
|
|
|
|
} |
|
1927
|
|
|
|
|
|
|
} |
|
1928
|
7766
|
|
|
|
|
33413
|
$sum; |
|
1929
|
|
|
|
|
|
|
} |
|
1930
|
|
|
|
|
|
|
|
|
1931
|
|
|
|
|
|
|
sub powerful_count { |
|
1932
|
20
|
|
|
20
|
0
|
25410
|
my($n, $k) = @_; |
|
1933
|
20
|
50
|
|
|
|
87
|
validate_integer($n); $n = 0 if $n < 0; |
|
|
20
|
|
|
|
|
71
|
|
|
1934
|
20
|
100
|
|
|
|
534
|
if (defined $k) { validate_integer_nonneg($k); } else { $k = 2; } |
|
|
19
|
|
|
|
|
72
|
|
|
|
1
|
|
|
|
|
12
|
|
|
1935
|
|
|
|
|
|
|
|
|
1936
|
20
|
50
|
33
|
|
|
162
|
return $n if $k <= 1 || $n <= 1; |
|
1937
|
|
|
|
|
|
|
|
|
1938
|
20
|
100
|
|
|
|
670
|
if ($k == 2) { |
|
1939
|
16
|
|
|
|
|
35
|
my $sum = 0; |
|
1940
|
|
|
|
|
|
|
# Simple but very slow for n > 2^64. |
|
1941
|
|
|
|
|
|
|
# Math::Prime::Util::forsquarefreeint( |
|
1942
|
|
|
|
|
|
|
# sub { $sum += Msqrtint(Mdivint($n,Mpowint($_,3))); }, |
|
1943
|
|
|
|
|
|
|
# Mrootint($n,3) |
|
1944
|
|
|
|
|
|
|
# ); |
|
1945
|
16
|
|
|
|
|
58
|
my($l,$j) = (0,Msqrtint($n)); |
|
1946
|
16
|
|
|
|
|
61
|
while ($j > 1) { |
|
1947
|
345
|
|
|
|
|
853
|
my $k2 = Mrootint(Mdivint($n,Mmulint($j,$j)),3)+1; |
|
1948
|
345
|
|
|
|
|
1008
|
my $w = Math::Prime::Util::powerfree_count($k2-1,2); |
|
1949
|
345
|
|
|
|
|
919
|
$sum += Mmulint($j,Msubint($w,$l)); |
|
1950
|
345
|
|
|
|
|
659
|
$l = $w; |
|
1951
|
345
|
|
|
|
|
902
|
$j = Msqrtint(Mdivint($n,Mpowint($k2,3))); |
|
1952
|
|
|
|
|
|
|
} |
|
1953
|
16
|
|
|
|
|
56
|
$sum += Math::Prime::Util::powerfree_count(Mrootint($n,3)) - $l; |
|
1954
|
16
|
|
|
|
|
82
|
return $sum; |
|
1955
|
|
|
|
|
|
|
} |
|
1956
|
|
|
|
|
|
|
|
|
1957
|
4
|
|
|
|
|
24
|
_powerful_count_recurse($n, $k, 1, 2*$k-1); |
|
1958
|
|
|
|
|
|
|
} |
|
1959
|
|
|
|
|
|
|
|
|
1960
|
|
|
|
|
|
|
sub nth_powerful { |
|
1961
|
1
|
|
|
1
|
0
|
5
|
my($n, $k) = @_; |
|
1962
|
1
|
|
|
|
|
6
|
validate_integer_nonneg($n); |
|
1963
|
1
|
50
|
|
|
|
17
|
if (defined $k) { validate_integer_nonneg($k); } else { $k = 2; } |
|
|
0
|
|
|
|
|
0
|
|
|
|
1
|
|
|
|
|
4
|
|
|
1964
|
|
|
|
|
|
|
|
|
1965
|
1
|
50
|
|
|
|
5
|
return undef if $n == 0; |
|
1966
|
1
|
50
|
33
|
|
|
8
|
return $n if $k <= 1 || $n <= 1; |
|
1967
|
1
|
50
|
|
|
|
5
|
return Mpowint(2,$k) if $n == 2; |
|
1968
|
1
|
50
|
|
|
|
5
|
return Mpowint(2,$k+1) if $n == 3; |
|
1969
|
|
|
|
|
|
|
|
|
1970
|
|
|
|
|
|
|
# For small n, we can generate k-powerful numbers rapidly. But without |
|
1971
|
|
|
|
|
|
|
# a reasonable upper limit, it's not clear how to effectively do it. |
|
1972
|
|
|
|
|
|
|
# E.g. nth_powerful(100,60) = 11972515182562019788602740026717047105681 |
|
1973
|
|
|
|
|
|
|
|
|
1974
|
1
|
|
|
|
|
5
|
my $lo = Mpowint(2, $k+1); |
|
1975
|
1
|
|
|
|
|
16
|
my $hi = ~0; |
|
1976
|
1
|
50
|
|
|
|
5
|
if ($k == 2) { |
|
1977
|
1
|
|
|
|
|
8
|
$lo = int( $n*$n/4.72303430688484 + 0.3 * $n**(5/3) ); |
|
1978
|
1
|
|
|
|
|
4
|
$hi = int( $n*$n/4.72303430688484 + 0.5 * $n**(5/3) ); # for n >= 170 |
|
1979
|
1
|
50
|
|
|
|
4
|
$hi = ~0 if $hi > ~0; |
|
1980
|
1
|
50
|
|
|
|
5
|
$lo = $hi >> 1 if $lo > $hi; |
|
1981
|
|
|
|
|
|
|
} |
|
1982
|
|
|
|
|
|
|
# We should use some power estimate here. |
|
1983
|
|
|
|
|
|
|
|
|
1984
|
|
|
|
|
|
|
# hi could be too low. |
|
1985
|
1
|
|
|
|
|
5
|
while (Math::Prime::Util::powerful_count($hi,$k) < $n) { |
|
1986
|
0
|
|
|
|
|
0
|
$lo = Madd1int($hi); |
|
1987
|
0
|
|
|
|
|
0
|
$hi = Mmulint($k, $hi); |
|
1988
|
|
|
|
|
|
|
} |
|
1989
|
|
|
|
|
|
|
|
|
1990
|
|
|
|
|
|
|
# Simple binary search |
|
1991
|
1
|
|
|
|
|
6
|
while ($lo < $hi) { |
|
1992
|
14
|
|
|
|
|
38
|
my $mid = $lo + (($hi-$lo) >> 1); |
|
1993
|
14
|
100
|
|
|
|
51
|
if (Math::Prime::Util::powerful_count($mid,$k) < $n) { $lo = $mid+1; } |
|
|
7
|
|
|
|
|
35
|
|
|
1994
|
7
|
|
|
|
|
35
|
else { $hi = $mid; } |
|
1995
|
|
|
|
|
|
|
} |
|
1996
|
1
|
|
|
|
|
25
|
$hi; |
|
1997
|
|
|
|
|
|
|
} |
|
1998
|
|
|
|
|
|
|
|
|
1999
|
|
|
|
|
|
|
sub _genpowerful { |
|
2000
|
|
|
|
|
|
|
# uncoverable subroutine |
|
2001
|
0
|
|
|
0
|
|
0
|
my($m, $r, $n, $k, $arr) = @_; |
|
2002
|
0
|
0
|
|
|
|
0
|
if ($r < $k) { push @$arr, $m; return; } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2003
|
0
|
|
|
|
|
0
|
my $rootdiv = Mrootint(Mdivint($n, $m), $r); |
|
2004
|
0
|
0
|
|
|
|
0
|
if ($r == $k) { |
|
2005
|
0
|
|
|
|
|
0
|
push @$arr, Mmulint($m, Mpowint($_,$k)) for 1 .. $rootdiv; |
|
2006
|
|
|
|
|
|
|
} else { |
|
2007
|
0
|
|
|
|
|
0
|
for my $i (1 .. $rootdiv) { |
|
2008
|
0
|
0
|
0
|
|
|
0
|
if (Mgcd($m,$i) == 1 && Mis_square_free($i)) { |
|
2009
|
0
|
|
|
|
|
0
|
_genpowerful(Mmulint($m, Mpowint($i,$r)), $r-1, $n, $k, $arr); |
|
2010
|
|
|
|
|
|
|
} |
|
2011
|
|
|
|
|
|
|
} |
|
2012
|
|
|
|
|
|
|
} |
|
2013
|
|
|
|
|
|
|
} |
|
2014
|
|
|
|
|
|
|
|
|
2015
|
|
|
|
|
|
|
sub _sumpowerful { |
|
2016
|
1368
|
|
|
1368
|
|
2939
|
my($m, $r, $n, $k) = @_; |
|
2017
|
1368
|
50
|
|
|
|
2761
|
return $m if $r < $k; |
|
2018
|
|
|
|
|
|
|
|
|
2019
|
1368
|
|
|
|
|
3890
|
my $rootdiv = Mrootint(Mdivint($n, $m), $r); |
|
2020
|
|
|
|
|
|
|
|
|
2021
|
1368
|
100
|
|
|
|
4275
|
return Mmulint($m, Mpowersum($rootdiv, $k)) if $r == $k; |
|
2022
|
|
|
|
|
|
|
|
|
2023
|
|
|
|
|
|
|
# Faster to generate the terms and add at the end |
|
2024
|
705
|
|
|
|
|
1140
|
my $R = $r-1; |
|
2025
|
705
|
|
|
|
|
1436
|
my @v = (_sumpowerful($m, $R, $n, $k)); |
|
2026
|
705
|
|
|
|
|
1808
|
for my $i (2 .. $rootdiv) { |
|
2027
|
17943
|
100
|
100
|
|
|
77226
|
next unless Mgcd($m,$i) == 1 && Mis_square_free($i); |
|
2028
|
9254
|
|
|
|
|
24626
|
my $M = Mmulint($m, Mpowint($i,$r)); |
|
2029
|
9254
|
100
|
|
|
|
38563
|
push @v, $R == $k ? Mmulint($M,Mpowersum(Mrootint(Mdivint($n,$M),$k),$k)) |
|
2030
|
|
|
|
|
|
|
: _sumpowerful($M, $R, $n, $k); |
|
2031
|
|
|
|
|
|
|
} |
|
2032
|
705
|
|
|
|
|
2555
|
Mvecsum(@v); |
|
2033
|
|
|
|
|
|
|
} |
|
2034
|
|
|
|
|
|
|
|
|
2035
|
|
|
|
|
|
|
sub _sumpowerful2 { |
|
2036
|
2
|
|
|
2
|
|
7
|
my($n) = @_; |
|
2037
|
2
|
|
|
|
|
7
|
my($lR,$lPS,@v) = (0,0); |
|
2038
|
|
|
|
|
|
|
Math::Prime::Util::forsquarefreeint(sub { |
|
2039
|
65233
|
|
|
65233
|
|
145337
|
my $M = Mpowint($_,3); |
|
2040
|
65233
|
|
|
|
|
168868
|
my $R = Msqrtint(Mdivint($n, $M)); |
|
2041
|
65233
|
100
|
|
|
|
131069
|
($lR,$lPS) = ($R,Mpowersum($R,2)) if $R != $lR; |
|
2042
|
65233
|
|
|
|
|
141154
|
push @v, Mmulint($M, $lPS); |
|
2043
|
2
|
|
|
|
|
51
|
},Mrootint($n,3)); |
|
2044
|
2
|
|
|
|
|
1256
|
Mvecsum(@v); |
|
2045
|
|
|
|
|
|
|
} |
|
2046
|
|
|
|
|
|
|
|
|
2047
|
|
|
|
|
|
|
sub sumpowerful { |
|
2048
|
12
|
|
|
12
|
0
|
25659
|
my($n, $k) = @_; |
|
2049
|
12
|
50
|
|
|
|
35
|
validate_integer($n); $n = 0 if $n < 0; |
|
|
12
|
|
|
|
|
36
|
|
|
2050
|
12
|
50
|
|
|
|
27
|
if (defined $k) { validate_integer_nonneg($k); } else { $k = 2; } |
|
|
12
|
|
|
|
|
34
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2051
|
|
|
|
|
|
|
|
|
2052
|
12
|
50
|
|
|
|
28
|
return $n if $n <= 1; |
|
2053
|
12
|
100
|
|
|
|
113
|
return Mrshiftint(Mmulint($n,Madd1int($n))) if $k <= 1; |
|
2054
|
|
|
|
|
|
|
|
|
2055
|
9
|
100
|
|
|
|
496
|
return _sumpowerful2($n) if $k == 2; |
|
2056
|
|
|
|
|
|
|
|
|
2057
|
|
|
|
|
|
|
# Alternate method for testing. |
|
2058
|
|
|
|
|
|
|
# my @a; _genpowerful(1, 2*$k-1, $n, $k, \@a); return Mvecsum(@a); |
|
2059
|
|
|
|
|
|
|
|
|
2060
|
7
|
|
|
|
|
975
|
return _sumpowerful(1, 2*$k-1, $n, $k); |
|
2061
|
|
|
|
|
|
|
} |
|
2062
|
|
|
|
|
|
|
|
|
2063
|
|
|
|
|
|
|
|
|
2064
|
|
|
|
|
|
|
# Generate k-powerful numbers. See Trizen, Feb 2020 and Feb 2024 |
|
2065
|
|
|
|
|
|
|
|
|
2066
|
|
|
|
|
|
|
sub _pcg { |
|
2067
|
16
|
|
|
16
|
|
55
|
my($lo, $hi, $k, $m, $r, $pn) = @_; |
|
2068
|
16
|
|
|
|
|
45
|
my($beg,$end) = (1, Mrootint(Mdivint($hi,$m), $r)); |
|
2069
|
|
|
|
|
|
|
|
|
2070
|
16
|
100
|
|
|
|
97
|
if ($r <= $k) { |
|
2071
|
15
|
100
|
|
|
|
46
|
if ($lo > $m) { |
|
2072
|
14
|
|
|
|
|
65
|
my $lom = Mcdivint($lo,$m); |
|
2073
|
14
|
100
|
|
|
|
34
|
if ( ($lom >> $r) == 0) { |
|
2074
|
3
|
|
|
|
|
6
|
$beg = 2; |
|
2075
|
|
|
|
|
|
|
} else { |
|
2076
|
11
|
|
|
|
|
31
|
$beg = Mrootint($lom,$r); |
|
2077
|
11
|
100
|
|
|
|
38
|
$beg++ if Mpowint($beg,$r) != $lom; |
|
2078
|
|
|
|
|
|
|
} |
|
2079
|
|
|
|
|
|
|
} |
|
2080
|
15
|
|
|
|
|
61
|
push @$pn, $m * Mpowint($_,$r) for ($beg .. $end); |
|
2081
|
15
|
|
|
|
|
61
|
return; |
|
2082
|
|
|
|
|
|
|
} |
|
2083
|
|
|
|
|
|
|
|
|
2084
|
1
|
|
|
|
|
6
|
for my $v ($beg .. $end) { |
|
2085
|
22
|
100
|
66
|
|
|
96
|
_pcg($lo, $hi, $k, $m * Mpowint($v,$r), $r-1, $pn) |
|
2086
|
|
|
|
|
|
|
if Mgcd($m,$v) == 1 && Mis_square_free($v); |
|
2087
|
|
|
|
|
|
|
} |
|
2088
|
|
|
|
|
|
|
} |
|
2089
|
|
|
|
|
|
|
sub powerful_numbers { |
|
2090
|
1
|
|
|
1
|
0
|
14
|
my($lo, $hi, $k) = @_; |
|
2091
|
1
|
50
|
|
|
|
6
|
if (defined $k) { validate_integer_nonneg($k); } else { $k = 2; } |
|
|
0
|
|
|
|
|
0
|
|
|
|
1
|
|
|
|
|
3
|
|
|
2092
|
1
|
50
|
|
|
|
4
|
if (defined $hi) { |
|
2093
|
1
|
|
|
|
|
5
|
validate_integer_nonneg($lo); |
|
2094
|
|
|
|
|
|
|
} else { |
|
2095
|
0
|
|
|
|
|
0
|
($lo, $hi) = (1, $lo); |
|
2096
|
|
|
|
|
|
|
} |
|
2097
|
1
|
|
|
|
|
5
|
validate_integer_nonneg($hi); |
|
2098
|
1
|
50
|
|
|
|
6
|
return [] if $hi < $lo; |
|
2099
|
1
|
50
|
|
|
|
5
|
return [$lo .. $hi] if $k <= 1; |
|
2100
|
|
|
|
|
|
|
|
|
2101
|
1
|
|
|
|
|
3
|
my $pn = []; |
|
2102
|
1
|
|
|
|
|
18
|
_pcg($lo, $hi, $k, 1, 2*$k-1, $pn); |
|
2103
|
1
|
|
|
|
|
5
|
Mvecsorti($pn); |
|
2104
|
|
|
|
|
|
|
} |
|
2105
|
|
|
|
|
|
|
|
|
2106
|
|
|
|
|
|
|
sub is_powerfree { |
|
2107
|
8
|
|
|
8
|
0
|
979
|
my($n, $k) = @_; |
|
2108
|
8
|
|
|
|
|
18
|
validate_integer_abs($n); |
|
2109
|
8
|
100
|
|
|
|
15
|
if (defined $k) { validate_integer_nonneg($k); } |
|
|
6
|
|
|
|
|
17
|
|
|
2110
|
2
|
|
|
|
|
47
|
else { $k = 2; } |
|
2111
|
|
|
|
|
|
|
|
|
2112
|
8
|
0
|
33
|
|
|
23
|
return (($n == 1) ? 1 : 0) if $k < 2 || $n <= 1; |
|
|
|
50
|
|
|
|
|
|
|
2113
|
|
|
|
|
|
|
#return 1 if $n < Mpowint(2,$k); |
|
2114
|
8
|
50
|
|
|
|
21
|
return 1 if $n < 4; |
|
2115
|
|
|
|
|
|
|
|
|
2116
|
8
|
50
|
|
|
|
17
|
if ($k == 2) { |
|
|
|
0
|
|
|
|
|
|
|
2117
|
8
|
100
|
100
|
|
|
43
|
return 0 if !($n % 4) || !($n % 9) || !($n % 25); |
|
|
|
|
66
|
|
|
|
|
|
2118
|
5
|
50
|
|
|
|
12
|
return 1 if $n < 49; # 7^2 |
|
2119
|
|
|
|
|
|
|
} elsif ($k == 3) { |
|
2120
|
0
|
0
|
0
|
|
|
0
|
return 0 if !($n % 8) || !($n % 27) || !($n % 125); |
|
|
|
|
0
|
|
|
|
|
|
2121
|
0
|
0
|
|
|
|
0
|
return 1 if $n < 343; # 7^3 |
|
2122
|
|
|
|
|
|
|
} |
|
2123
|
|
|
|
|
|
|
|
|
2124
|
|
|
|
|
|
|
# return (Mvecall(sub { $_->[1] < $k }, Mfactor_exp($n))) ? 1 : 0; |
|
2125
|
5
|
|
|
|
|
14
|
for my $pe (Mfactor_exp($n)) { |
|
2126
|
14
|
50
|
|
|
|
22
|
return 0 if $pe->[1] >= $k; |
|
2127
|
|
|
|
|
|
|
} |
|
2128
|
5
|
|
|
|
|
16
|
1; |
|
2129
|
|
|
|
|
|
|
} |
|
2130
|
|
|
|
|
|
|
|
|
2131
|
|
|
|
|
|
|
sub powerfree_count { |
|
2132
|
367
|
|
|
367
|
0
|
652
|
my($n, $k) = @_; |
|
2133
|
367
|
|
|
|
|
992
|
validate_integer_abs($n); |
|
2134
|
367
|
100
|
|
|
|
771
|
if (defined $k) { validate_integer_nonneg($k); } |
|
|
350
|
|
|
|
|
615
|
|
|
2135
|
17
|
|
|
|
|
41
|
else { $k = 2; } |
|
2136
|
|
|
|
|
|
|
|
|
2137
|
367
|
50
|
66
|
|
|
1301
|
return (($n >= 1) ? 1 : 0) if $k < 2 || $n <= 1; |
|
|
|
100
|
|
|
|
|
|
|
2138
|
|
|
|
|
|
|
|
|
2139
|
351
|
|
|
|
|
814
|
my $count = 0; |
|
2140
|
351
|
|
|
|
|
808
|
my $nk = Mrootint($n, $k); |
|
2141
|
|
|
|
|
|
|
|
|
2142
|
|
|
|
|
|
|
# If we can do everything native, do that. |
|
2143
|
351
|
100
|
100
|
|
|
5389
|
if ($n < SINTMAX && $nk < 20000) { |
|
|
|
100
|
66
|
|
|
|
|
|
2144
|
77
|
|
|
77
|
|
1215
|
use integer; |
|
|
77
|
|
|
|
|
219
|
|
|
|
77
|
|
|
|
|
834
|
|
|
2145
|
349
|
|
|
|
|
1010
|
my @mu = Mmoebius(0, $nk); |
|
2146
|
349
|
|
|
|
|
857
|
foreach my $i (2 .. $nk) { |
|
2147
|
1367
|
100
|
|
|
|
3034
|
$count += $mu[$i] * $n/($i**$k) if $mu[$i]; |
|
2148
|
|
|
|
|
|
|
} |
|
2149
|
349
|
|
|
|
|
924
|
return Maddint($count,$n); |
|
2150
|
|
|
|
|
|
|
} elsif ($n < SINTMAX && $nk < 1e8) { |
|
2151
|
|
|
|
|
|
|
# Split out the trailing n/i^k = 1, saves memory and time if large enough. |
|
2152
|
77
|
|
|
77
|
|
12122
|
use integer; |
|
|
77
|
|
|
|
|
215
|
|
|
|
77
|
|
|
|
|
631
|
|
|
2153
|
1
|
|
|
|
|
4
|
my $L1 = Mrootint($n/2,$k); |
|
2154
|
1
|
|
|
|
|
5
|
my @mu = Mmoebius(0, $L1); |
|
2155
|
1
|
|
|
|
|
65
|
foreach my $i (2 .. $L1) { |
|
2156
|
14141
|
100
|
|
|
|
30470
|
$count += $mu[$i] * $n/($i**$k) if $mu[$i]; |
|
2157
|
|
|
|
|
|
|
} |
|
2158
|
|
|
|
|
|
|
#@mu = Mmoebius($L1+1, $nk); my $c1 = 0; $c1 += $_ for @mu; |
|
2159
|
1
|
|
|
|
|
11
|
my $c1 = Math::Prime::Util::mertens($nk) - Math::Prime::Util::mertens($L1); |
|
2160
|
1
|
|
|
|
|
131
|
return Mvecsum($count,$c1,$n); |
|
2161
|
|
|
|
|
|
|
} |
|
2162
|
|
|
|
|
|
|
|
|
2163
|
|
|
|
|
|
|
# Simple way. All the bigint math kills performance. |
|
2164
|
|
|
|
|
|
|
# Math::Prime::Util::forsquarefree( |
|
2165
|
|
|
|
|
|
|
# sub { |
|
2166
|
|
|
|
|
|
|
# my $t = Mdivint($n, Mpowint($_, $k)); |
|
2167
|
|
|
|
|
|
|
# $count = (scalar(@_) & 1) ? Msubint($count,$t) : Maddint($count,$t); |
|
2168
|
|
|
|
|
|
|
# }, |
|
2169
|
|
|
|
|
|
|
# 2, $nk |
|
2170
|
|
|
|
|
|
|
# ); |
|
2171
|
|
|
|
|
|
|
|
|
2172
|
|
|
|
|
|
|
# Optimization 1: pull out all the ranges at the end with small constant |
|
2173
|
|
|
|
|
|
|
# multiplications. |
|
2174
|
|
|
|
|
|
|
# Optimization 2: Use GMP basic arithmetic functions if possible, saving |
|
2175
|
|
|
|
|
|
|
# all the bigint object overhead. Can be 10x faster. |
|
2176
|
|
|
|
|
|
|
|
|
2177
|
1
|
|
|
|
|
519
|
my $A = Msqrtint($nk); |
|
2178
|
1
|
|
|
|
|
5
|
my @L = (0, $nk, map { Mrootint(Mdivint($n,$_),$k) } 2..$A); |
|
|
3
|
|
|
|
|
15
|
|
|
2179
|
1
|
|
|
|
|
3
|
my @C; |
|
2180
|
|
|
|
|
|
|
|
|
2181
|
|
|
|
|
|
|
Math::Prime::Util::forsquarefree( |
|
2182
|
|
|
|
|
|
|
sub { |
|
2183
|
12
|
100
|
|
12
|
|
74
|
$count = (scalar(@_) & 1) |
|
2184
|
|
|
|
|
|
|
? Ssubint($count, Sdivint($n, Spowint($_, $k))) |
|
2185
|
|
|
|
|
|
|
: Saddint($count, Sdivint($n, Spowint($_, $k))); |
|
2186
|
|
|
|
|
|
|
}, |
|
2187
|
1
|
|
|
|
|
33
|
2, $L[$A] |
|
2188
|
|
|
|
|
|
|
); |
|
2189
|
1
|
|
|
|
|
30
|
for my $i (2 .. $A) { |
|
2190
|
3
|
|
|
|
|
14
|
my($c, $lo, $hi) = (0, $L[$i], $L[$i-1]); |
|
2191
|
3
|
50
|
|
|
|
12
|
if ($i < 15) { |
|
2192
|
3
|
|
|
|
|
12
|
$c = Math::Prime::Util::mertens($hi) - Math::Prime::Util::mertens($lo); |
|
2193
|
|
|
|
|
|
|
} else { |
|
2194
|
0
|
|
|
|
|
0
|
$c += $_ for Mmoebius( Madd1int($lo), $hi ); |
|
2195
|
|
|
|
|
|
|
} |
|
2196
|
3
|
|
|
|
|
11
|
push @C, $c * ($i-1); |
|
2197
|
3
|
50
|
|
|
|
13
|
@C = (Mvecsum(@C)) if scalar(@C) > 100000; # Save/restrict memory. |
|
2198
|
|
|
|
|
|
|
} |
|
2199
|
1
|
|
|
|
|
9
|
my $ctot = Mvecsum(@C); # Can typically be done in native math. |
|
2200
|
1
|
|
|
|
|
6
|
Mvecsum($count, $n, $ctot); |
|
2201
|
|
|
|
|
|
|
} |
|
2202
|
|
|
|
|
|
|
|
|
2203
|
|
|
|
|
|
|
sub nth_powerfree { |
|
2204
|
1
|
|
|
1
|
0
|
3
|
my($n, $k) = @_; |
|
2205
|
1
|
|
|
|
|
5
|
validate_integer_nonneg($n); |
|
2206
|
1
|
50
|
|
|
|
10
|
if (defined $k) { validate_integer_nonneg($k); } |
|
|
0
|
|
|
|
|
0
|
|
|
2207
|
1
|
|
|
|
|
2
|
else { $k = 2; } |
|
2208
|
|
|
|
|
|
|
|
|
2209
|
1
|
50
|
33
|
|
|
7
|
return undef if $n == 0 || $k < 2; |
|
2210
|
1
|
50
|
|
|
|
4
|
return $n if $n < 4; |
|
2211
|
|
|
|
|
|
|
|
|
2212
|
|
|
|
|
|
|
# 1. zm is the zeta multiplier (float), qk is the expected value (integer). |
|
2213
|
1
|
|
|
|
|
1
|
my($zm, $qk); |
|
2214
|
1
|
50
|
|
|
|
3
|
if ($n <= 2**52) { |
|
2215
|
1
|
50
|
|
|
|
4
|
$zm = ($k == 2) ? 1.644934066848226 : 1.0 + RiemannZeta($k); |
|
2216
|
|
|
|
|
|
|
} else { |
|
2217
|
0
|
0
|
|
|
|
0
|
do { require Math::BigFloat; Math::BigFloat->import(); } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2218
|
|
|
|
|
|
|
if !defined $Math::BigFloat::VERSION; |
|
2219
|
0
|
|
|
|
|
0
|
require Math::Prime::Util::ZetaBigFloat; |
|
2220
|
0
|
|
|
|
|
0
|
my $acc = length("$n")+10; |
|
2221
|
0
|
|
|
|
|
0
|
my $bk = Math::BigFloat->new($k); $bk->accuracy($acc); |
|
|
0
|
|
|
|
|
0
|
|
|
2222
|
0
|
|
|
|
|
0
|
$zm = Math::Prime::Util::ZetaBigFloat::RiemannZeta($bk)->badd(1)->numify; |
|
2223
|
|
|
|
|
|
|
} |
|
2224
|
1
|
|
|
|
|
5
|
my $verbose = getconfig()->{'verbose'}; |
|
2225
|
|
|
|
|
|
|
|
|
2226
|
1
|
|
|
|
|
9
|
$qk = Mtoint($zm * "$n"); |
|
2227
|
1
|
50
|
|
|
|
4
|
print "nth_powerfree: zm $zm qk $qk\n" if $verbose; |
|
2228
|
|
|
|
|
|
|
|
|
2229
|
1
|
|
|
|
|
2
|
my($count, $diff); |
|
2230
|
|
|
|
|
|
|
# In practice this converges very rapidly, usually needing only one iteration. |
|
2231
|
1
|
|
|
|
|
3
|
for (1 .. 10) { |
|
2232
|
|
|
|
|
|
|
# 2. Get the actual count at qk and the difference from our goal. |
|
2233
|
1
|
|
|
|
|
3
|
$count = Math::Prime::Util::powerfree_count($qk,$k); |
|
2234
|
1
|
50
|
|
|
|
5
|
$diff = ($count >= $n) ? $count-$n : $n-$count; |
|
2235
|
1
|
50
|
|
|
|
4
|
print "nth_powerfree: iter $_, count $count diff $diff\n" if $verbose; |
|
2236
|
1
|
50
|
|
|
|
14
|
last if $diff <= 300; # Threshold could be improved. |
|
2237
|
|
|
|
|
|
|
|
|
2238
|
|
|
|
|
|
|
# 3. If not close, update the estimate using the expected density zm. |
|
2239
|
0
|
|
|
|
|
0
|
my $delta = Mtoint($zm * "$diff"); |
|
2240
|
0
|
0
|
|
|
|
0
|
$qk = $count > $n ? Msubint($qk,$delta) : Maddint($qk,$delta); |
|
2241
|
|
|
|
|
|
|
} |
|
2242
|
1
|
50
|
|
|
|
20
|
print "nth_powerfree: $qk, moving down to a powerfree number\n" if $verbose; |
|
2243
|
|
|
|
|
|
|
|
|
2244
|
|
|
|
|
|
|
# 4. Make sure we're on a powerfree number. |
|
2245
|
1
|
|
|
|
|
4
|
$qk-- while !Math::Prime::Util::is_powerfree($qk,$k); |
|
2246
|
1
|
50
|
|
|
|
3
|
print "nth_powerfree: $qk, need to move ",abs($n-$count)," steps\n" if $verbose; |
|
2247
|
|
|
|
|
|
|
|
|
2248
|
|
|
|
|
|
|
# 5. Walk forward or backward to next/prev powerfree number. |
|
2249
|
1
|
50
|
|
|
|
12
|
my $adder = ($count < $n) ? 1 : -1; |
|
2250
|
1
|
|
|
|
|
4
|
while ($count != $n) { |
|
2251
|
3
|
|
|
|
|
5
|
do { $qk += $adder; } while !Math::Prime::Util::is_powerfree($qk,$k); |
|
|
4
|
|
|
|
|
9
|
|
|
2252
|
3
|
|
|
|
|
7
|
$count += $adder; |
|
2253
|
|
|
|
|
|
|
} |
|
2254
|
1
|
|
|
|
|
8
|
$qk; |
|
2255
|
|
|
|
|
|
|
} |
|
2256
|
|
|
|
|
|
|
|
|
2257
|
|
|
|
|
|
|
sub powerfree_sum { |
|
2258
|
8
|
|
|
8
|
0
|
33
|
my($n, $k) = @_; |
|
2259
|
8
|
|
|
|
|
25
|
validate_integer_nonneg($n); |
|
2260
|
8
|
50
|
|
|
|
16
|
if (defined $k) { validate_integer_nonneg($k); } |
|
|
8
|
|
|
|
|
16
|
|
|
2261
|
0
|
|
|
|
|
0
|
else { $k = 2; } |
|
2262
|
|
|
|
|
|
|
|
|
2263
|
8
|
50
|
66
|
|
|
33
|
return (($n >= 1) ? 1 : 0) if $k < 2 || $n <= 1; |
|
|
|
100
|
|
|
|
|
|
|
2264
|
|
|
|
|
|
|
|
|
2265
|
7
|
|
|
|
|
13
|
my $sum = 0; |
|
2266
|
7
|
|
|
|
|
12
|
my($ik, $nik, $T); |
|
2267
|
|
|
|
|
|
|
Math::Prime::Util::forsquarefree( |
|
2268
|
|
|
|
|
|
|
sub { |
|
2269
|
76
|
|
|
76
|
|
184
|
$ik = Mpowint($_, $k); |
|
2270
|
76
|
|
|
|
|
167
|
$nik = Mdivint($n, $ik); |
|
2271
|
76
|
|
|
|
|
176
|
$T = Mrshiftint(Mmulint($nik, Madd1int($nik))); |
|
2272
|
76
|
100
|
|
|
|
197
|
$sum = (scalar(@_) & 1) ? Msubint($sum, Mmulint($ik,$T)) : |
|
2273
|
|
|
|
|
|
|
Maddint($sum, Mmulint($ik,$T)); |
|
2274
|
|
|
|
|
|
|
}, |
|
2275
|
7
|
|
|
|
|
62
|
Mrootint($n, $k) |
|
2276
|
|
|
|
|
|
|
); |
|
2277
|
7
|
|
|
|
|
103
|
$sum; |
|
2278
|
|
|
|
|
|
|
} |
|
2279
|
|
|
|
|
|
|
|
|
2280
|
|
|
|
|
|
|
sub powerfree_part { |
|
2281
|
1003
|
|
|
1003
|
0
|
32081
|
my($n, $k) = @_; |
|
2282
|
1003
|
50
|
|
|
|
1528
|
my $negmul = ($n < 0) ? -1 : 1; |
|
2283
|
1003
|
|
|
|
|
1659
|
validate_integer_abs($n); |
|
2284
|
1003
|
100
|
|
|
|
2960
|
if (defined $k) { validate_integer_nonneg($k); } |
|
|
1001
|
|
|
|
|
1190
|
|
|
2285
|
2
|
|
|
|
|
3
|
else { $k = 2; } |
|
2286
|
|
|
|
|
|
|
|
|
2287
|
1003
|
50
|
|
|
|
1488
|
return $negmul if $n == 1; |
|
2288
|
1003
|
100
|
66
|
|
|
4087
|
return 0 if $k < 2 || $n == 0; |
|
2289
|
|
|
|
|
|
|
|
|
2290
|
|
|
|
|
|
|
#return Mvecprod(map { Mpowint($_->[0], $_->[1] % $k) } Mfactor_exp($n)); |
|
2291
|
|
|
|
|
|
|
|
|
2292
|
|
|
|
|
|
|
# Rather than build with k-free section, we will remove excess powers |
|
2293
|
9
|
|
|
|
|
1201
|
my $P = $n; |
|
2294
|
9
|
|
|
|
|
53
|
for my $pe (Mfactor_exp($n)) { |
|
2295
|
83
|
100
|
|
|
|
547
|
$P = Mdivint($P, Mpowint($pe->[0], $pe->[1] - ($pe->[1] % $k))) |
|
2296
|
|
|
|
|
|
|
if $pe->[1] >= $k; |
|
2297
|
|
|
|
|
|
|
} |
|
2298
|
9
|
50
|
|
|
|
64
|
$P = Mnegint($P) unless $negmul == 1; |
|
2299
|
9
|
|
|
|
|
84
|
$P; |
|
2300
|
|
|
|
|
|
|
} |
|
2301
|
|
|
|
|
|
|
|
|
2302
|
|
|
|
|
|
|
sub _T { |
|
2303
|
379
|
|
|
379
|
|
627
|
my($n) = @_; |
|
2304
|
379
|
100
|
|
|
|
1043
|
return $n < 65536 ? ($n*($n+1))>>1 : Mrshiftint(Mmulint($n, Madd1int($n))); |
|
2305
|
|
|
|
|
|
|
} |
|
2306
|
|
|
|
|
|
|
sub _fprod { |
|
2307
|
376
|
|
|
376
|
|
580
|
my($n,$k) = @_; |
|
2308
|
376
|
|
|
|
|
911
|
Mvecprod(map { 1 - Mpowint($_->[0], $k) } Mfactor_exp($n)); |
|
|
704
|
|
|
|
|
1321
|
|
|
2309
|
|
|
|
|
|
|
} |
|
2310
|
|
|
|
|
|
|
|
|
2311
|
|
|
|
|
|
|
sub powerfree_part_sum { |
|
2312
|
3
|
|
|
3
|
0
|
10
|
my($n, $k) = @_; |
|
2313
|
3
|
|
|
|
|
15
|
validate_integer_abs($n); |
|
2314
|
3
|
100
|
|
|
|
11
|
if (defined $k) { validate_integer_nonneg($k); } |
|
|
2
|
|
|
|
|
7
|
|
|
2315
|
1
|
|
|
|
|
3
|
else { $k = 2; } |
|
2316
|
|
|
|
|
|
|
|
|
2317
|
3
|
0
|
33
|
|
|
31
|
return (($n >= 1) ? 1 : 0) if $k < 2 || $n <= 1; |
|
|
|
50
|
|
|
|
|
|
|
2318
|
|
|
|
|
|
|
|
|
2319
|
|
|
|
|
|
|
Mvecsum( _T($n), |
|
2320
|
3
|
|
|
|
|
12
|
map { Mmulint(_fprod($_,$k), _T(Mdivint($n, Mpowint($_, $k)))) } |
|
|
376
|
|
|
|
|
650
|
|
|
2321
|
|
|
|
|
|
|
2 .. Mrootint($n,$k) |
|
2322
|
|
|
|
|
|
|
); |
|
2323
|
|
|
|
|
|
|
} |
|
2324
|
|
|
|
|
|
|
|
|
2325
|
|
|
|
|
|
|
sub squarefree_kernel { |
|
2326
|
2
|
|
|
2
|
0
|
6
|
my($n) = @_; |
|
2327
|
2
|
|
|
|
|
7
|
validate_integer($n); |
|
2328
|
2
|
50
|
|
|
|
5
|
return Mnegint(Mlcm(Mfactor(Mnegint($n)))) if $n < 0; |
|
2329
|
2
|
|
|
|
|
6
|
Mlcm(Mfactor($n)); |
|
2330
|
|
|
|
|
|
|
} |
|
2331
|
|
|
|
|
|
|
|
|
2332
|
|
|
|
|
|
|
sub is_perfect_power { |
|
2333
|
3
|
|
|
3
|
0
|
1156
|
my($n) = @_; |
|
2334
|
3
|
|
|
|
|
27
|
validate_integer($n); |
|
2335
|
3
|
50
|
|
|
|
10
|
if ($n < 0) { |
|
2336
|
0
|
|
|
|
|
0
|
my $res = Mis_power(Mnegint($n)); |
|
2337
|
0
|
0
|
0
|
|
|
0
|
return ($n == -1 || ($res > 2 && (($res & ($res-1)) != 0))) ? 1 : 0; |
|
2338
|
|
|
|
|
|
|
} |
|
2339
|
3
|
50
|
|
|
|
384
|
return (1,1,0,0,1,0,0,0,1,1)[$n] if $n <= 9; |
|
2340
|
3
|
100
|
|
|
|
275
|
return (Mis_power($n) > 1) ? 1 : 0; |
|
2341
|
|
|
|
|
|
|
} |
|
2342
|
|
|
|
|
|
|
|
|
2343
|
|
|
|
|
|
|
sub _perfect_power_count { |
|
2344
|
8
|
|
|
8
|
|
21
|
my($n) = @_; |
|
2345
|
8
|
50
|
|
|
|
32
|
return 0+($n>=1)+($n>=4) if $n < 8; |
|
2346
|
|
|
|
|
|
|
#return reftyped($_[0], Math::Prime::Util::GMP::perfect_power_count($n)) |
|
2347
|
|
|
|
|
|
|
# if $Math::Prime::Util::_GMPfunc{"perfect_power_count"}; |
|
2348
|
8
|
|
|
|
|
666
|
my @T = (1); |
|
2349
|
|
|
|
|
|
|
|
|
2350
|
8
|
|
|
|
|
35
|
my $log2n = Mlogint($n,2); |
|
2351
|
8
|
|
|
|
|
27
|
for my $k (2 .. $log2n) { |
|
2352
|
394
|
|
|
|
|
1145
|
my $m = Mmoebius($k); |
|
2353
|
394
|
100
|
|
|
|
954
|
next if $m == 0; |
|
2354
|
247
|
|
|
|
|
808
|
push @T, Mmulint(-$m, Msub1int(Mrootint($n,$k))); |
|
2355
|
|
|
|
|
|
|
} |
|
2356
|
8
|
|
|
|
|
92
|
Mvecsum(@T); |
|
2357
|
|
|
|
|
|
|
} |
|
2358
|
|
|
|
|
|
|
sub perfect_power_count { |
|
2359
|
2
|
|
|
2
|
0
|
10
|
my($lo,$hi) = @_; |
|
2360
|
2
|
100
|
|
|
|
11
|
if (defined $hi) { validate_integer_nonneg($lo); } |
|
|
1
|
|
|
|
|
5
|
|
|
2361
|
1
|
|
|
|
|
4
|
else { ($lo,$hi) = (1, $lo); } |
|
2362
|
2
|
|
|
|
|
11
|
validate_integer_nonneg($hi); |
|
2363
|
2
|
50
|
33
|
|
|
14
|
return 0 if $hi < $lo || $hi == 0; |
|
2364
|
2
|
100
|
|
|
|
10
|
return _perfect_power_count($hi) - (($lo <= 1) ? 0 : _perfect_power_count($lo-1)); |
|
2365
|
|
|
|
|
|
|
} |
|
2366
|
|
|
|
|
|
|
|
|
2367
|
|
|
|
|
|
|
sub perfect_power_count_approx { |
|
2368
|
1
|
|
|
1
|
0
|
4
|
my($n) = @_; |
|
2369
|
1
|
|
|
|
|
4
|
validate_integer_nonneg($n); |
|
2370
|
1
|
|
|
|
|
4
|
_perfect_power_count($n); |
|
2371
|
|
|
|
|
|
|
} |
|
2372
|
|
|
|
|
|
|
sub perfect_power_count_lower { |
|
2373
|
1
|
|
|
1
|
0
|
4
|
my($n) = @_; |
|
2374
|
1
|
|
|
|
|
4
|
validate_integer_nonneg($n); |
|
2375
|
1
|
|
|
|
|
4
|
_perfect_power_count($n); |
|
2376
|
|
|
|
|
|
|
} |
|
2377
|
|
|
|
|
|
|
sub perfect_power_count_upper { |
|
2378
|
1
|
|
|
1
|
0
|
4
|
my($n) = @_; |
|
2379
|
1
|
|
|
|
|
4
|
validate_integer_nonneg($n); |
|
2380
|
1
|
|
|
|
|
4
|
_perfect_power_count($n); |
|
2381
|
|
|
|
|
|
|
} |
|
2382
|
|
|
|
|
|
|
|
|
2383
|
|
|
|
|
|
|
sub _next_perfect_power { |
|
2384
|
5
|
|
|
5
|
|
153
|
my($n, $only_oddpowers) = @_; |
|
2385
|
5
|
50
|
|
|
|
16
|
croak "_npp must have positive n" if $n < 0; |
|
2386
|
|
|
|
|
|
|
|
|
2387
|
5
|
50
|
|
|
|
239
|
return 1 if $n == 0; |
|
2388
|
5
|
0
|
|
|
|
245
|
return ($only_oddpowers ? 8 : 4) if $n == 1; |
|
|
|
50
|
|
|
|
|
|
|
2389
|
|
|
|
|
|
|
|
|
2390
|
5
|
|
|
|
|
253
|
my $log2n = Mlogint($n,2); |
|
2391
|
5
|
100
|
|
|
|
147
|
my $kinit = $only_oddpowers ? 3 : 2; |
|
2392
|
5
|
100
|
|
|
|
15
|
my $kinc = $only_oddpowers ? 2 : 1; |
|
2393
|
|
|
|
|
|
|
|
|
2394
|
5
|
|
|
|
|
68
|
my $best = Mpowint(Madd1int(Mrootint($n,$kinit)),$kinit); |
|
2395
|
5
|
|
|
|
|
425
|
for (my $k = $kinit+$kinc; $k <= 1+$log2n; $k += $kinc) { |
|
2396
|
177
|
|
|
|
|
9811
|
my $r = Mrootint($n,$k); |
|
2397
|
177
|
|
|
|
|
12291
|
my $c = Mpowint(Madd1int($r),$k); |
|
2398
|
177
|
50
|
33
|
|
|
26358
|
$best = addint($c,0) if $c < $best && $c > $n; # OLD_PERL_VERSION |
|
2399
|
|
|
|
|
|
|
} |
|
2400
|
5
|
|
|
|
|
224
|
$best; |
|
2401
|
|
|
|
|
|
|
} |
|
2402
|
|
|
|
|
|
|
sub _prev_perfect_power { |
|
2403
|
8
|
|
|
8
|
|
155
|
my($n, $only_oddpowers) = @_; |
|
2404
|
8
|
50
|
|
|
|
34
|
croak "_ppp must have positive n" if $n < 0; |
|
2405
|
|
|
|
|
|
|
|
|
2406
|
8
|
50
|
|
|
|
1577
|
return 0 + ($n>1) - ($n==0) if $n <= 4; |
|
2407
|
8
|
0
|
|
|
|
1505
|
return $only_oddpowers ? 1 : 4 if $n <= 8; |
|
|
|
50
|
|
|
|
|
|
|
2408
|
|
|
|
|
|
|
|
|
2409
|
8
|
|
|
|
|
1483
|
my $log2n = Mlogint($n,2); |
|
2410
|
8
|
100
|
|
|
|
32
|
my $kinit = $only_oddpowers ? 3 : 2; |
|
2411
|
8
|
100
|
|
|
|
23
|
my $kinc = $only_oddpowers ? 2 : 1; |
|
2412
|
|
|
|
|
|
|
|
|
2413
|
8
|
|
|
|
|
16
|
my $best = 8; |
|
2414
|
8
|
|
|
|
|
28
|
for (my $k = $kinit; $k <= $log2n; $k += $kinc) { |
|
2415
|
425
|
|
|
|
|
54603
|
my $r = Mrootint($n,$k); |
|
2416
|
425
|
50
|
|
|
|
1419
|
if ($r > 1) { |
|
2417
|
425
|
|
|
|
|
4887
|
my $c = Mpowint($r,$k); |
|
2418
|
425
|
100
|
|
|
|
11092
|
$c = Mpowint(Msub1int($r),$k) if $c >= $n; |
|
2419
|
425
|
100
|
66
|
|
|
71660
|
$best = addint($c,0) if $c > $best && $c < $n; # OLD_PERL_VERSION |
|
2420
|
|
|
|
|
|
|
} |
|
2421
|
|
|
|
|
|
|
} |
|
2422
|
8
|
|
|
|
|
422
|
$best; |
|
2423
|
|
|
|
|
|
|
} |
|
2424
|
|
|
|
|
|
|
|
|
2425
|
|
|
|
|
|
|
sub next_perfect_power { |
|
2426
|
4
|
|
|
4
|
0
|
361
|
my($n) = @_; |
|
2427
|
4
|
|
|
|
|
30
|
validate_integer($n); |
|
2428
|
|
|
|
|
|
|
|
|
2429
|
4
|
50
|
66
|
|
|
24
|
return 0 + ($n>=0) - ($n<-1) if $n < 1 && $n >= -4; |
|
2430
|
|
|
|
|
|
|
|
|
2431
|
4
|
100
|
|
|
|
466
|
return Mnegint( _prev_perfect_power( Mnegint($n), 1 ) ) if $n < 0; |
|
2432
|
3
|
|
|
|
|
25
|
_next_perfect_power($n, 0); |
|
2433
|
|
|
|
|
|
|
} |
|
2434
|
|
|
|
|
|
|
|
|
2435
|
|
|
|
|
|
|
sub prev_perfect_power { |
|
2436
|
9
|
|
|
9
|
0
|
956
|
my($n) = @_; |
|
2437
|
9
|
|
|
|
|
67
|
validate_integer($n); |
|
2438
|
|
|
|
|
|
|
|
|
2439
|
9
|
50
|
66
|
|
|
307
|
return 0 + ($n>1) - ($n==0) if $n <= 4 && $n >= 0; |
|
2440
|
|
|
|
|
|
|
|
|
2441
|
9
|
100
|
|
|
|
2957
|
return Mnegint( _next_perfect_power( Mnegint($n), 1 ) ) if $n < 0; |
|
2442
|
7
|
|
|
|
|
1368
|
_prev_perfect_power($n, 0); |
|
2443
|
|
|
|
|
|
|
} |
|
2444
|
|
|
|
|
|
|
|
|
2445
|
|
|
|
|
|
|
|
|
2446
|
|
|
|
|
|
|
sub nth_perfect_power_approx { |
|
2447
|
3
|
|
|
3
|
0
|
11
|
my($n) = @_; |
|
2448
|
3
|
|
|
|
|
10
|
validate_integer_nonneg($n); |
|
2449
|
3
|
50
|
|
|
|
19
|
return (undef,1,4,8,9,16,25,27)[$n] if $n < 8; |
|
2450
|
|
|
|
|
|
|
|
|
2451
|
|
|
|
|
|
|
# See https://www.emis.de/journals/JIS/VOL15/Jakimczuk/jak29.pdf |
|
2452
|
|
|
|
|
|
|
# See https://www.researchgate.net/publication/268998744_Sums_of_perfect_powers |
|
2453
|
|
|
|
|
|
|
|
|
2454
|
|
|
|
|
|
|
# This is more accurate and about 200x faster than using BigFloat. |
|
2455
|
3
|
50
|
66
|
|
|
14
|
if ($n > 2**32 && $Math::Prime::Util::_GMPfunc{"powreal"}) { |
|
2456
|
0
|
|
|
|
|
0
|
*Gaddreal = \&Math::Prime::Util::GMP::addreal; |
|
2457
|
0
|
|
|
|
|
0
|
*Gmulreal = \&Math::Prime::Util::GMP::mulreal; |
|
2458
|
0
|
|
|
|
|
0
|
*Gpowreal = \&Math::Prime::Util::GMP::powreal; |
|
2459
|
0
|
|
|
|
|
0
|
my $d = 2 * length($n) + 2; |
|
2460
|
0
|
|
|
|
|
0
|
my $pp = Gmulreal($n,$n,$d); |
|
2461
|
0
|
|
|
|
|
0
|
$pp = Gaddreal($pp, Gmulreal(13/3 ,Gpowreal($n, 4/3 ,$d),$d),$d); |
|
2462
|
0
|
|
|
|
|
0
|
$pp = Gaddreal($pp, Gmulreal(32/15,Gpowreal($n,16/15,$d),$d),$d); |
|
2463
|
0
|
|
|
|
|
0
|
$pp = Gaddreal($pp, Gmulreal(-2 ,Gpowreal($n, 5/3 ,$d),$d),$d); |
|
2464
|
0
|
|
|
|
|
0
|
$pp = Gaddreal($pp, Gmulreal(-2 ,Gpowreal($n, 7/5 ,$d),$d),$d); |
|
2465
|
0
|
|
|
|
|
0
|
$pp = Gaddreal($pp, Gmulreal(-2 ,Gpowreal($n, 9/7 ,$d),$d),$d); |
|
2466
|
0
|
|
|
|
|
0
|
$pp = Gaddreal($pp, Gmulreal( 2 ,Gpowreal($n,12/10,$d),$d),$d); |
|
2467
|
0
|
|
|
|
|
0
|
$pp = Gaddreal($pp, Gmulreal(-2 ,Gpowreal($n,13/11,$d),$d),$d); |
|
2468
|
0
|
|
|
|
|
0
|
$pp = Gaddreal($pp, Gmulreal(-2 ,Gpowreal($n,15/13,$d),$d),$d); |
|
2469
|
0
|
|
|
|
|
0
|
$pp = Gaddreal($pp, Gmulreal( 2 ,Gpowreal($n,16/14,$d),$d),$d); |
|
2470
|
0
|
|
|
|
|
0
|
$pp = Gaddreal($pp, Gmulreal( 2 ,Gpowreal($n,17/15,$d),$d),$d); |
|
2471
|
0
|
|
|
|
|
0
|
$pp = Gaddreal($pp, Gmulreal(-0.48,Gpowreal($n,19/17,$d),$d),$d); |
|
2472
|
0
|
|
|
|
|
0
|
$pp = Gaddreal($pp, -1.5,$d); |
|
2473
|
0
|
|
|
|
|
0
|
$pp =~ s/\..*//; |
|
2474
|
0
|
|
|
|
|
0
|
return Mtoint("$pp"); |
|
2475
|
|
|
|
|
|
|
} |
|
2476
|
|
|
|
|
|
|
|
|
2477
|
|
|
|
|
|
|
# Without this upgrade, it will return non-integers. |
|
2478
|
3
|
100
|
|
|
|
16
|
$n = _upgrade_to_float($n) if $n > 2**32; |
|
2479
|
|
|
|
|
|
|
|
|
2480
|
3
|
100
|
|
|
|
208
|
if (!ref($n)) { |
|
2481
|
2
|
|
|
|
|
17
|
my $pp = $n*$n + (13/3)*$n**(4/3) + (32/15)*$n**(16/15); |
|
2482
|
2
|
|
|
|
|
6
|
$pp += -2*$n**( 5/ 3) + -2*$n**( 7/ 5); |
|
2483
|
2
|
|
|
|
|
7
|
$pp += -2*$n**( 9/ 7) + 2*$n**(12/10); |
|
2484
|
2
|
|
|
|
|
5
|
$pp += -2*$n**(13/11) + -2*$n**(15/13); |
|
2485
|
2
|
|
|
|
|
8
|
$pp += 2*$n**(16/14) + 2*$n**(17/15); |
|
2486
|
2
|
|
|
|
|
5
|
$pp -= 0.48*$n**(19/17); |
|
2487
|
2
|
|
|
|
|
20
|
return Mtoint($pp - 1.5); |
|
2488
|
|
|
|
|
|
|
} |
|
2489
|
|
|
|
|
|
|
|
|
2490
|
|
|
|
|
|
|
# Taking roots is very expensive with Math::BigFloat, so minimize. |
|
2491
|
1
|
|
|
|
|
6
|
my $n143 = $n->copy->broot(143); |
|
2492
|
1
|
|
|
|
|
250375
|
my $n105 = $n->copy->broot(105); |
|
2493
|
|
|
|
|
|
|
|
|
2494
|
1
|
|
|
|
|
295744
|
my $n15 = $n105->copy->bpow(7); |
|
2495
|
1
|
|
|
|
|
3272
|
my $n13 = $n143->copy->bpow(11); |
|
2496
|
1
|
|
|
|
|
5287
|
my $n11 = $n143->copy->bpow(13); |
|
2497
|
1
|
|
|
|
|
6255
|
my $n7 = $n105->copy->bpow(15); |
|
2498
|
1
|
|
|
|
|
7968
|
my $n5 = $n105->copy->bpow(21); |
|
2499
|
1
|
|
|
|
|
13049
|
my $n3 = $n105->copy->bpow(35); |
|
2500
|
|
|
|
|
|
|
|
|
2501
|
1
|
|
|
|
|
30022
|
my $pp = $n*$n + (13/3)*$n*$n3 + (32/15)*$n*$n15; |
|
2502
|
1
|
|
|
|
|
6775
|
$pp += -2*$n*$n3**2 + -2*$n*$n5**2; |
|
2503
|
1
|
|
|
|
|
116233
|
$pp += -2*$n*$n7**2 + 2*$n*$n5; |
|
2504
|
1
|
|
|
|
|
23495
|
$pp += -2*$n*$n11**2 + -2*$n*$n13**2; |
|
2505
|
1
|
|
|
|
|
32104
|
$pp += 2*$n*$n7 + 2*$n*$n15**2; |
|
2506
|
1
|
|
|
|
|
8184
|
$pp -= 0.48*$n*$n143**16.82352941176470588; # close to 2/17 |
|
2507
|
1
|
|
|
|
|
339603
|
$pp -= 1.5; |
|
2508
|
1
|
|
|
|
|
2638
|
$pp = $pp->as_int(); |
|
2509
|
1
|
|
|
|
|
841
|
Mtoint($pp); |
|
2510
|
|
|
|
|
|
|
} |
|
2511
|
|
|
|
|
|
|
|
|
2512
|
|
|
|
|
|
|
sub nth_perfect_power_lower { |
|
2513
|
1
|
|
|
1
|
0
|
3
|
my($n) = @_; |
|
2514
|
1
|
|
|
|
|
19
|
validate_integer_nonneg($n); |
|
2515
|
1
|
50
|
|
|
|
6
|
return (undef,1,4,8,9,16,25,27)[$n] if $n < 8; |
|
2516
|
1
|
50
|
33
|
|
|
9
|
$n = _upgrade_to_float($n) if ref($n) || $n > 2**32; |
|
2517
|
|
|
|
|
|
|
|
|
2518
|
1
|
|
|
|
|
7
|
my $pp = $n*$n + (13/3)*$n**(4/3) + (32/15)*$n**(16/15); |
|
2519
|
1
|
|
|
|
|
4
|
$pp += -2*$n**( 5/ 3) + -2*$n**( 7/ 5); |
|
2520
|
1
|
|
|
|
|
5
|
$pp += -2*$n**( 9/ 7) + 2*$n**(12/10); |
|
2521
|
1
|
|
|
|
|
3
|
$pp += -2*$n**(13/11) + -2*$n**(15/13); |
|
2522
|
1
|
|
|
|
|
13
|
$pp += 1.5; |
|
2523
|
1
|
|
|
|
|
7
|
Mtoint($pp); |
|
2524
|
|
|
|
|
|
|
} |
|
2525
|
|
|
|
|
|
|
sub nth_perfect_power_upper { |
|
2526
|
1
|
|
|
1
|
0
|
3
|
my($n) = @_; |
|
2527
|
1
|
|
|
|
|
5
|
validate_integer_nonneg($n); |
|
2528
|
1
|
50
|
|
|
|
6
|
return (undef,1,4,8,9,16,25,27)[$n] if $n < 8; |
|
2529
|
1
|
50
|
33
|
|
|
10
|
$n = _upgrade_to_float($n) if ref($n) || $n > 2**32; |
|
2530
|
|
|
|
|
|
|
|
|
2531
|
1
|
|
|
|
|
7
|
my $pp = $n*$n + (13/3)*$n**(4/3) + (32/15)*$n**(16/15); |
|
2532
|
1
|
|
|
|
|
5
|
$pp += -2*$n**( 5/ 3) + -2*$n**( 7/ 5); |
|
2533
|
1
|
|
|
|
|
5
|
$pp += -2*$n**( 9/ 7) + 2*$n**(12/10); |
|
2534
|
1
|
|
|
|
|
4
|
$pp += 2*$n**(16/14); |
|
2535
|
1
|
|
|
|
|
3
|
$pp -= 3.5; |
|
2536
|
1
|
|
|
|
|
4
|
Mtoint($pp); |
|
2537
|
|
|
|
|
|
|
} |
|
2538
|
|
|
|
|
|
|
|
|
2539
|
|
|
|
|
|
|
sub nth_perfect_power { |
|
2540
|
2
|
|
|
2
|
0
|
10491
|
my($n) = @_; |
|
2541
|
2
|
|
|
|
|
9
|
validate_integer_nonneg($n); |
|
2542
|
2
|
50
|
|
|
|
8
|
return (undef,1,4,8,9,16,25,27)[$n] if $n < 8; |
|
2543
|
2
|
|
|
|
|
4
|
my($g,$c,$apn,$gn); |
|
2544
|
|
|
|
|
|
|
|
|
2545
|
2
|
|
|
|
|
10
|
$gn = 1; |
|
2546
|
2
|
|
|
|
|
20
|
$g = $apn = nth_perfect_power_approx($n); |
|
2547
|
2
|
|
|
|
|
11
|
$c = _perfect_power_count($g); |
|
2548
|
2
|
|
33
|
|
|
40
|
while ($n != $c && abs($n-$c) > 1000) { |
|
2549
|
0
|
|
|
|
|
0
|
$g += $apn - nth_perfect_power_approx($c); |
|
2550
|
0
|
|
|
|
|
0
|
$c = _perfect_power_count($g); |
|
2551
|
0
|
0
|
|
|
|
0
|
last if $gn++ >= 20; |
|
2552
|
|
|
|
|
|
|
} |
|
2553
|
2
|
100
|
|
|
|
12
|
if ($c >= $n) { |
|
2554
|
1
|
|
|
|
|
8
|
for ($g = Math::Prime::Util::prev_perfect_power($g+1); $c > $n; $c--) { |
|
2555
|
4
|
|
|
|
|
27
|
$g = Math::Prime::Util::prev_perfect_power($g); |
|
2556
|
|
|
|
|
|
|
} |
|
2557
|
|
|
|
|
|
|
} else { |
|
2558
|
1
|
|
|
|
|
6
|
for ( ; $c < $n; $c++) { |
|
2559
|
1
|
|
|
|
|
8
|
$g = Math::Prime::Util::next_perfect_power($g); |
|
2560
|
|
|
|
|
|
|
} |
|
2561
|
|
|
|
|
|
|
} |
|
2562
|
2
|
|
|
|
|
26
|
$g; |
|
2563
|
|
|
|
|
|
|
} |
|
2564
|
|
|
|
|
|
|
|
|
2565
|
|
|
|
|
|
|
sub _prime_power_count { |
|
2566
|
13
|
|
|
13
|
|
26
|
my($n) = @_; |
|
2567
|
13
|
50
|
|
|
|
32
|
return (0,0,1,2,3,4)[$n] if $n <= 5; |
|
2568
|
|
|
|
|
|
|
Mvecsum( |
|
2569
|
13
|
|
|
|
|
60
|
map { Mprime_count( Mrootint($n, $_)) } 1 .. Mlogint($n,2) |
|
|
185
|
|
|
|
|
404
|
|
|
2570
|
|
|
|
|
|
|
); |
|
2571
|
|
|
|
|
|
|
} |
|
2572
|
|
|
|
|
|
|
sub prime_power_count { |
|
2573
|
13
|
|
|
13
|
0
|
50
|
my($lo,$hi) = @_; |
|
2574
|
13
|
50
|
|
|
|
50
|
if (defined $hi) { validate_integer_nonneg($lo); } |
|
|
0
|
|
|
|
|
0
|
|
|
2575
|
13
|
|
|
|
|
52
|
else { ($lo,$hi) = (2, $lo); } |
|
2576
|
13
|
|
|
|
|
45
|
validate_integer_nonneg($hi); |
|
2577
|
13
|
50
|
33
|
|
|
72
|
return 0 if $hi < $lo || $hi == 0; |
|
2578
|
13
|
50
|
|
|
|
50
|
return _prime_power_count($hi) - (($lo <= 2) ? 0 : _prime_power_count($lo-1)); |
|
2579
|
|
|
|
|
|
|
} |
|
2580
|
|
|
|
|
|
|
sub prime_power_count_lower { |
|
2581
|
20
|
|
|
20
|
0
|
52
|
my($n) = @_; |
|
2582
|
20
|
|
|
|
|
90
|
validate_integer_nonneg($n); |
|
2583
|
20
|
50
|
|
|
|
71
|
return (0,0,1,2,3,4)[$n] if $n <= 5; |
|
2584
|
|
|
|
|
|
|
Mvecsum( |
|
2585
|
20
|
|
|
|
|
85
|
map { Math::Prime::Util::prime_count_lower( Mrootint($n, $_)) } 1 .. Mlogint($n,2) |
|
|
455
|
|
|
|
|
1282
|
|
|
2586
|
|
|
|
|
|
|
); |
|
2587
|
|
|
|
|
|
|
} |
|
2588
|
|
|
|
|
|
|
sub prime_power_count_upper { |
|
2589
|
20
|
|
|
20
|
0
|
79
|
my($n) = @_; |
|
2590
|
20
|
|
|
|
|
76
|
validate_integer_nonneg($n); |
|
2591
|
20
|
50
|
|
|
|
56
|
return (0,0,1,2,3,4)[$n] if $n <= 5; |
|
2592
|
|
|
|
|
|
|
Mvecsum( |
|
2593
|
20
|
|
|
|
|
113
|
map { Math::Prime::Util::prime_count_upper( Mrootint($n, $_)) } 1 .. Mlogint($n,2) |
|
|
455
|
|
|
|
|
1260
|
|
|
2594
|
|
|
|
|
|
|
); |
|
2595
|
|
|
|
|
|
|
} |
|
2596
|
|
|
|
|
|
|
sub prime_power_count_approx { |
|
2597
|
19
|
|
|
19
|
0
|
44
|
my($n) = @_; |
|
2598
|
19
|
|
|
|
|
55
|
validate_integer_nonneg($n); |
|
2599
|
19
|
50
|
|
|
|
43
|
return (0,0,1,2,3,4)[$n] if $n <= 5; |
|
2600
|
|
|
|
|
|
|
Mvecsum( |
|
2601
|
19
|
|
|
|
|
68
|
map { Math::Prime::Util::prime_count_approx( Mrootint($n, $_)) } 1 .. Mlogint($n,2) |
|
|
432
|
|
|
|
|
831
|
|
|
2602
|
|
|
|
|
|
|
); |
|
2603
|
|
|
|
|
|
|
} |
|
2604
|
|
|
|
|
|
|
|
|
2605
|
|
|
|
|
|
|
sub _simple_nth_prime_power_upper { |
|
2606
|
4
|
|
|
4
|
|
13
|
my($n) = @_; |
|
2607
|
4
|
|
|
|
|
18
|
Mnth_prime_upper($n); |
|
2608
|
|
|
|
|
|
|
} |
|
2609
|
|
|
|
|
|
|
sub _simple_nth_prime_power_lower { |
|
2610
|
4
|
|
|
4
|
|
11
|
my $n = shift; |
|
2611
|
4
|
50
|
|
|
|
26
|
return nth_prime_lower(int(0.65*$n)) if $n < 90; |
|
2612
|
4
|
|
|
|
|
22
|
int( 0.98 * Math::Prime::Util::nth_prime_lower($n) - 400 ); |
|
2613
|
|
|
|
|
|
|
} |
|
2614
|
|
|
|
|
|
|
sub nth_prime_power_lower { |
|
2615
|
1
|
|
|
1
|
0
|
5
|
my($n) = @_; |
|
2616
|
1
|
|
|
|
|
6
|
validate_integer_nonneg($n); |
|
2617
|
1
|
50
|
|
|
|
5
|
return (undef,2,3,4,5,7,8,9)[$n] if $n < 8; |
|
2618
|
1
|
|
|
|
|
5
|
my($lo,$hi) = (_simple_nth_prime_power_lower($n), _simple_nth_prime_power_upper($n)); |
|
2619
|
|
|
|
|
|
|
_binary_search($n, $lo, $hi, |
|
2620
|
1
|
|
|
19
|
|
11
|
sub{Math::Prime::Util::prime_power_count_upper(shift)}); |
|
|
19
|
|
|
|
|
80
|
|
|
2621
|
|
|
|
|
|
|
} |
|
2622
|
|
|
|
|
|
|
sub nth_prime_power_upper { |
|
2623
|
1
|
|
|
1
|
0
|
17
|
my($n) = @_; |
|
2624
|
1
|
|
|
|
|
7
|
validate_integer_nonneg($n); |
|
2625
|
1
|
50
|
|
|
|
5
|
return (undef,2,3,4,5,7,8,9)[$n] if $n < 8; |
|
2626
|
1
|
|
|
|
|
6
|
my($lo,$hi) = (_simple_nth_prime_power_lower($n), _simple_nth_prime_power_upper($n)); |
|
2627
|
|
|
|
|
|
|
1+_binary_search($n, $lo, $hi, |
|
2628
|
1
|
|
|
19
|
|
11
|
sub{Math::Prime::Util::prime_power_count_lower(shift)}); |
|
|
19
|
|
|
|
|
73
|
|
|
2629
|
|
|
|
|
|
|
} |
|
2630
|
|
|
|
|
|
|
sub nth_prime_power_approx { |
|
2631
|
1
|
|
|
1
|
0
|
16
|
my($n) = @_; |
|
2632
|
1
|
|
|
|
|
5
|
validate_integer_nonneg($n); |
|
2633
|
1
|
50
|
|
|
|
6
|
return (undef,2,3,4,5,7,8,9)[$n] if $n < 8; |
|
2634
|
1
|
|
|
|
|
5
|
my($lo,$hi) = (_simple_nth_prime_power_lower($n), _simple_nth_prime_power_upper($n)); |
|
2635
|
|
|
|
|
|
|
_binary_search($n, $lo, $hi, |
|
2636
|
1
|
|
|
18
|
|
9
|
sub{Math::Prime::Util::prime_power_count_approx(shift)}); |
|
|
18
|
|
|
|
|
47
|
|
|
2637
|
|
|
|
|
|
|
} |
|
2638
|
|
|
|
|
|
|
sub nth_prime_power { |
|
2639
|
1
|
|
|
1
|
0
|
721
|
my($n) = @_; |
|
2640
|
1
|
|
|
|
|
4
|
validate_integer_nonneg($n); |
|
2641
|
1
|
50
|
|
|
|
4
|
return (undef,2,3,4,5,7,8,9)[$n] if $n < 8; |
|
2642
|
|
|
|
|
|
|
# TODO: This is a good candidte for the approx interpolation method |
|
2643
|
1
|
|
|
|
|
4
|
my($lo,$hi) = (_simple_nth_prime_power_lower($n), _simple_nth_prime_power_upper($n)); |
|
2644
|
|
|
|
|
|
|
1+_binary_search($n, $lo, $hi, |
|
2645
|
1
|
|
|
11
|
|
7
|
sub{Math::Prime::Util::prime_power_count(shift)}); |
|
|
11
|
|
|
|
|
38
|
|
|
2646
|
|
|
|
|
|
|
} |
|
2647
|
|
|
|
|
|
|
|
|
2648
|
|
|
|
|
|
|
|
|
2649
|
|
|
|
|
|
|
sub smooth_count { |
|
2650
|
710
|
|
|
710
|
0
|
1055
|
my($n, $k) = @_; |
|
2651
|
710
|
|
|
|
|
3344
|
validate_integer_nonneg($n); |
|
2652
|
710
|
|
|
|
|
1241
|
validate_integer_nonneg($k); |
|
2653
|
710
|
50
|
|
|
|
1309
|
return 0 if $n < 1; |
|
2654
|
710
|
50
|
|
|
|
1122
|
return 1 if $k <= 1; |
|
2655
|
710
|
50
|
|
|
|
1218
|
return $n if $k >= $n; |
|
2656
|
|
|
|
|
|
|
|
|
2657
|
710
|
|
|
|
|
1341
|
my $sum = 1 + Mlogint($n,2); |
|
2658
|
710
|
50
|
|
|
|
3337
|
if ($k >= 3) { |
|
2659
|
710
|
|
|
|
|
1350
|
my $n3 = Mdivint($n, 3); |
|
2660
|
710
|
|
|
|
|
1256
|
while ($n3 > 3) { |
|
2661
|
1623
|
|
|
|
|
2840
|
$sum += 1 + Mlogint($n3,2); |
|
2662
|
1623
|
|
|
|
|
2605
|
$n3 = Mdivint($n3, 3); |
|
2663
|
|
|
|
|
|
|
} |
|
2664
|
710
|
|
|
|
|
926
|
$sum += $n3; |
|
2665
|
|
|
|
|
|
|
} |
|
2666
|
710
|
50
|
|
|
|
1268
|
if ($k >= 5) { |
|
2667
|
710
|
|
|
|
|
1128
|
my $n5 = Mdivint($n, 5); |
|
2668
|
710
|
|
|
|
|
1220
|
while ($n5 > 5) { |
|
2669
|
815
|
|
|
|
|
1403
|
$sum += 1 + Mlogint($n5,2); |
|
2670
|
815
|
|
|
|
|
1284
|
my $n3 = Mdivint($n5, 3); |
|
2671
|
815
|
|
|
|
|
1562
|
while ($n3 > 3) { |
|
2672
|
1247
|
|
|
|
|
2029
|
$sum += 1 + Mlogint($n3,2); |
|
2673
|
1247
|
|
|
|
|
2046
|
$n3 = Mdivint($n3, 3); |
|
2674
|
|
|
|
|
|
|
} |
|
2675
|
815
|
|
|
|
|
1032
|
$sum += $n3; |
|
2676
|
815
|
|
|
|
|
1179
|
$n5 = Mdivint($n5, 5); |
|
2677
|
|
|
|
|
|
|
} |
|
2678
|
710
|
|
|
|
|
895
|
$sum += $n5; |
|
2679
|
|
|
|
|
|
|
} |
|
2680
|
710
|
|
|
|
|
2092
|
my $p = 7; |
|
2681
|
710
|
|
|
|
|
1124
|
while ($p <= $k) { |
|
2682
|
1663
|
|
|
|
|
2353
|
my $np = Mdivint($n, $p); |
|
2683
|
1663
|
100
|
|
|
|
3227
|
$sum += ($p >= $np) ? $np : Math::Prime::Util::smooth_count($np, $p); |
|
2684
|
1663
|
|
|
|
|
2772
|
$p = Mnext_prime($p); |
|
2685
|
|
|
|
|
|
|
} |
|
2686
|
710
|
|
|
|
|
990
|
$sum; |
|
2687
|
|
|
|
|
|
|
} |
|
2688
|
|
|
|
|
|
|
|
|
2689
|
|
|
|
|
|
|
sub rough_count { |
|
2690
|
1
|
|
|
1
|
0
|
2
|
my($n, $k) = @_; |
|
2691
|
1
|
|
|
|
|
5
|
validate_integer_nonneg($n); |
|
2692
|
1
|
|
|
|
|
2
|
validate_integer_nonneg($k); |
|
2693
|
1
|
50
|
|
|
|
4
|
return $n if $k <= 2; |
|
2694
|
1
|
50
|
|
|
|
3
|
return $n-($n>>1) if $k <= 3; |
|
2695
|
1
|
|
|
|
|
35
|
Math::Prime::Util::legendre_phi($n, Mprime_count($k-1)); |
|
2696
|
|
|
|
|
|
|
} |
|
2697
|
|
|
|
|
|
|
|
|
2698
|
|
|
|
|
|
|
|
|
2699
|
|
|
|
|
|
|
# Recursive almost primes from Trizen. |
|
2700
|
|
|
|
|
|
|
sub _genkap { |
|
2701
|
89
|
|
|
89
|
|
251
|
my($A, $B, $k, $m, $p, $cb) = @_; |
|
2702
|
89
|
100
|
|
|
|
184
|
if ($k == 1) { |
|
2703
|
|
|
|
|
|
|
Mforprimes( sub { |
|
2704
|
37
|
|
|
37
|
|
214
|
$cb->(Mmulint($m, $_)); |
|
2705
|
80
|
|
|
|
|
597
|
}, Mvecmax($p, Mcdivint($A, $m)), Mdivint($B, $m)); |
|
2706
|
|
|
|
|
|
|
} else { |
|
2707
|
9
|
|
|
|
|
30
|
my $s = Mrootint(Mdivint($B, $m), $k); |
|
2708
|
9
|
|
|
|
|
32
|
while ($p <= $s) { |
|
2709
|
154
|
|
|
|
|
566
|
my $t = mulint($m, $p); |
|
2710
|
154
|
100
|
|
|
|
481
|
_genkap($A, $B, $k-1, $t, $p, $cb) |
|
2711
|
|
|
|
|
|
|
if Mcdivint($A, $t) <= Mdivint($B, $t); # Faster for tight ranges |
|
2712
|
154
|
|
|
|
|
792
|
$p = next_prime($p); |
|
2713
|
|
|
|
|
|
|
} |
|
2714
|
|
|
|
|
|
|
} |
|
2715
|
|
|
|
|
|
|
} |
|
2716
|
|
|
|
|
|
|
|
|
2717
|
|
|
|
|
|
|
sub _generate_almost_primes { |
|
2718
|
5
|
|
|
5
|
|
15
|
my($A, $B, $k, $cb) = @_; |
|
2719
|
5
|
|
|
|
|
37
|
$A = Mvecmax($A, Mpowint(2, $k)); |
|
2720
|
5
|
50
|
|
|
|
51
|
_genkap($A, $B, $k, 1, 2, $cb) if $A <= $B; |
|
2721
|
|
|
|
|
|
|
} |
|
2722
|
|
|
|
|
|
|
|
|
2723
|
|
|
|
|
|
|
|
|
2724
|
|
|
|
|
|
|
sub almost_primes { |
|
2725
|
8
|
|
|
8
|
0
|
1590
|
my($k, $low, $high) = @_; |
|
2726
|
8
|
|
|
|
|
44
|
validate_integer_nonneg($k); |
|
2727
|
8
|
100
|
|
|
|
27
|
if (defined $high) { validate_integer_nonneg($low); } |
|
|
4
|
|
|
|
|
34
|
|
|
2728
|
4
|
|
|
|
|
11
|
else { ($low,$high) = (1, $low); } |
|
2729
|
8
|
|
|
|
|
181
|
validate_integer_nonneg($high); |
|
2730
|
|
|
|
|
|
|
|
|
2731
|
8
|
0
|
0
|
|
|
125
|
if ($k == 0) { return ($low <= 1 && $high >= 1) ? [1] : [] } |
|
|
0
|
50
|
|
|
|
0
|
|
|
2732
|
8
|
100
|
|
|
|
31
|
if ($k == 1) { return Mprimes($low,$high); } |
|
|
1
|
|
|
|
|
6
|
|
|
2733
|
|
|
|
|
|
|
# Don't call this, we could end up back here |
|
2734
|
|
|
|
|
|
|
#if ($k == 2) { return Math::Prime::Util::semi_primes($low,$high); } |
|
2735
|
|
|
|
|
|
|
|
|
2736
|
7
|
|
|
|
|
37
|
my $minlow = Mpowint(2,$k); |
|
2737
|
7
|
100
|
|
|
|
29
|
$low = $minlow if $low < $minlow; |
|
2738
|
7
|
50
|
|
|
|
534
|
return [] if $low > $high; |
|
2739
|
7
|
|
|
|
|
171
|
my @ap; |
|
2740
|
|
|
|
|
|
|
|
|
2741
|
7
|
100
|
|
|
|
27
|
if ($low > 1e9) { |
|
2742
|
|
|
|
|
|
|
#while ($low <= $high) { |
|
2743
|
|
|
|
|
|
|
# push @ap, $low if is_almost_prime($k, $low); |
|
2744
|
|
|
|
|
|
|
# $low = add1int($low); |
|
2745
|
|
|
|
|
|
|
#} |
|
2746
|
2
|
100
|
|
5
|
|
676
|
Math::Prime::Util::forfactored(sub { push @ap,$_ if scalar(@_) == $k }, $low, $high); |
|
|
5
|
|
|
|
|
42
|
|
|
2747
|
2
|
|
|
|
|
29
|
return \@ap; |
|
2748
|
|
|
|
|
|
|
} |
|
2749
|
|
|
|
|
|
|
|
|
2750
|
5
|
|
|
37
|
|
103
|
_generate_almost_primes($low, $high, $k, sub { push @ap,$_[0]; }); |
|
|
37
|
|
|
|
|
114
|
|
|
2751
|
5
|
|
|
|
|
42
|
Mvecsorti(\@ap); |
|
2752
|
|
|
|
|
|
|
} |
|
2753
|
|
|
|
|
|
|
|
|
2754
|
|
|
|
|
|
|
sub _rec_omega_primes { |
|
2755
|
2613
|
|
|
2613
|
|
7521
|
my($k, $lo, $hi, $m, $p, $opl) = @_; |
|
2756
|
2613
|
|
|
|
|
6433
|
my $s = Mrootint(Mdivint($hi, $m), $k); |
|
2757
|
2613
|
|
|
|
|
4416
|
foreach my $q (@{Mprimes($p, $s)}) { |
|
|
2613
|
|
|
|
|
6850
|
|
|
2758
|
1065
|
100
|
|
|
|
4912
|
next if $m % $q == 0; |
|
2759
|
367
|
|
|
|
|
1186
|
for (my $v = Mmulint($m, $q); $v <= $hi ; $v = Mmulint($v, $q)) { |
|
2760
|
2979
|
100
|
|
|
|
5841
|
if ($k == 1) { |
|
2761
|
5
|
50
|
|
|
|
43
|
push @$opl, $v if $v >= $lo; |
|
2762
|
|
|
|
|
|
|
} else { |
|
2763
|
2974
|
100
|
|
|
|
5758
|
_rec_omega_primes($k-1,$lo,$hi,$v,$q,$opl) if Mmulint($v,$q) <= $hi; |
|
2764
|
|
|
|
|
|
|
} |
|
2765
|
|
|
|
|
|
|
} |
|
2766
|
|
|
|
|
|
|
} |
|
2767
|
|
|
|
|
|
|
} |
|
2768
|
|
|
|
|
|
|
|
|
2769
|
|
|
|
|
|
|
sub omega_primes { |
|
2770
|
5
|
|
|
5
|
0
|
1579
|
my($k, $low, $high) = @_; |
|
2771
|
5
|
|
|
|
|
26
|
validate_integer_nonneg($k); |
|
2772
|
5
|
100
|
|
|
|
18
|
if (defined $high) { validate_integer_nonneg($low); } |
|
|
1
|
|
|
|
|
5
|
|
|
2773
|
4
|
|
|
|
|
13
|
else { ($low,$high) = (1, $low); } |
|
2774
|
5
|
|
|
|
|
19
|
validate_integer_nonneg($high); |
|
2775
|
|
|
|
|
|
|
|
|
2776
|
5
|
0
|
0
|
|
|
20
|
if ($k == 0) { return ($low <= 1 && $high >= 1) ? [1] : [] } |
|
|
0
|
50
|
|
|
|
0
|
|
|
2777
|
5
|
100
|
|
|
|
18
|
if ($k == 1) { return Math::Prime::Util::prime_powers($low,$high); } |
|
|
1
|
|
|
|
|
23
|
|
|
2778
|
|
|
|
|
|
|
|
|
2779
|
4
|
|
|
|
|
27
|
$low = Mvecmax($low, Mpn_primorial($k)); |
|
2780
|
4
|
50
|
|
|
|
29
|
return [] if $low > $high; |
|
2781
|
|
|
|
|
|
|
|
|
2782
|
4
|
|
|
|
|
12
|
my $opl = []; |
|
2783
|
|
|
|
|
|
|
|
|
2784
|
4
|
100
|
33
|
|
|
28
|
if ($high-$low > 1000000000 || ($k >= 10 && $high-$low > 10000000)) { |
|
|
|
|
66
|
|
|
|
|
|
2785
|
|
|
|
|
|
|
# Recursive method from trizen |
|
2786
|
1
|
|
|
|
|
7
|
_rec_omega_primes($k, $low, $high, 1, 2, $opl); |
|
2787
|
1
|
|
|
|
|
9
|
Mvecsorti($opl); |
|
2788
|
|
|
|
|
|
|
} else { |
|
2789
|
|
|
|
|
|
|
# Simple iteration |
|
2790
|
3
|
|
|
|
|
9
|
while ($low <= $high) { |
|
2791
|
377
|
100
|
|
|
|
960
|
push @$opl, $low if Mprime_omega($low) == $k; |
|
2792
|
377
|
|
|
|
|
1058
|
$low++; |
|
2793
|
|
|
|
|
|
|
} |
|
2794
|
|
|
|
|
|
|
} |
|
2795
|
4
|
|
|
|
|
57
|
$opl; |
|
2796
|
|
|
|
|
|
|
} |
|
2797
|
|
|
|
|
|
|
|
|
2798
|
|
|
|
|
|
|
sub is_semiprime { |
|
2799
|
9
|
|
|
9
|
0
|
1623
|
my($n) = @_; |
|
2800
|
9
|
|
|
|
|
43
|
validate_integer($n); |
|
2801
|
9
|
50
|
|
|
|
39
|
return 0+($n == 4) if $n < 6; |
|
2802
|
9
|
50
|
|
|
|
395
|
if ($n > 15) { |
|
2803
|
9
|
50
|
33
|
|
|
356
|
return 0 if ($n % 4) == 0 || ($n % 6) == 0 || ($n % 9) == 0 |
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
2804
|
|
|
|
|
|
|
|| ($n % 10) == 0 || ($n % 14) == 0 || ($n % 15) == 0; |
|
2805
|
|
|
|
|
|
|
} |
|
2806
|
8
|
0
|
|
|
|
25
|
return (Math::Prime::Util::is_prob_prime($n>>1) ? 1 : 0) if ($n % 2) == 0; |
|
|
|
50
|
|
|
|
|
|
|
2807
|
8
|
50
|
|
|
|
33
|
return (Math::Prime::Util::is_prob_prime($n/3) ? 1 : 0) if ($n % 3) == 0; |
|
|
|
100
|
|
|
|
|
|
|
2808
|
6
|
50
|
|
|
|
73
|
return (Math::Prime::Util::is_prob_prime($n/5) ? 1 : 0) if ($n % 5) == 0; |
|
|
|
100
|
|
|
|
|
|
|
2809
|
|
|
|
|
|
|
|
|
2810
|
5
|
|
|
|
|
13
|
if (0) { # TODO: This is all REALLY slow without GMP |
|
2811
|
|
|
|
|
|
|
# TODO: Something with GMP. If nothing else, just factor. |
|
2812
|
|
|
|
|
|
|
{ |
|
2813
|
|
|
|
|
|
|
my @f = trial_factor($n, 4999); |
|
2814
|
|
|
|
|
|
|
return 0 if @f > 2; |
|
2815
|
|
|
|
|
|
|
return (_is_prime7($f[1]) ? 1 : 0) if @f == 2; |
|
2816
|
|
|
|
|
|
|
} |
|
2817
|
|
|
|
|
|
|
return 0 if _is_prime7($n); |
|
2818
|
|
|
|
|
|
|
{ |
|
2819
|
|
|
|
|
|
|
my @f = pminus1_factor ($n, 250_000); |
|
2820
|
|
|
|
|
|
|
return 0 if @f > 2; |
|
2821
|
|
|
|
|
|
|
return (_is_prime7($f[1]) ? 1 : 0) if @f == 2; |
|
2822
|
|
|
|
|
|
|
} |
|
2823
|
|
|
|
|
|
|
{ |
|
2824
|
|
|
|
|
|
|
my @f = pbrent_factor ($n, 128*1024, 3, 1); |
|
2825
|
|
|
|
|
|
|
return 0 if @f > 2; |
|
2826
|
|
|
|
|
|
|
return (_is_prime7($f[1]) ? 1 : 0) if @f == 2; |
|
2827
|
|
|
|
|
|
|
} |
|
2828
|
|
|
|
|
|
|
} |
|
2829
|
5
|
100
|
|
|
|
27
|
return (scalar(Mfactor($n)) == 2) ? 1 : 0; |
|
2830
|
|
|
|
|
|
|
} |
|
2831
|
|
|
|
|
|
|
|
|
2832
|
|
|
|
|
|
|
sub is_almost_prime { |
|
2833
|
32
|
|
|
32
|
0
|
212
|
my($k, $n) = @_; |
|
2834
|
32
|
|
|
|
|
122
|
validate_integer_nonneg($k); |
|
2835
|
32
|
|
|
|
|
97
|
validate_integer($n); |
|
2836
|
32
|
50
|
|
|
|
73
|
return 0 if $n <= 0; |
|
2837
|
|
|
|
|
|
|
|
|
2838
|
32
|
50
|
|
|
|
92
|
return 0+($n==1) if $k == 0; |
|
2839
|
32
|
100
|
|
|
|
104
|
return (Mis_prime($n) ? 1 : 0) if $k == 1; |
|
|
|
100
|
|
|
|
|
|
|
2840
|
28
|
100
|
|
|
|
79
|
return Mis_semiprime($n) if $k == 2; |
|
2841
|
24
|
50
|
|
|
|
107
|
return 0 if ($n >> $k) == 0; |
|
2842
|
|
|
|
|
|
|
|
|
2843
|
|
|
|
|
|
|
# TODO: Optimization here |
|
2844
|
24
|
|
|
|
|
35
|
if (0) { # This seems to just be slower |
|
2845
|
|
|
|
|
|
|
while ($k > 0 && !($n % 2)) { $k--; $n >>= 1; } |
|
2846
|
|
|
|
|
|
|
while ($k > 0 && !($n % 3)) { $k--; $n /= 3; } |
|
2847
|
|
|
|
|
|
|
while ($k > 0 && !($n % 5)) { $k--; $n /= 5; } |
|
2848
|
|
|
|
|
|
|
while ($k > 0 && !($n % 7)) { $k--; $n /= 7; } |
|
2849
|
|
|
|
|
|
|
return 0+($n == 1) if $k == 0; |
|
2850
|
|
|
|
|
|
|
return (Mis_prime($n) ? 1 : 0) if $k == 1; |
|
2851
|
|
|
|
|
|
|
return Mis_semiprime($n) if $k == 2; |
|
2852
|
|
|
|
|
|
|
return 0 if $n < Mpowint(11,$k); |
|
2853
|
|
|
|
|
|
|
} |
|
2854
|
|
|
|
|
|
|
|
|
2855
|
24
|
100
|
|
|
|
70
|
return (scalar(Mfactor($n)) == $k) ? 1 : 0; |
|
2856
|
|
|
|
|
|
|
} |
|
2857
|
|
|
|
|
|
|
sub is_chen_prime { |
|
2858
|
1
|
|
|
1
|
0
|
5
|
my($n) = @_; |
|
2859
|
1
|
|
|
|
|
6
|
validate_integer($n); |
|
2860
|
1
|
50
|
|
|
|
5
|
return 0 if $n < 2; |
|
2861
|
1
|
|
|
|
|
5
|
my $n2 = Maddint($n,2); |
|
2862
|
1
|
|
33
|
|
|
5
|
return (Mis_prime($n) && (Mis_prime($n2) || Mis_semiprime($n2))); |
|
2863
|
|
|
|
|
|
|
} |
|
2864
|
|
|
|
|
|
|
sub next_chen_prime { |
|
2865
|
1
|
|
|
1
|
0
|
4
|
my($n) = @_; |
|
2866
|
1
|
|
|
|
|
14
|
validate_integer_nonneg($n); |
|
2867
|
1
|
|
|
|
|
7
|
$n = Mnext_prime($n); |
|
2868
|
1
|
|
|
|
|
3
|
while (1) { |
|
2869
|
2
|
|
|
|
|
18
|
my $n2 = Maddint($n,2); |
|
2870
|
2
|
100
|
66
|
|
|
8
|
return $n if Mis_prime($n2) || Mis_semiprime($n2); |
|
2871
|
1
|
|
|
|
|
4
|
$n = Mnext_prime($n2); |
|
2872
|
|
|
|
|
|
|
} |
|
2873
|
|
|
|
|
|
|
} |
|
2874
|
|
|
|
|
|
|
|
|
2875
|
|
|
|
|
|
|
sub is_omega_prime { |
|
2876
|
22
|
|
|
22
|
0
|
169
|
my($k, $n) = @_; |
|
2877
|
22
|
|
|
|
|
115
|
validate_integer_nonneg($k); |
|
2878
|
22
|
|
|
|
|
105
|
validate_integer($n); |
|
2879
|
22
|
50
|
|
|
|
62
|
return 0 if $n <= 0; |
|
2880
|
|
|
|
|
|
|
|
|
2881
|
22
|
50
|
|
|
|
1134
|
return 0+($n==1) if $k == 0; |
|
2882
|
|
|
|
|
|
|
|
|
2883
|
22
|
100
|
|
|
|
128
|
return (Mprime_omega($n) == $k) ? 1 : 0; |
|
2884
|
|
|
|
|
|
|
} |
|
2885
|
|
|
|
|
|
|
|
|
2886
|
|
|
|
|
|
|
sub is_practical { |
|
2887
|
2
|
|
|
2
|
0
|
17
|
my($n) = @_; |
|
2888
|
2
|
|
|
|
|
10
|
validate_integer($n); |
|
2889
|
2
|
50
|
|
|
|
7
|
return 0 if $n <= 0; |
|
2890
|
|
|
|
|
|
|
|
|
2891
|
2
|
50
|
|
|
|
27
|
return $n==1?1:0 if $n % 2; |
|
|
|
100
|
|
|
|
|
|
|
2892
|
1
|
50
|
|
|
|
7
|
return 1 if ($n & ($n-1)) == 0; |
|
2893
|
1
|
0
|
33
|
|
|
7
|
return 0 if ($n % 6) && ($n % 20) && ($n % 28) && ($n % 88) && ($n % 104) && ($n % 16); |
|
|
|
|
33
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
2894
|
|
|
|
|
|
|
|
|
2895
|
1
|
|
|
|
|
4
|
my $prod = 1; |
|
2896
|
1
|
|
|
|
|
6
|
my @pe = Mfactor_exp($n); |
|
2897
|
1
|
|
|
|
|
4
|
for my $i (1 .. $#pe) { |
|
2898
|
3
|
|
|
|
|
7
|
my($f,$e) = @{$pe[$i-1]}; |
|
|
3
|
|
|
|
|
27
|
|
|
2899
|
3
|
|
|
|
|
8
|
my $fmult = $f + 1; |
|
2900
|
3
|
100
|
|
|
|
10
|
if ($e >= 2) { |
|
2901
|
1
|
|
|
|
|
2
|
my $pke = $f; |
|
2902
|
1
|
|
|
|
|
4
|
for (2 .. $e) { |
|
2903
|
1
|
|
|
|
|
4
|
$pke = Mmulint($pke, $f); |
|
2904
|
1
|
|
|
|
|
24
|
$fmult = Maddint($fmult, $pke); |
|
2905
|
|
|
|
|
|
|
} |
|
2906
|
|
|
|
|
|
|
} |
|
2907
|
3
|
|
|
|
|
14
|
$prod = Mmulint($prod, $fmult); |
|
2908
|
3
|
50
|
|
|
|
17
|
return 0 if $pe[$i]->[0] > (1 + $prod); |
|
2909
|
|
|
|
|
|
|
} |
|
2910
|
1
|
|
|
|
|
12
|
1; |
|
2911
|
|
|
|
|
|
|
} |
|
2912
|
|
|
|
|
|
|
|
|
2913
|
|
|
|
|
|
|
sub is_delicate_prime { |
|
2914
|
3
|
|
|
3
|
0
|
25
|
my($n, $b) = @_; |
|
2915
|
3
|
|
|
|
|
55
|
validate_integer_nonneg($n); |
|
2916
|
3
|
100
|
|
|
|
15
|
if (defined $b) { |
|
2917
|
1
|
|
|
|
|
5
|
validate_integer_nonneg($b); |
|
2918
|
1
|
50
|
|
|
|
6
|
croak "is_delicate_prime base must be >= 2" if $b < 2; |
|
2919
|
|
|
|
|
|
|
} else { |
|
2920
|
2
|
|
|
|
|
986
|
$b = 10; |
|
2921
|
|
|
|
|
|
|
} |
|
2922
|
|
|
|
|
|
|
|
|
2923
|
3
|
50
|
66
|
|
|
41
|
return 0 if $b == 10 && $n < 100; # Easy shown. |
|
2924
|
3
|
50
|
33
|
|
|
264
|
return 1 if $b == 3 && $n == 2; |
|
2925
|
3
|
50
|
|
|
|
16
|
return 0 unless Mis_prime($n); |
|
2926
|
|
|
|
|
|
|
|
|
2927
|
3
|
100
|
|
|
|
14
|
if ($b == 10) { |
|
2928
|
|
|
|
|
|
|
# String replacement method. Faster in Perl. |
|
2929
|
2
|
|
|
|
|
30
|
my $ndigits = length($n); |
|
2930
|
2
|
|
|
|
|
53
|
for my $d (0 .. $ndigits-1) { |
|
2931
|
27
|
|
|
|
|
493
|
my $N = "$n"; |
|
2932
|
27
|
|
|
|
|
1202
|
my $dold = substr($N,$d,1); |
|
2933
|
27
|
|
|
|
|
82
|
for my $dnew (0 .. 9) { |
|
2934
|
270
|
100
|
|
|
|
25078
|
next if $dnew == $dold; |
|
2935
|
243
|
100
|
100
|
|
|
817
|
if ($d == 0 && $dnew == 0) { # Leading zeros |
|
2936
|
2
|
|
|
|
|
17
|
(my $T = substr($N,1)) =~ s/^0*//; |
|
2937
|
2
|
50
|
|
|
|
101
|
return 0 if Mis_prime($T); |
|
2938
|
|
|
|
|
|
|
} else { |
|
2939
|
241
|
|
|
|
|
726
|
substr($N,$d,1) = $dnew; |
|
2940
|
241
|
50
|
|
|
|
19203
|
return 0 if Mis_prime($N); |
|
2941
|
|
|
|
|
|
|
} |
|
2942
|
|
|
|
|
|
|
} |
|
2943
|
|
|
|
|
|
|
} |
|
2944
|
|
|
|
|
|
|
} else { |
|
2945
|
|
|
|
|
|
|
# Using todigitstring is slightly faster for bases < 10, but this is |
|
2946
|
|
|
|
|
|
|
# decent and works for all 32-bit bases. |
|
2947
|
|
|
|
|
|
|
# This is faster than Stamm's algorithm (in Perl, for possible bigints). |
|
2948
|
1
|
|
|
|
|
8
|
my $D = [Mtodigits($n, $b)]; |
|
2949
|
1
|
|
|
|
|
6
|
for my $d (0 .. $#$D) { |
|
2950
|
5
|
|
|
|
|
16
|
my $dold = $D->[$d]; |
|
2951
|
5
|
|
|
|
|
20
|
for my $dnew (0 .. $b-1) { |
|
2952
|
80
|
100
|
|
|
|
236
|
next if $dnew == $dold; |
|
2953
|
75
|
|
|
|
|
184
|
$D->[$d] = $dnew; |
|
2954
|
75
|
50
|
|
|
|
204
|
return 0 if Mis_prime(Mfromdigits($D,$b)); |
|
2955
|
|
|
|
|
|
|
} |
|
2956
|
5
|
|
|
|
|
19
|
$D->[$d] = $dold; |
|
2957
|
|
|
|
|
|
|
} |
|
2958
|
|
|
|
|
|
|
} |
|
2959
|
3
|
|
|
|
|
36
|
1; |
|
2960
|
|
|
|
|
|
|
} |
|
2961
|
|
|
|
|
|
|
|
|
2962
|
|
|
|
|
|
|
sub _totpred { |
|
2963
|
34
|
|
|
34
|
|
1834
|
my($n, $maxd) = @_; |
|
2964
|
34
|
100
|
100
|
|
|
179
|
return 0 if $maxd <= 1 || Mis_odd($n); |
|
2965
|
11
|
100
|
|
|
|
1320
|
return 1 if ($n & ($n-1)) == 0; |
|
2966
|
9
|
|
|
|
|
4647
|
$n >>= 1; |
|
2967
|
9
|
100
|
100
|
|
|
1557
|
return 1 if $n == 1 || ($n < $maxd && Mis_prime(2*$n+1)); |
|
|
|
|
66
|
|
|
|
|
|
2968
|
8
|
|
|
|
|
874
|
for my $d (Mdivisors($n)) { |
|
2969
|
67
|
100
|
|
|
|
1689
|
last if $d >= $maxd; |
|
2970
|
63
|
100
|
|
|
|
1949
|
my $p = ($d < (INTMAX >> 2)) ? ($d << 1) + 1 : |
|
2971
|
|
|
|
|
|
|
Madd1int(Mlshiftint($d)); |
|
2972
|
63
|
100
|
|
|
|
2312
|
next unless Mis_prime($p); |
|
2973
|
25
|
|
|
|
|
103
|
my $r = Mdivint($n,$d); |
|
2974
|
25
|
|
|
|
|
53
|
while (1) { |
|
2975
|
29
|
100
|
66
|
|
|
119
|
return 1 if $r == $p || _totpred($r, $d); |
|
2976
|
27
|
|
|
|
|
435
|
my($Q,$R) = divrem($r,$p); |
|
2977
|
27
|
100
|
|
|
|
113
|
last if $R != 0; |
|
2978
|
4
|
|
|
|
|
8
|
$r = $Q; |
|
2979
|
|
|
|
|
|
|
} |
|
2980
|
|
|
|
|
|
|
} |
|
2981
|
6
|
|
|
|
|
209
|
0; |
|
2982
|
|
|
|
|
|
|
} |
|
2983
|
|
|
|
|
|
|
sub is_totient { |
|
2984
|
5
|
|
|
5
|
0
|
1718
|
my($n) = @_; |
|
2985
|
5
|
|
|
|
|
52
|
validate_integer($n); |
|
2986
|
5
|
50
|
|
|
|
22
|
return 0+($n==1) if $n <= 1; |
|
2987
|
5
|
|
|
|
|
737
|
return _totpred($n,$n); |
|
2988
|
|
|
|
|
|
|
} |
|
2989
|
|
|
|
|
|
|
|
|
2990
|
|
|
|
|
|
|
|
|
2991
|
|
|
|
|
|
|
sub _moebius_range { |
|
2992
|
371
|
|
|
371
|
|
778
|
my($lo, $hi) = @_; |
|
2993
|
371
|
|
|
|
|
1005
|
validate_integer($lo); |
|
2994
|
371
|
|
|
|
|
768
|
validate_integer($hi); |
|
2995
|
371
|
50
|
|
|
|
773
|
return () if $hi < $lo; |
|
2996
|
371
|
50
|
|
|
|
1232
|
return moebius($lo) if $lo == $hi; |
|
2997
|
371
|
100
|
|
|
|
1142
|
if ($lo < 0) { |
|
2998
|
2
|
100
|
|
|
|
8
|
if ($hi < 0) { |
|
2999
|
1
|
|
|
|
|
7
|
return reverse(_moebius_range(-$hi,-$lo)); |
|
3000
|
|
|
|
|
|
|
} else { |
|
3001
|
1
|
|
|
|
|
5
|
return (reverse(_moebius_range(1,-$lo)), _moebius_range(0,$hi)); |
|
3002
|
|
|
|
|
|
|
} |
|
3003
|
|
|
|
|
|
|
} |
|
3004
|
369
|
|
|
|
|
601
|
my @mu; |
|
3005
|
369
|
100
|
|
|
|
921
|
if ($hi > 2**32) { |
|
3006
|
2
|
50
|
|
|
|
394
|
($lo,$hi) = (tobigint($lo),tobigint($hi)) if $hi > 2**49; |
|
3007
|
2
|
|
|
|
|
6
|
push @mu, moebius($lo++) while $lo <= $hi; |
|
3008
|
2
|
|
|
|
|
509
|
return @mu; |
|
3009
|
|
|
|
|
|
|
} |
|
3010
|
367
|
|
|
|
|
935
|
for (my $i = $lo; $i <= $hi; $i++) { push @mu, 1; } |
|
|
17233
|
|
|
|
|
22194
|
|
|
3011
|
367
|
100
|
|
|
|
849
|
$mu[0] = 0 if $lo == 0; |
|
3012
|
367
|
|
|
|
|
1179
|
my($p, $sqrtn) = (2, Msqrtint($hi)); |
|
3013
|
367
|
|
|
|
|
1205
|
while ($p <= $sqrtn) { |
|
3014
|
223
|
|
|
|
|
459
|
my $i = $p * $p; |
|
3015
|
223
|
100
|
|
|
|
463
|
$i = $i * int($lo/$i) + (($lo % $i) ? $i : 0) if $i < $lo; |
|
|
|
100
|
|
|
|
|
|
|
3016
|
223
|
|
|
|
|
473
|
while ($i <= $hi) { |
|
3017
|
7150
|
|
|
|
|
9632
|
$mu[$i-$lo] = 0; |
|
3018
|
7150
|
|
|
|
|
11514
|
$i += $p * $p; |
|
3019
|
|
|
|
|
|
|
} |
|
3020
|
223
|
|
|
|
|
329
|
$i = $p; |
|
3021
|
223
|
100
|
|
|
|
495
|
$i = $i * int($lo/$i) + (($lo % $i) ? $i : 0) if $i < $lo; |
|
|
|
100
|
|
|
|
|
|
|
3022
|
223
|
|
|
|
|
470
|
while ($i <= $hi) { |
|
3023
|
28475
|
|
|
|
|
43082
|
$mu[$i-$lo] *= -$p; |
|
3024
|
28475
|
|
|
|
|
51778
|
$i += $p; |
|
3025
|
|
|
|
|
|
|
} |
|
3026
|
223
|
|
|
|
|
702
|
$p = Mnext_prime($p); |
|
3027
|
|
|
|
|
|
|
} |
|
3028
|
367
|
|
|
|
|
834
|
for (my $i = $lo; $i <= $hi; $i++) { |
|
3029
|
17233
|
|
|
|
|
27011
|
my $m = $mu[$i-$lo]; |
|
3030
|
17233
|
100
|
|
|
|
31704
|
$m *= -1 if abs($m) != $i; |
|
3031
|
17233
|
|
|
|
|
36989
|
$mu[$i-$lo] = ($m>0) - ($m<0); |
|
3032
|
|
|
|
|
|
|
} |
|
3033
|
367
|
|
|
|
|
3500
|
return @mu; |
|
3034
|
|
|
|
|
|
|
} |
|
3035
|
|
|
|
|
|
|
|
|
3036
|
|
|
|
|
|
|
sub _omertens { |
|
3037
|
9
|
|
|
9
|
|
32
|
my($n) = @_; |
|
3038
|
|
|
|
|
|
|
# This is the most basic Deléglise and Rivat algorithm. u = n^1/2 |
|
3039
|
|
|
|
|
|
|
# and no segmenting is done. Their algorithm uses u = n^1/3, breaks |
|
3040
|
|
|
|
|
|
|
# the summation into two parts, and calculates those in segments. Their |
|
3041
|
|
|
|
|
|
|
# computation time growth is half of this code. |
|
3042
|
9
|
50
|
|
|
|
34
|
return $n if $n <= 1; |
|
3043
|
9
|
|
|
|
|
30
|
my $u = int(sqrt($n)); |
|
3044
|
9
|
|
|
|
|
62
|
my @mu = (0, Mmoebius(1, $u)); # Hold values of mu for 0-u |
|
3045
|
9
|
|
|
|
|
37
|
my $musum = 0; |
|
3046
|
9
|
|
|
|
|
33
|
my @M = map { $musum += $_; } @mu; # Hold values of M for 0-u |
|
|
238
|
|
|
|
|
409
|
|
|
3047
|
9
|
|
|
|
|
37
|
my $sum = $M[$u]; |
|
3048
|
9
|
|
|
|
|
32
|
foreach my $m (1 .. $u) { |
|
3049
|
229
|
100
|
|
|
|
615
|
next if $mu[$m] == 0; |
|
3050
|
148
|
|
|
|
|
231
|
my $inner_sum = 0; |
|
3051
|
148
|
|
|
|
|
312
|
my $lower = int($u/$m) + 1; |
|
3052
|
148
|
|
|
|
|
307
|
my $last_nmk = int($n/($m*$lower)); |
|
3053
|
148
|
|
|
|
|
390
|
my ($denom, $this_k, $next_k) = ($m, 0, int($n/($m*1))); |
|
3054
|
148
|
|
|
|
|
326
|
for my $nmk (1 .. $last_nmk) { |
|
3055
|
9754
|
|
|
|
|
16264
|
$denom += $m; |
|
3056
|
9754
|
|
|
|
|
15662
|
$this_k = int($n/$denom); |
|
3057
|
9754
|
100
|
|
|
|
23763
|
next if $this_k == $next_k; |
|
3058
|
3995
|
|
|
|
|
7171
|
($this_k, $next_k) = ($next_k, $this_k); |
|
3059
|
3995
|
|
|
|
|
16009
|
$inner_sum += $M[$nmk] * ($this_k - $next_k); |
|
3060
|
|
|
|
|
|
|
} |
|
3061
|
148
|
|
|
|
|
351
|
$sum -= $mu[$m] * $inner_sum; |
|
3062
|
|
|
|
|
|
|
} |
|
3063
|
9
|
|
|
|
|
169
|
return $sum; |
|
3064
|
|
|
|
|
|
|
} |
|
3065
|
|
|
|
|
|
|
|
|
3066
|
|
|
|
|
|
|
sub _rmertens { |
|
3067
|
1173
|
|
|
1173
|
|
2523
|
my($n, $Mref, $Href, $size) = @_; |
|
3068
|
1173
|
50
|
|
|
|
2602
|
return $Mref->[$n] if $n <= $size; |
|
3069
|
1173
|
100
|
|
|
|
4874
|
return $Href->{$n} if exists $Href->{$n}; |
|
3070
|
304
|
|
|
|
|
973
|
my $s = Msqrtint($n); |
|
3071
|
304
|
|
|
|
|
811
|
my $ns = int($n/($s+1)); |
|
3072
|
|
|
|
|
|
|
|
|
3073
|
304
|
|
|
|
|
1108
|
my ($nk, $nk1) = ($n, Mrshiftint($n)); |
|
3074
|
304
|
|
|
|
|
890
|
my $SUM = Msubint(1,Msubint($nk,$nk1)); |
|
3075
|
304
|
|
|
|
|
624
|
my @S; |
|
3076
|
304
|
|
|
|
|
797
|
foreach my $k (2 .. $ns) { |
|
3077
|
6524
|
|
|
|
|
12513
|
($nk, $nk1) = ($nk1, Mdivint($n,$k+1)); |
|
3078
|
6524
|
100
|
|
|
|
14080
|
push @S, ($nk <= $size) ? $Mref->[$nk] |
|
3079
|
|
|
|
|
|
|
: _rmertens($nk, $Mref, $Href, $size); |
|
3080
|
6524
|
|
|
|
|
12336
|
push @S, $Mref->[$k] * ($nk - $nk1); |
|
3081
|
|
|
|
|
|
|
} |
|
3082
|
304
|
100
|
|
|
|
1035
|
push @S, Mmulint($Mref->[$s], Mdivint($n,$s) - $ns) if $s > $ns; |
|
3083
|
304
|
|
|
|
|
1621
|
$SUM = Msubint($SUM, Mvecsum(@S)); |
|
3084
|
|
|
|
|
|
|
|
|
3085
|
304
|
|
|
|
|
1882
|
$Href->{$n} = $SUM; |
|
3086
|
304
|
|
|
|
|
1556
|
$SUM; |
|
3087
|
|
|
|
|
|
|
} |
|
3088
|
|
|
|
|
|
|
|
|
3089
|
|
|
|
|
|
|
sub mertens { |
|
3090
|
11
|
|
|
11
|
0
|
36
|
my($n) = @_; |
|
3091
|
11
|
|
|
|
|
56
|
validate_integer_nonneg($n); |
|
3092
|
|
|
|
|
|
|
|
|
3093
|
11
|
100
|
|
|
|
105
|
return _omertens($n) if $n < 20000; |
|
3094
|
|
|
|
|
|
|
|
|
3095
|
|
|
|
|
|
|
# Larger size would be faster, but more memory. |
|
3096
|
2
|
|
|
|
|
13
|
my $size = (Mrootint($n, 3)**2) >> 2; |
|
3097
|
2
|
50
|
|
|
|
10
|
$size = Msqrtint($n) if $size < Msqrtint($n); |
|
3098
|
|
|
|
|
|
|
|
|
3099
|
2
|
|
|
|
|
7
|
my @M = (0); |
|
3100
|
2
|
|
|
|
|
26
|
push @M, $M[-1] + $_ for Mmoebius(1, $size); |
|
3101
|
|
|
|
|
|
|
|
|
3102
|
2
|
|
|
|
|
12
|
my %seen; |
|
3103
|
2
|
|
|
|
|
28
|
return _rmertens($n, \@M, \%seen, $size); |
|
3104
|
|
|
|
|
|
|
} |
|
3105
|
|
|
|
|
|
|
|
|
3106
|
|
|
|
|
|
|
|
|
3107
|
|
|
|
|
|
|
sub ramanujan_sum { |
|
3108
|
1
|
|
|
1
|
0
|
5
|
my($k,$n) = @_; |
|
3109
|
1
|
|
|
|
|
7
|
validate_integer_nonneg($k); |
|
3110
|
1
|
|
|
|
|
4
|
validate_integer_nonneg($n); |
|
3111
|
1
|
50
|
33
|
|
|
8
|
return 0 if $k < 1 || $n < 1; |
|
3112
|
1
|
|
|
|
|
9
|
my $g = $k / Mgcd($k,$n); |
|
3113
|
1
|
|
|
|
|
8
|
my $m = Mmoebius($g); |
|
3114
|
1
|
50
|
33
|
|
|
9
|
return $m if $m == 0 || $k == $g; |
|
3115
|
1
|
|
|
|
|
7
|
$m * (Mtotient($k) / Mtotient($g)); |
|
3116
|
|
|
|
|
|
|
} |
|
3117
|
|
|
|
|
|
|
|
|
3118
|
|
|
|
|
|
|
sub liouville { |
|
3119
|
4
|
|
|
4
|
0
|
4346
|
my($n) = @_; |
|
3120
|
4
|
|
|
|
|
34
|
validate_integer_nonneg($n); |
|
3121
|
4
|
100
|
|
|
|
137
|
return (scalar Mfactor($n)) & 1 ? -1 : 1; |
|
3122
|
|
|
|
|
|
|
} |
|
3123
|
|
|
|
|
|
|
|
|
3124
|
|
|
|
|
|
|
sub sumliouville { |
|
3125
|
1
|
|
|
1
|
0
|
4
|
my($n) = @_; |
|
3126
|
1
|
|
|
|
|
15
|
validate_integer_nonneg($n); |
|
3127
|
1
|
50
|
|
|
|
15
|
return (0,1,0,-1,0,-1,0,-1,-2,-1,0,-1,-2,-3,-2,-1)[$n] if $n < 16; |
|
3128
|
|
|
|
|
|
|
|
|
3129
|
|
|
|
|
|
|
# Build the Mertens lookup info once. |
|
3130
|
1
|
|
|
|
|
8
|
my $sqrtn = Msqrtint($n); |
|
3131
|
1
|
|
|
|
|
36
|
my $size = (Mrootint($n, 3)**2) >> 2; |
|
3132
|
1
|
50
|
|
|
|
19
|
$size = $sqrtn if $size < $sqrtn; |
|
3133
|
1
|
|
|
|
|
3
|
my %seen; |
|
3134
|
1
|
|
|
|
|
4
|
my @M = (0); |
|
3135
|
1
|
|
|
|
|
8
|
push @M, $M[-1] + $_ for Mmoebius(1, $size); |
|
3136
|
|
|
|
|
|
|
|
|
3137
|
|
|
|
|
|
|
# L(n) = sum[k=1..sqrt(n)](Mertens(n/(k^2))) |
|
3138
|
1
|
|
|
|
|
18
|
my $L = 0; |
|
3139
|
1
|
|
|
|
|
4
|
for my $k (1 .. $sqrtn) { |
|
3140
|
|
|
|
|
|
|
#my $nk = Mdivint($n, Mmulint($k,$k)); |
|
3141
|
53
|
|
|
|
|
112
|
my $nk = int($n/($k*$k)); |
|
3142
|
53
|
100
|
|
|
|
167
|
return Mvecsum($L, $sqrtn, -$k, 1) if $nk == 1; |
|
3143
|
52
|
100
|
|
|
|
175
|
$L = Maddint($L,($nk <= $size) ? $M[$nk] : _rmertens($nk,\@M,\%seen,$size)); |
|
3144
|
|
|
|
|
|
|
} |
|
3145
|
0
|
|
|
|
|
0
|
return $L; |
|
3146
|
|
|
|
|
|
|
} |
|
3147
|
|
|
|
|
|
|
|
|
3148
|
|
|
|
|
|
|
# Exponential of Mangoldt function (A014963). |
|
3149
|
|
|
|
|
|
|
# Return p if n = p^m [p prime, m >= 1], 1 otherwise. |
|
3150
|
|
|
|
|
|
|
sub exp_mangoldt { |
|
3151
|
5
|
|
|
5
|
0
|
16
|
my($n) = @_; |
|
3152
|
5
|
|
|
|
|
24
|
validate_integer_nonneg($n); |
|
3153
|
5
|
50
|
|
|
|
15
|
return 1 if $n <= 1; |
|
3154
|
5
|
100
|
|
|
|
39
|
if (Mis_prime_power($n, \my $p)) { |
|
3155
|
3
|
|
|
|
|
40
|
return $p; |
|
3156
|
|
|
|
|
|
|
} |
|
3157
|
2
|
|
|
|
|
15
|
1; |
|
3158
|
|
|
|
|
|
|
} |
|
3159
|
|
|
|
|
|
|
|
|
3160
|
|
|
|
|
|
|
sub carmichael_lambda { |
|
3161
|
2
|
|
|
2
|
0
|
1095
|
my($n) = @_; |
|
3162
|
2
|
|
|
|
|
11
|
validate_integer_nonneg($n); |
|
3163
|
2
|
50
|
|
|
|
51
|
return Mtotient($n) if $n < 8; # = phi(n) for n < 8 |
|
3164
|
2
|
50
|
|
|
|
164
|
return $n >> 2 if ($n & ($n-1)) == 0; # = phi(n)/2 = n/4 for 2^k, k>2 |
|
3165
|
|
|
|
|
|
|
|
|
3166
|
2
|
|
|
|
|
929
|
my @pe = Mfactor_exp($n); |
|
3167
|
2
|
50
|
33
|
|
|
33
|
$pe[0]->[1]-- if $pe[0]->[0] == 2 && $pe[0]->[1] > 2; |
|
3168
|
|
|
|
|
|
|
|
|
3169
|
2
|
|
|
|
|
5
|
Mlcm( map { Mmulint(Mpowint($_->[0],$_->[1]-1),$_->[0]-1) } @pe ); |
|
|
14
|
|
|
|
|
63
|
|
|
3170
|
|
|
|
|
|
|
} |
|
3171
|
|
|
|
|
|
|
|
|
3172
|
|
|
|
|
|
|
sub is_cyclic { |
|
3173
|
2
|
|
|
2
|
0
|
7
|
my($n) = @_; |
|
3174
|
2
|
|
|
|
|
11
|
validate_integer($n); |
|
3175
|
|
|
|
|
|
|
|
|
3176
|
2
|
50
|
|
|
|
8
|
return 0+($n > 0) if $n < 4; |
|
3177
|
2
|
50
|
|
|
|
7
|
return 0 if ($n % 2) == 0; |
|
3178
|
2
|
50
|
66
|
|
|
23
|
return 0 if (!($n % 9) || !($n%25) || !($n%49) || !($n%121)); |
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
3179
|
1
|
50
|
33
|
|
|
41
|
return 0 if (!($n %21) || !($n%39) || !($n%55) || !($n%57) || !($n%93)); |
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
3180
|
|
|
|
|
|
|
|
|
3181
|
1
|
50
|
|
|
|
10
|
return 1 if Mgcd($n,Mtotient($n)) == 1; |
|
3182
|
0
|
|
|
|
|
0
|
0; |
|
3183
|
|
|
|
|
|
|
} |
|
3184
|
|
|
|
|
|
|
|
|
3185
|
|
|
|
|
|
|
sub is_carmichael { |
|
3186
|
8
|
|
|
8
|
0
|
69
|
my($n) = @_; |
|
3187
|
8
|
|
|
|
|
84
|
validate_integer($n); |
|
3188
|
8
|
50
|
33
|
|
|
43
|
return 0 if $n < 561 || ($n % 2) == 0; |
|
3189
|
|
|
|
|
|
|
|
|
3190
|
|
|
|
|
|
|
return reftyped($_[0], Math::Prime::Util::GMP::is_carmichael($n)) |
|
3191
|
8
|
50
|
|
|
|
2200
|
if $Math::Prime::Util::_GMPfunc{"is_carmichael"}; |
|
3192
|
|
|
|
|
|
|
|
|
3193
|
|
|
|
|
|
|
# This works fine, but very slow |
|
3194
|
|
|
|
|
|
|
# return !is_prime($n) && ($n % carmichael_lambda($n)) == 1; |
|
3195
|
|
|
|
|
|
|
|
|
3196
|
8
|
50
|
100
|
|
|
59
|
return 0 if (!($n % 9) || !($n % 25) || !($n%49) || !($n%121)); |
|
|
|
|
66
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
3197
|
|
|
|
|
|
|
|
|
3198
|
|
|
|
|
|
|
# Check Korselt's criterion for small divisors |
|
3199
|
6
|
|
|
|
|
3752
|
my $fn = $n; |
|
3200
|
6
|
|
|
|
|
35
|
for my $a (5,7,11,13,17,19,23,29,31,37,41,43) { |
|
3201
|
62
|
100
|
|
|
|
14406
|
if (($fn % $a) == 0) { |
|
3202
|
17
|
100
|
|
|
|
6452
|
return 0 if (($n-1) % ($a-1)) != 0; # Korselt |
|
3203
|
16
|
|
|
|
|
10452
|
$fn /= $a; |
|
3204
|
16
|
50
|
|
|
|
5589
|
return 0 unless $fn % $a; # not square free |
|
3205
|
|
|
|
|
|
|
} |
|
3206
|
|
|
|
|
|
|
} |
|
3207
|
5
|
100
|
|
|
|
1197
|
return 0 if Mpowmod(2, $n-1, $n) != 1; |
|
3208
|
|
|
|
|
|
|
|
|
3209
|
|
|
|
|
|
|
# After pre-tests, it's reasonably likely $n is a Carmichael number or prime |
|
3210
|
|
|
|
|
|
|
|
|
3211
|
|
|
|
|
|
|
# Use probabilistic test if too large to reasonably factor. |
|
3212
|
4
|
50
|
|
|
|
287
|
if (length($fn) > 50) { |
|
3213
|
0
|
0
|
|
|
|
0
|
return 0 if Mis_prime($n); |
|
3214
|
0
|
|
|
|
|
0
|
for my $t (13 .. 150) { |
|
3215
|
0
|
|
|
|
|
0
|
my $a = $_primes_small[$t]; |
|
3216
|
0
|
|
|
|
|
0
|
my $gcd = Mgcd($a, $fn); |
|
3217
|
0
|
0
|
|
|
|
0
|
if ($gcd == 1) { |
|
3218
|
0
|
0
|
|
|
|
0
|
return 0 if Mpowmod($a, $n-1, $n) != 1; |
|
3219
|
|
|
|
|
|
|
} else { |
|
3220
|
0
|
0
|
|
|
|
0
|
return 0 if $gcd != $a; # Not square free |
|
3221
|
0
|
0
|
|
|
|
0
|
return 0 if (($n-1) % ($a-1)) != 0; # factor doesn't divide |
|
3222
|
0
|
|
|
|
|
0
|
$fn /= $a; |
|
3223
|
|
|
|
|
|
|
} |
|
3224
|
|
|
|
|
|
|
} |
|
3225
|
0
|
|
|
|
|
0
|
return 1; |
|
3226
|
|
|
|
|
|
|
} |
|
3227
|
|
|
|
|
|
|
|
|
3228
|
|
|
|
|
|
|
# Verify with factoring. |
|
3229
|
4
|
|
|
|
|
115
|
my @pe = Mfactor_exp($n); |
|
3230
|
4
|
100
|
|
|
|
50
|
return 0 if scalar(@pe) < 3; |
|
3231
|
3
|
|
|
|
|
10
|
for my $pe (@pe) { |
|
3232
|
34
|
50
|
33
|
|
|
25210
|
return 0 if $pe->[1] > 1 || (($n-1) % ($pe->[0]-1)) != 0; |
|
3233
|
|
|
|
|
|
|
} |
|
3234
|
3
|
|
|
|
|
1720
|
1; |
|
3235
|
|
|
|
|
|
|
} |
|
3236
|
|
|
|
|
|
|
|
|
3237
|
|
|
|
|
|
|
sub is_quasi_carmichael { |
|
3238
|
3
|
|
|
3
|
0
|
10
|
my($n) = @_; |
|
3239
|
3
|
|
|
|
|
16
|
validate_integer_nonneg($n); |
|
3240
|
|
|
|
|
|
|
|
|
3241
|
3
|
50
|
|
|
|
20
|
return 0 if $n < 35; |
|
3242
|
3
|
50
|
33
|
|
|
38
|
return 0 if (!($n % 4) || !($n % 9) || !($n % 25) || !($n%49) || !($n%121)); |
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
3243
|
|
|
|
|
|
|
|
|
3244
|
3
|
|
|
|
|
13
|
my @pe = Mfactor_exp($n); |
|
3245
|
|
|
|
|
|
|
# Not quasi-Carmichael if prime |
|
3246
|
3
|
50
|
|
|
|
37
|
return 0 if scalar(@pe) < 2; |
|
3247
|
|
|
|
|
|
|
# Not quasi-Carmichael if not square free |
|
3248
|
3
|
|
|
|
|
9
|
for my $pe (@pe) { |
|
3249
|
7
|
50
|
|
|
|
32
|
return 0 if $pe->[1] > 1; |
|
3250
|
|
|
|
|
|
|
} |
|
3251
|
3
|
|
|
|
|
6
|
my @f = map { $_->[0] } @pe; |
|
|
7
|
|
|
|
|
25
|
|
|
3252
|
3
|
|
|
|
|
16
|
my $nbases = 0; |
|
3253
|
3
|
100
|
|
|
|
12
|
if ($n < 2000) { |
|
3254
|
|
|
|
|
|
|
# In theory for performance, but mainly keeping to show direct method. |
|
3255
|
1
|
|
|
|
|
5
|
my $lim = $f[-1]; |
|
3256
|
1
|
|
|
|
|
5
|
$lim = (($n-$lim*$lim) + $lim - 1) / $lim; |
|
3257
|
1
|
|
|
|
|
4
|
for my $b (1 .. $f[0]-1) { |
|
3258
|
36
|
|
|
|
|
44
|
my $nb = $n - $b; |
|
3259
|
36
|
100
|
|
43
|
|
118
|
$nbases++ if Mvecall(sub { $nb % ($_-$b) == 0 }, @f); |
|
|
43
|
|
|
|
|
172
|
|
|
3260
|
|
|
|
|
|
|
} |
|
3261
|
1
|
50
|
|
|
|
5
|
if (scalar(@f) > 2) { |
|
3262
|
0
|
|
|
|
|
0
|
for my $b (1 .. $lim-1) { |
|
3263
|
0
|
|
|
|
|
0
|
my $nb = $n + $b; |
|
3264
|
0
|
0
|
|
0
|
|
0
|
$nbases++ if Mvecall(sub { $nb % ($_+$b) == 0 }, @f); |
|
|
0
|
|
|
|
|
0
|
|
|
3265
|
|
|
|
|
|
|
} |
|
3266
|
|
|
|
|
|
|
} |
|
3267
|
|
|
|
|
|
|
} else { |
|
3268
|
2
|
|
|
|
|
8
|
my($spf,$lpf) = ($f[0], $f[-1]); |
|
3269
|
2
|
100
|
|
|
|
22
|
if (scalar(@f) == 2) { |
|
3270
|
1
|
|
|
|
|
10
|
foreach my $d (Mdivisors($n/$spf - 1)) { |
|
3271
|
8
|
|
|
|
|
15
|
my $k = $spf - $d; |
|
3272
|
8
|
|
|
|
|
30
|
my $p = $n - $k; |
|
3273
|
8
|
100
|
|
|
|
18
|
last if $d >= $spf; |
|
3274
|
7
|
50
|
|
14
|
|
45
|
$nbases++ if Mvecall(sub { my $j = $_-$k; $j && ($p % $j) == 0 }, @f); |
|
|
14
|
100
|
|
|
|
18
|
|
|
|
14
|
|
|
|
|
78
|
|
|
3275
|
|
|
|
|
|
|
} |
|
3276
|
|
|
|
|
|
|
} else { |
|
3277
|
1
|
|
|
|
|
9
|
foreach my $d (Mdivisors($lpf * ($n/$lpf - 1))) { |
|
3278
|
36
|
|
|
|
|
85
|
my $k = $lpf - $d; |
|
3279
|
36
|
|
|
|
|
56
|
my $p = $n - $k; |
|
3280
|
36
|
100
|
100
|
|
|
121
|
next if $k == 0 || $k >= $spf; |
|
3281
|
23
|
50
|
|
27
|
|
99
|
$nbases++ if Mvecall(sub { my $j = $_-$k; $j && ($p % $j) == 0 }, @f); |
|
|
27
|
100
|
|
|
|
45
|
|
|
|
27
|
|
|
|
|
165
|
|
|
3282
|
|
|
|
|
|
|
} |
|
3283
|
|
|
|
|
|
|
} |
|
3284
|
|
|
|
|
|
|
} |
|
3285
|
3
|
|
|
|
|
67
|
$nbases; |
|
3286
|
|
|
|
|
|
|
} |
|
3287
|
|
|
|
|
|
|
|
|
3288
|
|
|
|
|
|
|
sub is_pillai { |
|
3289
|
1
|
|
|
1
|
0
|
5
|
my($p) = @_; |
|
3290
|
1
|
|
|
|
|
5
|
validate_integer($p); |
|
3291
|
1
|
50
|
|
|
|
5
|
return 0 if $p < 23; |
|
3292
|
1
|
50
|
33
|
|
|
18
|
return 0 unless $p % 2 && $p % 3 && $p % 5 && $p % 7; |
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
3293
|
|
|
|
|
|
|
|
|
3294
|
1
|
|
|
|
|
3
|
my $pm1 = $p-1; |
|
3295
|
1
|
|
|
|
|
4
|
my $nfac = 5040 % $p; |
|
3296
|
1
|
|
|
|
|
6
|
for (my $n = 8; $n < $p; $n++) { |
|
3297
|
11
|
|
|
|
|
37
|
$nfac = Mmulmod($nfac, $n, $p); |
|
3298
|
11
|
100
|
66
|
|
|
62
|
return $n if $nfac == $pm1 && ($p % $n) != 1; |
|
3299
|
|
|
|
|
|
|
} |
|
3300
|
0
|
|
|
|
|
0
|
0; |
|
3301
|
|
|
|
|
|
|
} |
|
3302
|
|
|
|
|
|
|
|
|
3303
|
|
|
|
|
|
|
sub is_fundamental { |
|
3304
|
4
|
|
|
4
|
0
|
36
|
my($n) = @_; |
|
3305
|
4
|
|
|
|
|
45
|
validate_integer($n); |
|
3306
|
4
|
|
|
|
|
16
|
my $neg = ($n < 0); |
|
3307
|
4
|
100
|
|
|
|
664
|
$n = -$n if $neg; |
|
3308
|
4
|
|
|
|
|
203
|
my $r = $n & 15; |
|
3309
|
4
|
50
|
|
|
|
1200
|
if ($r) { |
|
3310
|
4
|
|
|
|
|
110
|
my $r4 = $r & 3; |
|
3311
|
4
|
100
|
|
|
|
902
|
if (!$neg) { |
|
3312
|
2
|
50
|
|
|
|
35
|
return (($r == 4) ? 0 : Mis_square_free($n >> 2)) if $r4 == 0; |
|
|
|
100
|
|
|
|
|
|
|
3313
|
1
|
50
|
|
|
|
241
|
return Mis_square_free($n) if $r4 == 1; |
|
3314
|
|
|
|
|
|
|
} else { |
|
3315
|
2
|
50
|
|
|
|
21
|
return (($r == 12) ? 0 : Mis_square_free($n >> 2)) if $r4 == 0; |
|
|
|
100
|
|
|
|
|
|
|
3316
|
1
|
50
|
|
|
|
235
|
return Mis_square_free($n) if $r4 == 3; |
|
3317
|
|
|
|
|
|
|
} |
|
3318
|
|
|
|
|
|
|
} |
|
3319
|
0
|
|
|
|
|
0
|
0; |
|
3320
|
|
|
|
|
|
|
} |
|
3321
|
|
|
|
|
|
|
|
|
3322
|
|
|
|
|
|
|
my @_ds_overflow = # We'll use BigInt math if the input is larger than this. |
|
3323
|
|
|
|
|
|
|
(~0 > 4294967295) |
|
3324
|
|
|
|
|
|
|
? (124, 3000000000000000000, 3000000000, 2487240, 64260, 7026) |
|
3325
|
|
|
|
|
|
|
: ( 50, 845404560, 52560, 1548, 252, 84); |
|
3326
|
|
|
|
|
|
|
sub divisor_sum { |
|
3327
|
930
|
|
|
930
|
0
|
80227
|
my($n, $k) = @_; |
|
3328
|
930
|
|
|
|
|
2421
|
validate_integer_nonneg($n); |
|
3329
|
930
|
50
|
|
|
|
2495
|
return 0 if $n == 0; |
|
3330
|
|
|
|
|
|
|
|
|
3331
|
930
|
100
|
100
|
|
|
5409
|
if (defined $k && ref($k) eq 'CODE') { |
|
3332
|
916
|
|
|
|
|
1370
|
my $sum = $n-$n; |
|
3333
|
916
|
|
|
|
|
1741
|
my $refn = ref($n); |
|
3334
|
916
|
|
|
|
|
4020
|
foreach my $d (Mdivisors($n)) { |
|
3335
|
3571
|
100
|
|
|
|
24305
|
$sum += $k->( $refn ? $refn->new("$d") : $d ); |
|
3336
|
|
|
|
|
|
|
} |
|
3337
|
916
|
|
|
|
|
10565
|
return $sum; |
|
3338
|
|
|
|
|
|
|
} |
|
3339
|
14
|
50
|
|
|
|
43
|
return 1 if $n == 1; |
|
3340
|
|
|
|
|
|
|
|
|
3341
|
14
|
50
|
66
|
|
|
1001
|
croak "Second argument must be a code ref or number" |
|
3342
|
|
|
|
|
|
|
unless !defined $k || validate_integer_nonneg($k); |
|
3343
|
14
|
100
|
|
|
|
244
|
$k = 1 if !defined $k; |
|
3344
|
|
|
|
|
|
|
|
|
3345
|
|
|
|
|
|
|
return reftyped($_[0], Math::Prime::Util::GMP::sigma($n, $k)) |
|
3346
|
14
|
50
|
|
|
|
53
|
if $Math::Prime::Util::_GMPfunc{"sigma"}; |
|
3347
|
|
|
|
|
|
|
|
|
3348
|
14
|
|
|
|
|
68
|
my @factors = Mfactor_exp($n); |
|
3349
|
|
|
|
|
|
|
|
|
3350
|
14
|
100
|
|
|
|
63
|
return Mvecprod(map { $_->[1]+1 } @factors) if $k == 0; |
|
|
102
|
|
|
|
|
324
|
|
|
3351
|
|
|
|
|
|
|
|
|
3352
|
11
|
|
|
|
|
32
|
my @prod; |
|
3353
|
|
|
|
|
|
|
|
|
3354
|
11
|
100
|
|
|
|
30
|
if ($k == 1) { |
|
3355
|
4
|
|
|
|
|
11
|
foreach my $f (@factors) { |
|
3356
|
49
|
|
|
|
|
109
|
my ($p, $e) = @$f; |
|
3357
|
49
|
100
|
66
|
|
|
104
|
if ($e == 1) { |
|
|
|
100
|
|
|
|
|
|
|
3358
|
38
|
|
|
|
|
79
|
push @prod, $p+1; |
|
3359
|
|
|
|
|
|
|
} elsif ($e == 2 && $p < 65536) { |
|
3360
|
5
|
|
|
|
|
12
|
push @prod, ($p+1) + $p * $p; |
|
3361
|
|
|
|
|
|
|
} else { |
|
3362
|
6
|
|
|
|
|
10
|
push @prod, Mvecsum($p+1, map { Mpowint($p,$_) } 2..$e); |
|
|
90
|
|
|
|
|
118
|
|
|
3363
|
|
|
|
|
|
|
} |
|
3364
|
|
|
|
|
|
|
} |
|
3365
|
|
|
|
|
|
|
} else { |
|
3366
|
7
|
|
|
|
|
17
|
foreach my $f (@factors) { |
|
3367
|
51
|
|
|
|
|
81
|
my ($p, $e) = @$f; |
|
3368
|
51
|
|
|
|
|
105
|
my $pk = Mpowint($p,$k); |
|
3369
|
51
|
50
|
|
|
|
130
|
if ($e == 1) { |
|
3370
|
51
|
|
|
|
|
129
|
push @prod, Madd1int($pk); |
|
3371
|
|
|
|
|
|
|
} else { |
|
3372
|
0
|
|
|
|
|
0
|
push @prod, Mvecsum(Madd1int($pk), map { Mpowint($pk,$_) } 2..$e); |
|
|
0
|
|
|
|
|
0
|
|
|
3373
|
|
|
|
|
|
|
} |
|
3374
|
|
|
|
|
|
|
} |
|
3375
|
|
|
|
|
|
|
} |
|
3376
|
11
|
50
|
|
|
|
33
|
return $prod[0] if @prod == 1; |
|
3377
|
11
|
100
|
100
|
|
|
42
|
if ($k == 1 && $n < 845404560) { # divisor_sum(n) < 2^32 |
|
3378
|
2
|
|
|
|
|
14
|
my $r = 1; |
|
3379
|
2
|
|
|
|
|
7
|
$r *= $_ for @prod; |
|
3380
|
2
|
|
|
|
|
14
|
return $r; |
|
3381
|
|
|
|
|
|
|
} |
|
3382
|
9
|
50
|
|
|
|
468
|
return Mmulint($prod[0],$prod[1]) if @prod == 2; |
|
3383
|
9
|
|
|
|
|
252
|
Mvecprod(@prod); |
|
3384
|
|
|
|
|
|
|
} |
|
3385
|
|
|
|
|
|
|
|
|
3386
|
|
|
|
|
|
|
############################################################################# |
|
3387
|
|
|
|
|
|
|
# Lehmer prime count |
|
3388
|
|
|
|
|
|
|
# |
|
3389
|
|
|
|
|
|
|
#my @_s0 = (0); |
|
3390
|
|
|
|
|
|
|
#my @_s1 = (0,1); |
|
3391
|
|
|
|
|
|
|
#my @_s2 = (0,1,1,1,1,2); |
|
3392
|
|
|
|
|
|
|
#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); |
|
3393
|
|
|
|
|
|
|
#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); |
|
3394
|
|
|
|
|
|
|
my(@_s3,@_s4); |
|
3395
|
|
|
|
|
|
|
my @_pred5 = (1,0,1,2,3,4,5,0,1,2,3,0,1,0,1,2,3,0,1,0,1,2,3,0,1,2,3,4,5,0); |
|
3396
|
|
|
|
|
|
|
|
|
3397
|
|
|
|
|
|
|
sub _tablephi { |
|
3398
|
942
|
|
|
942
|
|
1239
|
my($x, $a) = @_; |
|
3399
|
942
|
50
|
|
|
|
2454
|
if ($a == 0) { return $x; } |
|
|
0
|
50
|
|
|
|
0
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
3400
|
0
|
|
|
|
|
0
|
elsif ($a == 1) { return $x-int($x/2); } |
|
3401
|
0
|
|
|
|
|
0
|
elsif ($a == 2) { return $x-int($x/2) - int($x/3) + int($x/6); } |
|
3402
|
4
|
|
|
|
|
38
|
elsif ($a == 3) { return 8 * int($x / 30) + $_s3[$x % 30]; } |
|
3403
|
4
|
|
|
|
|
28
|
elsif ($a == 4) { return 48 * int($x / 210) + $_s4[$x % 210]; } |
|
3404
|
2
|
|
|
|
|
13
|
elsif ($a == 5) { my $xp = int($x/11); |
|
3405
|
2
|
|
|
|
|
26
|
return ( (48 * int($x / 210) + $_s4[$x % 210]) - |
|
3406
|
|
|
|
|
|
|
(48 * int($xp / 210) + $_s4[$xp % 210]) ); } |
|
3407
|
932
|
|
|
|
|
1572
|
else { my ($xp,$x2) = (int($x/11),int($x/13)); |
|
3408
|
932
|
|
|
|
|
1202
|
my $x2p = int($x2/11); |
|
3409
|
932
|
|
|
|
|
3213
|
return ( (48 * int($x / 210) + $_s4[$x % 210]) - |
|
3410
|
|
|
|
|
|
|
(48 * int($xp / 210) + $_s4[$xp % 210]) - |
|
3411
|
|
|
|
|
|
|
(48 * int($x2 / 210) + $_s4[$x2 % 210]) + |
|
3412
|
|
|
|
|
|
|
(48 * int($x2p / 210) + $_s4[$x2p % 210]) ); } |
|
3413
|
|
|
|
|
|
|
} |
|
3414
|
|
|
|
|
|
|
|
|
3415
|
|
|
|
|
|
|
sub legendre_phi { |
|
3416
|
29
|
|
|
29
|
0
|
100
|
my ($x, $a, $primes) = @_; |
|
3417
|
29
|
|
|
|
|
131
|
validate_integer_nonneg($x); |
|
3418
|
29
|
|
|
|
|
96
|
validate_integer_nonneg($a); |
|
3419
|
29
|
100
|
|
|
|
137
|
if ($#_s3 == -1) { |
|
3420
|
2
|
|
|
|
|
12
|
@_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); |
|
3421
|
2
|
|
|
|
|
42
|
@_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); |
|
3422
|
|
|
|
|
|
|
} |
|
3423
|
29
|
100
|
|
|
|
186
|
return _tablephi($x,$a) if $a <= 6; |
|
3424
|
15
|
100
|
|
|
|
81
|
$primes = Mprimes(Mnth_prime_upper($a+1)) unless defined $primes; |
|
3425
|
15
|
0
|
|
|
|
99
|
return ($x > 0 ? 1 : 0) if $x < $primes->[$a]; |
|
|
|
50
|
|
|
|
|
|
|
3426
|
|
|
|
|
|
|
|
|
3427
|
15
|
|
|
|
|
56
|
my $sum = 0; |
|
3428
|
15
|
|
|
|
|
97
|
my %vals = ( $x => 1 ); |
|
3429
|
15
|
|
|
|
|
64
|
while ($a > 6) { |
|
3430
|
83
|
|
|
|
|
148
|
my $primea = $primes->[$a-1]; |
|
3431
|
83
|
|
|
|
|
141
|
my %newvals; |
|
3432
|
83
|
|
|
|
|
254
|
while (my($v,$c) = each %vals) { |
|
3433
|
2016
|
|
|
|
|
2679
|
my $sval = int($v / $primea); |
|
3434
|
2016
|
|
|
|
|
2382
|
$sval -= $_pred5[$sval % 30]; # Reduce sval to one with same phi. |
|
3435
|
2016
|
100
|
|
|
|
2516
|
if ($sval < $primea) { |
|
3436
|
777
|
|
|
|
|
1534
|
$sum -= $c; |
|
3437
|
|
|
|
|
|
|
} else { |
|
3438
|
1239
|
|
|
|
|
3493
|
$newvals{$sval} -= $c; |
|
3439
|
|
|
|
|
|
|
} |
|
3440
|
|
|
|
|
|
|
} |
|
3441
|
|
|
|
|
|
|
# merge newvals into vals |
|
3442
|
83
|
|
|
|
|
234
|
while (my($v,$c) = each %newvals) { |
|
3443
|
1086
|
|
|
|
|
1570
|
$vals{$v} += $c; |
|
3444
|
1086
|
50
|
|
|
|
2540
|
delete $vals{$v} if $vals{$v} == 0; |
|
3445
|
|
|
|
|
|
|
} |
|
3446
|
83
|
|
|
|
|
269
|
$a--; |
|
3447
|
|
|
|
|
|
|
} |
|
3448
|
15
|
|
|
|
|
61
|
while (my($v,$c) = each %vals) { |
|
3449
|
928
|
|
|
|
|
1359
|
$sum += $c * _tablephi($v, $a); |
|
3450
|
|
|
|
|
|
|
} |
|
3451
|
15
|
|
|
|
|
382
|
return $sum; |
|
3452
|
|
|
|
|
|
|
} |
|
3453
|
|
|
|
|
|
|
|
|
3454
|
|
|
|
|
|
|
sub _sieve_prime_count { |
|
3455
|
1677
|
|
|
1677
|
|
3206
|
my($high) = @_; |
|
3456
|
1677
|
100
|
|
|
|
2986
|
return (0,0,1,2,2,3,3)[$high] if $high < 7; |
|
3457
|
1673
|
100
|
|
|
|
3250
|
$high-- unless ($high % 2); |
|
3458
|
1673
|
|
|
|
|
2122
|
return 1 + ${_sieve_erat($high)} =~ tr/0//; |
|
|
1673
|
|
|
|
|
2908
|
|
|
3459
|
|
|
|
|
|
|
} |
|
3460
|
|
|
|
|
|
|
|
|
3461
|
|
|
|
|
|
|
sub _count_with_sieve { |
|
3462
|
9223
|
|
|
9223
|
|
14925
|
my ($sref, $low, $high) = @_; |
|
3463
|
9223
|
100
|
|
|
|
16033
|
($low, $high) = (2, $low) if !defined $high; |
|
3464
|
9223
|
|
|
|
|
11378
|
my $count = 0; |
|
3465
|
9223
|
100
|
|
|
|
12782
|
if ($low < 3) { $low = 3; $count++; } |
|
|
5884
|
|
|
|
|
6449
|
|
|
|
5884
|
|
|
|
|
6467
|
|
|
3466
|
3339
|
|
|
|
|
4411
|
else { $low |= 1; } |
|
3467
|
9223
|
100
|
|
|
|
14264
|
$high-- unless ($high % 2); |
|
3468
|
9223
|
50
|
|
|
|
13577
|
return $count if $low > $high; |
|
3469
|
9223
|
|
|
|
|
11378
|
my $sbeg = $low >> 1; |
|
3470
|
9223
|
|
|
|
|
10732
|
my $send = $high >> 1; |
|
3471
|
|
|
|
|
|
|
|
|
3472
|
9223
|
100
|
66
|
|
|
22902
|
if ( !defined $sref || $send >= length($$sref) ) { |
|
3473
|
|
|
|
|
|
|
# outside our range, so call the segment siever. |
|
3474
|
597
|
|
|
|
|
1571
|
my $seg_ref = _sieve_segment($low, $high); |
|
3475
|
597
|
|
|
|
|
3198
|
return $count + $$seg_ref =~ tr/0//; |
|
3476
|
|
|
|
|
|
|
} |
|
3477
|
8626
|
|
|
|
|
20571
|
return $count + substr($$sref, $sbeg, $send-$sbeg+1) =~ tr/0//; |
|
3478
|
|
|
|
|
|
|
} |
|
3479
|
|
|
|
|
|
|
|
|
3480
|
|
|
|
|
|
|
sub _lehmer_pi { |
|
3481
|
100
|
|
|
100
|
|
2088
|
my($x) = @_; |
|
3482
|
100
|
100
|
|
|
|
323
|
return _sieve_prime_count($x) if $x < 1_000; |
|
3483
|
|
|
|
|
|
|
|
|
3484
|
27
|
|
|
|
|
313
|
my $z = Msqrtint($x); |
|
3485
|
27
|
|
|
|
|
95
|
my $a = _lehmer_pi(Msqrtint($z)); |
|
3486
|
27
|
|
|
|
|
92
|
my $b = _lehmer_pi($z); |
|
3487
|
27
|
|
|
|
|
212
|
my $c = _lehmer_pi(Mrootint($x,3)); |
|
3488
|
|
|
|
|
|
|
|
|
3489
|
|
|
|
|
|
|
# Generate at least b primes. |
|
3490
|
27
|
50
|
|
|
|
348
|
my $bth_prime_upper = ($b <= 10) ? 29 : int("$b"*(log("$b")+log(log("$b")))) + 1; |
|
3491
|
27
|
|
|
|
|
246
|
my $primes = Mprimes( $bth_prime_upper ); |
|
3492
|
|
|
|
|
|
|
|
|
3493
|
27
|
|
|
|
|
307
|
my $sum = Mmulint(Mvecsum($b,$a,-2),Mvecsum($b,-$a,1)) >> 1; |
|
3494
|
27
|
|
|
|
|
192
|
$sum += legendre_phi($x, $a, $primes); |
|
3495
|
|
|
|
|
|
|
|
|
3496
|
|
|
|
|
|
|
# Get a big sieve for our primecounts. The C code compromises with either |
|
3497
|
|
|
|
|
|
|
# b*10 or x^3/5, as that cuts out all the inner loop sieves and about half |
|
3498
|
|
|
|
|
|
|
# of the big outer loop counts. |
|
3499
|
|
|
|
|
|
|
# Our sieve count isn't nearly as optimized here, so error on the side of |
|
3500
|
|
|
|
|
|
|
# more primes. This uses a lot more memory but saves a lot of time. |
|
3501
|
27
|
|
|
|
|
183
|
my $sref = _sieve_erat( Mdivint(Mdivint($x,$primes->[$a]),5) ); |
|
3502
|
|
|
|
|
|
|
|
|
3503
|
27
|
|
|
|
|
100
|
my ($lastw, $lastwpc) = (0,0); |
|
3504
|
27
|
|
|
|
|
511
|
foreach my $i (reverse $a+1 .. $b) { |
|
3505
|
3366
|
|
|
|
|
6294
|
my $w = int($x / $primes->[$i-1]); |
|
3506
|
3366
|
|
|
|
|
5576
|
$lastwpc += _count_with_sieve($sref,$lastw+1, $w); |
|
3507
|
3366
|
|
|
|
|
4770
|
$lastw = $w; |
|
3508
|
3366
|
|
|
|
|
4397
|
$sum -= $lastwpc; |
|
3509
|
|
|
|
|
|
|
#$sum -= _count_with_sieve($sref,$w); |
|
3510
|
3366
|
100
|
|
|
|
6187
|
if ($i <= $c) { |
|
3511
|
299
|
|
|
|
|
1201
|
my $bi = _count_with_sieve($sref,int(sqrt($w)+0.5)); |
|
3512
|
299
|
|
|
|
|
1075
|
foreach my $j ($i .. $bi) { |
|
3513
|
5558
|
|
|
|
|
12976
|
$sum = $sum - _count_with_sieve($sref,int($w / $primes->[$j-1])) + $j - 1; |
|
3514
|
|
|
|
|
|
|
} |
|
3515
|
|
|
|
|
|
|
} |
|
3516
|
|
|
|
|
|
|
} |
|
3517
|
27
|
|
|
|
|
472
|
$sum; |
|
3518
|
|
|
|
|
|
|
} |
|
3519
|
|
|
|
|
|
|
############################################################################# |
|
3520
|
|
|
|
|
|
|
|
|
3521
|
|
|
|
|
|
|
|
|
3522
|
|
|
|
|
|
|
sub prime_count { |
|
3523
|
2559
|
|
|
2559
|
0
|
32988
|
my($low,$high) = @_; |
|
3524
|
2559
|
100
|
|
|
|
4729
|
if (defined $high) { validate_integer_nonneg($low); } |
|
|
13
|
|
|
|
|
71
|
|
|
3525
|
2546
|
|
|
|
|
5712
|
else { ($low,$high) = (2, $low); } |
|
3526
|
2559
|
|
|
|
|
6698
|
validate_integer_nonneg($high); |
|
3527
|
|
|
|
|
|
|
|
|
3528
|
2559
|
100
|
100
|
|
|
8942
|
return 0 if $high < 2 || $low > $high; |
|
3529
|
|
|
|
|
|
|
|
|
3530
|
|
|
|
|
|
|
return reftyped($high, Math::Prime::Util::GMP::prime_count($low,$high)) |
|
3531
|
2557
|
0
|
0
|
|
|
6193
|
if $Math::Prime::Util::_GMPfunc{"prime_count"} |
|
|
|
|
33
|
|
|
|
|
|
3532
|
|
|
|
|
|
|
&& (ref($high) eq 'Math::BigInt' || ($high-$low) < int($low/1_000_000)); |
|
3533
|
|
|
|
|
|
|
|
|
3534
|
2557
|
|
|
|
|
3846
|
my $count = 0; |
|
3535
|
2557
|
100
|
66
|
|
|
10627
|
$count++ if ($low <= 2) && ($high >= 2); # Count 2 |
|
3536
|
2557
|
100
|
|
|
|
5571
|
$low = 3 if $low < 3; |
|
3537
|
2557
|
100
|
|
|
|
5386
|
$low++ if ($low % 2) == 0; # Make low go to odd number. |
|
3538
|
2557
|
100
|
|
|
|
5782
|
$high-- if ($high % 2) == 0; # Make high go to odd number. |
|
3539
|
2557
|
100
|
|
|
|
6020
|
return $count if $low > $high; |
|
3540
|
|
|
|
|
|
|
|
|
3541
|
2382
|
100
|
66
|
|
|
14360
|
if ( ref($low) eq 'Math::BigInt' || ref($high) eq 'Math::BigInt' |
|
|
|
|
100
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
3542
|
|
|
|
|
|
|
|| ($high-$low) < 10 |
|
3543
|
|
|
|
|
|
|
|| ($high-$low) < int($low/100_000_000_000) ) { |
|
3544
|
|
|
|
|
|
|
# Trial primes seems best. Needs some tuning. |
|
3545
|
763
|
|
|
|
|
3660
|
my $curprime = Mnext_prime($low-1); |
|
3546
|
763
|
|
|
|
|
2313
|
while ($curprime <= $high) { |
|
3547
|
1612
|
|
|
|
|
2490
|
$count++; |
|
3548
|
1612
|
|
|
|
|
3075
|
$curprime = Mnext_prime($curprime); |
|
3549
|
|
|
|
|
|
|
} |
|
3550
|
763
|
|
|
|
|
2498
|
return $count; |
|
3551
|
|
|
|
|
|
|
} |
|
3552
|
|
|
|
|
|
|
|
|
3553
|
|
|
|
|
|
|
# TODO: Needs tuning |
|
3554
|
1619
|
100
|
|
|
|
3326
|
if ($high > 50_000) { |
|
3555
|
15
|
100
|
|
|
|
87
|
if ( ($high / ($high-$low+1)) < 100 ) { |
|
3556
|
10
|
|
|
|
|
49
|
$count += _lehmer_pi($high); |
|
3557
|
10
|
100
|
|
|
|
68
|
$count -= ($low == 3) ? 1 : _lehmer_pi($low-1); |
|
3558
|
10
|
|
|
|
|
121
|
return $count; |
|
3559
|
|
|
|
|
|
|
} |
|
3560
|
|
|
|
|
|
|
} |
|
3561
|
|
|
|
|
|
|
|
|
3562
|
1609
|
100
|
|
|
|
4218
|
return (_sieve_prime_count($high) - 1 + $count) if $low == 3; |
|
3563
|
|
|
|
|
|
|
|
|
3564
|
7
|
|
|
|
|
37
|
my $sieveref = _sieve_segment($low,$high); |
|
3565
|
7
|
|
|
|
|
44
|
$count += $$sieveref =~ tr/0//; |
|
3566
|
7
|
|
|
|
|
117
|
return $count; |
|
3567
|
|
|
|
|
|
|
} |
|
3568
|
|
|
|
|
|
|
|
|
3569
|
|
|
|
|
|
|
|
|
3570
|
|
|
|
|
|
|
sub nth_prime { |
|
3571
|
37
|
|
|
37
|
0
|
18087
|
my($n) = @_; |
|
3572
|
37
|
|
|
|
|
264
|
validate_integer_nonneg($n); |
|
3573
|
|
|
|
|
|
|
|
|
3574
|
37
|
100
|
|
|
|
403
|
return undef if $n <= 0; ## no critic qw(ProhibitExplicitReturnUndef) |
|
3575
|
36
|
100
|
|
|
|
2378
|
return $_primes_small[$n] if $n <= 0+$#_primes_small; |
|
3576
|
|
|
|
|
|
|
|
|
3577
|
8
|
50
|
33
|
|
|
104
|
$n = _upgrade_to_float($n) if ref($n) || $n > MPU_MAXPRIMEIDX || $n > 2**45; |
|
|
|
|
33
|
|
|
|
|
|
3578
|
|
|
|
|
|
|
|
|
3579
|
8
|
|
|
|
|
19
|
my $prime = 0; |
|
3580
|
8
|
|
|
|
|
18
|
my $count = 1; |
|
3581
|
8
|
|
|
|
|
19
|
my $start = 3; |
|
3582
|
|
|
|
|
|
|
|
|
3583
|
8
|
|
|
|
|
90
|
my $logn = log($n); |
|
3584
|
8
|
|
|
|
|
25
|
my $loglogn = log($logn); |
|
3585
|
8
|
50
|
|
|
|
52
|
my $nth_prime_upper = ($n <= 10) ? 29 : int($n*($logn + $loglogn)) + 1; |
|
3586
|
8
|
100
|
|
|
|
33
|
if ($nth_prime_upper > 100000) { |
|
3587
|
|
|
|
|
|
|
# Use fast Lehmer prime count combined with lower bound to get close. |
|
3588
|
4
|
|
|
|
|
35
|
my $nth_prime_lower = int($n * ($logn + $loglogn - 1.0 + (($loglogn-2.10)/$logn))); |
|
3589
|
4
|
100
|
|
|
|
22
|
$nth_prime_lower-- unless $nth_prime_lower % 2; |
|
3590
|
4
|
|
|
|
|
28
|
$count = _lehmer_pi($nth_prime_lower); |
|
3591
|
4
|
|
|
|
|
20
|
$start = $nth_prime_lower + 2; |
|
3592
|
|
|
|
|
|
|
} |
|
3593
|
|
|
|
|
|
|
|
|
3594
|
|
|
|
|
|
|
{ |
|
3595
|
|
|
|
|
|
|
# Make sure incr is an even number. |
|
3596
|
8
|
100
|
|
|
|
19
|
my $incr = ($n < 1000) ? 1000 : ($n < 10000) ? 10000 : 100000; |
|
|
8
|
50
|
|
|
|
55
|
|
|
3597
|
8
|
|
|
|
|
16
|
my $sieveref; |
|
3598
|
8
|
|
|
|
|
21
|
while (1) { |
|
3599
|
20
|
|
|
|
|
159
|
$sieveref = _sieve_segment($start, $start+$incr); |
|
3600
|
20
|
|
|
|
|
398
|
my $segcount = $$sieveref =~ tr/0//; |
|
3601
|
20
|
100
|
|
|
|
147
|
last if ($count + $segcount) >= $n; |
|
3602
|
12
|
|
|
|
|
48
|
$count += $segcount; |
|
3603
|
12
|
|
|
|
|
33
|
$start += $incr+2; |
|
3604
|
|
|
|
|
|
|
} |
|
3605
|
|
|
|
|
|
|
# Our count is somewhere in this segment. Need to look for it. |
|
3606
|
8
|
|
|
|
|
24
|
$prime = $start - 2; |
|
3607
|
8
|
|
|
|
|
32
|
while ($count < $n) { |
|
3608
|
15786
|
|
|
|
|
21408
|
$prime += 2; |
|
3609
|
15786
|
100
|
|
|
|
30894
|
$count++ if !substr($$sieveref, ($prime-$start)>>1, 1); |
|
3610
|
|
|
|
|
|
|
} |
|
3611
|
|
|
|
|
|
|
} |
|
3612
|
8
|
|
|
|
|
9751
|
$prime; |
|
3613
|
|
|
|
|
|
|
} |
|
3614
|
|
|
|
|
|
|
|
|
3615
|
|
|
|
|
|
|
# The nth prime will be less or equal to this number |
|
3616
|
|
|
|
|
|
|
sub nth_prime_upper { |
|
3617
|
34
|
|
|
34
|
0
|
142
|
my($n) = @_; |
|
3618
|
34
|
|
|
|
|
103
|
validate_integer_nonneg($n); |
|
3619
|
|
|
|
|
|
|
|
|
3620
|
34
|
50
|
|
|
|
96
|
return undef if $n <= 0; ## no critic qw(ProhibitExplicitReturnUndef) |
|
3621
|
34
|
100
|
|
|
|
163
|
return $_primes_small[$n] if $n <= 0+$#_primes_small; |
|
3622
|
|
|
|
|
|
|
|
|
3623
|
29
|
50
|
33
|
|
|
193
|
$n = _upgrade_to_float($n) if ref($n) || $n > MPU_MAXPRIMEIDX || $n > 2**45; |
|
|
|
|
33
|
|
|
|
|
|
3624
|
|
|
|
|
|
|
|
|
3625
|
29
|
|
|
|
|
91
|
my $flogn = log($n); |
|
3626
|
29
|
|
|
|
|
55
|
my $flog2n = log($flogn); # Note distinction between log_2(n) and log^2(n) |
|
3627
|
|
|
|
|
|
|
|
|
3628
|
29
|
|
|
|
|
76
|
my $upper; |
|
3629
|
29
|
50
|
|
|
|
154
|
if ($n >= 46254381) { # Axler 2017 Corollary 1.2 |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
3630
|
0
|
|
|
|
|
0
|
$upper = $n * ( $flogn + $flog2n-1.0 + (($flog2n-2.00)/$flogn) - (($flog2n*$flog2n - 6*$flog2n + 10.667)/(2*$flogn*$flogn)) ); |
|
3631
|
|
|
|
|
|
|
} elsif ($n >= 8009824) { # Axler 2013 page viii Korollar G |
|
3632
|
0
|
|
|
|
|
0
|
$upper = $n * ( $flogn + $flog2n-1.0 + (($flog2n-2.00)/$flogn) - (($flog2n*$flog2n - 6*$flog2n + 10.273)/(2*$flogn*$flogn)) ); |
|
3633
|
|
|
|
|
|
|
} elsif ($n >= 688383) { # Dusart 2010 page 2 |
|
3634
|
4
|
|
|
|
|
13
|
$upper = $n * ( $flogn + $flog2n - 1.0 + (($flog2n-2.00)/$flogn) ); |
|
3635
|
|
|
|
|
|
|
} elsif ($n >= 178974) { # Dusart 2010 page 7 |
|
3636
|
0
|
|
|
|
|
0
|
$upper = $n * ( $flogn + $flog2n - 1.0 + (($flog2n-1.95)/$flogn) ); |
|
3637
|
|
|
|
|
|
|
} elsif ($n >= 39017) { # Dusart 1999 page 14 |
|
3638
|
2
|
|
|
|
|
7
|
$upper = $n * ( $flogn + $flog2n - 0.9484 ); |
|
3639
|
|
|
|
|
|
|
} elsif ($n >= 6) { # Modified Robin 1983, for 6-39016 only |
|
3640
|
23
|
|
|
|
|
70
|
$upper = $n * ( $flogn + 0.6000 * $flog2n ); |
|
3641
|
|
|
|
|
|
|
} else { |
|
3642
|
0
|
|
|
|
|
0
|
$upper = $n * ( $flogn + $flog2n ); |
|
3643
|
|
|
|
|
|
|
} |
|
3644
|
|
|
|
|
|
|
|
|
3645
|
29
|
|
|
|
|
106
|
Mtoint($upper + 1.0); |
|
3646
|
|
|
|
|
|
|
} |
|
3647
|
|
|
|
|
|
|
|
|
3648
|
|
|
|
|
|
|
# The nth prime will be greater than or equal to this number |
|
3649
|
|
|
|
|
|
|
sub nth_prime_lower { |
|
3650
|
29
|
|
|
29
|
0
|
509
|
my($n) = @_; |
|
3651
|
29
|
|
|
|
|
99
|
validate_integer_nonneg($n); |
|
3652
|
|
|
|
|
|
|
|
|
3653
|
29
|
50
|
|
|
|
86
|
return undef if $n <= 0; ## no critic qw(ProhibitExplicitReturnUndef) |
|
3654
|
29
|
50
|
|
|
|
113
|
return $_primes_small[$n] if $n <= 0+$#_primes_small; |
|
3655
|
|
|
|
|
|
|
|
|
3656
|
29
|
100
|
66
|
|
|
212
|
$n = _upgrade_to_float($n) if ref($n) || $n > MPU_MAXPRIMEIDX || $n > 2**45; |
|
|
|
|
66
|
|
|
|
|
|
3657
|
|
|
|
|
|
|
|
|
3658
|
29
|
|
|
|
|
389
|
my $flogn = log($n); |
|
3659
|
29
|
|
|
|
|
127005
|
my $flog2n = log($flogn); # Note distinction between log_2(n) and log^2(n) |
|
3660
|
|
|
|
|
|
|
|
|
3661
|
|
|
|
|
|
|
# Dusart 1999 page 14, for all n >= 2 |
|
3662
|
|
|
|
|
|
|
#my $lower = $n * ($flogn + $flog2n - 1.0 + (($flog2n-2.25)/$flogn)); |
|
3663
|
|
|
|
|
|
|
# Dusart 2010 page 2, for all n >= 3 |
|
3664
|
|
|
|
|
|
|
#my $lower = $n * ($flogn + $flog2n - 1.0 + (($flog2n-2.10)/$flogn)); |
|
3665
|
|
|
|
|
|
|
# Axler 2013 page viii Korollar I, for all n >= 2 |
|
3666
|
|
|
|
|
|
|
#my $lower = $n * ($flogn + $flog2n-1.0 + (($flog2n-2.00)/$flogn) - (($flog2n*$flog2n - 6*$flog2n + 11.847)/(2*$flogn*$flogn)) ); |
|
3667
|
|
|
|
|
|
|
# Axler 2017 Corollary 1.4 |
|
3668
|
29
|
|
|
|
|
80667
|
my $lower = $n * ($flogn + $flog2n-1.0 + (($flog2n-2.00)/$flogn) - (($flog2n*$flog2n - 6*$flog2n + 11.508)/(2*$flogn*$flogn)) ); |
|
3669
|
|
|
|
|
|
|
|
|
3670
|
29
|
|
|
|
|
14091
|
my $plower = Mtoint($lower + 0.999999999); |
|
3671
|
|
|
|
|
|
|
# We clamp to the max UV representable. |
|
3672
|
29
|
|
|
|
|
87
|
if (MPU_32BIT) { |
|
3673
|
|
|
|
|
|
|
$plower = 4294967291 if $n >= 203280221 && $plower < 4294967291; |
|
3674
|
|
|
|
|
|
|
} else { |
|
3675
|
29
|
100
|
66
|
|
|
94
|
$plower = 18446744073709551557 if $n >= 425656284035217743 && $plower < 18446744073709551557; |
|
3676
|
|
|
|
|
|
|
} |
|
3677
|
29
|
|
|
|
|
793
|
$plower; |
|
3678
|
|
|
|
|
|
|
} |
|
3679
|
|
|
|
|
|
|
|
|
3680
|
|
|
|
|
|
|
sub inverse_li_nv { |
|
3681
|
2
|
|
|
2
|
0
|
7
|
my($n) = @_; |
|
3682
|
2
|
|
|
|
|
8
|
$n = 0.0 + "$n"; |
|
3683
|
2
|
|
|
|
|
9
|
my $t = $n * log($n); |
|
3684
|
|
|
|
|
|
|
|
|
3685
|
|
|
|
|
|
|
# Iterate Halley's method until error term grows |
|
3686
|
2
|
|
|
|
|
5
|
my $old_term = MPU_INFINITY; |
|
3687
|
2
|
|
|
|
|
6
|
for my $iter (1 .. 10000) { |
|
3688
|
6
|
|
|
|
|
27
|
my $dn = MLi($t) - $n; |
|
3689
|
6
|
50
|
|
|
|
24
|
$dn = 0.0 + "$dn" if ref($dn); |
|
3690
|
6
|
|
|
|
|
15
|
my $term = $dn * log($t) / (1.0 + $dn/(2*$t)); |
|
3691
|
6
|
50
|
|
|
|
18
|
last if abs($term) >= abs($old_term); |
|
3692
|
6
|
|
|
|
|
13
|
$old_term = $term; |
|
3693
|
6
|
|
|
|
|
9
|
$t -= $term; |
|
3694
|
6
|
100
|
|
|
|
20
|
last if abs($term) < 1e-6; |
|
3695
|
|
|
|
|
|
|
} |
|
3696
|
2
|
|
|
|
|
47
|
$t; |
|
3697
|
|
|
|
|
|
|
} |
|
3698
|
|
|
|
|
|
|
|
|
3699
|
|
|
|
|
|
|
sub inverse_li { |
|
3700
|
1
|
|
|
1
|
0
|
4
|
my($n) = @_; |
|
3701
|
1
|
|
|
|
|
6
|
validate_integer_nonneg($n); |
|
3702
|
|
|
|
|
|
|
|
|
3703
|
1
|
50
|
|
|
|
5
|
return (0,2,3,5,6,8)[$n] if $n <= 5; |
|
3704
|
1
|
|
|
|
|
21
|
my $t = Math::Prime::Util::inverse_li_nv(0.0 + "$n"); |
|
3705
|
|
|
|
|
|
|
|
|
3706
|
1
|
|
|
|
|
9
|
$t = Mtoint($t + 0.5); |
|
3707
|
|
|
|
|
|
|
|
|
3708
|
|
|
|
|
|
|
# Make it an exact answer |
|
3709
|
1
|
50
|
|
|
|
19
|
my $inc = ($n > 4e16) ? 2048 : 128; |
|
3710
|
1
|
50
|
|
|
|
7
|
if (int(MLi($t-1)) >= $n) { |
|
|
|
50
|
|
|
|
|
|
|
3711
|
0
|
|
|
|
|
0
|
$t -= $inc while int(MLi($t-$inc)) >= $n; |
|
3712
|
0
|
|
|
|
|
0
|
for ($inc = $inc >> 1; $inc > 0; $inc >>= 1) { |
|
3713
|
0
|
0
|
|
|
|
0
|
$t -= $inc if int(MLi($t-$inc)) >= $n; |
|
3714
|
|
|
|
|
|
|
} |
|
3715
|
|
|
|
|
|
|
} elsif (int(MLi($t)) < $n) { |
|
3716
|
0
|
|
|
|
|
0
|
$t += $inc while int(MLi($t+$inc-1)) < $n; |
|
3717
|
0
|
|
|
|
|
0
|
for ($inc = $inc >> 1; $inc > 0; $inc >>= 1) { |
|
3718
|
0
|
0
|
|
|
|
0
|
$t += $inc if int(MLi($t+$inc-1)) < $n; |
|
3719
|
|
|
|
|
|
|
} |
|
3720
|
|
|
|
|
|
|
} |
|
3721
|
|
|
|
|
|
|
|
|
3722
|
1
|
|
|
|
|
8
|
$t; |
|
3723
|
|
|
|
|
|
|
} |
|
3724
|
|
|
|
|
|
|
sub _inverse_R { |
|
3725
|
|
|
|
|
|
|
# uncoverable subroutine |
|
3726
|
0
|
|
|
0
|
|
0
|
my($n) = @_; |
|
3727
|
0
|
|
|
|
|
0
|
validate_integer_nonneg($n); |
|
3728
|
|
|
|
|
|
|
|
|
3729
|
0
|
0
|
|
|
|
0
|
return (0,2,3,5,6,8)[$n] if $n <= 5; |
|
3730
|
0
|
0
|
0
|
|
|
0
|
$n = _upgrade_to_float($n) if ref($n) || $n > MPU_MAXPRIMEIDX || $n > 2**45; |
|
|
|
|
0
|
|
|
|
|
|
3731
|
0
|
|
|
|
|
0
|
my $t = $n * log($n); |
|
3732
|
|
|
|
|
|
|
|
|
3733
|
|
|
|
|
|
|
# Iterate Halley's method until error term grows |
|
3734
|
0
|
|
|
|
|
0
|
my $old_term = MPU_INFINITY; |
|
3735
|
0
|
|
|
|
|
0
|
for my $iter (1 .. 10000) { |
|
3736
|
0
|
|
|
|
|
0
|
my $dn = Math::Prime::Util::RiemannR($t) - $n; |
|
3737
|
0
|
|
|
|
|
0
|
my $term = $dn * log($t) / (1.0 + $dn/(2*$t)); |
|
3738
|
0
|
0
|
|
|
|
0
|
last if abs($term) >= abs($old_term); |
|
3739
|
0
|
|
|
|
|
0
|
$old_term = $term; |
|
3740
|
0
|
|
|
|
|
0
|
$t -= $term; |
|
3741
|
0
|
0
|
|
|
|
0
|
last if abs($term) < 1e-6; |
|
3742
|
|
|
|
|
|
|
} |
|
3743
|
0
|
0
|
|
|
|
0
|
Mtoint( ref($t) ? $t->bceil->bstr : $t+0.99999 ); |
|
3744
|
|
|
|
|
|
|
} |
|
3745
|
|
|
|
|
|
|
|
|
3746
|
|
|
|
|
|
|
sub nth_prime_approx { |
|
3747
|
2
|
|
|
2
|
0
|
1490
|
my($n) = @_; |
|
3748
|
2
|
|
|
|
|
10
|
validate_integer_nonneg($n); |
|
3749
|
|
|
|
|
|
|
|
|
3750
|
2
|
50
|
|
|
|
6
|
return undef if $n <= 0; ## no critic qw(ProhibitExplicitReturnUndef) |
|
3751
|
2
|
50
|
|
|
|
6
|
return $_primes_small[$n] if $n <= 0+$#_primes_small; |
|
3752
|
|
|
|
|
|
|
|
|
3753
|
|
|
|
|
|
|
# Once past 10^12 or so, inverse_li gives better results. |
|
3754
|
2
|
50
|
|
|
|
4
|
return Math::Prime::Util::inverse_li($n) if $n > 1e12; |
|
3755
|
|
|
|
|
|
|
|
|
3756
|
2
|
50
|
33
|
|
|
10
|
$n = _upgrade_to_float($n) if ref($n) || $n >= MPU_MAXPRIMEIDX; |
|
3757
|
|
|
|
|
|
|
|
|
3758
|
2
|
|
|
|
|
6
|
my $flogn = log($n); |
|
3759
|
2
|
|
|
|
|
5
|
my $flog2n = log($flogn); |
|
3760
|
|
|
|
|
|
|
|
|
3761
|
|
|
|
|
|
|
# Cipolla 1902: |
|
3762
|
|
|
|
|
|
|
# m=0 fn * ( flogn + flog2n - 1 ); |
|
3763
|
|
|
|
|
|
|
# m=1 + ((flog2n - 2)/flogn) ); |
|
3764
|
|
|
|
|
|
|
# m=2 - (((flog2n*flog2n) - 6*flog2n + 11) / (2*flogn*flogn)) |
|
3765
|
|
|
|
|
|
|
# + O((flog2n/flogn)^3) |
|
3766
|
|
|
|
|
|
|
# |
|
3767
|
|
|
|
|
|
|
# Shown in Dusart 1999 page 12, as well as other sources such as: |
|
3768
|
|
|
|
|
|
|
# http://www.emis.de/journals/JIPAM/images/153_02_JIPAM/153_02.pdf |
|
3769
|
|
|
|
|
|
|
# where the main issue you run into is that you're doing polynomial |
|
3770
|
|
|
|
|
|
|
# interpolation, so it oscillates like crazy with many high-order terms. |
|
3771
|
|
|
|
|
|
|
# Hence I'm leaving it at m=2. |
|
3772
|
|
|
|
|
|
|
|
|
3773
|
2
|
|
|
|
|
8
|
my $approx = $n * ( $flogn + $flog2n - 1 |
|
3774
|
|
|
|
|
|
|
+ (($flog2n - 2)/$flogn) |
|
3775
|
|
|
|
|
|
|
- ((($flog2n*$flog2n) - 6*$flog2n + 11) / (2*$flogn*$flogn)) |
|
3776
|
|
|
|
|
|
|
); |
|
3777
|
|
|
|
|
|
|
|
|
3778
|
|
|
|
|
|
|
# Apply a correction to help keep values close. |
|
3779
|
2
|
|
|
|
|
2
|
my $order = $flog2n/$flogn; |
|
3780
|
2
|
|
|
|
|
4
|
$order = $order*$order*$order * $n; |
|
3781
|
|
|
|
|
|
|
|
|
3782
|
2
|
50
|
|
|
|
18
|
if ($n < 259) { $approx += 10.4 * $order; } |
|
|
0
|
50
|
|
|
|
0
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
3783
|
0
|
|
|
|
|
0
|
elsif ($n < 775) { $approx += 6.3 * $order; } |
|
3784
|
0
|
|
|
|
|
0
|
elsif ($n < 1271) { $approx += 5.3 * $order; } |
|
3785
|
0
|
|
|
|
|
0
|
elsif ($n < 2000) { $approx += 4.7 * $order; } |
|
3786
|
0
|
|
|
|
|
0
|
elsif ($n < 4000) { $approx += 3.9 * $order; } |
|
3787
|
0
|
|
|
|
|
0
|
elsif ($n < 12000) { $approx += 2.8 * $order; } |
|
3788
|
0
|
|
|
|
|
0
|
elsif ($n < 150000) { $approx += 1.2 * $order; } |
|
3789
|
2
|
|
|
|
|
3
|
elsif ($n < 20000000) { $approx += 0.11 * $order; } |
|
3790
|
0
|
|
|
|
|
0
|
elsif ($n < 100000000) { $approx += 0.008 * $order; } |
|
3791
|
0
|
|
|
|
|
0
|
elsif ($n < 500000000) { $approx += -0.038 * $order; } |
|
3792
|
0
|
|
|
|
|
0
|
elsif ($n < 2000000000) { $approx += -0.054 * $order; } |
|
3793
|
0
|
|
|
|
|
0
|
else { $approx += -0.058 * $order; } |
|
3794
|
|
|
|
|
|
|
# If we want the asymptotic approximation to be >= actual, use -0.010. |
|
3795
|
|
|
|
|
|
|
|
|
3796
|
2
|
|
|
|
|
8
|
Mtoint($approx + 0.5); |
|
3797
|
|
|
|
|
|
|
} |
|
3798
|
|
|
|
|
|
|
|
|
3799
|
|
|
|
|
|
|
############################################################################# |
|
3800
|
|
|
|
|
|
|
|
|
3801
|
|
|
|
|
|
|
sub prime_count_approx { |
|
3802
|
437
|
|
|
437
|
0
|
65687
|
my($x) = @_; |
|
3803
|
437
|
|
|
|
|
931
|
validate_integer_nonneg($x); |
|
3804
|
|
|
|
|
|
|
#return (0,0,1,2,2,3,3,4,4,4,4,5,5,6,6,6)[$x] if $x < 16; |
|
3805
|
437
|
100
|
|
|
|
1193
|
return _tiny_prime_count($x) if $x < $_primes_small[-1]; |
|
3806
|
|
|
|
|
|
|
|
|
3807
|
|
|
|
|
|
|
# Turn on high precision FP if needed (TODO assumes NV >= double prec) |
|
3808
|
24
|
100
|
|
|
|
1809
|
$x = _upgrade_to_float($x) if $x > 10000000000000000; |
|
3809
|
24
|
|
|
|
|
1502
|
my $floatx = ref($x) eq 'Math::BigFloat'; |
|
3810
|
24
|
50
|
66
|
|
|
77
|
$x = "$x" if ref($x) && !$floatx; |
|
3811
|
|
|
|
|
|
|
|
|
3812
|
|
|
|
|
|
|
# Method 10^10 %error 10^19 %error |
|
3813
|
|
|
|
|
|
|
# ----------------- ------------ ------------ |
|
3814
|
|
|
|
|
|
|
# n/(log(n)-1) .22% .058% |
|
3815
|
|
|
|
|
|
|
# n/(ln(n)-1-1/ln(n)) .032% .0041% |
|
3816
|
|
|
|
|
|
|
# average bounds .0005% .0000002% |
|
3817
|
|
|
|
|
|
|
# asymp .0006% .00000004% |
|
3818
|
|
|
|
|
|
|
# li(n) .0007% .00000004% |
|
3819
|
|
|
|
|
|
|
# li(n)-li(n^.5)/2 .0004% .00000001% |
|
3820
|
|
|
|
|
|
|
# R(n) .0004% .00000001% |
|
3821
|
|
|
|
|
|
|
# |
|
3822
|
|
|
|
|
|
|
# Also consider: http://trac.sagemath.org/sage_trac/ticket/8135 |
|
3823
|
|
|
|
|
|
|
|
|
3824
|
|
|
|
|
|
|
# Asymp: |
|
3825
|
|
|
|
|
|
|
# my $l1 = log($x); my $l2 = $l1*$l1; my $l4 = $l2*$l2; |
|
3826
|
|
|
|
|
|
|
# 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 ); |
|
3827
|
|
|
|
|
|
|
# my $result = int( (prime_count_upper($x) + prime_count_lower($x)) / 2); |
|
3828
|
|
|
|
|
|
|
# my $result = int( LogarithmicIntegral($x) ); |
|
3829
|
|
|
|
|
|
|
# my $result = int(LogarithmicIntegral($x) - LogarithmicIntegral(sqrt($x))/2); |
|
3830
|
|
|
|
|
|
|
# my $result = RiemannR($x) + 0.5; |
|
3831
|
|
|
|
|
|
|
|
|
3832
|
|
|
|
|
|
|
# Make sure we get enough accuracy, and also not too much more than needed |
|
3833
|
24
|
100
|
|
|
|
78
|
$x->accuracy(length($x->copy->as_int->bstr())+2) if $floatx; |
|
3834
|
|
|
|
|
|
|
|
|
3835
|
24
|
|
|
|
|
2541
|
my $result; |
|
3836
|
24
|
100
|
66
|
|
|
157
|
if ($Math::Prime::Util::_GMPfunc{"riemannr"} || !ref($x)) { |
|
3837
|
|
|
|
|
|
|
# Fast if we have our GMP backend, and ok for native. |
|
3838
|
20
|
|
|
|
|
74
|
$result = Math::Prime::Util::PP::RiemannR($x); |
|
3839
|
|
|
|
|
|
|
} else { |
|
3840
|
4
|
50
|
|
|
|
30
|
$result = $floatx ? Math::BigFloat->bzero : 0; |
|
3841
|
4
|
50
|
|
|
|
306
|
$result->accuracy($x->accuracy) if $floatx; |
|
3842
|
4
|
|
|
|
|
372
|
$result += MLi($x); |
|
3843
|
4
|
|
|
|
|
1708
|
$result -= MLi(sqrt($x))/2; |
|
3844
|
4
|
50
|
|
|
|
8762
|
my $intx = $floatx ? tobigint($x->bfround(0)) : $x; |
|
3845
|
4
|
|
|
|
|
18
|
for my $k (3 .. 1000) { |
|
3846
|
88
|
|
|
|
|
88361
|
my $m = Mmoebius($k); |
|
3847
|
88
|
100
|
|
|
|
262
|
next unless $m != 0; |
|
3848
|
|
|
|
|
|
|
# With Math::BigFloat and the Calc backend, FP root is ungodly slow. |
|
3849
|
|
|
|
|
|
|
# Use integer root instead. For more accuracy (not useful here): |
|
3850
|
|
|
|
|
|
|
# my $v = Math::BigFloat->new( "" . Mrootint($x->as_int,$k) ); |
|
3851
|
|
|
|
|
|
|
# $v->accuracy(length($v)+5); |
|
3852
|
|
|
|
|
|
|
# $v = $v - Math::BigFloat->new(($v**$k - $x))->bdiv($k * $v**($k-1)); |
|
3853
|
|
|
|
|
|
|
# my $term = LogarithmicIntegral($v)/$k; |
|
3854
|
56
|
|
|
|
|
298
|
my $term = MLi(Mrootint($intx,$k)) / $k; |
|
3855
|
56
|
100
|
|
|
|
223
|
last if $term < .25; |
|
3856
|
52
|
100
|
|
|
|
122
|
if ($m == 1) { $result += $term; } |
|
|
22
|
|
|
|
|
111
|
|
|
3857
|
30
|
|
|
|
|
142
|
else { $result -= $term; } |
|
3858
|
|
|
|
|
|
|
} |
|
3859
|
|
|
|
|
|
|
} |
|
3860
|
|
|
|
|
|
|
|
|
3861
|
24
|
|
|
|
|
107
|
Mtoint($result+0.5); |
|
3862
|
|
|
|
|
|
|
} |
|
3863
|
|
|
|
|
|
|
|
|
3864
|
|
|
|
|
|
|
sub prime_count_lower { |
|
3865
|
470
|
|
|
470
|
0
|
9704
|
my($x) = @_; |
|
3866
|
470
|
|
|
|
|
1323
|
validate_integer_nonneg($x); |
|
3867
|
|
|
|
|
|
|
|
|
3868
|
470
|
100
|
|
|
|
2332
|
return _tiny_prime_count($x) if $x < $_primes_small[-1]; |
|
3869
|
|
|
|
|
|
|
|
|
3870
|
|
|
|
|
|
|
return reftyped($_[0], Math::Prime::Util::GMP::prime_count_lower($x)) |
|
3871
|
34
|
50
|
|
|
|
2297
|
if $Math::Prime::Util::_GMPfunc{"prime_count_lower"}; |
|
3872
|
|
|
|
|
|
|
|
|
3873
|
34
|
100
|
|
|
|
132
|
$x = _upgrade_to_float($x) if $x > 10000000000000000; |
|
3874
|
34
|
|
|
|
|
4119
|
my $floatx = ref($x) eq 'Math::BigFloat'; |
|
3875
|
34
|
50
|
66
|
|
|
173
|
$x = "$x" if ref($x) && !$floatx; |
|
3876
|
|
|
|
|
|
|
|
|
3877
|
34
|
|
|
|
|
73
|
my($result,$a); |
|
3878
|
34
|
|
|
|
|
147
|
my $fl1 = log($x); |
|
3879
|
34
|
|
|
|
|
1376272
|
my $fl2 = $fl1*$fl1; |
|
3880
|
34
|
100
|
|
|
|
3606
|
my $one = $floatx ? $x->copy->bone : 1.0; |
|
3881
|
|
|
|
|
|
|
|
|
3882
|
|
|
|
|
|
|
# Chebyshev 1*x/logx x >= 17 |
|
3883
|
|
|
|
|
|
|
# Rosser & Schoenfeld x/(logx-1/2) x >= 67 |
|
3884
|
|
|
|
|
|
|
# Dusart 1999 x/logx*(1+1/logx+1.8/logxlogx) x >= 32299 |
|
3885
|
|
|
|
|
|
|
# Dusart 2010 x/logx*(1+1/logx+2.0/logxlogx) x >= 88783 |
|
3886
|
|
|
|
|
|
|
# Axler 2014 (1.2) ""+... x >= 1332450001 |
|
3887
|
|
|
|
|
|
|
# Axler 2014 (1.2) x/(logx-1-1/logx-...) x >= 1332479531 |
|
3888
|
|
|
|
|
|
|
# Büthe 2015 (1.9) li(x)-(sqrtx/logx)*(...) x <= 10^19 |
|
3889
|
|
|
|
|
|
|
# Büthe 2014 Th 2 li(x)-logx*sqrtx/8Pi x > 2657, x <= 1.4 * 10^25 |
|
3890
|
|
|
|
|
|
|
# Johnston 2021 Cor3.3 li(x)-logx*sqrtx/8Pi x > 2657, x <= 1.101 * 10^26 |
|
3891
|
|
|
|
|
|
|
|
|
3892
|
|
|
|
|
|
|
# Also see Dusart 2018: if RH and x >= 5639, |
|
3893
|
|
|
|
|
|
|
# |pi(x)-li(x)|<= x * (logx-loglogx)/(8*Pi*sqrtx) |
|
3894
|
|
|
|
|
|
|
# TODO: evaluate this |
|
3895
|
|
|
|
|
|
|
|
|
3896
|
34
|
50
|
33
|
|
|
1090
|
if ($x < 599) { # Decent for small numbers |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
3897
|
0
|
|
|
|
|
0
|
$result = $x / ($fl1 - 0.7); |
|
3898
|
|
|
|
|
|
|
} elsif ($x < 52600000) { # Dusart 2010 tweaked |
|
3899
|
25
|
50
|
|
|
|
270
|
if ($x < 2700) { $a = 0.30; } |
|
|
0
|
50
|
|
|
|
0
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
3900
|
0
|
|
|
|
|
0
|
elsif ($x < 5500) { $a = 0.90; } |
|
3901
|
4
|
|
|
|
|
10
|
elsif ($x < 19400) { $a = 1.30; } |
|
3902
|
0
|
|
|
|
|
0
|
elsif ($x < 32299) { $a = 1.60; } |
|
3903
|
0
|
|
|
|
|
0
|
elsif ($x < 88783) { $a = 1.83; } |
|
3904
|
0
|
|
|
|
|
0
|
elsif ($x < 176000) { $a = 1.99; } |
|
3905
|
0
|
|
|
|
|
0
|
elsif ($x < 315000) { $a = 2.11; } |
|
3906
|
1
|
|
|
|
|
2
|
elsif ($x < 1100000) { $a = 2.19; } |
|
3907
|
1
|
|
|
|
|
4
|
elsif ($x < 4500000) { $a = 2.31; } |
|
3908
|
19
|
|
|
|
|
43
|
else { $a = 2.35; } |
|
3909
|
25
|
|
|
|
|
71
|
$result = ($x/$fl1) * ($one + $one/$fl1 + $a/$fl2); |
|
3910
|
|
|
|
|
|
|
} elsif ($x < 1.1e26 || getconfig()->{'assume_rh'}){ |
|
3911
|
|
|
|
|
|
|
# Büthe 2014/2015 |
|
3912
|
9
|
|
|
|
|
15468
|
my $lix = MLi($x); |
|
3913
|
9
|
|
|
|
|
48
|
my $sqx = sqrt($x); |
|
3914
|
9
|
100
|
|
|
|
32911
|
if ($x < 1e19) { |
|
3915
|
1
|
|
|
|
|
5
|
$result = $lix - ($sqx/$fl1) * (1.94 + 3.88/$fl1 + 27.57/$fl2); |
|
3916
|
|
|
|
|
|
|
} else { |
|
3917
|
8
|
50
|
|
|
|
5239
|
if (ref($x) eq 'Math::BigFloat') { |
|
3918
|
8
|
|
|
|
|
40
|
my $xdigits = _find_big_acc($x); |
|
3919
|
8
|
|
|
|
|
57
|
$result = $lix - ($fl1*$sqx / (Math::BigFloat->bpi($xdigits)*8)); |
|
3920
|
|
|
|
|
|
|
} else { |
|
3921
|
0
|
|
|
|
|
0
|
$result = $lix - ($fl1*$sqx / PI_TIMES_8); |
|
3922
|
|
|
|
|
|
|
} |
|
3923
|
|
|
|
|
|
|
} |
|
3924
|
|
|
|
|
|
|
} else { # Axler 2014 1.4 |
|
3925
|
0
|
|
|
|
|
0
|
my($fl3,$fl4) = ($fl2*$fl1,$fl2*$fl2); |
|
3926
|
0
|
|
|
|
|
0
|
my($fl5,$fl6) = ($fl4*$fl1,$fl4*$fl2); |
|
3927
|
0
|
|
|
|
|
0
|
$result = $x / ($fl1 - $one - $one/$fl1 - 2.65/$fl2 - 13.35/$fl3 - 70.3/$fl4 - 455.6275/$fl5 - 3404.4225/$fl6); |
|
3928
|
|
|
|
|
|
|
} |
|
3929
|
|
|
|
|
|
|
# This will truncate bigfloat or floats to native int or bigint class. |
|
3930
|
34
|
|
|
|
|
35836
|
Mtoint($result); |
|
3931
|
|
|
|
|
|
|
} |
|
3932
|
|
|
|
|
|
|
|
|
3933
|
|
|
|
|
|
|
sub prime_count_upper { |
|
3934
|
474
|
|
|
474
|
0
|
2330
|
my($x) = @_; |
|
3935
|
474
|
|
|
|
|
1223
|
validate_integer_nonneg($x); |
|
3936
|
|
|
|
|
|
|
|
|
3937
|
|
|
|
|
|
|
# Give an exact answer for what we have in our little table. |
|
3938
|
474
|
100
|
|
|
|
1844
|
return _tiny_prime_count($x) if $x < $_primes_small[-1]; |
|
3939
|
|
|
|
|
|
|
|
|
3940
|
|
|
|
|
|
|
return reftyped($_[0], Math::Prime::Util::GMP::prime_count_upper($x)) |
|
3941
|
35
|
50
|
|
|
|
2075
|
if $Math::Prime::Util::_GMPfunc{"prime_count_upper"}; |
|
3942
|
|
|
|
|
|
|
|
|
3943
|
35
|
100
|
|
|
|
147
|
$x = _upgrade_to_float($x) if $x > 10000000000000000; |
|
3944
|
35
|
|
|
|
|
3315
|
my $floatx = ref($x) eq 'Math::BigFloat'; |
|
3945
|
35
|
50
|
66
|
|
|
193
|
$x = "$x" if ref($x) && !$floatx; |
|
3946
|
|
|
|
|
|
|
|
|
3947
|
|
|
|
|
|
|
# Chebyshev: 1.25506*x/logx x >= 17 |
|
3948
|
|
|
|
|
|
|
# Rosser & Schoenfeld: x/(logx-3/2) x >= 67 |
|
3949
|
|
|
|
|
|
|
# Panaitopol 1999: x/(logx-1.112) x >= 4 |
|
3950
|
|
|
|
|
|
|
# Dusart 1999: x/logx*(1+1/logx+2.51/logxlogx) x >= 355991 |
|
3951
|
|
|
|
|
|
|
# Dusart 2010: x/logx*(1+1/logx+2.334/logxlogx) x >= 2_953_652_287 |
|
3952
|
|
|
|
|
|
|
# Dusart 2018: x/lx*(1+1/lx+2/lxlx+7.59/lxlxlx) x > 1 |
|
3953
|
|
|
|
|
|
|
# Axler 2014: x/(logx-1-1/logx-3.35/logxlogx...) x >= e^3.804 |
|
3954
|
|
|
|
|
|
|
# Büthe 2014 7.4 Schoenfeld bounds hold to x <= 1.4e25 |
|
3955
|
|
|
|
|
|
|
# Axler 2017 Prop 2.2 Schoenfeld bounds hold to x <= 5.5e25 |
|
3956
|
|
|
|
|
|
|
# Johnston 2021 Cor 3.3 Schoenfeld bounds hold to x <= 1.0e26 |
|
3957
|
|
|
|
|
|
|
# Skewes li(x) x < 1e14 |
|
3958
|
|
|
|
|
|
|
|
|
3959
|
|
|
|
|
|
|
# TODO: Also look at these from Dusart (2018) [paywalled]. |
|
3960
|
|
|
|
|
|
|
# 1 If RH and x >= 5639, |pi(x)-li(x)|<= x * (logx-loglogx)/(8*Pi*sqrtx) |
|
3961
|
|
|
|
|
|
|
# 2 pi(x) <= li(x) for all 2 <= x <= 10^20 |
|
3962
|
|
|
|
|
|
|
# 3 [li(x) - 2sqrt(x)/log(x)] <= pi(x) for 1090877 <= x <= 10^20 |
|
3963
|
|
|
|
|
|
|
# |
|
3964
|
|
|
|
|
|
|
# See https://arxiv.org/pdf/2404.17165 page 9 for Mossinghoff and Trudgian. |
|
3965
|
|
|
|
|
|
|
# Page 26 also points out the Dusart 2018 improvement to Schoenfeld. |
|
3966
|
|
|
|
|
|
|
# https://math.colgate.edu/~integers/y34/y34.pdf |
|
3967
|
|
|
|
|
|
|
# Axler 2022: |
|
3968
|
|
|
|
|
|
|
# https://arxiv.org/pdf/2203.05917 |
|
3969
|
|
|
|
|
|
|
|
|
3970
|
35
|
|
|
|
|
80
|
my($result,$a); |
|
3971
|
35
|
|
|
|
|
112
|
my $fl1 = log($x); |
|
3972
|
35
|
|
|
|
|
1234342
|
my $fl2 = $fl1 * $fl1; |
|
3973
|
35
|
100
|
|
|
|
3607
|
my $one = $floatx ? $x->copy->bone : 1.0; |
|
3974
|
|
|
|
|
|
|
|
|
3975
|
35
|
100
|
33
|
|
|
1114
|
if ($x < 15900) { # Tweaked Rosser-type |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
3976
|
5
|
50
|
|
|
|
20
|
$a = ($x < 1621) ? 1.048 : ($x < 5000) ? 1.071 : 1.098; |
|
|
|
50
|
|
|
|
|
|
|
3977
|
5
|
|
|
|
|
13
|
$result = ($x / ($fl1 - $a)) + 1.0; |
|
3978
|
|
|
|
|
|
|
} elsif ($x < 821800000) { # Tweaked Dusart 2010 |
|
3979
|
22
|
50
|
|
|
|
256
|
if ($x < 24000) { $a = 2.30; } |
|
|
0
|
50
|
|
|
|
0
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
3980
|
0
|
|
|
|
|
0
|
elsif ($x < 59000) { $a = 2.48; } |
|
3981
|
0
|
|
|
|
|
0
|
elsif ($x < 350000) { $a = 2.52; } |
|
3982
|
0
|
|
|
|
|
0
|
elsif ($x < 355991) { $a = 2.54; } |
|
3983
|
0
|
|
|
|
|
0
|
elsif ($x < 356000) { $a = 2.51; } |
|
3984
|
2
|
|
|
|
|
6
|
elsif ($x < 3550000) { $a = 2.50; } |
|
3985
|
0
|
|
|
|
|
0
|
elsif ($x < 3560000) { $a = 2.49; } |
|
3986
|
0
|
|
|
|
|
0
|
elsif ($x < 5000000) { $a = 2.48; } |
|
3987
|
0
|
|
|
|
|
0
|
elsif ($x < 8000000) { $a = 2.47; } |
|
3988
|
0
|
|
|
|
|
0
|
elsif ($x < 13000000) { $a = 2.46; } |
|
3989
|
19
|
|
|
|
|
58
|
elsif ($x < 18000000) { $a = 2.45; } |
|
3990
|
0
|
|
|
|
|
0
|
elsif ($x < 31000000) { $a = 2.44; } |
|
3991
|
0
|
|
|
|
|
0
|
elsif ($x < 41000000) { $a = 2.43; } |
|
3992
|
0
|
|
|
|
|
0
|
elsif ($x < 48000000) { $a = 2.42; } |
|
3993
|
0
|
|
|
|
|
0
|
elsif ($x < 119000000) { $a = 2.41; } |
|
3994
|
0
|
|
|
|
|
0
|
elsif ($x < 182000000) { $a = 2.40; } |
|
3995
|
0
|
|
|
|
|
0
|
elsif ($x < 192000000) { $a = 2.395; } |
|
3996
|
0
|
|
|
|
|
0
|
elsif ($x < 213000000) { $a = 2.390; } |
|
3997
|
0
|
|
|
|
|
0
|
elsif ($x < 271000000) { $a = 2.385; } |
|
3998
|
0
|
|
|
|
|
0
|
elsif ($x < 322000000) { $a = 2.380; } |
|
3999
|
0
|
|
|
|
|
0
|
elsif ($x < 400000000) { $a = 2.375; } |
|
4000
|
1
|
|
|
|
|
2
|
elsif ($x < 510000000) { $a = 2.370; } |
|
4001
|
0
|
|
|
|
|
0
|
elsif ($x < 682000000) { $a = 2.367; } |
|
4002
|
0
|
|
|
|
|
0
|
elsif ($x < 2953652287) { $a = 2.362; } |
|
4003
|
0
|
|
|
|
|
0
|
else { $a = 2.334; } # Dusart 2010, page 2 |
|
4004
|
22
|
|
|
|
|
75
|
$result = ($x/$fl1) * ($one + $one/$fl1 + $a/$fl2) + $one; |
|
4005
|
|
|
|
|
|
|
} elsif ($x < 1e19) { # Skewes number lower limit |
|
4006
|
0
|
0
|
|
|
|
0
|
$a = ($x < 110e7) ? 0.032 : ($x < 1001e7) ? 0.027 : ($x < 10126e7) ? 0.021 : 0.0; |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
4007
|
0
|
|
|
|
|
0
|
$result = MLi($x) - $a * $fl1*sqrt($x)/PI_TIMES_8; |
|
4008
|
|
|
|
|
|
|
} elsif ($x < 1.1e26 || getconfig()->{'assume_rh'}) { |
|
4009
|
|
|
|
|
|
|
# Schoenfeld / Büthe 2014 Th 7.4 |
|
4010
|
8
|
|
|
|
|
24920
|
my $lix = MLi($x); |
|
4011
|
8
|
|
|
|
|
50
|
my $sqx = sqrt($x); |
|
4012
|
8
|
50
|
|
|
|
37401
|
if (ref($x) eq 'Math::BigFloat') { |
|
4013
|
8
|
|
|
|
|
50
|
my $xdigits = _find_big_acc($x); |
|
4014
|
8
|
|
|
|
|
51
|
$result = $lix + ($fl1*$sqx / (Math::BigFloat->bpi($xdigits)*8)); |
|
4015
|
|
|
|
|
|
|
} else { |
|
4016
|
0
|
|
|
|
|
0
|
$result = $lix + ($fl1*$sqx / PI_TIMES_8); |
|
4017
|
|
|
|
|
|
|
} |
|
4018
|
|
|
|
|
|
|
} else { # Axler 2014 1.3 |
|
4019
|
0
|
|
|
|
|
0
|
my($fl3,$fl4) = ($fl2*$fl1,$fl2*$fl2); |
|
4020
|
0
|
|
|
|
|
0
|
my($fl5,$fl6) = ($fl4*$fl1,$fl4*$fl2); |
|
4021
|
0
|
|
|
|
|
0
|
$result = $x / ($fl1 - $one - $one/$fl1 - 3.35/$fl2 - 12.65/$fl3 - 71.7/$fl4 - 466.1275/$fl5 - 3489.8225/$fl6); |
|
4022
|
|
|
|
|
|
|
} |
|
4023
|
|
|
|
|
|
|
# This will truncate bigfloat or floats to native int or bigint class. |
|
4024
|
35
|
|
|
|
|
37534
|
Mtoint($result); |
|
4025
|
|
|
|
|
|
|
} |
|
4026
|
|
|
|
|
|
|
|
|
4027
|
|
|
|
|
|
|
sub twin_prime_count { |
|
4028
|
2
|
|
|
2
|
0
|
1419
|
my($low,$high) = @_; |
|
4029
|
2
|
100
|
|
|
|
9
|
if (defined $high) { validate_integer_nonneg($low); } |
|
|
1
|
|
|
|
|
5
|
|
|
4030
|
1
|
|
|
|
|
3
|
else { ($low,$high) = (2, $low); } |
|
4031
|
2
|
|
|
|
|
10
|
validate_integer_nonneg($high); |
|
4032
|
2
|
|
|
|
|
5
|
my $sum = 0; |
|
4033
|
2
|
|
|
|
|
9
|
while ($low <= $high) { |
|
4034
|
2
|
|
|
|
|
7
|
my $seghigh = ($high-$high) + $low + 1e7 - 1; |
|
4035
|
2
|
50
|
|
|
|
6
|
$seghigh = $high if $seghigh > $high; |
|
4036
|
2
|
|
|
|
|
4
|
$sum += scalar(@{Math::Prime::Util::twin_primes($low,$seghigh)}); |
|
|
2
|
|
|
|
|
8
|
|
|
4037
|
2
|
|
|
|
|
12
|
$low = $seghigh + 1; |
|
4038
|
|
|
|
|
|
|
} |
|
4039
|
2
|
|
|
|
|
24
|
$sum; |
|
4040
|
|
|
|
|
|
|
} |
|
4041
|
|
|
|
|
|
|
sub _semiprime_count { |
|
4042
|
15
|
|
|
15
|
|
39
|
my($n) = @_; |
|
4043
|
15
|
|
|
|
|
35
|
my($sum,$pc) = (0,0); |
|
4044
|
|
|
|
|
|
|
Mforprimes( sub { |
|
4045
|
291
|
|
|
291
|
|
1098
|
$sum += Mprime_count(int($n/$_))-$pc++; |
|
4046
|
15
|
|
|
|
|
137
|
}, Msqrtint($n)); |
|
4047
|
15
|
|
|
|
|
140
|
$sum; |
|
4048
|
|
|
|
|
|
|
} |
|
4049
|
|
|
|
|
|
|
sub semiprime_count { |
|
4050
|
15
|
|
|
15
|
0
|
1115
|
my($lo,$hi) = @_; |
|
4051
|
15
|
100
|
|
|
|
38
|
if (defined $hi) { validate_integer_nonneg($lo); } |
|
|
1
|
|
|
|
|
6
|
|
|
4052
|
14
|
|
|
|
|
58
|
else { ($lo,$hi) = (2, $lo); } |
|
4053
|
15
|
|
|
|
|
67
|
validate_integer_nonneg($hi); |
|
4054
|
|
|
|
|
|
|
# todo: threshold of fast count vs. walk |
|
4055
|
15
|
50
|
|
|
|
67
|
if (($hi-$lo+1) < $hi / (sqrt($hi)/4)) { |
|
4056
|
0
|
|
|
|
|
0
|
my $sum = 0; |
|
4057
|
0
|
|
|
|
|
0
|
while ($lo <= $hi) { |
|
4058
|
0
|
0
|
|
|
|
0
|
$sum++ if Mis_semiprime($lo); |
|
4059
|
0
|
|
|
|
|
0
|
$lo++; |
|
4060
|
|
|
|
|
|
|
} |
|
4061
|
0
|
|
|
|
|
0
|
return $sum; |
|
4062
|
|
|
|
|
|
|
} |
|
4063
|
15
|
100
|
|
|
|
80
|
my $sum = _semiprime_count($hi) - (($lo < 4) ? 0 : semiprime_count($lo-1)); |
|
4064
|
15
|
|
|
|
|
60
|
$sum; |
|
4065
|
|
|
|
|
|
|
} |
|
4066
|
|
|
|
|
|
|
|
|
4067
|
|
|
|
|
|
|
sub _kap_reduce_count { # returns new k and n |
|
4068
|
351
|
|
|
351
|
|
719
|
my($k, $n) = @_; |
|
4069
|
|
|
|
|
|
|
|
|
4070
|
351
|
|
|
|
|
1264
|
my $pow3k = Mpowint(3, $k); |
|
4071
|
351
|
|
|
|
|
2005
|
while ($n < $pow3k) { |
|
4072
|
416
|
|
|
|
|
16002
|
$n = Mdivint($n, 2); |
|
4073
|
416
|
|
|
|
|
917
|
$k--; |
|
4074
|
416
|
|
|
|
|
1390
|
$pow3k = Mdivint($pow3k, 3); |
|
4075
|
|
|
|
|
|
|
} |
|
4076
|
351
|
|
|
|
|
2058
|
($k, $n); |
|
4077
|
|
|
|
|
|
|
} |
|
4078
|
|
|
|
|
|
|
sub _kapc_final { # k = 2 |
|
4079
|
432
|
|
|
432
|
|
1028
|
my($n, $pdiv, $lo) = @_; |
|
4080
|
432
|
|
|
|
|
1138
|
my($sum, $hi, $pc) = (0, Msqrtint(Mdivint($n,$pdiv)), Mprime_count($lo)-1); |
|
4081
|
432
|
|
|
|
|
1227
|
my $nlim = int(INTMAX / $pdiv); |
|
4082
|
|
|
|
|
|
|
Mforprimes( sub { |
|
4083
|
1617
|
50
|
|
1617
|
|
4275
|
my $npp = ($_<=$nlim) ? int($n/($pdiv*$_)) : Mdivint($n,Mmulint($pdiv,$_)); |
|
4084
|
1617
|
|
|
|
|
3159
|
$sum += Mprime_count($npp)-$pc++; |
|
4085
|
432
|
|
|
|
|
4958
|
}, $lo, $hi); |
|
4086
|
432
|
|
|
|
|
3087
|
$sum; |
|
4087
|
|
|
|
|
|
|
} |
|
4088
|
|
|
|
|
|
|
sub _kapc_count { |
|
4089
|
334
|
|
|
334
|
|
897
|
my($n, $pdiv, $lo, $k) = @_; |
|
4090
|
334
|
50
|
|
|
|
676
|
return _kapc_final($n, $pdiv, $lo) if $k == 2; |
|
4091
|
334
|
|
|
|
|
933
|
my($sum, $hi) = (0, Mrootint(Mdivint($n,$pdiv),$k)); |
|
4092
|
|
|
|
|
|
|
Mforprimes( |
|
4093
|
432
|
|
|
432
|
|
1222
|
($k == 3) ? sub { $sum += _kapc_final($n, Mmulint($pdiv,$_), $_); } |
|
4094
|
233
|
|
|
233
|
|
802
|
: sub { $sum += _kapc_count($n, Mmulint($pdiv,$_), $_, $k-1); }, |
|
4095
|
334
|
100
|
|
|
|
3484
|
$lo, $hi |
|
4096
|
|
|
|
|
|
|
); |
|
4097
|
334
|
|
|
|
|
1547
|
$sum; |
|
4098
|
|
|
|
|
|
|
} |
|
4099
|
|
|
|
|
|
|
sub almost_prime_count { |
|
4100
|
103
|
|
|
103
|
0
|
308
|
my($k,$n) = @_; |
|
4101
|
103
|
|
|
|
|
326
|
validate_integer_nonneg($k); |
|
4102
|
103
|
|
|
|
|
295
|
validate_integer_nonneg($n); |
|
4103
|
103
|
50
|
|
|
|
292
|
return ($n >= 1) if $k == 0; |
|
4104
|
103
|
|
|
|
|
174
|
my $ok = $k; |
|
4105
|
103
|
|
|
|
|
288
|
($k, $n) = _kap_reduce_count($k, $n); |
|
4106
|
103
|
50
|
|
|
|
398
|
return $n if $k == 0; |
|
4107
|
|
|
|
|
|
|
# If we reduced parameters, try again if XS might be able to do it. |
|
4108
|
103
|
50
|
66
|
|
|
400
|
return Math::Prime::Util::almost_prime_count($k,$n) if $ok != $k && !ref($n) && getconfig()->{'xs'}; |
|
|
|
|
66
|
|
|
|
|
|
4109
|
103
|
100
|
|
|
|
289
|
return Mprime_count($n) if $k == 1; |
|
4110
|
102
|
100
|
|
|
|
277
|
return Math::Prime::Util::semiprime_count($n) if $k == 2; |
|
4111
|
101
|
50
|
|
|
|
298
|
return 0 if ($n >> $k) == 0; |
|
4112
|
|
|
|
|
|
|
|
|
4113
|
101
|
|
|
|
|
328
|
_kapc_count($n, 1, 2, $k); |
|
4114
|
|
|
|
|
|
|
} |
|
4115
|
|
|
|
|
|
|
|
|
4116
|
|
|
|
|
|
|
sub _omega_prime_count_rec { |
|
4117
|
32
|
|
|
32
|
|
104
|
my($k, $n, $m, $p, $s, $j) = @_; |
|
4118
|
32
|
100
|
|
|
|
84
|
$s = Mrootint(Mdivint($n,$m),$k) unless defined $s; |
|
4119
|
32
|
100
|
|
|
|
77
|
$j = 1 unless defined $j; |
|
4120
|
32
|
|
|
|
|
58
|
my $count = 0; |
|
4121
|
|
|
|
|
|
|
|
|
4122
|
32
|
100
|
|
|
|
90
|
if ($k == 2) { |
|
4123
|
|
|
|
|
|
|
|
|
4124
|
12
|
|
|
|
|
33
|
for (; $p <= $s ; ++$j) { |
|
4125
|
16
|
|
|
|
|
45
|
my $r = Mnext_prime($p); |
|
4126
|
16
|
|
|
|
|
51
|
for (my $t = Mmulint($m, $p) ; $t <= $n ; $t = Mmulint($t, $p)) { |
|
4127
|
27
|
|
|
|
|
71
|
my $w = Mdivint($n, $t); |
|
4128
|
27
|
100
|
|
|
|
69
|
last if $r > $w; |
|
4129
|
11
|
|
|
|
|
35
|
$count += Mprime_count($w) - $j; |
|
4130
|
11
|
|
|
|
|
37
|
for (my $r2 = $r ; $r2 <= $w ; $r2 = Mnext_prime($r2)) { |
|
4131
|
11
|
|
|
|
|
46
|
my $u = Mvecprod($t, $r2, $r2); |
|
4132
|
11
|
50
|
|
|
|
51
|
last if $u > $n; |
|
4133
|
0
|
|
|
|
|
0
|
for (; $u <= $n ; $u = Mmulint($u, $r2)) { |
|
4134
|
0
|
|
|
|
|
0
|
++$count; |
|
4135
|
|
|
|
|
|
|
} |
|
4136
|
|
|
|
|
|
|
} |
|
4137
|
|
|
|
|
|
|
} |
|
4138
|
16
|
|
|
|
|
67
|
$p = $r; |
|
4139
|
|
|
|
|
|
|
} |
|
4140
|
|
|
|
|
|
|
|
|
4141
|
|
|
|
|
|
|
} else { |
|
4142
|
|
|
|
|
|
|
|
|
4143
|
20
|
|
|
|
|
69
|
for (; $p <= $s ; ++$j) { |
|
4144
|
30
|
|
|
|
|
101
|
my $r = Mnext_prime($p); |
|
4145
|
30
|
|
|
|
|
98
|
for (my $t = Mmulint($m, $p) ; $t <= $n ; $t = Mmulint($t, $p)) { |
|
4146
|
58
|
|
|
|
|
182
|
my $s = Mrootint(Mdivint($n, $t), $k - 1); |
|
4147
|
58
|
100
|
|
|
|
161
|
last if $r > $s; |
|
4148
|
28
|
|
|
|
|
109
|
$count += _omega_prime_count_rec($k-1, $n, $t, $r, $s, $j+1); |
|
4149
|
|
|
|
|
|
|
} |
|
4150
|
30
|
|
|
|
|
87
|
$p = $r; |
|
4151
|
|
|
|
|
|
|
} |
|
4152
|
|
|
|
|
|
|
|
|
4153
|
|
|
|
|
|
|
} |
|
4154
|
32
|
|
|
|
|
130
|
$count; |
|
4155
|
|
|
|
|
|
|
} |
|
4156
|
|
|
|
|
|
|
sub omega_prime_count { |
|
4157
|
5
|
|
|
5
|
0
|
26
|
my($k,$n) = @_; |
|
4158
|
5
|
|
|
|
|
17
|
validate_integer_nonneg($k); |
|
4159
|
5
|
|
|
|
|
40
|
validate_integer_nonneg($n); |
|
4160
|
|
|
|
|
|
|
|
|
4161
|
5
|
0
|
|
|
|
16
|
return ($n >= 1) ? 1 : 0 if $k == 0; |
|
|
|
50
|
|
|
|
|
|
|
4162
|
5
|
100
|
|
|
|
19
|
return prime_power_count($n) if $k == 1; |
|
4163
|
|
|
|
|
|
|
# find a simple formula for k=2. |
|
4164
|
|
|
|
|
|
|
|
|
4165
|
|
|
|
|
|
|
# Naive method |
|
4166
|
|
|
|
|
|
|
# my ($sum, $low) = (0, Mpn_primorial($k)); |
|
4167
|
|
|
|
|
|
|
# for (my $i = $low; $i <= $n; $i++) { |
|
4168
|
|
|
|
|
|
|
# $sum++ if Mprime_omega($i) == $k; |
|
4169
|
|
|
|
|
|
|
# } |
|
4170
|
|
|
|
|
|
|
# return $sum; |
|
4171
|
|
|
|
|
|
|
|
|
4172
|
|
|
|
|
|
|
# Recursive method from trizen |
|
4173
|
4
|
|
|
|
|
17
|
return _omega_prime_count_rec($k, $n, 1, 2); |
|
4174
|
|
|
|
|
|
|
} |
|
4175
|
|
|
|
|
|
|
sub ramanujan_prime_count { |
|
4176
|
1
|
|
|
1
|
0
|
21
|
my($low,$high) = @_; |
|
4177
|
1
|
50
|
|
|
|
5
|
if (defined $high) { validate_integer_nonneg($low); } |
|
|
0
|
|
|
|
|
0
|
|
|
4178
|
1
|
|
|
|
|
4
|
else { ($low,$high) = (2, $low); } |
|
4179
|
1
|
|
|
|
|
4
|
validate_integer_nonneg($high); |
|
4180
|
1
|
|
|
|
|
2
|
my $sum = 0; |
|
4181
|
1
|
|
|
|
|
5
|
while ($low <= $high) { |
|
4182
|
1
|
|
|
|
|
4
|
my $seghigh = ($high-$high) + $low + 1e9 - 1; |
|
4183
|
1
|
50
|
|
|
|
5
|
$seghigh = $high if $seghigh > $high; |
|
4184
|
1
|
|
|
|
|
2
|
$sum += scalar(@{Math::Prime::Util::ramanujan_primes($low,$seghigh)}); |
|
|
1
|
|
|
|
|
5
|
|
|
4185
|
1
|
|
|
|
|
43
|
$low = $seghigh + 1; |
|
4186
|
|
|
|
|
|
|
} |
|
4187
|
1
|
|
|
|
|
41
|
$sum; |
|
4188
|
|
|
|
|
|
|
} |
|
4189
|
|
|
|
|
|
|
|
|
4190
|
|
|
|
|
|
|
sub twin_prime_count_approx { |
|
4191
|
41
|
|
|
41
|
0
|
116
|
my($n) = @_; |
|
4192
|
41
|
|
|
|
|
159
|
validate_integer_nonneg($n); |
|
4193
|
41
|
50
|
|
|
|
105
|
return twin_prime_count(3,$n) if $n < 2000; |
|
4194
|
|
|
|
|
|
|
# Remove bigint / bigfloat. Everything here will be done with native NV. |
|
4195
|
41
|
100
|
|
|
|
339
|
$n = 0.0+"$n" if ref($n); |
|
4196
|
41
|
|
|
|
|
208
|
my $logn = log($n); |
|
4197
|
41
|
|
|
|
|
171
|
my $li2 = Math::Prime::Util::ExponentialIntegral($logn) + 2.8853900817779268147198494 - ($n/$logn); |
|
4198
|
|
|
|
|
|
|
|
|
4199
|
|
|
|
|
|
|
# Empirical correction factor |
|
4200
|
41
|
|
|
|
|
84
|
my $fm; |
|
4201
|
41
|
50
|
|
|
|
403
|
if ($n < 4000) { $fm = 0.2952; } |
|
|
0
|
50
|
|
|
|
0
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
4202
|
0
|
|
|
|
|
0
|
elsif ($n < 8000) { $fm = 0.3151; } |
|
4203
|
0
|
|
|
|
|
0
|
elsif ($n < 16000) { $fm = 0.3090; } |
|
4204
|
0
|
|
|
|
|
0
|
elsif ($n < 32000) { $fm = 0.3096; } |
|
4205
|
0
|
|
|
|
|
0
|
elsif ($n < 64000) { $fm = 0.3100; } |
|
4206
|
0
|
|
|
|
|
0
|
elsif ($n < 128000) { $fm = 0.3089; } |
|
4207
|
0
|
|
|
|
|
0
|
elsif ($n < 256000) { $fm = 0.3099; } |
|
4208
|
0
|
|
|
|
|
0
|
elsif ($n < 600000) { my($x0, $x1, $y0, $y1) = (1e6, 6e5, .3091, .3059); |
|
4209
|
0
|
|
|
|
|
0
|
$fm = $y0 + ($n - $x0) * ($y1-$y0) / ($x1 - $x0); } |
|
4210
|
0
|
|
|
|
|
0
|
elsif ($n < 1000000) { my($x0, $x1, $y0, $y1) = (6e5, 1e6, .3062, .3042); |
|
4211
|
0
|
|
|
|
|
0
|
$fm = $y0 + ($n - $x0) * ($y1-$y0) / ($x1 - $x0); } |
|
4212
|
0
|
|
|
|
|
0
|
elsif ($n < 4000000) { my($x0, $x1, $y0, $y1) = (1e6, 4e6, .3067, .3041); |
|
4213
|
0
|
|
|
|
|
0
|
$fm = $y0 + ($n - $x0) * ($y1-$y0) / ($x1 - $x0); } |
|
4214
|
0
|
|
|
|
|
0
|
elsif ($n < 16000000) { my($x0, $x1, $y0, $y1) = (4e6, 16e6, .3033, .2983); |
|
4215
|
0
|
|
|
|
|
0
|
$fm = $y0 + ($n - $x0) * ($y1-$y0) / ($x1 - $x0); } |
|
4216
|
0
|
|
|
|
|
0
|
elsif ($n < 32000000) { my($x0, $x1, $y0, $y1) = (16e6, 32e6, .2980, .2965); |
|
4217
|
0
|
|
|
|
|
0
|
$fm = $y0 + ($n - $x0) * ($y1-$y0) / ($x1 - $x0); } |
|
4218
|
41
|
50
|
|
|
|
107
|
$li2 *= $fm * log(12+$logn) if defined $fm; |
|
4219
|
|
|
|
|
|
|
|
|
4220
|
41
|
|
|
|
|
255
|
return int(1.32032363169373914785562422 * $li2 + 0.5); |
|
4221
|
|
|
|
|
|
|
} |
|
4222
|
|
|
|
|
|
|
|
|
4223
|
|
|
|
|
|
|
sub semiprime_count_approx { |
|
4224
|
7
|
|
|
7
|
0
|
22
|
my($n) = @_; |
|
4225
|
7
|
|
|
|
|
32
|
validate_integer_nonneg($n); |
|
4226
|
7
|
50
|
|
|
|
152
|
return 0 if $n < 4; |
|
4227
|
7
|
|
|
|
|
573
|
$n = "$n" + 0.00000001; |
|
4228
|
7
|
|
|
|
|
139
|
my $l1 = log($n); |
|
4229
|
7
|
|
|
|
|
15
|
my $l2 = log($l1); |
|
4230
|
|
|
|
|
|
|
#my $est = $n * $l2 / $l1; |
|
4231
|
|
|
|
|
|
|
#my $est = $n * ($l2 + 0.302) / $l1; |
|
4232
|
7
|
|
|
|
|
36
|
my $est = ($n/$l1) * (0.11147910114 + 0.00223801350*$l1 + 0.44233207922*$l2 + 1.65236647896*log($l2)); |
|
4233
|
7
|
|
|
|
|
37
|
Mtoint($est + 0.5); |
|
4234
|
|
|
|
|
|
|
} |
|
4235
|
|
|
|
|
|
|
|
|
4236
|
|
|
|
|
|
|
sub almost_prime_count_approx { |
|
4237
|
37
|
|
|
37
|
0
|
714
|
my($k,$n) = @_; |
|
4238
|
37
|
|
|
|
|
103
|
validate_integer_nonneg($k); |
|
4239
|
37
|
|
|
|
|
116
|
validate_integer_nonneg($n); |
|
4240
|
37
|
50
|
|
|
|
307
|
return ($n >= 1) if $k == 0; |
|
4241
|
37
|
50
|
|
|
|
76
|
return Math::Prime::Util::prime_count_approx($n) if $k == 1; |
|
4242
|
37
|
100
|
|
|
|
153
|
return Math::Prime::Util::semiprime_count_approx($n) if $k == 2; |
|
4243
|
31
|
50
|
|
|
|
63
|
return 0 if ($n >> $k) == 0; |
|
4244
|
|
|
|
|
|
|
|
|
4245
|
31
|
|
|
|
|
3701
|
my $lo = Math::Prime::Util::almost_prime_count_lower($k, $n); |
|
4246
|
31
|
|
|
|
|
102
|
my $hi = Math::Prime::Util::almost_prime_count_upper($k, $n); |
|
4247
|
|
|
|
|
|
|
|
|
4248
|
31
|
100
|
|
|
|
78
|
if ($k == 3) { |
|
4249
|
4
|
|
|
|
|
54
|
my $x = 0.0 + "$n"; |
|
4250
|
4
|
|
|
|
|
129
|
my $l1 = log($x); |
|
4251
|
4
|
|
|
|
|
12
|
my $l2 = log($l1); |
|
4252
|
4
|
|
|
|
|
12
|
my($a,$s) = (1.0,2.0); |
|
4253
|
4
|
50
|
|
|
|
95
|
if ($x <= 638) { $s = 1.554688; $a = 0.865814; } |
|
|
0
|
50
|
|
|
|
0
|
|
|
|
0
|
50
|
|
|
|
0
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
4254
|
0
|
|
|
|
|
0
|
elsif ($x <= 1544) { $s = 1.050000; $a = 0.822256; } |
|
|
0
|
|
|
|
|
0
|
|
|
4255
|
0
|
|
|
|
|
0
|
elsif ($x <= 1927) { $s = 0.625000; $a = 0.791747; } |
|
|
0
|
|
|
|
|
0
|
|
|
4256
|
2
|
|
|
|
|
5
|
elsif ($x <= 486586) { $s = 2.865611; $a = 1.004090; } |
|
|
2
|
|
|
|
|
4
|
|
|
4257
|
0
|
|
|
|
|
0
|
elsif ($x <= 1913680) { $s = 2.790963; $a = 0.999618; } |
|
|
0
|
|
|
|
|
0
|
|
|
4258
|
0
|
|
|
|
|
0
|
elsif ($x <= 22347532) { $s = 2.719238; $a = 0.995635; } |
|
|
0
|
|
|
|
|
0
|
|
|
4259
|
0
|
|
|
|
|
0
|
elsif ($x <= 2.95e8) { $s = 2.584473; $a = 0.988802; } |
|
|
0
|
|
|
|
|
0
|
|
|
4260
|
0
|
|
|
|
|
0
|
elsif ($x <= 4.20e9) { $s = 2.457108; $a = 0.983098; } |
|
|
0
|
|
|
|
|
0
|
|
|
4261
|
0
|
|
|
|
|
0
|
elsif ($x <= 7.07e10) { $s = 2.352818; $a = 0.978931; } |
|
|
0
|
|
|
|
|
0
|
|
|
4262
|
0
|
|
|
|
|
0
|
elsif ($x <= 1.36e12) { $s = 2.269745; $a = 0.975953; } |
|
|
0
|
|
|
|
|
0
|
|
|
4263
|
0
|
|
|
|
|
0
|
elsif ($x <= 4.1e13) { $s = 2.203002; $a = 0.973796; } |
|
|
0
|
|
|
|
|
0
|
|
|
4264
|
0
|
|
|
|
|
0
|
elsif ($x <= 9.2e14) { $s = 2.148463; $a = 0.972213; } |
|
|
0
|
|
|
|
|
0
|
|
|
4265
|
2
|
|
|
|
|
6
|
else { $s = 2.119279; $a = 0.971438; } |
|
|
2
|
|
|
|
|
5
|
|
|
4266
|
4
|
|
|
|
|
18
|
my $est = 0.5*$a*$x*(($l2+0.26153)*($l2+0.26153)) / ($l1+$s) + 0.5; |
|
4267
|
4
|
50
|
|
|
|
26
|
return $est < $lo ? $lo : $est > $hi ? $hi : Mtoint($est); |
|
|
|
50
|
|
|
|
|
|
|
4268
|
|
|
|
|
|
|
} |
|
4269
|
|
|
|
|
|
|
|
|
4270
|
|
|
|
|
|
|
{ |
|
4271
|
27
|
|
|
|
|
34
|
my $mult = 0.5; |
|
|
27
|
|
|
|
|
37
|
|
|
4272
|
27
|
100
|
66
|
|
|
112
|
if ($n < 2**32 && $k < 13) { |
|
|
|
100
|
|
|
|
|
|
|
4273
|
24
|
|
|
|
|
29
|
$mult = 0.9; |
|
4274
|
|
|
|
|
|
|
} elsif ($k > 11) { |
|
4275
|
2
|
|
|
|
|
473
|
$mult = 0.20; |
|
4276
|
|
|
|
|
|
|
} else { |
|
4277
|
1
|
|
|
|
|
2
|
$mult = 0.76; |
|
4278
|
|
|
|
|
|
|
} |
|
4279
|
27
|
50
|
33
|
|
|
128
|
return Mtoint($lo + ($hi - $lo) * $mult + 0.5) unless ref($lo) || ref($hi); |
|
4280
|
|
|
|
|
|
|
|
|
4281
|
0
|
|
|
|
|
0
|
my $imult = int($mult * (1<<16)); |
|
4282
|
0
|
|
|
|
|
0
|
my $est = Maddint( Mlshiftint($lo,16), Mmulint(Msubint($hi,$lo),$imult) ); |
|
4283
|
0
|
|
|
|
|
0
|
return Mrshiftint($est,16); |
|
4284
|
|
|
|
|
|
|
} |
|
4285
|
|
|
|
|
|
|
} |
|
4286
|
|
|
|
|
|
|
|
|
4287
|
|
|
|
|
|
|
sub nth_twin_prime { |
|
4288
|
1
|
|
|
1
|
0
|
3
|
my($n) = @_; |
|
4289
|
1
|
50
|
|
|
|
5
|
return undef if $n < 0; ## no critic qw(ProhibitExplicitReturnUndef) |
|
4290
|
1
|
50
|
|
|
|
5
|
return (undef,3,5,11,17,29,41)[$n] if $n <= 6; |
|
4291
|
|
|
|
|
|
|
|
|
4292
|
1
|
|
|
|
|
5
|
my $p = Math::Prime::Util::nth_twin_prime_approx($n+200); |
|
4293
|
1
|
|
|
|
|
7
|
my $tp = Math::Prime::Util::twin_primes($p); |
|
4294
|
1
|
|
|
|
|
8
|
while ($n > scalar(@$tp)) { |
|
4295
|
0
|
|
|
|
|
0
|
$n -= scalar(@$tp); |
|
4296
|
0
|
|
|
|
|
0
|
$tp = Math::Prime::Util::twin_primes($p+1,$p+1e5); |
|
4297
|
0
|
|
|
|
|
0
|
$p += 1e5; |
|
4298
|
|
|
|
|
|
|
} |
|
4299
|
1
|
|
|
|
|
23
|
return $tp->[$n-1]; |
|
4300
|
|
|
|
|
|
|
} |
|
4301
|
|
|
|
|
|
|
|
|
4302
|
|
|
|
|
|
|
sub nth_twin_prime_approx { |
|
4303
|
2
|
|
|
2
|
0
|
8
|
my($n) = @_; |
|
4304
|
2
|
|
|
|
|
13
|
validate_integer_nonneg($n); |
|
4305
|
2
|
50
|
|
|
|
7
|
return nth_twin_prime($n) if $n < 6; |
|
4306
|
2
|
50
|
33
|
|
|
49
|
$n = _upgrade_to_float($n) if ref($n) || $n > 127e14; # TODO lower for 32-bit |
|
4307
|
2
|
|
|
|
|
11
|
my $logn = log($n); |
|
4308
|
2
|
|
|
|
|
7
|
my $nlogn2 = $n * $logn * $logn; |
|
4309
|
|
|
|
|
|
|
|
|
4310
|
2
|
100
|
66
|
|
|
21
|
return int(5.158 * $nlogn2/log(9+log($n*$n))) if $n > 59 && $n <= 1092; |
|
4311
|
|
|
|
|
|
|
|
|
4312
|
1
|
|
|
|
|
4
|
my $lo = int(0.7 * $nlogn2); |
|
4313
|
1
|
50
|
|
|
|
9
|
my $hi = int( ($n > 1e16) ? 1.1 * $nlogn2 |
|
|
|
50
|
|
|
|
|
|
|
4314
|
|
|
|
|
|
|
: ($n > 480) ? 1.7 * $nlogn2 |
|
4315
|
|
|
|
|
|
|
: 2.3 * $nlogn2 + 3 ); |
|
4316
|
|
|
|
|
|
|
|
|
4317
|
|
|
|
|
|
|
_binary_search($n, $lo, $hi, |
|
4318
|
39
|
|
|
39
|
|
132
|
sub{Math::Prime::Util::twin_prime_count_approx(shift)}, |
|
4319
|
1
|
|
|
39
|
|
13
|
sub{ ($_[2]-$_[1])/$_[1] < 1e-15 } ); |
|
|
39
|
|
|
|
|
186
|
|
|
4320
|
|
|
|
|
|
|
} |
|
4321
|
|
|
|
|
|
|
|
|
4322
|
|
|
|
|
|
|
sub nth_semiprime { |
|
4323
|
2
|
|
|
2
|
0
|
7
|
my($n) = @_; |
|
4324
|
2
|
|
|
|
|
9
|
validate_integer_nonneg($n); |
|
4325
|
2
|
50
|
|
|
|
7
|
return (undef,4,6,9,10,14,15,21,22)[$n] if $n <= 8; |
|
4326
|
2
|
|
|
|
|
14
|
my $x = "$n" + 0.000000001; # Get rid of bigint so we can safely call log |
|
4327
|
2
|
|
|
|
|
9
|
my $logx = log($x); |
|
4328
|
2
|
|
|
|
|
6
|
my $loglogx = log($logx); |
|
4329
|
2
|
50
|
|
|
|
12
|
my $a = ($n < 1000) ? 1.027 : ($n < 10000) ? 0.995 : 0.966; |
|
|
|
100
|
|
|
|
|
|
|
4330
|
2
|
|
|
|
|
6
|
my $est = $a * $x * $logx / $loglogx; |
|
4331
|
2
|
50
|
|
|
|
39
|
my $lo = ($n < 20000) ? int(0.97*$est)-1 : int(0.98*$est)-1; |
|
4332
|
2
|
50
|
|
|
|
41
|
my $hi = ($n < 20000) ? int(1.07*$est)+1 : int(1.02*$est)+1; |
|
4333
|
2
|
|
|
12
|
|
18
|
1+_binary_search($n,$lo,$hi, sub{Math::Prime::Util::semiprime_count(shift)}); |
|
|
12
|
|
|
|
|
36
|
|
|
4334
|
|
|
|
|
|
|
} |
|
4335
|
|
|
|
|
|
|
|
|
4336
|
|
|
|
|
|
|
sub nth_semiprime_approx { |
|
4337
|
1
|
|
|
1
|
0
|
4
|
my($n) = @_; |
|
4338
|
1
|
|
|
|
|
5
|
validate_integer_nonneg($n); |
|
4339
|
1
|
50
|
|
|
|
4
|
return (undef,4,6,9,10,14,15,21,22)[$n] if $n <= 8; |
|
4340
|
1
|
|
|
|
|
7
|
$n = "$n" + 0.00000001; |
|
4341
|
1
|
|
|
|
|
4
|
my $l1 = log($n); |
|
4342
|
1
|
|
|
|
|
4
|
my $l2 = log($l1); |
|
4343
|
1
|
|
|
|
|
4
|
my $est = 0.966 * $n * $l1 / $l2; |
|
4344
|
1
|
|
|
|
|
6
|
Mtoint($est+0.5); |
|
4345
|
|
|
|
|
|
|
} |
|
4346
|
|
|
|
|
|
|
|
|
4347
|
|
|
|
|
|
|
sub _almost_prime_count_asymptotic { |
|
4348
|
|
|
|
|
|
|
# uncoverable subroutine |
|
4349
|
0
|
|
|
0
|
|
0
|
my($k, $n) = @_; |
|
4350
|
0
|
0
|
|
|
|
0
|
return 0 if ($n >> $k) == 0; |
|
4351
|
0
|
0
|
|
|
|
0
|
return ($n >= 1) if $k == 0; |
|
4352
|
|
|
|
|
|
|
|
|
4353
|
0
|
|
|
|
|
0
|
my $x; |
|
4354
|
0
|
0
|
0
|
|
|
0
|
if (ref($n) || $n > ~0) { |
|
4355
|
0
|
|
|
|
|
0
|
$x = _upgrade_to_float($n); |
|
4356
|
|
|
|
|
|
|
} else { |
|
4357
|
0
|
|
|
|
|
0
|
$x = 0.0 + "$n"; |
|
4358
|
|
|
|
|
|
|
} |
|
4359
|
0
|
|
|
|
|
0
|
my $logx = log($x); |
|
4360
|
0
|
|
|
|
|
0
|
my $loglogx = log($logx); |
|
4361
|
0
|
|
|
|
|
0
|
my $est = $x / $logx; |
|
4362
|
0
|
0
|
|
|
|
0
|
my $numk = $k - ( ($k<7) ? 1 : ($k<12) ? 2 : ($k-6)>>2 ); |
|
|
|
0
|
|
|
|
|
|
|
4363
|
0
|
|
|
|
|
0
|
$est *= ($loglogx/$_) for 1 .. $numk; |
|
4364
|
0
|
|
|
|
|
0
|
$est; # Returns FP |
|
4365
|
|
|
|
|
|
|
} |
|
4366
|
|
|
|
|
|
|
sub _almost_prime_nth_asymptotic { |
|
4367
|
14
|
|
|
14
|
|
47
|
my($k, $n) = @_; |
|
4368
|
14
|
50
|
33
|
|
|
72
|
return 0 if $k == 0 || $n == 0; |
|
4369
|
14
|
50
|
|
|
|
43
|
return Mpowint(2,$k) if $n == 1; |
|
4370
|
|
|
|
|
|
|
|
|
4371
|
14
|
|
|
|
|
25
|
my $x; |
|
4372
|
14
|
50
|
33
|
|
|
82
|
if (ref($n) || $n > ~0) { |
|
4373
|
0
|
|
|
|
|
0
|
require Math::BigFloat; |
|
4374
|
0
|
|
|
|
|
0
|
Math::BigFloat->import(); |
|
4375
|
0
|
|
|
|
|
0
|
$x = Math::BigFloat->new($n); |
|
4376
|
|
|
|
|
|
|
} else { |
|
4377
|
14
|
|
|
|
|
63
|
$x = 0.0 + "$n"; |
|
4378
|
|
|
|
|
|
|
} |
|
4379
|
14
|
|
|
|
|
53
|
my $logx = log($x); |
|
4380
|
14
|
|
|
|
|
29
|
my $loglogx = log($logx); |
|
4381
|
14
|
|
|
|
|
32
|
my $est = $x * $logx; |
|
4382
|
14
|
0
|
|
|
|
53
|
my $numk = $k - ( ($k<7) ? 1 : ($k<12) ? 2 : ($k-6)>>2 ); |
|
|
|
50
|
|
|
|
|
|
|
4383
|
14
|
|
|
|
|
127
|
$est *= ($_/$loglogx) for 1 .. $numk; |
|
4384
|
14
|
|
|
|
|
76
|
$est; # Returns FP |
|
4385
|
|
|
|
|
|
|
} |
|
4386
|
|
|
|
|
|
|
|
|
4387
|
|
|
|
|
|
|
sub almost_prime_count_lower { |
|
4388
|
83
|
|
|
83
|
0
|
928
|
my($k, $n) = @_; |
|
4389
|
83
|
|
|
|
|
287
|
validate_integer_nonneg($k); |
|
4390
|
83
|
|
|
|
|
154
|
validate_integer_nonneg($n); |
|
4391
|
|
|
|
|
|
|
|
|
4392
|
|
|
|
|
|
|
|
|
4393
|
83
|
50
|
|
|
|
351
|
return 0 if ($n >> $k) == 0; |
|
4394
|
83
|
|
|
|
|
3428
|
($k, $n) = _kap_reduce_count($k, $n); |
|
4395
|
83
|
50
|
|
|
|
257
|
return ($n >= 1) if $k == 0; |
|
4396
|
83
|
50
|
|
|
|
146
|
return Math::Prime::Util::prime_count_lower($n) if $k == 1; |
|
4397
|
|
|
|
|
|
|
|
|
4398
|
83
|
|
|
|
|
118
|
my $bound = 0; |
|
4399
|
83
|
|
|
|
|
224
|
my $x = 0.0 + "$n"; |
|
4400
|
83
|
|
|
|
|
354
|
my $logx = log($x); |
|
4401
|
83
|
|
|
|
|
154
|
my $loglogx = log($logx); |
|
4402
|
83
|
|
|
|
|
121
|
my $logplus = $loglogx + 0.26153; |
|
4403
|
|
|
|
|
|
|
|
|
4404
|
83
|
|
|
|
|
195
|
my @lower20 = (0,0, 0.8197, 0.8418, 0.5242, 0.5154,0.3053,0.1901,0.1253,0.0892,0.06551,0.05082,0.04101); |
|
4405
|
83
|
|
|
|
|
181
|
my @lower32 = (0,0, 1.004, 0.7383, 0.6828, 0.5939,0.3594,0.2222,0.1438,0.09754,0.06981,0.05245,0.04151, 0.03461,0.03006,0.02709,0.02553,0.02502,0.02552,0.02697,0.02945); |
|
4406
|
83
|
|
|
|
|
305
|
my @lower64 = (0,0,1.011,0.8093,0.7484,0.6465,0.3982,0.2463,0.1571,0.1048,0.07363,0.0545,0.0422, 0.0331,0.0270,0.0232,0.0208,0.0194,0.0190,0.0193,0.0203, 0.0222,0.0252,0.0295,0.0356,0.0444,0.0570,0.0753,0.102,0.14,0.20,0.297,0.44,0.68,1.07,1.71,2.8,4.7,8.0,13.89,23.98); |
|
4407
|
|
|
|
|
|
|
# TODO: These are likely still too high |
|
4408
|
83
|
|
|
|
|
550
|
my @lower = (0,0,1.011,0.8093,0.7484,0.6465,0.3982,0.2463,0.1571,0.1048,0.07363,0.0545,0.0422, 0.0331,0.0270, |
|
4409
|
|
|
|
|
|
|
0.0230,0.0200,0.0187,0.018,0.018,0.019,0.020,0.020,0.027,0.032,0.040,0.051,0.068,0.090,0.12,0.18,0.26,0.355); |
|
4410
|
|
|
|
|
|
|
|
|
4411
|
83
|
|
|
|
|
99
|
my $multl; |
|
4412
|
83
|
|
|
|
|
186
|
my $isn64bit = Mrshiftint($n,64) == 0; |
|
4413
|
83
|
100
|
|
|
|
276
|
if ($n <= 1048575) { $multl = $lower20[$k]; } |
|
|
6
|
100
|
|
|
|
17
|
|
|
|
|
100
|
|
|
|
|
|
|
4414
|
74
|
|
|
|
|
109
|
elsif ($n <= 4294967295) { $multl = $lower32[$k]; } |
|
4415
|
1
|
|
|
|
|
3
|
elsif ($isn64bit) { $multl = $lower64[$k]; } |
|
4416
|
|
|
|
|
|
|
else { |
|
4417
|
2
|
|
|
|
|
1065
|
push @lower, 1.5 * $lower[$#lower] until defined $lower[$k]; |
|
4418
|
2
|
|
|
|
|
5
|
$multl = $lower[$k]; |
|
4419
|
|
|
|
|
|
|
} |
|
4420
|
|
|
|
|
|
|
|
|
4421
|
83
|
50
|
|
|
|
264
|
if ($k == 2) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
4422
|
0
|
0
|
|
|
|
0
|
if ($x <= 1e12) { |
|
4423
|
0
|
|
|
|
|
0
|
$bound = $x * ($loglogx + 0.261536) / $logx; |
|
4424
|
|
|
|
|
|
|
} else { |
|
4425
|
|
|
|
|
|
|
# Bayless Theorem 5.2 |
|
4426
|
0
|
|
|
|
|
0
|
$bound = ($x * ($loglogx+0.1769)/$logx) * (1 + 0.4232/$logx); |
|
4427
|
0
|
|
|
|
|
0
|
$multl = 1; |
|
4428
|
|
|
|
|
|
|
} |
|
4429
|
|
|
|
|
|
|
} elsif ($k == 3) { |
|
4430
|
|
|
|
|
|
|
# Kinlaw Theorem 1, using custom multipliers for 64-bit n |
|
4431
|
5
|
|
|
|
|
20
|
$bound = $x * $loglogx * $loglogx / (2*$logx); |
|
4432
|
5
|
50
|
|
|
|
25
|
if ($n < 638) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
4433
|
0
|
|
|
|
|
0
|
$multl = 0.8418; |
|
4434
|
|
|
|
|
|
|
} elsif ($n < 1927) { |
|
4435
|
0
|
|
|
|
|
0
|
my $dist = ($x - 638) / (1926 - 638); |
|
4436
|
0
|
|
|
|
|
0
|
$multl = (1.0-$dist) * 0.8939 + $dist * 0.9233; |
|
4437
|
|
|
|
|
|
|
} elsif ($n < 500194) { |
|
4438
|
3
|
|
|
|
|
9
|
my $dist = ($x - 1927) / (500194 - 1927); |
|
4439
|
3
|
|
|
|
|
9
|
$multl = (1.0-$dist) * 0.9233 + $dist * 1.000; |
|
4440
|
|
|
|
|
|
|
} elsif ($n <= 3184393786) { |
|
4441
|
0
|
|
|
|
|
0
|
my $dist = ($x - 500194) / (3184393786 - 500194); |
|
4442
|
0
|
|
|
|
|
0
|
$multl = (1.0-$dist) * 1.0000 + $dist * 1.039; |
|
4443
|
|
|
|
|
|
|
} else { |
|
4444
|
2
|
50
|
|
|
|
1996
|
$multl = $isn64bit ? 1.0004 : 1.0; |
|
4445
|
|
|
|
|
|
|
} |
|
4446
|
|
|
|
|
|
|
} elsif ($k == 4) { |
|
4447
|
72
|
|
|
|
|
132
|
$bound = $x * $logplus*$logplus*$logplus / (6*$logx); |
|
4448
|
72
|
50
|
|
|
|
132
|
$multl = 0.4999 if !$isn64bit; |
|
4449
|
|
|
|
|
|
|
} else { |
|
4450
|
6
|
|
|
|
|
16
|
$bound = $x / $logx; |
|
4451
|
6
|
|
|
|
|
43
|
$logplus = $loglogx + (log("$k") * log(log("$k")) - 0.504377); |
|
4452
|
6
|
|
|
|
|
41
|
$bound *= $logplus/$_ for 1 .. $k-1; |
|
4453
|
|
|
|
|
|
|
} |
|
4454
|
83
|
|
|
|
|
125
|
$bound *= $multl; |
|
4455
|
83
|
50
|
|
|
|
168
|
$bound = 1 if $bound < 1; # We would have returned zero earlier |
|
4456
|
83
|
|
|
|
|
168
|
Mtoint($bound) |
|
4457
|
|
|
|
|
|
|
} |
|
4458
|
|
|
|
|
|
|
sub almost_prime_count_upper { |
|
4459
|
165
|
|
|
165
|
0
|
400
|
my($k, $n) = @_; |
|
4460
|
165
|
|
|
|
|
426
|
validate_integer_nonneg($k); |
|
4461
|
165
|
|
|
|
|
357
|
validate_integer_nonneg($n); |
|
4462
|
|
|
|
|
|
|
|
|
4463
|
165
|
50
|
|
|
|
620
|
return 0 if ($n >> $k) == 0; |
|
4464
|
165
|
|
|
|
|
4148
|
($k, $n) = _kap_reduce_count($k, $n); |
|
4465
|
165
|
50
|
|
|
|
346
|
return ($n >= 1) if $k == 0; |
|
4466
|
165
|
50
|
|
|
|
339
|
return Math::Prime::Util::prime_count_upper($n) if $k == 1; |
|
4467
|
|
|
|
|
|
|
|
|
4468
|
|
|
|
|
|
|
# In theory we might have reduced k/n to where XS can handle it. |
|
4469
|
|
|
|
|
|
|
# We should consider handling that, especially for k >= 5. |
|
4470
|
|
|
|
|
|
|
|
|
4471
|
165
|
|
|
|
|
245
|
my $bound = 0; |
|
4472
|
165
|
|
|
|
|
401
|
my $x = 0.0 + "$n"; |
|
4473
|
165
|
|
|
|
|
555
|
my $logx = log($x); |
|
4474
|
165
|
|
|
|
|
319
|
my $loglogx = log($logx); |
|
4475
|
165
|
|
|
|
|
295
|
my $logplus = $loglogx + 0.26153; |
|
4476
|
|
|
|
|
|
|
|
|
4477
|
165
|
|
|
|
|
500
|
my @upper20 = (0,0, 1.006,0.7385,0.6830,0.5940,0.3596,0.2227,0.1439, 0.09785,0.07016,0.05303,0.04202); |
|
4478
|
165
|
|
|
|
|
485
|
my @upper32 = (0,0, 1.013,0.8094,0.7485, 0.6467,0.3984,0.2464,0.1572,0.1049,0.07364,0.05452,0.04266, 0.03542,0.03082,0.02798,0.02642,0.02585,0.02615,0.02808,0.03054); |
|
4479
|
165
|
|
|
|
|
776
|
my @upper64 = (0,0, 1.028, 1.028, 1.3043, |
|
4480
|
|
|
|
|
|
|
0.72208, 0.46609, 0.29340,0.18571,0.12063,0.0815,0.0575,0.0427, |
|
4481
|
|
|
|
|
|
|
0.03490, 0.03007, 0.02710, 0.02554, 0.02504, 0.02554, 0.02699, 0.02954, |
|
4482
|
|
|
|
|
|
|
0.03294, 0.03779, 0.04453, 0.05393, 0.06703, 0.08543, 0.1117, 0.1494, |
|
4483
|
|
|
|
|
|
|
0.205,0.287,0.410, |
|
4484
|
|
|
|
|
|
|
0.60,0.90,1.36,2.12,3.35,5.38,8.83,14.75,25.07); |
|
4485
|
|
|
|
|
|
|
|
|
4486
|
|
|
|
|
|
|
# TODO: These bounds are likely to not be accurate for large inputs |
|
4487
|
|
|
|
|
|
|
|
|
4488
|
165
|
|
|
|
|
241
|
my $multu; |
|
4489
|
165
|
|
|
|
|
546
|
my $isn64bit = Mrshiftint($n,64) == 0; |
|
4490
|
165
|
100
|
|
|
|
477
|
if ($n <= 1048575) { $multu = $upper20[$k]; } |
|
|
94
|
100
|
|
|
|
196
|
|
|
4491
|
68
|
|
|
|
|
106
|
elsif ($n <= 4294967295) { $multu = $upper32[$k]; } |
|
4492
|
|
|
|
|
|
|
else { |
|
4493
|
3
|
|
|
|
|
1054
|
push @upper64, 2.1 * $upper64[$#upper64] until defined $upper64[$k]; |
|
4494
|
3
|
|
|
|
|
8
|
$multu = $upper64[$k]; |
|
4495
|
|
|
|
|
|
|
} |
|
4496
|
|
|
|
|
|
|
|
|
4497
|
165
|
50
|
|
|
|
486
|
if ($k == 2) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
4498
|
|
|
|
|
|
|
# Bayless Corollary 5.1 |
|
4499
|
0
|
|
|
|
|
0
|
$bound = 1.028 * $x * ($loglogx + 0.261536) / $logx; |
|
4500
|
|
|
|
|
|
|
} elsif ($k == 3) { |
|
4501
|
|
|
|
|
|
|
# Bayless Theorem 5.3 |
|
4502
|
21
|
|
|
|
|
68
|
$bound = $x * ($logplus * $logplus + 1.055852) / (2*$logx); |
|
4503
|
21
|
50
|
66
|
|
|
102
|
$multu = 0.8711 if $n > 4294967295 && $isn64bit; |
|
4504
|
|
|
|
|
|
|
} elsif ($k == 4) { |
|
4505
|
|
|
|
|
|
|
# Bayless Theorem 5.4 part 1, multu = 1.3043 |
|
4506
|
138
|
|
|
|
|
299
|
$bound = $x * $logplus*$logplus*$logplus / (6*$logx); |
|
4507
|
138
|
50
|
|
|
|
287
|
if ($x >= 1e12) { # part 2 |
|
4508
|
0
|
|
|
|
|
0
|
$bound += + 0.511977 * $x * (log(log($x/4)) + 0.261536) / $logx; |
|
4509
|
0
|
|
|
|
|
0
|
$multu = 1.028; |
|
4510
|
|
|
|
|
|
|
} |
|
4511
|
138
|
50
|
|
|
|
260
|
if ($isn64bit) { |
|
4512
|
138
|
50
|
|
|
|
252
|
$multu = 0.780 if $n > 4294967295; |
|
4513
|
138
|
50
|
|
|
|
256
|
$multu = 0.6921 if $x > 1e12; |
|
4514
|
|
|
|
|
|
|
} |
|
4515
|
|
|
|
|
|
|
} else { |
|
4516
|
|
|
|
|
|
|
# We could use Bayless (2018) Theorem 3.5: |
|
4517
|
|
|
|
|
|
|
# # First we have Pi_k(x) -- the upper bound for the square free kaps. |
|
4518
|
|
|
|
|
|
|
# $bound = 1.028 * $x / $logx; |
|
4519
|
|
|
|
|
|
|
# $bound *= ($logplus/$_) for 1..$k-1; |
|
4520
|
|
|
|
|
|
|
# # Second, turn into Tau_k(x) using the paragraph before Theorem 5.4. |
|
4521
|
|
|
|
|
|
|
# my $sigmalim = Msqrtint(Mdivint($n, Mpowint(2,$k-2))); |
|
4522
|
|
|
|
|
|
|
# my $ix = Math::BigInt->new("$x"); |
|
4523
|
|
|
|
|
|
|
# Mforprimes( sub { |
|
4524
|
|
|
|
|
|
|
# $bound += almost_prime_count_upper($k-2, Mdivint($ix,Mmulint($_,$_))); |
|
4525
|
|
|
|
|
|
|
# }, 2, $sigmalim); |
|
4526
|
|
|
|
|
|
|
# # This is incredibly slow. ) |
|
4527
|
|
|
|
|
|
|
# |
|
4528
|
|
|
|
|
|
|
# Or use theorem 1 from: |
|
4529
|
|
|
|
|
|
|
# Erdős & Sárközy, "On the number of prime factors of integers", 1980. |
|
4530
|
|
|
|
|
|
|
# |
|
4531
|
|
|
|
|
|
|
# Or Hildebrand & Tenenbaum 1988: |
|
4532
|
|
|
|
|
|
|
# https://www.researchgate.net/publication/38333551_On_the_number_of_prime_factors_of_an_integer |
|
4533
|
|
|
|
|
|
|
# Section 1 has lots of info. Corollary 2 (page 476) is what we want. |
|
4534
|
|
|
|
|
|
|
|
|
4535
|
6
|
|
|
|
|
13
|
$bound = $x / $logx; |
|
4536
|
6
|
|
|
|
|
42
|
$logplus = $loglogx + (log("$k") * log(log("$k")) - 0.504377); |
|
4537
|
6
|
|
|
|
|
38
|
$bound *= $logplus/$_ for 1 .. $k-1; |
|
4538
|
|
|
|
|
|
|
} |
|
4539
|
|
|
|
|
|
|
|
|
4540
|
165
|
|
|
|
|
838
|
$bound *= $multu; |
|
4541
|
165
|
50
|
|
|
|
367
|
$bound = 1 if $bound < 1; # We would have returned zero earlier |
|
4542
|
165
|
|
|
|
|
436
|
Mtoint($bound + 1) |
|
4543
|
|
|
|
|
|
|
} |
|
4544
|
|
|
|
|
|
|
|
|
4545
|
|
|
|
|
|
|
sub _kap_reduce_nth { # returns reduction amount r |
|
4546
|
35
|
|
|
35
|
|
78
|
my($k, $n) = @_; |
|
4547
|
35
|
50
|
|
|
|
94
|
return 0 if $k <= 1; |
|
4548
|
|
|
|
|
|
|
|
|
4549
|
|
|
|
|
|
|
# We could calculate new values as needed. |
|
4550
|
35
|
|
|
|
|
401
|
my @A078843 = (1, 2, 3, 5, 8, 14, 23, 39, 64, 103, 169, 269, 427, 676, 1065, 1669, 2628, 4104, 6414, 10023, 15608, 24281, 37733, 58503, 90616, 140187, 216625, 334527, 516126, 795632, 1225641, 1886570, 2901796, 4460359, 6851532, 10518476, 16138642, 24748319, 37932129, 58110457, 88981343, 136192537, 208364721, 318653143, 487128905, 744398307, 1137129971, 1736461477, 2650785552, 4045250962, 6171386419, 9412197641, 14350773978, 21874583987, 33334053149, 50783701654, 77348521640, 117780873397, 179306456282, 272909472119, 415284741506); |
|
4551
|
35
|
|
|
|
|
80
|
my $r = 0; |
|
4552
|
35
|
100
|
|
|
|
125
|
if ($k > $#A078843) { |
|
4553
|
2
|
50
|
|
|
|
6
|
return 0 if $n >= $A078843[-1]; |
|
4554
|
2
|
|
|
|
|
7
|
$r = $k - $#A078843; |
|
4555
|
|
|
|
|
|
|
} |
|
4556
|
35
|
|
|
|
|
194
|
$r++ while $n < $A078843[$k-$r]; |
|
4557
|
35
|
|
|
|
|
153
|
$r; |
|
4558
|
|
|
|
|
|
|
} |
|
4559
|
|
|
|
|
|
|
sub _fast_small_nth_almost_prime { |
|
4560
|
1
|
|
|
1
|
|
4
|
my($k,$n) = @_; |
|
4561
|
1
|
50
|
33
|
|
|
9
|
croak "Internal kap out of range error" if $n >= 8 || $k < 2; |
|
4562
|
1
|
50
|
|
|
|
4
|
return (0, 4, 6, 9, 10, 14, 15, 21)[$n] if $k == 2; |
|
4563
|
1
|
|
|
|
|
179
|
return Mmulint((0, 8, 12, 18, 20, 27, 28, 30)[$n], Mlshiftint(1,$k-3)); |
|
4564
|
|
|
|
|
|
|
} |
|
4565
|
|
|
|
|
|
|
|
|
4566
|
|
|
|
|
|
|
sub nth_almost_prime_upper { |
|
4567
|
2
|
|
|
2
|
0
|
6
|
my($k, $n) = @_; |
|
4568
|
2
|
50
|
|
|
|
8
|
return undef if $n == 0; |
|
4569
|
2
|
0
|
|
|
|
7
|
return (($n == 1) ? 1 : 0) if $k == 0; |
|
|
|
50
|
|
|
|
|
|
|
4570
|
2
|
50
|
|
|
|
8
|
return Mnth_prime_upper($n) if $k == 1; |
|
4571
|
2
|
50
|
|
|
|
6
|
return _fast_small_nth_almost_prime($k,$n) if $n < 8; |
|
4572
|
|
|
|
|
|
|
|
|
4573
|
2
|
|
|
|
|
41
|
my $r = _kap_reduce_nth($k,$n); |
|
4574
|
2
|
50
|
|
|
|
8
|
if ($r > 0) { |
|
4575
|
0
|
|
|
|
|
0
|
my $nth = Math::Prime::Util::nth_almost_prime_upper($k-$r, $n); |
|
4576
|
0
|
|
|
|
|
0
|
return Mlshiftint($nth, $r); |
|
4577
|
|
|
|
|
|
|
} |
|
4578
|
|
|
|
|
|
|
|
|
4579
|
2
|
|
|
|
|
8
|
my $lo = Mlshiftint(5,$k); # $k >= 1, $n >= 8 |
|
4580
|
2
|
|
|
|
|
7
|
my $hi = Mtoint(1 + _almost_prime_nth_asymptotic($k, $n)); |
|
4581
|
|
|
|
|
|
|
# We just guessed at hi, so bump it up until it's in range |
|
4582
|
2
|
|
|
|
|
8
|
my $rhi = almost_prime_count_lower($k, $hi); |
|
4583
|
2
|
|
|
|
|
8
|
while ($rhi < $n) { |
|
4584
|
2
|
|
|
|
|
7
|
$lo = Madd1int($hi); |
|
4585
|
2
|
|
|
|
|
16
|
$hi = Mvecsum($hi, int(1.02 * ("$hi"/"$rhi") * ("$n"-"$rhi")), 100); |
|
4586
|
2
|
|
|
|
|
6
|
$rhi = almost_prime_count_lower($k, $hi); |
|
4587
|
|
|
|
|
|
|
} |
|
4588
|
2
|
|
|
|
|
8
|
while ($lo < $hi) { |
|
4589
|
46
|
|
|
|
|
64
|
my $mid = $lo + (($hi-$lo) >> 1); |
|
4590
|
46
|
100
|
|
|
|
82
|
if (almost_prime_count_lower($k,$mid) < $n) { $lo = $mid+1; } |
|
|
28
|
|
|
|
|
90
|
|
|
4591
|
18
|
|
|
|
|
44
|
else { $hi = $mid; } |
|
4592
|
|
|
|
|
|
|
} |
|
4593
|
2
|
|
|
|
|
13
|
$lo; |
|
4594
|
|
|
|
|
|
|
} |
|
4595
|
|
|
|
|
|
|
sub nth_almost_prime_lower { |
|
4596
|
12
|
|
|
12
|
0
|
40
|
my($k, $n) = @_; |
|
4597
|
12
|
50
|
|
|
|
44
|
return undef if $n == 0; |
|
4598
|
12
|
0
|
|
|
|
34
|
return (($n == 1) ? 1 : 0) if $k == 0; |
|
|
|
50
|
|
|
|
|
|
|
4599
|
12
|
50
|
|
|
|
51
|
return Math::Prime::Util::nth_prime_lower($n) if $k == 1; |
|
4600
|
12
|
50
|
|
|
|
37
|
return _fast_small_nth_almost_prime($k,$n) if $n < 8; |
|
4601
|
|
|
|
|
|
|
|
|
4602
|
12
|
|
|
|
|
33
|
my $r = _kap_reduce_nth($k,$n); |
|
4603
|
12
|
50
|
|
|
|
62
|
if ($r > 0) { |
|
4604
|
0
|
|
|
|
|
0
|
my $nth = Math::Prime::Util::nth_almost_prime_lower($k-$r, $n); |
|
4605
|
0
|
|
|
|
|
0
|
return Mlshiftint($nth, $r); |
|
4606
|
|
|
|
|
|
|
} |
|
4607
|
|
|
|
|
|
|
|
|
4608
|
12
|
|
|
|
|
91
|
my $lo = Mlshiftint(5,$k); # $k >= 1, $n >= 8 |
|
4609
|
12
|
|
|
|
|
66
|
my $hi = Mtoint(1 + _almost_prime_nth_asymptotic($k, $n)); |
|
4610
|
|
|
|
|
|
|
# We just guessed at hi, so bump it up until it's in range |
|
4611
|
12
|
|
|
|
|
86
|
my $rhi = almost_prime_count_upper($k, $hi); |
|
4612
|
12
|
|
|
|
|
100
|
while ($rhi < $n) { |
|
4613
|
2
|
|
|
|
|
8
|
$lo = Madd1int($hi); |
|
4614
|
2
|
|
|
|
|
17
|
$hi = Mvecsum($hi, int(1.02 * ("$hi"/"$rhi") * ("$n"-"$rhi")), 100); |
|
4615
|
2
|
|
|
|
|
7
|
$rhi = almost_prime_count_upper($k, $hi); |
|
4616
|
|
|
|
|
|
|
} |
|
4617
|
12
|
|
|
|
|
79
|
while ($lo < $hi) { |
|
4618
|
118
|
|
|
|
|
252
|
my $mid = $lo + (($hi-$lo) >> 1); |
|
4619
|
118
|
100
|
|
|
|
233
|
if (almost_prime_count_upper($k,$mid) < $n) { $lo = $mid+1; } |
|
|
28
|
|
|
|
|
113
|
|
|
4620
|
90
|
|
|
|
|
295
|
else { $hi = $mid; } |
|
4621
|
|
|
|
|
|
|
} |
|
4622
|
12
|
|
|
|
|
42
|
$lo; |
|
4623
|
|
|
|
|
|
|
} |
|
4624
|
|
|
|
|
|
|
|
|
4625
|
|
|
|
|
|
|
sub nth_almost_prime_approx { |
|
4626
|
3
|
|
|
3
|
0
|
15641
|
my($k, $n) = @_; |
|
4627
|
3
|
50
|
|
|
|
15
|
return undef if $n == 0; |
|
4628
|
3
|
50
|
|
|
|
10
|
return Mlshiftint(1,$k) if $n == 1; |
|
4629
|
3
|
50
|
|
|
|
10
|
return undef if $k == 0; # n==1 already returned |
|
4630
|
3
|
50
|
|
|
|
12
|
return Math::Prime::Util::nth_prime_approx($n) if $k == 1; |
|
4631
|
3
|
50
|
|
|
|
10
|
return Math::Prime::Util::nth_semiprime_approx($n) if $k == 2; |
|
4632
|
3
|
50
|
|
|
|
12
|
return _fast_small_nth_almost_prime($k,$n) if $n < 8; |
|
4633
|
|
|
|
|
|
|
|
|
4634
|
3
|
|
|
|
|
12
|
my $r = _kap_reduce_nth($k,$n); |
|
4635
|
3
|
100
|
|
|
|
10
|
if ($r > 0) { |
|
4636
|
2
|
|
|
|
|
56
|
my $nth = Math::Prime::Util::nth_almost_prime_approx($k-$r, $n); |
|
4637
|
2
|
|
|
|
|
139
|
return Mmulint($nth, Mpowint(2,$r)); |
|
4638
|
|
|
|
|
|
|
} |
|
4639
|
|
|
|
|
|
|
|
|
4640
|
1
|
|
|
|
|
4
|
my $lo = Math::Prime::Util::nth_almost_prime_lower($k, $n); |
|
4641
|
1
|
|
|
|
|
6
|
my $hi = Math::Prime::Util::nth_almost_prime_upper($k, $n); |
|
4642
|
|
|
|
|
|
|
|
|
4643
|
|
|
|
|
|
|
# TODO: Add interpolation speedup steps |
|
4644
|
|
|
|
|
|
|
|
|
4645
|
1
|
|
|
|
|
7
|
while ($lo < $hi) { |
|
4646
|
22
|
|
|
|
|
43
|
my $mid = $lo + (($hi-$lo) >> 1); |
|
4647
|
22
|
100
|
|
|
|
38
|
if (almost_prime_count_approx($k,$mid) < $n) { $lo = $mid+1; } |
|
|
11
|
|
|
|
|
27
|
|
|
4648
|
11
|
|
|
|
|
22
|
else { $hi = $mid; } |
|
4649
|
|
|
|
|
|
|
} |
|
4650
|
1
|
|
|
|
|
20
|
$lo; |
|
4651
|
|
|
|
|
|
|
} |
|
4652
|
|
|
|
|
|
|
|
|
4653
|
|
|
|
|
|
|
sub _interp_linear { |
|
4654
|
10
|
|
|
10
|
|
39
|
my($n, $rlo, $rhi, $lo, $hi) = @_; |
|
4655
|
|
|
|
|
|
|
#return int( ($n-$rlo) * ($hi-$lo) / ($rhi-$rlo) ); |
|
4656
|
10
|
|
|
|
|
54
|
my $num = Mmulint( Msubint($n,$rlo), Msubint($hi,$lo) ); |
|
4657
|
10
|
|
|
|
|
38
|
my $den = Msubint($rhi, $rlo); |
|
4658
|
10
|
|
|
|
|
81
|
return Mdivint(Maddint($num,$den>>1), $den); |
|
4659
|
|
|
|
|
|
|
#return divint($num, $den); |
|
4660
|
|
|
|
|
|
|
} |
|
4661
|
|
|
|
|
|
|
sub _inverse_interpolate { |
|
4662
|
10
|
|
|
10
|
|
57
|
my($lo, $hi, $n, $k, $callback) = @_; |
|
4663
|
10
|
|
|
|
|
25
|
my($mid, $rmid, $rlo, $rhi); |
|
4664
|
|
|
|
|
|
|
|
|
4665
|
10
|
|
|
|
|
31
|
$rlo = $callback->($k, $lo); |
|
4666
|
10
|
50
|
|
|
|
38
|
croak "interp: bad lower bound" if $rlo > $n; |
|
4667
|
10
|
50
|
|
|
|
32
|
return $lo if $rlo == $n; # If lo wasn't small enough, this could be wrong. |
|
4668
|
|
|
|
|
|
|
|
|
4669
|
|
|
|
|
|
|
# We have the exact value (rlo) at lo. |
|
4670
|
|
|
|
|
|
|
#print "1 $lo $hi ",$hi-$lo,"\n"; |
|
4671
|
|
|
|
|
|
|
|
|
4672
|
10
|
50
|
|
|
|
76
|
$rhi = $callback->($k, $hi) if $hi != 0; |
|
4673
|
|
|
|
|
|
|
|
|
4674
|
10
|
|
|
|
|
33
|
while ($hi == 0) { |
|
4675
|
|
|
|
|
|
|
# Use lo/rlo to make an estimate |
|
4676
|
|
|
|
|
|
|
|
|
4677
|
|
|
|
|
|
|
# Make an estimate of where we will end up |
|
4678
|
10
|
50
|
|
|
|
60
|
my $estf = ($rlo == 0) ? 1 : Mdivint(Mlshiftint($n,8),$rlo) - 1; # slightly lower |
|
4679
|
10
|
50
|
|
|
|
34
|
$estf = 1+(1<<8) if $estf <= (1<<8); |
|
4680
|
10
|
50
|
|
|
|
34
|
$estf = (8<<8) if $estf > (8<<8); |
|
4681
|
10
|
|
|
|
|
41
|
$mid = Mrshiftint(Mmulint($estf,$lo),8); |
|
4682
|
|
|
|
|
|
|
# rmid is the exact count at this estimate |
|
4683
|
10
|
|
|
|
|
39
|
$rmid = $callback->($k, $mid); |
|
4684
|
|
|
|
|
|
|
|
|
4685
|
|
|
|
|
|
|
# Either we have a hi value, or we pull in lo and do it again. |
|
4686
|
10
|
50
|
|
|
|
36
|
if ($rmid >= $n) { $hi = $mid; $rhi = $rmid; } |
|
|
10
|
|
|
|
|
28
|
|
|
|
10
|
|
|
|
|
35
|
|
|
4687
|
0
|
|
|
|
|
0
|
else { $lo = $mid; $rlo = $rmid; } |
|
|
0
|
|
|
|
|
0
|
|
|
4688
|
|
|
|
|
|
|
#print "2 $lo $hi ",$hi-$lo,"\n"; |
|
4689
|
|
|
|
|
|
|
} |
|
4690
|
10
|
50
|
33
|
|
|
78
|
croak "interp bad initial" unless $rlo <= $n && $rhi >= $n; |
|
4691
|
10
|
50
|
|
|
|
44
|
return $lo if $rlo == $n; |
|
4692
|
10
|
0
|
0
|
|
|
44
|
return (($rlo==$n || ($rlo<$n && $rhi>$n)) ? $lo : $hi) if $hi-$lo <= 1; |
|
|
|
50
|
|
|
|
|
|
|
4693
|
|
|
|
|
|
|
|
|
4694
|
|
|
|
|
|
|
# Step 1. Linear interpolation while it centers. |
|
4695
|
|
|
|
|
|
|
|
|
4696
|
10
|
50
|
|
|
|
85
|
$mid = ($n == $rhi) ? $hi-1 |
|
4697
|
|
|
|
|
|
|
: Maddint($lo, _interp_linear($n,$rlo,$rhi,$lo,$hi)); |
|
4698
|
10
|
50
|
|
|
|
53
|
if ($mid == $lo) { $mid++; } elsif ($mid == $hi) { $mid--; } |
|
|
0
|
50
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4699
|
|
|
|
|
|
|
|
|
4700
|
10
|
|
33
|
|
|
108
|
while ($rhi > $n && ($hi-$lo) > 1) { |
|
4701
|
19
|
50
|
33
|
|
|
82
|
croak "interp: need 3 unique points" unless $lo < $mid && $mid < $hi; |
|
4702
|
|
|
|
|
|
|
#print "I $lo $hi ",$hi-$lo,"\n"; |
|
4703
|
19
|
|
|
|
|
57
|
$rmid = $callback->($k, $mid); |
|
4704
|
19
|
50
|
|
|
|
59
|
if ($rmid >= $n) { ($hi,$rhi) = ($mid,$rmid); } |
|
|
19
|
|
|
|
|
50
|
|
|
4705
|
0
|
|
|
|
|
0
|
else { ($lo,$rlo) = ($mid,$rmid); } |
|
4706
|
19
|
100
|
|
|
|
58
|
last if $rhi == $n; |
|
4707
|
|
|
|
|
|
|
|
|
4708
|
9
|
|
|
|
|
46
|
my $num = Mmulint(Msubint($n,$rmid),Msubint($hi,$lo)); |
|
4709
|
9
|
|
|
|
|
32
|
my $den = Msubint($rhi,$rlo); |
|
4710
|
9
|
|
|
|
|
34
|
$mid = Maddint($mid, Mdivint($num, $den)); |
|
4711
|
|
|
|
|
|
|
# Fairly crude way of pulling in opposite side so we bracket. |
|
4712
|
9
|
50
|
|
|
|
41
|
if ($mid <= $lo) { $mid = Maddint($lo, Mdivint(Msubint($hi,$lo),100)); } |
|
|
0
|
50
|
|
|
|
0
|
|
|
4713
|
0
|
|
|
|
|
0
|
elsif ($mid >= $hi) { $mid = Msubint($hi, Mdivint(Msubint($hi,$lo),100)); } |
|
4714
|
9
|
50
|
|
|
|
82
|
if ($mid == $lo) { $mid++; } elsif ($mid == $hi) { $mid--; } |
|
|
0
|
50
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4715
|
9
|
50
|
33
|
|
|
86
|
croak "interp: range error" unless $lo <= $mid && $mid <= $hi; |
|
4716
|
|
|
|
|
|
|
} |
|
4717
|
|
|
|
|
|
|
|
|
4718
|
10
|
50
|
|
|
|
33
|
return $lo if $rlo == $n; |
|
4719
|
10
|
0
|
0
|
|
|
63
|
return (($rlo==$n || ($rlo<$n && $rhi>$n)) ? $lo : $hi) if $hi-$lo <= 1; |
|
|
|
50
|
|
|
|
|
|
|
4720
|
|
|
|
|
|
|
|
|
4721
|
10
|
50
|
33
|
|
|
60
|
croak "interp: bad step 1 interpolation" unless $rlo < $n && $rhi == $n; |
|
4722
|
|
|
|
|
|
|
|
|
4723
|
|
|
|
|
|
|
# Step 2. Ridder's method until we're very close. |
|
4724
|
|
|
|
|
|
|
|
|
4725
|
10
|
50
|
33
|
|
|
49
|
croak "interp: Ridder initial assumption error" unless $rlo<$n && $rhi>=$n; |
|
4726
|
|
|
|
|
|
|
#print "F $lo $hi ",$hi-$lo,"\n"; |
|
4727
|
|
|
|
|
|
|
|
|
4728
|
10
|
|
66
|
|
|
60
|
while (($hi-$lo > 8) && ($hi-$lo) > 1) { |
|
4729
|
10
|
|
|
|
|
49
|
my($x0, $x2, $x1) = ($lo, $hi, Maddint($lo, Msubint($hi,$lo)>>1)); |
|
4730
|
10
|
|
|
|
|
37
|
my($rx1) = $callback->($k, $x1); |
|
4731
|
10
|
|
|
|
|
75
|
my($fx0, $fx1, $fx2) = (Msubint($rlo,$n), Msubint($rx1,$n), Msubint($rhi,$n)+1); |
|
4732
|
|
|
|
|
|
|
|
|
4733
|
|
|
|
|
|
|
# Calculate new point using false position method |
|
4734
|
|
|
|
|
|
|
#my $pos = (($x1-$x0) * "$fx1") / sqrt( "$fx1"*"$fx1" - "$fx0"*"$fx2" ); |
|
4735
|
|
|
|
|
|
|
#my $x3 = $x1 - int($pos+0.5); |
|
4736
|
|
|
|
|
|
|
# Rather convoluted so it's all in integer. |
|
4737
|
10
|
|
|
|
|
35
|
my $num = Mmulint($fx1, Msubint($x1,$x0)); |
|
4738
|
10
|
|
|
|
|
35
|
my $d1 = Msubint(Mmulint($fx1,$fx1),Mmulint($fx0,$fx2)); |
|
4739
|
10
|
|
|
|
|
59
|
my $den = Msqrtint(Mlshiftint($d1,64)); |
|
4740
|
10
|
|
|
|
|
63
|
$num = Mlshiftint($num, 32); |
|
4741
|
10
|
|
|
|
|
57
|
my $pos = Mdivint(Maddint($num,$den>>1), $den); |
|
4742
|
10
|
|
|
|
|
39
|
my $x3 = Msubint($x1, $pos); |
|
4743
|
|
|
|
|
|
|
|
|
4744
|
|
|
|
|
|
|
# print " Ridder mid = $x1 - $pos = $x3\n"; |
|
4745
|
|
|
|
|
|
|
# print " $lo $x1 $x3 $hi\n"; |
|
4746
|
|
|
|
|
|
|
|
|
4747
|
10
|
50
|
33
|
|
|
77
|
if ($x3 >= $hi || $x3 <= $lo || $x3 == $x1) { |
|
|
|
|
33
|
|
|
|
|
|
4748
|
|
|
|
|
|
|
|
|
4749
|
|
|
|
|
|
|
# The new point hasn't given us anything. Just bisect. |
|
4750
|
0
|
0
|
|
|
|
0
|
if ($rx1 >= $n) { $hi = $x1; $rhi = $rx1; } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4751
|
0
|
|
|
|
|
0
|
else { $lo = $x1; $rlo = $rx1; } |
|
|
0
|
|
|
|
|
0
|
|
|
4752
|
|
|
|
|
|
|
|
|
4753
|
|
|
|
|
|
|
} else { |
|
4754
|
|
|
|
|
|
|
|
|
4755
|
10
|
|
|
|
|
35
|
my $rx3 = $callback->($k,$x3); |
|
4756
|
10
|
50
|
|
|
|
39
|
if ($rx1 > $rx3) { ($x1,$x3,$rx1,$rx3) = ($x3,$x1,$rx3,$rx1); } |
|
|
0
|
|
|
|
|
0
|
|
|
4757
|
10
|
50
|
|
|
|
53
|
if ($rx1 >= $n) { $hi = $x1; $rhi = $rx1; } |
|
|
0
|
100
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
4758
|
1
|
|
|
|
|
2
|
elsif ($rx3 >= $n) { $lo = $x1; $rlo = $rx1; $hi = $x3; $rhi = $rx3; } |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
2
|
|
|
4759
|
9
|
|
|
|
|
20
|
else { $lo = $x3; $rlo = $rx3; } |
|
|
9
|
|
|
|
|
50
|
|
|
4760
|
|
|
|
|
|
|
|
|
4761
|
|
|
|
|
|
|
} |
|
4762
|
|
|
|
|
|
|
#print "R $lo $hi ",$hi-$lo,"\n"; |
|
4763
|
10
|
50
|
33
|
|
|
115
|
croak "interp: Ridder step error" unless $rlo < $n && $rhi >= $n; |
|
4764
|
|
|
|
|
|
|
} |
|
4765
|
|
|
|
|
|
|
|
|
4766
|
|
|
|
|
|
|
# Step 3. Binary search. Invariant: f(lo) < n, f(hi) >= n |
|
4767
|
|
|
|
|
|
|
|
|
4768
|
10
|
|
|
|
|
39
|
while ($hi-$lo > 1) { |
|
4769
|
30
|
|
|
|
|
68
|
$mid = $lo + (($hi-$lo) >> 1); |
|
4770
|
30
|
|
|
|
|
91
|
$rmid = $callback->($k, $mid); |
|
4771
|
30
|
100
|
|
|
|
108
|
if ($rmid < $n) { $lo = $mid; } |
|
|
11
|
|
|
|
|
36
|
|
|
4772
|
19
|
|
|
|
|
59
|
else { $hi = $mid; } |
|
4773
|
|
|
|
|
|
|
#print "B $lo $hi ",$hi-$lo,"\n"; |
|
4774
|
|
|
|
|
|
|
} |
|
4775
|
10
|
|
|
|
|
94
|
$hi; |
|
4776
|
|
|
|
|
|
|
} |
|
4777
|
|
|
|
|
|
|
|
|
4778
|
|
|
|
|
|
|
sub nth_almost_prime { |
|
4779
|
21
|
|
|
21
|
0
|
58
|
my($k, $n) = @_; |
|
4780
|
21
|
50
|
|
|
|
74
|
return undef if $n == 0; |
|
4781
|
21
|
50
|
|
|
|
61
|
return Mlshiftint(1,$k) if $n == 1; |
|
4782
|
21
|
50
|
|
|
|
80
|
return undef if $k == 0; # n==1 already returned |
|
4783
|
21
|
100
|
|
|
|
66
|
return Math::Prime::Util::nth_prime($n) if $k == 1; |
|
4784
|
20
|
100
|
|
|
|
72
|
return Math::Prime::Util::nth_semiprime($n) if $k == 2; |
|
4785
|
19
|
100
|
|
|
|
70
|
return _fast_small_nth_almost_prime($k,$n) if $n < 8; |
|
4786
|
|
|
|
|
|
|
|
|
4787
|
18
|
|
|
|
|
92
|
my $r = _kap_reduce_nth($k,$n); |
|
4788
|
18
|
100
|
|
|
|
66
|
if ($r > 0) { |
|
4789
|
8
|
|
|
|
|
44
|
my $nth = Math::Prime::Util::nth_almost_prime($k-$r, $n); |
|
4790
|
8
|
|
|
|
|
39
|
return Mmulint($nth, Mpowint(2,$r)); |
|
4791
|
|
|
|
|
|
|
} |
|
4792
|
|
|
|
|
|
|
|
|
4793
|
10
|
|
|
|
|
52
|
my $lo = Math::Prime::Util::nth_almost_prime_lower($k, $n); |
|
4794
|
|
|
|
|
|
|
|
|
4795
|
10
|
|
|
89
|
|
118
|
return _inverse_interpolate($lo, 0, $n, $k, sub { Math::Prime::Util::almost_prime_count($_[0],$_[1]); }); |
|
|
89
|
|
|
|
|
339
|
|
|
4796
|
|
|
|
|
|
|
#my $ncalls = 0; |
|
4797
|
|
|
|
|
|
|
#my $res = _inverse_interpolate($lo, 0, $n, $k, sub { $ncalls++; Math::Prime::Util::almost_prime_count($_[0],$_[1]); }); |
|
4798
|
|
|
|
|
|
|
#print "ncalls: $ncalls\n"; |
|
4799
|
|
|
|
|
|
|
#return $ncalls; |
|
4800
|
|
|
|
|
|
|
#return $res; |
|
4801
|
|
|
|
|
|
|
} |
|
4802
|
|
|
|
|
|
|
|
|
4803
|
|
|
|
|
|
|
sub nth_omega_prime { |
|
4804
|
5
|
|
|
5
|
0
|
16
|
my($k, $n) = @_; |
|
4805
|
5
|
50
|
|
|
|
16
|
return undef if $n == 0; |
|
4806
|
5
|
50
|
|
|
|
15
|
return Mpn_primorial($k) if $n == 1; |
|
4807
|
5
|
50
|
|
|
|
18
|
return undef if $k == 0; # n==1 already returned |
|
4808
|
|
|
|
|
|
|
|
|
4809
|
|
|
|
|
|
|
# Very inefficient algorithm. |
|
4810
|
5
|
|
|
|
|
24
|
my $i = Mpn_primorial($k); |
|
4811
|
5
|
|
|
|
|
29
|
while (1) { |
|
4812
|
30
|
|
|
|
|
146
|
$i++ while Mprime_omega($i) != $k; |
|
4813
|
30
|
100
|
|
|
|
128
|
return $i if --$n == 0; |
|
4814
|
25
|
|
|
|
|
47
|
$i++; |
|
4815
|
|
|
|
|
|
|
} |
|
4816
|
|
|
|
|
|
|
} |
|
4817
|
|
|
|
|
|
|
|
|
4818
|
|
|
|
|
|
|
sub nth_ramanujan_prime_upper { |
|
4819
|
23
|
|
|
23
|
0
|
50
|
my($n) = @_; |
|
4820
|
23
|
|
|
|
|
69
|
validate_integer_nonneg($n); |
|
4821
|
23
|
50
|
|
|
|
61
|
return (0,2,11)[$n] if $n <= 2; |
|
4822
|
|
|
|
|
|
|
|
|
4823
|
23
|
50
|
|
|
|
56
|
if ($n < 50) { |
|
4824
|
0
|
0
|
|
|
|
0
|
return Mnth_prime_upper(int(2.6*$n)) if $n <= 20; |
|
4825
|
0
|
|
|
|
|
0
|
return 33+((310*Mnth_prime_upper(2*$n))>>8); |
|
4826
|
|
|
|
|
|
|
} |
|
4827
|
|
|
|
|
|
|
|
|
4828
|
23
|
|
|
|
|
69
|
my $nth = Mnth_prime_upper(Mmulint($n,3)); |
|
4829
|
|
|
|
|
|
|
|
|
4830
|
23
|
100
|
|
|
|
106
|
return 115+((727*$nth) >> 10) if $n < 647; |
|
4831
|
|
|
|
|
|
|
|
|
4832
|
|
|
|
|
|
|
# TODO: Ideally these would all be adjusted to make smooth transitions. |
|
4833
|
|
|
|
|
|
|
|
|
4834
|
2
|
0
|
|
|
|
14
|
my($add,$mul) = $n < 16000 ? ( 271,358) |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
4835
|
|
|
|
|
|
|
: $n < 1200000 ? (9450,350) |
|
4836
|
|
|
|
|
|
|
: $n < 7000000 ? (5000,349) |
|
4837
|
|
|
|
|
|
|
: $n < 90000000 ? ( 0,348) |
|
4838
|
|
|
|
|
|
|
: $n < 3100000000 ? ( 0,347) |
|
4839
|
|
|
|
|
|
|
: ( 0,346); |
|
4840
|
|
|
|
|
|
|
|
|
4841
|
2
|
|
|
|
|
8
|
my $ret = Mrshiftint(Mmulint($mul,$nth),9); |
|
4842
|
2
|
50
|
|
|
|
14
|
$ret = Maddint($ret,$add) if $add != 0; |
|
4843
|
2
|
|
|
|
|
10
|
$ret; |
|
4844
|
|
|
|
|
|
|
} |
|
4845
|
|
|
|
|
|
|
sub nth_ramanujan_prime_lower { |
|
4846
|
23
|
|
|
23
|
0
|
72
|
my($n) = @_; |
|
4847
|
23
|
|
|
|
|
68
|
validate_integer_nonneg($n); |
|
4848
|
23
|
50
|
|
|
|
74
|
return (0,2,11)[$n] if $n <= 2; |
|
4849
|
23
|
|
|
|
|
70
|
my $nth = Math::Prime::Util::nth_prime_lower(Mmulint($n,2)); |
|
4850
|
23
|
100
|
|
|
|
121
|
return Mdivint(Mmulint(275,$nth),256) if $n < 10000; |
|
4851
|
2
|
50
|
|
|
|
13
|
return Mdivint(Mmulint(262,$nth),256) if $n < 1e10; |
|
4852
|
0
|
|
|
|
|
0
|
$nth; |
|
4853
|
|
|
|
|
|
|
} |
|
4854
|
|
|
|
|
|
|
sub nth_ramanujan_prime_approx { |
|
4855
|
6
|
|
|
6
|
0
|
17
|
my($n) = @_; |
|
4856
|
6
|
|
|
|
|
22
|
validate_integer_nonneg($n); |
|
4857
|
6
|
50
|
|
|
|
19
|
return (0,2,11)[$n] if $n <= 2; |
|
4858
|
6
|
|
|
|
|
19
|
my($lo,$hi) = (nth_ramanujan_prime_lower($n),nth_ramanujan_prime_upper($n)); |
|
4859
|
6
|
|
|
|
|
28
|
$lo + (($hi-$lo)>>1); |
|
4860
|
|
|
|
|
|
|
} |
|
4861
|
|
|
|
|
|
|
sub ramanujan_prime_count_upper { |
|
4862
|
2
|
|
|
2
|
0
|
15
|
my($n) = @_; |
|
4863
|
2
|
|
|
|
|
8
|
validate_integer_nonneg($n); |
|
4864
|
2
|
0
|
|
|
|
6
|
return (($n < 2) ? 0 : 1) if $n < 11; |
|
|
|
50
|
|
|
|
|
|
|
4865
|
2
|
|
|
|
|
7
|
my $lo = Mdivint(prime_count_lower($n),3); |
|
4866
|
2
|
|
|
|
|
7
|
my $hi = Mrshiftint(prime_count_upper($n)); |
|
4867
|
|
|
|
|
|
|
1+_binary_search($n, $lo, $hi, |
|
4868
|
2
|
|
|
16
|
|
18
|
sub{Math::Prime::Util::nth_ramanujan_prime_lower(shift)}); |
|
|
16
|
|
|
|
|
39
|
|
|
4869
|
|
|
|
|
|
|
} |
|
4870
|
|
|
|
|
|
|
sub ramanujan_prime_count_lower { |
|
4871
|
2
|
|
|
2
|
0
|
4
|
my($n) = @_; |
|
4872
|
2
|
|
|
|
|
10
|
validate_integer_nonneg($n); |
|
4873
|
2
|
0
|
|
|
|
6
|
return (($n < 2) ? 0 : 1) if $n < 11; |
|
|
|
50
|
|
|
|
|
|
|
4874
|
2
|
|
|
|
|
9
|
my $lo = int(prime_count_lower($n) / 3); |
|
4875
|
2
|
|
|
|
|
9
|
my $hi = prime_count_upper($n) >> 1; |
|
4876
|
|
|
|
|
|
|
_binary_search($n, $lo, $hi, |
|
4877
|
2
|
|
|
16
|
|
18
|
sub{Math::Prime::Util::nth_ramanujan_prime_upper(shift)}); |
|
|
16
|
|
|
|
|
45
|
|
|
4878
|
|
|
|
|
|
|
} |
|
4879
|
|
|
|
|
|
|
sub ramanujan_prime_count_approx { |
|
4880
|
1
|
|
|
1
|
0
|
13
|
my($n) = @_; |
|
4881
|
1
|
|
|
|
|
8
|
validate_integer_nonneg($n); |
|
4882
|
1
|
0
|
|
|
|
6
|
return (($n < 2) ? 0 : 1) if $n < 11; |
|
|
|
50
|
|
|
|
|
|
|
4883
|
|
|
|
|
|
|
#$n = _upgrade_to_float($n) if ref($n) || $n > 2e16; |
|
4884
|
1
|
|
|
|
|
6
|
my $lo = ramanujan_prime_count_lower($n); |
|
4885
|
1
|
|
|
|
|
10
|
my $hi = ramanujan_prime_count_upper($n); |
|
4886
|
|
|
|
|
|
|
_binary_search($n, $lo, $hi, |
|
4887
|
5
|
|
|
5
|
|
14
|
sub{Math::Prime::Util::nth_ramanujan_prime_approx(shift)}, |
|
4888
|
1
|
|
|
5
|
|
33
|
sub{ ($_[2]-$_[1])/$_[1] < 1e-15 } ); |
|
|
5
|
|
|
|
|
25
|
|
|
4889
|
|
|
|
|
|
|
} |
|
4890
|
|
|
|
|
|
|
|
|
4891
|
|
|
|
|
|
|
sub _sum_primes_n { |
|
4892
|
3
|
|
|
3
|
|
11
|
my($n) = @_; |
|
4893
|
3
|
50
|
|
|
|
18
|
return (0,0,2,5,5)[$n] if $n < 5; |
|
4894
|
3
|
|
|
|
|
32
|
my $r = Msqrtint($n); |
|
4895
|
3
|
|
|
|
|
30
|
my $r2 = $r + Mdivint($n, $r+1); |
|
4896
|
3
|
|
|
|
|
9
|
my(@V,@S); |
|
4897
|
3
|
|
|
|
|
12
|
for my $k (0 .. $r2) { |
|
4898
|
9184
|
100
|
|
|
|
36065
|
my $v = ($k <= $r) ? $k : Mdivint($n,($r2-$k+1)); |
|
4899
|
9184
|
|
|
|
|
15480
|
$V[$k] = $v; |
|
4900
|
9184
|
|
|
|
|
20508
|
$S[$k] = Maddint( |
|
4901
|
|
|
|
|
|
|
Mrshiftint(Mmulint($v, $v-1)), |
|
4902
|
|
|
|
|
|
|
$v-1); |
|
4903
|
|
|
|
|
|
|
} |
|
4904
|
3
|
|
|
|
|
15
|
for my $p (2 .. $r) { |
|
4905
|
4589
|
100
|
|
|
|
12734
|
next unless $S[$p] > $S[$p-1]; |
|
4906
|
724
|
|
|
|
|
1515
|
my $sp = $S[$p-1]; |
|
4907
|
724
|
|
|
|
|
1890
|
my $p2 = Mmulint($p,$p); |
|
4908
|
724
|
|
|
|
|
11231
|
for my $v (reverse @V) { |
|
4909
|
134363
|
100
|
|
|
|
283717
|
last if $v < $p2; |
|
4910
|
133639
|
|
|
|
|
243467
|
my($a,$b) = ($v,Mdivint($v,$p)); |
|
4911
|
133639
|
100
|
|
|
|
298524
|
$a = $r2 - Mdivint($n,$a) + 1 if $a > $r; |
|
4912
|
133639
|
100
|
|
|
|
262422
|
$b = $r2 - Mdivint($n,$b) + 1 if $b > $r; |
|
4913
|
133639
|
|
|
|
|
384671
|
$S[$a] -= Mmulint($p, $S[$b]-$sp); |
|
4914
|
|
|
|
|
|
|
#$S[$a] = Msubint($S[$a], Mmulint($p, Msubint($S[$b],$sp))); |
|
4915
|
|
|
|
|
|
|
} |
|
4916
|
|
|
|
|
|
|
} |
|
4917
|
3
|
|
|
|
|
1733
|
$S[$r2]; |
|
4918
|
|
|
|
|
|
|
} |
|
4919
|
|
|
|
|
|
|
sub sum_primes { |
|
4920
|
3
|
|
|
3
|
0
|
15
|
my($low,$high) = @_; |
|
4921
|
3
|
100
|
|
|
|
21
|
if (defined $high) { validate_integer_nonneg($low); } |
|
|
1
|
|
|
|
|
15
|
|
|
4922
|
2
|
|
|
|
|
8
|
else { ($low,$high) = (2, $low); } |
|
4923
|
3
|
|
|
|
|
15
|
validate_integer_nonneg($high); |
|
4924
|
3
|
|
|
|
|
24
|
my $sum = 0; |
|
4925
|
|
|
|
|
|
|
|
|
4926
|
3
|
50
|
|
|
|
26
|
return $sum if $high < $low; |
|
4927
|
|
|
|
|
|
|
|
|
4928
|
|
|
|
|
|
|
# It's very possible we're here because they've counted too high. Skip fwd. |
|
4929
|
3
|
50
|
66
|
|
|
31
|
if ($low <= 2 && $high >= 29505444491) { |
|
4930
|
0
|
|
|
|
|
0
|
($low, $sum) = (29505444503, tobigint("18446744087046669523")); |
|
4931
|
|
|
|
|
|
|
} |
|
4932
|
|
|
|
|
|
|
|
|
4933
|
3
|
50
|
|
|
|
23
|
return $sum if $low > $high; |
|
4934
|
|
|
|
|
|
|
|
|
4935
|
|
|
|
|
|
|
# Easy, not unreasonable, but seems slower than the windowed sum. |
|
4936
|
|
|
|
|
|
|
# return _sum_primes_n($high) if $low <= 2; |
|
4937
|
|
|
|
|
|
|
|
|
4938
|
|
|
|
|
|
|
# Performance decision, which to use. |
|
4939
|
3
|
50
|
66
|
|
|
65
|
if ( $high <= ~0 && |
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
4940
|
|
|
|
|
|
|
$high > (MPU_64BIT ? 2000000 : 320000) && |
|
4941
|
|
|
|
|
|
|
($high-$low) > $high/50 && |
|
4942
|
|
|
|
|
|
|
!getconfig()->{'xs'}) { |
|
4943
|
2
|
|
|
|
|
45
|
my $hsum = _sum_primes_n($high); |
|
4944
|
2
|
100
|
|
|
|
31
|
my $lsum = ($low <= 2) ? 0 : _sum_primes_n($low - 1); |
|
4945
|
2
|
|
|
|
|
103
|
return $hsum - $lsum; |
|
4946
|
|
|
|
|
|
|
} |
|
4947
|
|
|
|
|
|
|
|
|
4948
|
|
|
|
|
|
|
# Sum in windows. |
|
4949
|
|
|
|
|
|
|
# TODO: consider some skipping forward with small tables. |
|
4950
|
1
|
|
33
|
|
|
25
|
my $xssum = (MPU_64BIT && $high < 6e14 && getconfig()->{'xs'}); |
|
4951
|
1
|
50
|
33
|
|
|
10
|
my $step = ($xssum && $high > 5e13) ? 1_000_000 : 11_000_000; |
|
4952
|
1
|
|
|
|
|
9
|
Math::Prime::Util::prime_precalc(Msqrtint($high)); |
|
4953
|
1
|
|
|
|
|
5
|
while ($low <= $high) { |
|
4954
|
1
|
|
|
|
|
6
|
my $next = Maddint($low, $step) - 1; |
|
4955
|
1
|
50
|
|
|
|
7
|
$next = $high if $next > $high; |
|
4956
|
|
|
|
|
|
|
$sum = Maddint($sum, |
|
4957
|
|
|
|
|
|
|
($xssum) ? Math::Prime::Util::sum_primes($low,$next) |
|
4958
|
1
|
50
|
|
|
|
5
|
: Mvecsum( @{Mprimes($low,$next)} )); |
|
|
1
|
|
|
|
|
9
|
|
|
4959
|
1
|
50
|
|
|
|
35
|
last if $next == $high; |
|
4960
|
0
|
|
|
|
|
0
|
$low = Madd1int($next); |
|
4961
|
|
|
|
|
|
|
} |
|
4962
|
1
|
|
|
|
|
14
|
$sum; |
|
4963
|
|
|
|
|
|
|
} |
|
4964
|
|
|
|
|
|
|
|
|
4965
|
|
|
|
|
|
|
sub print_primes { |
|
4966
|
0
|
|
|
0
|
0
|
0
|
my($low,$high,$fd) = @_; |
|
4967
|
0
|
0
|
|
|
|
0
|
if (defined $high) { validate_integer_nonneg($low); } |
|
|
0
|
|
|
|
|
0
|
|
|
4968
|
0
|
|
|
|
|
0
|
else { ($low,$high) = (2, $low); } |
|
4969
|
0
|
|
|
|
|
0
|
validate_integer_nonneg($high); |
|
4970
|
|
|
|
|
|
|
|
|
4971
|
0
|
0
|
|
|
|
0
|
$fd = fileno(STDOUT) unless defined $fd; |
|
4972
|
0
|
|
|
|
|
0
|
open(my $fh, ">>&=", $fd); # TODO .... or die |
|
4973
|
|
|
|
|
|
|
|
|
4974
|
0
|
0
|
|
|
|
0
|
if ($high >= $low) { |
|
4975
|
0
|
|
|
|
|
0
|
my $p1 = $low; |
|
4976
|
0
|
|
|
|
|
0
|
while ($p1 <= $high) { |
|
4977
|
0
|
|
|
|
|
0
|
my $p2 = $p1 + 15_000_000 - 1; |
|
4978
|
0
|
0
|
|
|
|
0
|
$p2 = $high if $p2 > $high; |
|
4979
|
0
|
0
|
|
|
|
0
|
if ($Math::Prime::Util::_GMPfunc{"sieve_primes"}) { |
|
4980
|
0
|
|
|
|
|
0
|
print $fh "$_\n" for Math::Prime::Util::GMP::sieve_primes($p1,$p2,0); |
|
4981
|
|
|
|
|
|
|
} else { |
|
4982
|
0
|
|
|
|
|
0
|
print $fh "$_\n" for @{Mprimes($p1,$p2)}; |
|
|
0
|
|
|
|
|
0
|
|
|
4983
|
|
|
|
|
|
|
} |
|
4984
|
0
|
|
|
|
|
0
|
$p1 = $p2+1; |
|
4985
|
|
|
|
|
|
|
} |
|
4986
|
|
|
|
|
|
|
} |
|
4987
|
0
|
|
|
|
|
0
|
close($fh); |
|
4988
|
|
|
|
|
|
|
} |
|
4989
|
|
|
|
|
|
|
|
|
4990
|
|
|
|
|
|
|
|
|
4991
|
|
|
|
|
|
|
############################################################################# |
|
4992
|
|
|
|
|
|
|
|
|
4993
|
|
|
|
|
|
|
sub _mulmod { |
|
4994
|
13578
|
|
|
13578
|
|
28058
|
my($x, $y, $n) = @_; |
|
4995
|
13578
|
100
|
|
|
|
77886
|
return (($x * $y) % $n) if ($x|$y) < MPU_HALFWORD; |
|
4996
|
|
|
|
|
|
|
#return (($x * $y) % $n) if ($x|$y) < MPU_HALFWORD || $y == 0 || $x < int(~0/$y); |
|
4997
|
13578
|
|
|
|
|
10592
|
my $r = 0; |
|
4998
|
13578
|
50
|
|
|
|
13889
|
$x %= $n if $x >= $n; |
|
4999
|
13578
|
50
|
|
|
|
14588
|
$y %= $n if $y >= $n; |
|
5000
|
13578
|
100
|
|
|
|
15377
|
($x,$y) = ($y,$x) if $x < $y; |
|
5001
|
13578
|
100
|
|
|
|
13701
|
if ($n <= (~0 >> 1)) { |
|
5002
|
5882
|
|
|
|
|
12162
|
while ($y > 1) { |
|
5003
|
261173
|
100
|
|
|
|
474494
|
if ($y & 1) { $r += $x; $r -= $n if $r >= $n; } |
|
|
126810
|
100
|
|
|
|
173384
|
|
|
|
126810
|
|
|
|
|
228803
|
|
|
5004
|
261173
|
|
|
|
|
354140
|
$y >>= 1; |
|
5005
|
261173
|
100
|
|
|
|
350111
|
$x += $x; $x -= $n if $x >= $n; |
|
|
261173
|
|
|
|
|
590102
|
|
|
5006
|
|
|
|
|
|
|
} |
|
5007
|
5882
|
100
|
|
|
|
12486
|
if ($y & 1) { $r += $x; $r -= $n if $r >= $n; } |
|
|
5882
|
50
|
|
|
|
8585
|
|
|
|
5882
|
|
|
|
|
12466
|
|
|
5008
|
|
|
|
|
|
|
} else { |
|
5009
|
7696
|
|
|
|
|
2237
|
while ($y > 1) { |
|
5010
|
65241
|
100
|
|
|
|
123061
|
if ($y & 1) { $r = $n-$r; $r = ($x >= $r) ? $x-$r : $n-$r+$x; } |
|
|
32609
|
100
|
|
|
|
46754
|
|
|
|
32609
|
|
|
|
|
59974
|
|
|
5011
|
65241
|
|
|
|
|
90819
|
$y >>= 1; |
|
5012
|
65241
|
100
|
|
|
|
150376
|
$x = ($x > ($n - $x)) ? ($x - $n) + $x : $x + $x; |
|
5013
|
|
|
|
|
|
|
} |
|
5014
|
7696
|
100
|
|
|
|
2600
|
if ($y & 1) { $r = $n-$r; $r = ($x >= $r) ? $x-$r : $n-$r+$x; } |
|
|
1088
|
50
|
|
|
|
1600
|
|
|
|
1088
|
|
|
|
|
2191
|
|
|
5015
|
|
|
|
|
|
|
} |
|
5016
|
13578
|
|
|
|
|
23959
|
$r; |
|
5017
|
|
|
|
|
|
|
} |
|
5018
|
|
|
|
|
|
|
sub _addmod { |
|
5019
|
3436
|
|
|
3436
|
|
6995
|
my($x, $y, $n) = @_; |
|
5020
|
3436
|
50
|
|
|
|
6714
|
$x %= $n if $x >= $n; |
|
5021
|
3436
|
50
|
|
|
|
6634
|
$y %= $n if $y >= $n; |
|
5022
|
3436
|
100
|
|
|
|
7451
|
if (($n-$x) <= $y) { |
|
5023
|
1393
|
100
|
|
|
|
3671
|
($x,$y) = ($y,$x) if $y > $x; |
|
5024
|
1393
|
|
|
|
|
2295
|
$x -= $n; |
|
5025
|
|
|
|
|
|
|
} |
|
5026
|
3436
|
|
|
|
|
10543
|
$x + $y; |
|
5027
|
|
|
|
|
|
|
} |
|
5028
|
|
|
|
|
|
|
|
|
5029
|
|
|
|
|
|
|
# Note that Perl 5.6.2 with largish 64-bit numbers will break. As usual. |
|
5030
|
|
|
|
|
|
|
sub _native_powmod { |
|
5031
|
3607
|
|
|
3607
|
|
6136
|
my($n, $power, $m) = @_; |
|
5032
|
3607
|
|
|
|
|
4622
|
my $t = 1; |
|
5033
|
3607
|
|
|
|
|
4687
|
$n = $n % $m; |
|
5034
|
3607
|
|
|
|
|
6348
|
while ($power) { |
|
5035
|
67036
|
100
|
|
|
|
115557
|
$t = ($t * $n) % $m if ($power & 1); |
|
5036
|
67036
|
|
|
|
|
80146
|
$power >>= 1; |
|
5037
|
67036
|
100
|
|
|
|
130827
|
$n = ($n * $n) % $m if $power; |
|
5038
|
|
|
|
|
|
|
} |
|
5039
|
3607
|
|
|
|
|
7561
|
$t; |
|
5040
|
|
|
|
|
|
|
} |
|
5041
|
|
|
|
|
|
|
|
|
5042
|
|
|
|
|
|
|
sub _powmod { |
|
5043
|
83
|
|
|
83
|
|
290
|
my($n, $power, $m) = @_; |
|
5044
|
83
|
|
|
|
|
184
|
my $t = 1; |
|
5045
|
|
|
|
|
|
|
|
|
5046
|
83
|
50
|
|
|
|
279
|
$n %= $m if $n >= $m; |
|
5047
|
83
|
50
|
|
|
|
288
|
if ($m < MPU_HALFWORD) { |
|
5048
|
0
|
|
|
|
|
0
|
while ($power) { |
|
5049
|
0
|
0
|
|
|
|
0
|
$t = ($t * $n) % $m if ($power & 1); |
|
5050
|
0
|
|
|
|
|
0
|
$power >>= 1; |
|
5051
|
0
|
0
|
|
|
|
0
|
$n = ($n * $n) % $m if $power; |
|
5052
|
|
|
|
|
|
|
} |
|
5053
|
|
|
|
|
|
|
} else { |
|
5054
|
83
|
|
|
|
|
301
|
while ($power) { |
|
5055
|
3794
|
100
|
|
|
|
9765
|
$t = _mulmod($t, $n, $m) if ($power & 1); |
|
5056
|
3794
|
|
|
|
|
6181
|
$power >>= 1; |
|
5057
|
3794
|
100
|
|
|
|
9824
|
$n = _mulmod($n, $n, $m) if $power; |
|
5058
|
|
|
|
|
|
|
} |
|
5059
|
|
|
|
|
|
|
} |
|
5060
|
83
|
|
|
|
|
359
|
$t; |
|
5061
|
|
|
|
|
|
|
} |
|
5062
|
|
|
|
|
|
|
|
|
5063
|
|
|
|
|
|
|
sub powint { |
|
5064
|
8688
|
|
|
8688
|
0
|
54563
|
my($a, $b) = @_; |
|
5065
|
8688
|
|
|
|
|
32611
|
validate_integer($a); |
|
5066
|
8688
|
|
|
|
|
46846
|
validate_integer($b); |
|
5067
|
|
|
|
|
|
|
return reftyped($_[0], Math::Prime::Util::GMP::powint($a,$b)) |
|
5068
|
8688
|
50
|
|
|
|
29084
|
if $Math::Prime::Util::_GMPfunc{"powint"}; |
|
5069
|
8688
|
50
|
|
|
|
26598
|
croak "powint: exponent must be >= 0" if $b < 0; |
|
5070
|
|
|
|
|
|
|
|
|
5071
|
|
|
|
|
|
|
# Special cases for small a and b |
|
5072
|
8688
|
100
|
100
|
|
|
41754
|
if ($a >= -1 && $a <= 4) { |
|
5073
|
1599
|
0
|
|
|
|
3346
|
return ($b == 0) ? 1 : 0 if $a == 0; |
|
|
|
50
|
|
|
|
|
|
|
5074
|
1599
|
100
|
|
|
|
3636
|
return 1 if $a == 1; |
|
5075
|
1555
|
0
|
|
|
|
3209
|
return ($b % 2) ? -1 : 1 if $a == -1; |
|
|
|
50
|
|
|
|
|
|
|
5076
|
1555
|
100
|
|
|
|
3105
|
if ($a == 2) { |
|
5077
|
589
|
100
|
|
|
|
14518
|
return ($b < MPU_MAXBITS) ? 1<<$b : Mlshiftint(1,$b); |
|
5078
|
|
|
|
|
|
|
} |
|
5079
|
966
|
100
|
|
|
|
2091
|
if ($a == 4) { |
|
5080
|
151
|
100
|
|
|
|
590
|
return 1 << (2*$b) if $b < MPU_MAXBITS/2; |
|
5081
|
107
|
50
|
|
|
|
7497
|
return Mlshiftint(1,2*$b) if $b < 4000000000; |
|
5082
|
|
|
|
|
|
|
} |
|
5083
|
|
|
|
|
|
|
} |
|
5084
|
|
|
|
|
|
|
|
|
5085
|
7904
|
100
|
|
|
|
206780
|
return 1 if $b == 0; |
|
5086
|
7885
|
100
|
|
|
|
18453
|
return $a if $b == 1; |
|
5087
|
7855
|
100
|
|
|
|
18533
|
if ($b == 2) { |
|
5088
|
1462
|
100
|
|
|
|
6714
|
return int("$a")*int("$a") if abs($a) < MPU_HALFWORD; |
|
5089
|
484
|
|
|
|
|
123813
|
return Mmulint($a,$a); |
|
5090
|
|
|
|
|
|
|
} |
|
5091
|
|
|
|
|
|
|
|
|
5092
|
6393
|
100
|
66
|
|
|
40036
|
if (!ref($a) && !ref($b) && $b < MPU_MAXBITS) { |
|
|
|
|
100
|
|
|
|
|
|
5093
|
3871
|
100
|
|
|
|
9033
|
if ($b == 3) { |
|
5094
|
723
|
100
|
|
|
|
2574
|
return int($a*$a*$a) if $a <= 99999; |
|
5095
|
187
|
100
|
|
|
|
4088
|
return Mmulint(int($a*$a), $a) if $a <= 31622776; |
|
5096
|
|
|
|
|
|
|
} else { |
|
5097
|
|
|
|
|
|
|
# Check if inside limit of int on 32-bit |
|
5098
|
3148
|
|
|
|
|
10974
|
my $r = $a ** $b; |
|
5099
|
3148
|
100
|
100
|
|
|
10600
|
return int($r) if $r < 1000000000000000 && $r > -1000000000000000; |
|
5100
|
|
|
|
|
|
|
# Try to complete using a single mulint if we can |
|
5101
|
2629
|
|
|
|
|
8222
|
$r = $a ** (($b+1)>>1); |
|
5102
|
2629
|
100
|
66
|
|
|
10588
|
if ($r < 1000000000000000 && $r > -1000000000000000) { |
|
5103
|
1400
|
100
|
|
|
|
92385
|
return Mmulint(int($r), $b&1 ? int($a**($b>>1)) : int($r)); |
|
5104
|
|
|
|
|
|
|
} |
|
5105
|
|
|
|
|
|
|
} |
|
5106
|
|
|
|
|
|
|
# Fall through |
|
5107
|
|
|
|
|
|
|
} |
|
5108
|
|
|
|
|
|
|
|
|
5109
|
3886
|
100
|
|
|
|
20449
|
return Mmulint(Mmulint($a,$a),$a) if $b == 3; |
|
5110
|
|
|
|
|
|
|
|
|
5111
|
3654
|
|
|
|
|
15209
|
my $r = tobigint($a) ** tobigint($b); |
|
5112
|
3654
|
50
|
33
|
|
|
3697850
|
return $r <= INTMAX && $r >= INTMIN ? _bigint_to_int($r) : $r; |
|
5113
|
|
|
|
|
|
|
} |
|
5114
|
|
|
|
|
|
|
|
|
5115
|
|
|
|
|
|
|
sub mulint { |
|
5116
|
206222
|
|
|
206222
|
0
|
7175365
|
my($a, $b) = @_; |
|
5117
|
206222
|
|
|
|
|
587099
|
validate_integer($a); |
|
5118
|
206222
|
|
|
|
|
876870
|
validate_integer($b); |
|
5119
|
206222
|
100
|
100
|
|
|
2949859
|
return 0 if $a == 0 || $b == 0; |
|
5120
|
|
|
|
|
|
|
return reftyped($_[0], Math::Prime::Util::GMP::mulint($a,$b)) |
|
5121
|
205005
|
50
|
|
|
|
8036804
|
if $Math::Prime::Util::_GMPfunc{"mulint"}; |
|
5122
|
|
|
|
|
|
|
|
|
5123
|
205005
|
|
|
|
|
420677
|
my $r = $a * $b; |
|
5124
|
|
|
|
|
|
|
|
|
5125
|
205005
|
100
|
|
|
|
12549269
|
if (!ref($r)) { |
|
5126
|
172178
|
100
|
100
|
|
|
782794
|
return $r if $r < INTMAX && $r > INTMIN; |
|
5127
|
6831
|
|
|
|
|
29085
|
$r = tobigint($a) * $b; |
|
5128
|
|
|
|
|
|
|
} |
|
5129
|
39658
|
100
|
100
|
|
|
2606005
|
return $r <= INTMAX && $r >= INTMIN ? _bigint_to_int($r) : $r; |
|
5130
|
|
|
|
|
|
|
} |
|
5131
|
|
|
|
|
|
|
sub addint { |
|
5132
|
53916
|
|
|
53916
|
0
|
6426125
|
my($a, $b) = @_; |
|
5133
|
53916
|
|
|
|
|
245078
|
validate_integer($a); |
|
5134
|
53916
|
|
|
|
|
2744697
|
validate_integer($b); |
|
5135
|
|
|
|
|
|
|
return reftyped($_[0], Math::Prime::Util::GMP::addint($a,$b)) |
|
5136
|
53916
|
50
|
|
|
|
2371866
|
if $Math::Prime::Util::_GMPfunc{"addint"}; |
|
5137
|
|
|
|
|
|
|
|
|
5138
|
53916
|
|
|
|
|
148254
|
my $r = $a + $b; |
|
5139
|
|
|
|
|
|
|
|
|
5140
|
53916
|
100
|
|
|
|
7223247
|
if (!ref($r)) { |
|
5141
|
21033
|
100
|
100
|
|
|
95539
|
return $r if $r < INTMAX && $r > INTMIN; |
|
5142
|
85
|
|
|
|
|
377
|
$r = tobigint($a) + $b; |
|
5143
|
|
|
|
|
|
|
} |
|
5144
|
32968
|
100
|
100
|
|
|
149003
|
return $r <= INTMAX && $r >= INTMIN ? _bigint_to_int($r) : $r; |
|
5145
|
|
|
|
|
|
|
} |
|
5146
|
|
|
|
|
|
|
sub subint { |
|
5147
|
2913
|
|
|
2913
|
0
|
61013
|
my($a, $b) = @_; |
|
5148
|
2913
|
|
|
|
|
9891
|
validate_integer($a); |
|
5149
|
2913
|
|
|
|
|
39129
|
validate_integer($b); |
|
5150
|
|
|
|
|
|
|
return reftyped($_[0], Math::Prime::Util::GMP::subint($a,$b)) |
|
5151
|
2913
|
50
|
|
|
|
13577
|
if $Math::Prime::Util::_GMPfunc{"subint"}; |
|
5152
|
|
|
|
|
|
|
|
|
5153
|
2913
|
|
|
|
|
6470
|
my $r = $a - $b; |
|
5154
|
|
|
|
|
|
|
|
|
5155
|
2913
|
100
|
|
|
|
261501
|
if (!ref($r)) { |
|
5156
|
2149
|
100
|
100
|
|
|
10660
|
return $r if $r < INTMAX && $r > INTMIN; |
|
5157
|
21
|
|
|
|
|
86
|
$r = tobigint($a) - $b; |
|
5158
|
|
|
|
|
|
|
} |
|
5159
|
785
|
100
|
100
|
|
|
11552
|
return $r <= INTMAX && $r >= INTMIN ? _bigint_to_int($r) : $r; |
|
5160
|
|
|
|
|
|
|
} |
|
5161
|
|
|
|
|
|
|
sub add1int { |
|
5162
|
1475
|
|
|
1475
|
0
|
13160
|
my($a) = @_; |
|
5163
|
1475
|
|
|
|
|
8663
|
validate_integer($a); |
|
5164
|
1475
|
|
|
|
|
60638
|
my $r = $a+1; |
|
5165
|
1475
|
100
|
|
|
|
392132
|
if (!ref($r)) { |
|
5166
|
329
|
100
|
|
|
|
1277
|
return $r if $r < INTMAX; |
|
5167
|
3
|
|
|
|
|
11
|
$r = tobigint($a) + 1; |
|
5168
|
|
|
|
|
|
|
} |
|
5169
|
1149
|
50
|
33
|
|
|
5297
|
return $r <= INTMAX && $r >= INTMIN ? _bigint_to_int($r) : $r; |
|
5170
|
|
|
|
|
|
|
} |
|
5171
|
|
|
|
|
|
|
sub sub1int { |
|
5172
|
818
|
|
|
818
|
0
|
8184
|
my($a) = @_; |
|
5173
|
818
|
|
|
|
|
6344
|
validate_integer($a); |
|
5174
|
818
|
|
|
|
|
30266
|
my $r = $a-1; |
|
5175
|
818
|
100
|
|
|
|
198412
|
if (!ref($r)) { |
|
5176
|
285
|
50
|
|
|
|
979
|
return $r if $r < INTMAX; |
|
5177
|
0
|
|
|
|
|
0
|
$r = tobigint($a) - 1; |
|
5178
|
|
|
|
|
|
|
} |
|
5179
|
533
|
100
|
66
|
|
|
2131
|
return $r <= INTMAX && $r >= INTMIN ? _bigint_to_int($r) : $r; |
|
5180
|
|
|
|
|
|
|
} |
|
5181
|
|
|
|
|
|
|
|
|
5182
|
|
|
|
|
|
|
# For division / modulo, see: |
|
5183
|
|
|
|
|
|
|
# |
|
5184
|
|
|
|
|
|
|
# https://www.researchgate.net/publication/234829884_The_Euclidean_definition_of_the_functions_div_and_mod |
|
5185
|
|
|
|
|
|
|
# |
|
5186
|
|
|
|
|
|
|
# https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf |
|
5187
|
|
|
|
|
|
|
|
|
5188
|
|
|
|
|
|
|
sub _tquotient { |
|
5189
|
21103
|
|
|
21103
|
|
45657
|
my($a,$b) = @_; |
|
5190
|
21103
|
100
|
|
|
|
55323
|
return $a if $b == 1; |
|
5191
|
|
|
|
|
|
|
|
|
5192
|
21070
|
100
|
100
|
|
|
1807228
|
$a = tobigint($a) if ($a >= SINTMAX || $a <= INTMIN) && !ref($a); |
|
|
|
|
100
|
|
|
|
|
|
5193
|
21070
|
100
|
66
|
|
|
4905889
|
$b = tobigint($b) if ($b >= SINTMAX || $b <= INTMIN) && !ref($b); |
|
|
|
|
100
|
|
|
|
|
|
5194
|
21070
|
|
|
|
|
1966710
|
my($refa,$refb) = (ref($a),ref($b)); |
|
5195
|
|
|
|
|
|
|
|
|
5196
|
21070
|
100
|
100
|
|
|
61507
|
if (!$refa && !$refb) { |
|
5197
|
|
|
|
|
|
|
# Both numbers are in signed range, so we can negate them. |
|
5198
|
77
|
|
|
77
|
|
2424641
|
use integer; # This is >>> SIGNED <<< integer. |
|
|
77
|
|
|
|
|
237
|
|
|
|
77
|
|
|
|
|
1088
|
|
|
5199
|
|
|
|
|
|
|
# Signed division is implementation defined in C89. |
|
5200
|
19
|
50
|
33
|
|
|
183
|
return -(-$a / $b) if $a < 0 && $b > 0; |
|
5201
|
0
|
0
|
0
|
|
|
0
|
return -( $a / -$b) if $b < 0 && $a > 0; |
|
5202
|
0
|
0
|
0
|
|
|
0
|
return (-$a / -$b) if $a < 0 && $b < 0; |
|
5203
|
0
|
|
|
|
|
0
|
return ( $a / $b); |
|
5204
|
|
|
|
|
|
|
} |
|
5205
|
|
|
|
|
|
|
|
|
5206
|
21051
|
|
|
|
|
35602
|
my $q; # set this, turn into int and return at end |
|
5207
|
21051
|
50
|
33
|
|
|
158147
|
if ($refa eq 'Math::GMPz' || $refb eq 'Math::GMPz') { |
|
|
|
50
|
33
|
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
|
5208
|
0
|
|
|
|
|
0
|
$q = Math::GMPz->new(); |
|
5209
|
0
|
0
|
|
|
|
0
|
$a = Math::GMPz->new($a) unless $refa eq 'Math::GMPz'; |
|
5210
|
0
|
0
|
|
|
|
0
|
$b = Math::GMPz->new($b) unless $refb eq 'Math::GMPz'; |
|
5211
|
0
|
|
|
|
|
0
|
Math::GMPz::Rmpz_tdiv_q($q,$a,$b); |
|
5212
|
|
|
|
|
|
|
} elsif ($refa eq 'Math::GMP' || $refb eq 'Math::GMP') { |
|
5213
|
0
|
0
|
|
|
|
0
|
$a = Math::GMP->new($a) unless $refa eq 'Math::GMP'; |
|
5214
|
0
|
0
|
|
|
|
0
|
$b = Math::GMP->new($b) unless $refb eq 'Math::GMP'; |
|
5215
|
|
|
|
|
|
|
# op_div => mpz_div function (obsolete!). bdiv => tdiv_qr |
|
5216
|
0
|
|
|
|
|
0
|
($q) = $a->bdiv($b); |
|
5217
|
|
|
|
|
|
|
} elsif ($refa eq 'Math::Pari' || $refb eq 'Math::Pari') { |
|
5218
|
0
|
0
|
|
|
|
0
|
$a = Math::Pari->new("$a") unless $refa eq 'Math::Pari'; |
|
5219
|
0
|
0
|
|
|
|
0
|
$b = Math::Pari->new("$b") unless $refb eq 'Math::Pari'; |
|
5220
|
0
|
|
|
|
|
0
|
$q = Math::Pari::gdivent(abs($a),abs($b)); |
|
5221
|
0
|
0
|
|
|
|
0
|
$q = Math::Pari::gneg($q) if ($a < 0) != ($b < 0); |
|
5222
|
|
|
|
|
|
|
} else { |
|
5223
|
|
|
|
|
|
|
# Force no upgrade so 'use bignum' won't screw us over. |
|
5224
|
21051
|
|
|
|
|
75480
|
my $A = Math::BigInt->new("$a")->upgrade(undef); |
|
5225
|
21051
|
|
|
|
|
3688029
|
my $B = Math::BigInt->new("$b")->upgrade(undef); |
|
5226
|
21051
|
|
|
|
|
2869756
|
$q = abs($a) / abs($b); |
|
5227
|
21051
|
100
|
|
|
|
13266955
|
$q = -$q if ($a < 0) != ($b < 0); |
|
5228
|
21051
|
50
|
66
|
|
|
6495513
|
$q = $refa->new("$q") if $refa ne 'Math::BigInt' && $refb ne 'Math::BigInt'; |
|
5229
|
|
|
|
|
|
|
} |
|
5230
|
21051
|
|
|
|
|
65635
|
$q; |
|
5231
|
|
|
|
|
|
|
#return $q <= INTMAX && $q >= INTMIN ? _bigint_to_int($q) : $q; |
|
5232
|
|
|
|
|
|
|
} |
|
5233
|
|
|
|
|
|
|
|
|
5234
|
|
|
|
|
|
|
# Truncated Division |
|
5235
|
|
|
|
|
|
|
sub tdivrem { |
|
5236
|
216
|
|
|
216
|
0
|
4063
|
my($a,$b) = @_; |
|
5237
|
216
|
|
|
|
|
6421
|
validate_integer($a); |
|
5238
|
216
|
|
|
|
|
9223
|
validate_integer($b); |
|
5239
|
216
|
50
|
|
|
|
6843
|
croak "tdivrem: divide by zero" if $b == 0; |
|
5240
|
216
|
|
|
|
|
41172
|
my($q,$r); |
|
5241
|
216
|
100
|
66
|
|
|
1486
|
if (!ref($a) && !ref($b) && $a>=0 && $b>=0 && $a
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
5242
|
77
|
|
|
77
|
|
44765
|
{ use integer; $q = $a / $b; } |
|
|
77
|
|
|
|
|
649
|
|
|
|
77
|
|
|
|
|
796
|
|
|
|
70
|
|
|
|
|
112
|
|
|
|
70
|
|
|
|
|
115
|
|
|
5243
|
70
|
|
|
|
|
118
|
$r = $a - $b * $q; |
|
5244
|
|
|
|
|
|
|
} else { |
|
5245
|
146
|
|
|
|
|
586
|
$q = _tquotient($a, $b); |
|
5246
|
146
|
|
|
|
|
614
|
$r = $a - $b * $q; |
|
5247
|
146
|
100
|
66
|
|
|
63762
|
$q = _bigint_to_int($q) if ref($q) && $q <= INTMAX && $q >= INTMIN; |
|
|
|
|
100
|
|
|
|
|
|
5248
|
146
|
100
|
66
|
|
|
9448
|
$r = _bigint_to_int($r) if ref($r) && $r <= INTMAX && $r >= INTMIN; |
|
|
|
|
66
|
|
|
|
|
|
5249
|
|
|
|
|
|
|
} |
|
5250
|
216
|
|
|
|
|
46767
|
($q,$r); |
|
5251
|
|
|
|
|
|
|
} |
|
5252
|
|
|
|
|
|
|
# Floored Division |
|
5253
|
|
|
|
|
|
|
sub fdivrem { |
|
5254
|
73
|
|
|
73
|
0
|
5542
|
my($a,$b) = @_; |
|
5255
|
73
|
|
|
|
|
501
|
validate_integer($a); |
|
5256
|
73
|
|
|
|
|
14135
|
validate_integer($b); |
|
5257
|
73
|
50
|
|
|
|
938
|
croak "fdivrem: divide by zero" if $b == 0; |
|
5258
|
73
|
|
|
|
|
5087
|
my($q,$r); |
|
5259
|
73
|
100
|
100
|
|
|
646
|
if (!ref($a) && !ref($b) && $a>=0 && $b>=0 && $a
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
5260
|
77
|
|
|
77
|
|
21749
|
use integer; $q = $a / $b; |
|
|
77
|
|
|
|
|
493
|
|
|
|
77
|
|
|
|
|
665
|
|
|
|
1
|
|
|
|
|
3
|
|
|
5261
|
|
|
|
|
|
|
} else { |
|
5262
|
72
|
|
|
|
|
267
|
$q = _tquotient($a, $b); |
|
5263
|
|
|
|
|
|
|
} |
|
5264
|
73
|
|
|
|
|
329
|
$r = $a - $b * $q; |
|
5265
|
|
|
|
|
|
|
# qe = qt-I re = rt+I*d I = (rt >= 0) ? 0 : (b>0) ? 1 : -1; |
|
5266
|
|
|
|
|
|
|
# qf = qt-I rf = rt+I*d I = (signum(rt) = -signum(b)) 1 : 0 |
|
5267
|
73
|
100
|
100
|
|
|
28295
|
if ( ($r < 0 && $b > 0) || ($r > 0 && $b < 0) ) |
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
5268
|
51
|
|
|
|
|
9637
|
{ $q--; $r += $b; } |
|
|
51
|
|
|
|
|
2955
|
|
|
5269
|
73
|
100
|
100
|
|
|
17777
|
$q = _bigint_to_int($q) if ref($q) && $q <= INTMAX && $q >= INTMIN; |
|
|
|
|
100
|
|
|
|
|
|
5270
|
73
|
100
|
100
|
|
|
13478
|
$r = _bigint_to_int($r) if ref($r) && $r <= INTMAX && $r >= INTMIN; |
|
|
|
|
66
|
|
|
|
|
|
5271
|
73
|
|
|
|
|
4668
|
($q,$r); |
|
5272
|
|
|
|
|
|
|
} |
|
5273
|
|
|
|
|
|
|
# Ceiling Division |
|
5274
|
|
|
|
|
|
|
sub cdivrem { |
|
5275
|
14
|
|
|
14
|
0
|
10768
|
my($a,$b) = @_; |
|
5276
|
14
|
|
|
|
|
124
|
validate_integer($a); |
|
5277
|
14
|
|
|
|
|
146
|
validate_integer($b); |
|
5278
|
14
|
50
|
|
|
|
219
|
croak "cdivrem: divide by zero" if $b == 0; |
|
5279
|
14
|
|
|
|
|
33
|
my($q,$r); |
|
5280
|
14
|
100
|
66
|
|
|
127
|
if (!ref($a) && !ref($b) && $a>=0 && $b>=0 && $a
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
5281
|
77
|
|
|
77
|
|
22579
|
use integer; $q = $a / $b; |
|
|
77
|
|
|
|
|
165
|
|
|
|
77
|
|
|
|
|
484
|
|
|
|
1
|
|
|
|
|
4
|
|
|
5282
|
|
|
|
|
|
|
} else { |
|
5283
|
13
|
|
|
|
|
46
|
$q = _tquotient($a, $b); |
|
5284
|
|
|
|
|
|
|
} |
|
5285
|
14
|
|
|
|
|
63
|
$r = $a - $b * $q; |
|
5286
|
14
|
100
|
66
|
|
|
8031
|
if ($r != 0 && (($a >= 0) == ($b >= 0))) |
|
5287
|
7
|
|
|
|
|
2820
|
{ $q++; $r -= $b; } |
|
|
7
|
|
|
|
|
591
|
|
|
5288
|
14
|
100
|
100
|
|
|
5211
|
$q = _bigint_to_int($q) if ref($q) && $q <= INTMAX && $q >= INTMIN; |
|
|
|
|
100
|
|
|
|
|
|
5289
|
14
|
100
|
66
|
|
|
3992
|
$r = _bigint_to_int($r) if ref($r) && $r <= INTMAX && $r >= INTMIN; |
|
|
|
|
100
|
|
|
|
|
|
5290
|
14
|
|
|
|
|
3179
|
($q,$r); |
|
5291
|
|
|
|
|
|
|
} |
|
5292
|
|
|
|
|
|
|
# Euclidean Division |
|
5293
|
|
|
|
|
|
|
sub divrem { |
|
5294
|
339
|
|
|
339
|
0
|
13310
|
my($a,$b) = @_; |
|
5295
|
339
|
|
|
|
|
1015
|
validate_integer($a); |
|
5296
|
339
|
|
|
|
|
3297
|
validate_integer($b); |
|
5297
|
339
|
50
|
|
|
|
2374
|
croak "divrem: divide by zero" if $b == 0; |
|
5298
|
339
|
|
|
|
|
11205
|
my($q,$r); |
|
5299
|
339
|
100
|
66
|
|
|
2532
|
if (!ref($a) && !ref($b) && $a>=0 && $b>=0 && $a
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
5300
|
77
|
|
|
77
|
|
18666
|
use integer; $q = $a / $b; |
|
|
77
|
|
|
|
|
212
|
|
|
|
77
|
|
|
|
|
445
|
|
|
|
283
|
|
|
|
|
430
|
|
|
5301
|
|
|
|
|
|
|
} else { |
|
5302
|
56
|
|
|
|
|
206
|
$q = _tquotient($a, $b); |
|
5303
|
|
|
|
|
|
|
} |
|
5304
|
339
|
|
|
|
|
726
|
$r = $a - $b * $q; |
|
5305
|
339
|
100
|
|
|
|
26352
|
if ($r <0) { |
|
5306
|
5
|
100
|
|
|
|
1197
|
if ($b > 0) { $q--; $r += $b; } |
|
|
4
|
|
|
|
|
20
|
|
|
|
4
|
|
|
|
|
374
|
|
|
5307
|
1
|
|
|
|
|
6
|
else { $q++; $r -= $b; } |
|
|
1
|
|
|
|
|
97
|
|
|
5308
|
|
|
|
|
|
|
} |
|
5309
|
339
|
100
|
100
|
|
|
14247
|
$q = _bigint_to_int($q) if ref($q) && $q <= INTMAX && $q >= INTMIN; |
|
|
|
|
100
|
|
|
|
|
|
5310
|
339
|
100
|
100
|
|
|
7166
|
$r = _bigint_to_int($r) if ref($r) && $r <= INTMAX && $r >= INTMIN; |
|
|
|
|
66
|
|
|
|
|
|
5311
|
339
|
|
|
|
|
15766
|
($q,$r); |
|
5312
|
|
|
|
|
|
|
} |
|
5313
|
|
|
|
|
|
|
|
|
5314
|
|
|
|
|
|
|
sub divint { |
|
5315
|
282933
|
100
|
100
|
282933
|
0
|
993070
|
if (!OLD_PERL_VERSION && $_[1] > 0 && $_[0] >= 0) { |
|
5316
|
|
|
|
|
|
|
# Simple no-error all positive case |
|
5317
|
282889
|
|
|
|
|
6914872
|
my($a,$b) = @_; |
|
5318
|
282889
|
|
|
|
|
388276
|
my $q; |
|
5319
|
282889
|
100
|
66
|
|
|
1359765
|
if (!ref($a) && !ref($b) && $a
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
5320
|
77
|
|
|
77
|
|
19128
|
use integer; $q = $a / $b; |
|
|
77
|
|
|
|
|
244
|
|
|
|
77
|
|
|
|
|
548
|
|
|
|
262086
|
|
|
|
|
392679
|
|
|
5321
|
|
|
|
|
|
|
} else { |
|
5322
|
20803
|
|
|
|
|
67622
|
$q = _tquotient($a, $b); |
|
5323
|
20803
|
100
|
100
|
|
|
91959
|
$q = _bigint_to_int($q) if ref($q) && $q <= INTMAX; |
|
5324
|
|
|
|
|
|
|
} |
|
5325
|
282889
|
|
|
|
|
1794954
|
return $q; |
|
5326
|
|
|
|
|
|
|
} |
|
5327
|
44
|
|
|
|
|
3667
|
(fdivrem(@_))[0]; |
|
5328
|
|
|
|
|
|
|
} |
|
5329
|
|
|
|
|
|
|
sub _posmodint { # Simple no-error all positive case |
|
5330
|
|
|
|
|
|
|
#croak "Invalid call to _posmodint(@_)" unless $_[1] > 0 && $_[0] >= 0; |
|
5331
|
1831
|
|
|
1831
|
|
4994
|
my($a,$b) = @_; |
|
5332
|
1831
|
|
|
|
|
10159
|
validate_integer($a); |
|
5333
|
1831
|
|
|
|
|
79275
|
validate_integer($b); |
|
5334
|
1831
|
|
|
|
|
8756
|
my $r; |
|
5335
|
1831
|
100
|
100
|
|
|
11473
|
if (ref($b) || ref($a)) { |
|
|
|
50
|
33
|
|
|
|
|
|
5336
|
1592
|
|
|
|
|
5129
|
$r = $a % $b; |
|
5337
|
1592
|
100
|
|
|
|
705720
|
$r = _bigint_to_int($r) if $r <= INTMAX; |
|
5338
|
|
|
|
|
|
|
} elsif ($b < INTMAX && $a < INTMAX) { |
|
5339
|
239
|
|
|
|
|
452
|
$r = $a % $b; |
|
5340
|
|
|
|
|
|
|
} else { |
|
5341
|
0
|
|
|
|
|
0
|
$r = tobigint($a) % tobigint($b); |
|
5342
|
0
|
0
|
|
|
|
0
|
$r = _bigint_to_int($r) if $r <= INTMAX; |
|
5343
|
|
|
|
|
|
|
} |
|
5344
|
1831
|
|
|
|
|
92292
|
$r; |
|
5345
|
|
|
|
|
|
|
} |
|
5346
|
|
|
|
|
|
|
sub modint { |
|
5347
|
|
|
|
|
|
|
# Fast processing for simple cases |
|
5348
|
1847
|
100
|
100
|
1847
|
0
|
25807
|
if ($_[1] > 0 && $_[0] >= 0) { |
|
|
|
100
|
100
|
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
|
5349
|
1821
|
|
|
|
|
393233
|
return _posmodint(@_); |
|
5350
|
|
|
|
|
|
|
} elsif ($_[1] < 0 && $_[0] >= 0) { |
|
5351
|
2
|
50
|
33
|
|
|
15
|
if ($_[0] < INTMAX && -$_[1] < INTMAX) { |
|
5352
|
0
|
|
|
|
|
0
|
my $r = _posmodint($_[0],-$_[1]); |
|
5353
|
0
|
0
|
|
|
|
0
|
return $r == 0 ? 0 : $_[1]+$r; |
|
5354
|
|
|
|
|
|
|
} |
|
5355
|
|
|
|
|
|
|
} elsif ($_[1] > 0 && $_[0] <= 0) { |
|
5356
|
22
|
100
|
100
|
|
|
7181
|
if (-$_[0] < INTMAX && $_[1] < INTMAX) { |
|
5357
|
10
|
|
|
|
|
37
|
my $r = _posmodint(-$_[0],$_[1]); |
|
5358
|
10
|
50
|
|
|
|
42
|
return $r == 0 ? 0 : $_[1]-$r; |
|
5359
|
|
|
|
|
|
|
} |
|
5360
|
|
|
|
|
|
|
} elsif ($_[1] < 0 && $_[0] <= 0) { |
|
5361
|
2
|
50
|
33
|
|
|
15
|
if (-$_[0] < INTMAX && -$_[1] < INTMAX) { |
|
5362
|
0
|
|
|
|
|
0
|
my $r = _posmodint(-$_[0],-$_[1]); |
|
5363
|
0
|
0
|
|
|
|
0
|
return $r == 0 ? 0 : -$r; |
|
5364
|
|
|
|
|
|
|
} |
|
5365
|
|
|
|
|
|
|
} |
|
5366
|
16
|
|
|
|
|
2526
|
(fdivrem(@_))[1]; |
|
5367
|
|
|
|
|
|
|
} |
|
5368
|
|
|
|
|
|
|
sub cdivint { |
|
5369
|
484
|
100
|
100
|
484
|
0
|
6486
|
if ($_[1] > 0 && $_[0] >= 0) { # Simple no-error all positive case |
|
5370
|
480
|
|
|
|
|
4647
|
my($a,$b) = @_; |
|
5371
|
480
|
|
|
|
|
1428
|
validate_integer($a); |
|
5372
|
480
|
|
|
|
|
1834
|
validate_integer($b); |
|
5373
|
480
|
|
|
|
|
846
|
my $q; |
|
5374
|
480
|
100
|
66
|
|
|
3343
|
if (!ref($a) && !ref($b) && $a
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
5375
|
77
|
|
|
77
|
|
47971
|
use integer; $q = $a / $b; |
|
|
77
|
|
|
|
|
174
|
|
|
|
77
|
|
|
|
|
458
|
|
|
|
467
|
|
|
|
|
848
|
|
|
5376
|
467
|
100
|
|
|
|
1203
|
$q++ if $a != $b*$q; |
|
5377
|
|
|
|
|
|
|
} else { |
|
5378
|
13
|
|
|
|
|
60
|
$q = _tquotient($a, $b); |
|
5379
|
13
|
100
|
|
|
|
63
|
$q++ if $a != $b*$q; |
|
5380
|
13
|
100
|
66
|
|
|
6568
|
$q = _bigint_to_int($q) if ref($q) && $q <= INTMAX; |
|
5381
|
|
|
|
|
|
|
} |
|
5382
|
480
|
|
|
|
|
2812
|
return $q; |
|
5383
|
|
|
|
|
|
|
} |
|
5384
|
4
|
|
|
|
|
501
|
(cdivrem(@_))[0]; |
|
5385
|
|
|
|
|
|
|
} |
|
5386
|
|
|
|
|
|
|
|
|
5387
|
|
|
|
|
|
|
sub absint { |
|
5388
|
201
|
|
|
201
|
0
|
11910
|
my($n) = @_; |
|
5389
|
201
|
|
|
|
|
654
|
validate_integer_abs($n); |
|
5390
|
201
|
|
|
|
|
9573
|
reftyped($_[0], $n); |
|
5391
|
|
|
|
|
|
|
} |
|
5392
|
|
|
|
|
|
|
sub negint { |
|
5393
|
1669
|
|
|
1669
|
0
|
65498
|
my($n) = @_; |
|
5394
|
1669
|
|
|
|
|
9889
|
validate_integer($n); |
|
5395
|
1669
|
50
|
|
|
|
107882
|
return 0 if $n == 0; # Perl 5.6 has to have this: if $n=0 => -$n = -0 |
|
5396
|
1669
|
100
|
100
|
|
|
367540
|
return -$n if ref($n) || $n < SINTMAX; |
|
5397
|
25
|
50
|
|
|
|
124
|
if ($n > 0) { $n = "-$n"; } |
|
|
25
|
|
|
|
|
117
|
|
|
5398
|
0
|
|
|
|
|
0
|
else { $n =~ s/^-//; } |
|
5399
|
25
|
|
|
|
|
167
|
reftyped($_[0], $n); |
|
5400
|
|
|
|
|
|
|
} |
|
5401
|
|
|
|
|
|
|
sub signint { |
|
5402
|
5
|
|
|
5
|
0
|
9
|
my($n) = @_; |
|
5403
|
5
|
|
|
|
|
8
|
validate_integer($n); |
|
5404
|
|
|
|
|
|
|
# -1,0,1 Native ints, Math::BigInt, Math::GMP, Math::GMPz 0.68+ |
|
5405
|
|
|
|
|
|
|
# neg,0,pos Math::GMPz 0.67 and earlier |
|
5406
|
|
|
|
|
|
|
# -1 or 4294967295, 0, 1 Math::Pari |
|
5407
|
5
|
|
|
|
|
6
|
my $r = $n <=> 0; |
|
5408
|
5
|
50
|
33
|
|
|
8
|
$r = -1 if $r == 4294967295 && ref($n) eq 'Math::Pari'; |
|
5409
|
5
|
100
|
|
|
|
14
|
return $r < 0 ? -1 : $r > 0 ? 1 : 0; |
|
|
|
100
|
|
|
|
|
|
|
5410
|
|
|
|
|
|
|
} |
|
5411
|
|
|
|
|
|
|
sub cmpint { |
|
5412
|
15
|
|
|
15
|
0
|
2632
|
my($a, $b) = @_; |
|
5413
|
15
|
|
|
|
|
72
|
validate_integer($a); |
|
5414
|
15
|
|
|
|
|
59
|
validate_integer($b); |
|
5415
|
15
|
|
|
|
|
698
|
my $r = $a <=> $b; |
|
5416
|
15
|
0
|
0
|
|
|
661
|
$r = -1 if $r == 4294967295 && (ref($a) eq 'Math::Pari' || ref($b) eq 'Math::Pari'); |
|
|
|
|
33
|
|
|
|
|
|
5417
|
15
|
100
|
|
|
|
172
|
return $r < 0 ? -1 : $r > 0 ? 1 : 0; |
|
|
|
100
|
|
|
|
|
|
|
5418
|
|
|
|
|
|
|
} |
|
5419
|
|
|
|
|
|
|
|
|
5420
|
|
|
|
|
|
|
sub lshiftint { |
|
5421
|
1365
|
|
|
1365
|
0
|
22964
|
my($n, $k) = @_; |
|
5422
|
1365
|
|
|
|
|
6962
|
validate_integer($n); |
|
5423
|
1365
|
100
|
|
|
|
21786
|
if (!defined $k) { $k = 1; } else { validate_integer($k); } |
|
|
374
|
|
|
|
|
1002
|
|
|
|
991
|
|
|
|
|
2870
|
|
|
5424
|
|
|
|
|
|
|
|
|
5425
|
1365
|
50
|
|
|
|
4704
|
return rshiftint($n, Mnegint($k)) if $k < 0; |
|
5426
|
1365
|
100
|
|
|
|
3971
|
return Mnegint(lshiftint(Mnegint($n),$k)) if $n < 0; |
|
5427
|
|
|
|
|
|
|
|
|
5428
|
1343
|
100
|
|
|
|
90912
|
if (!ref($n)) { |
|
5429
|
959
|
100
|
100
|
|
|
40900
|
return $n << $k if $n < INTMAX && $k < MPU_MAXBITS && $n == ($n<<$k)>>$k; |
|
|
|
|
100
|
|
|
|
|
|
5430
|
918
|
|
|
|
|
4451
|
$n = tobigint($n); |
|
5431
|
|
|
|
|
|
|
} |
|
5432
|
1302
|
|
|
|
|
5695
|
$n = $n << $k; |
|
5433
|
1302
|
100
|
|
|
|
736447
|
return $n <= INTMAX ? _bigint_to_int($n) : $n; |
|
5434
|
|
|
|
|
|
|
|
|
5435
|
|
|
|
|
|
|
#my $k2 = (!defined $k) ? 2 : ($k < MPU_MAXBITS) ? (1<<$k) : Mpowint(2,$k); |
|
5436
|
|
|
|
|
|
|
#Mmulint($n, $k2); |
|
5437
|
|
|
|
|
|
|
} |
|
5438
|
|
|
|
|
|
|
sub rshiftint { |
|
5439
|
12724
|
|
|
12724
|
0
|
53625
|
my($n, $k) = @_; |
|
5440
|
12724
|
|
|
|
|
40864
|
validate_integer($n); |
|
5441
|
12724
|
100
|
|
|
|
166293
|
if (!defined $k) { $k = 1; } else { validate_integer($k); } |
|
|
11849
|
|
|
|
|
20395
|
|
|
|
875
|
|
|
|
|
2583
|
|
|
5442
|
|
|
|
|
|
|
|
|
5443
|
12724
|
100
|
|
|
|
29277
|
return lshiftint($n, Mnegint($k)) if $k < 0; |
|
5444
|
12720
|
100
|
|
|
|
27432
|
return Mnegint(rshiftint(Mnegint($n),$k)) if $n < 0; |
|
5445
|
|
|
|
|
|
|
|
|
5446
|
12713
|
100
|
|
|
|
638245
|
if (!ref($n)) { |
|
5447
|
|
|
|
|
|
|
# Pre 5.24.0, large right shifts were undefined. |
|
5448
|
10248
|
100
|
|
|
|
40968
|
return $k < MPU_MAXBITS ? $n >> $k : 0 if $n < INTMAX; |
|
|
|
50
|
|
|
|
|
|
|
5449
|
0
|
|
|
|
|
0
|
$n = tobigint($n); |
|
5450
|
|
|
|
|
|
|
} |
|
5451
|
2465
|
|
|
|
|
9448
|
$n = $n >> $k; |
|
5452
|
2465
|
100
|
|
|
|
1139137
|
return $n <= INTMAX ? _bigint_to_int($n) : $n; |
|
5453
|
|
|
|
|
|
|
|
|
5454
|
|
|
|
|
|
|
#my $k2 = (!defined $k) ? 2 : ($k < MPU_MAXBITS) ? (1<<$k) : Mpowint(2,$k); |
|
5455
|
|
|
|
|
|
|
#(Mtdivrem($n, $k2))[0]; |
|
5456
|
|
|
|
|
|
|
} |
|
5457
|
|
|
|
|
|
|
|
|
5458
|
|
|
|
|
|
|
sub rashiftint { |
|
5459
|
23
|
|
|
23
|
0
|
11148
|
my($n, $k) = @_; |
|
5460
|
23
|
|
|
|
|
210
|
validate_integer($n); |
|
5461
|
23
|
50
|
|
|
|
187
|
if (!defined $k) { $k = 1; } else { validate_integer($k); } |
|
|
0
|
|
|
|
|
0
|
|
|
|
23
|
|
|
|
|
71
|
|
|
5462
|
23
|
100
|
|
|
|
133
|
return lshiftint($n, Mnegint($k)) if $k < 0; |
|
5463
|
19
|
100
|
|
|
|
459
|
my $k2 = $k < MPU_MAXBITS ? (1<<$k) : Mpowint(2,$k); |
|
5464
|
19
|
|
|
|
|
4126
|
Mdivint($n, $k2); |
|
5465
|
|
|
|
|
|
|
} |
|
5466
|
|
|
|
|
|
|
|
|
5467
|
|
|
|
|
|
|
sub powersum { |
|
5468
|
73
|
|
|
73
|
0
|
40891
|
my($n, $k) = @_; |
|
5469
|
73
|
|
|
|
|
217
|
validate_integer_nonneg($n); |
|
5470
|
73
|
|
|
|
|
159
|
validate_integer_nonneg($k); |
|
5471
|
|
|
|
|
|
|
|
|
5472
|
73
|
100
|
66
|
|
|
316
|
return $n if $n <= 1 || $k == 0; |
|
5473
|
|
|
|
|
|
|
|
|
5474
|
45
|
100
|
|
|
|
646
|
return Mdivint(Mvecprod($n, Madd1int($n), Madd1int(Mmulint($n,2))),6) if $k==2; |
|
5475
|
34
|
100
|
|
|
|
189
|
return Mdivint(Mvecprod( |
|
5476
|
|
|
|
|
|
|
$n, Madd1int($n), Madd1int(Mmulint($n,2)), |
|
5477
|
|
|
|
|
|
|
Mvecsum( Mmulint(3,Mpowint($n,2)), Mmulint(3,$n), -1 ) |
|
5478
|
|
|
|
|
|
|
),30) if $k==4; |
|
5479
|
|
|
|
|
|
|
|
|
5480
|
27
|
|
|
|
|
1257
|
my $a = Mrshiftint(Mmulint($n,Madd1int($n))); |
|
5481
|
27
|
100
|
|
|
|
367
|
return $a if $k == 1; |
|
5482
|
26
|
100
|
|
|
|
184
|
return Mmulint($a,$a) if $k == 3; |
|
5483
|
18
|
100
|
|
|
|
53
|
return Mdivint(Msubint(Mmulint(4,Mpowint($a,3)),Mmulint($a,$a)),3) if $k == 5; |
|
5484
|
|
|
|
|
|
|
|
|
5485
|
14
|
|
|
|
|
51
|
my @v; |
|
5486
|
14
|
100
|
|
|
|
46
|
if ($k < $n) { |
|
5487
|
10
|
|
|
|
|
213
|
for my $j (1..$k) { |
|
5488
|
90
|
|
|
|
|
4621
|
my $F = Mfactorial($j); |
|
5489
|
90
|
|
|
|
|
1951
|
my $B = Mbinomial($n+1,$j+1); |
|
5490
|
90
|
|
|
|
|
9975
|
my $S = Mstirling($k,$j,2); |
|
5491
|
90
|
|
|
|
|
2326
|
push @v, Mvecprod($F,$B,$S); |
|
5492
|
|
|
|
|
|
|
} |
|
5493
|
|
|
|
|
|
|
} else { |
|
5494
|
4
|
|
|
|
|
18
|
@v = map { Mpowint($_,$k) } 1..$n; |
|
|
39
|
|
|
|
|
10688
|
|
|
5495
|
|
|
|
|
|
|
} |
|
5496
|
14
|
|
|
|
|
389
|
Mvecsum(@v); |
|
5497
|
|
|
|
|
|
|
} |
|
5498
|
|
|
|
|
|
|
|
|
5499
|
|
|
|
|
|
|
# Make sure to work around RT71548, Math::BigInt::Lite, |
|
5500
|
|
|
|
|
|
|
# and use correct lcm semantics. |
|
5501
|
|
|
|
|
|
|
sub gcd { |
|
5502
|
6385
|
|
|
6385
|
0
|
25004
|
my $REF = undef; |
|
5503
|
6385
|
|
|
|
|
20194
|
for my $n (@_) { |
|
5504
|
8002
|
|
|
|
|
19801
|
my $refn = ref($n); |
|
5505
|
8002
|
100
|
|
|
|
25346
|
if ($refn) { $REF = $refn; last; } |
|
|
5305
|
|
|
|
|
10712
|
|
|
|
5305
|
|
|
|
|
12985
|
|
|
5506
|
|
|
|
|
|
|
} |
|
5507
|
|
|
|
|
|
|
|
|
5508
|
|
|
|
|
|
|
# Try all-native if all inputs are native ints. |
|
5509
|
6385
|
100
|
|
|
|
19663
|
if (!$REF) { |
|
5510
|
1080
|
|
100
|
|
|
2963
|
my($x,$y) = (shift || 0, 0); |
|
5511
|
1080
|
100
|
|
|
|
2632
|
$x = -$x if $x < 0; |
|
5512
|
1080
|
|
|
|
|
2440
|
while (@_) { |
|
5513
|
1082
|
|
|
|
|
1750
|
$y = shift; |
|
5514
|
1082
|
|
|
|
|
2376
|
while ($y) { ($x,$y) = ($y, $x % $y); } |
|
|
6576
|
|
|
|
|
14676
|
|
|
5515
|
1082
|
100
|
|
|
|
2844
|
$x = -$x if $x < 0; |
|
5516
|
|
|
|
|
|
|
} |
|
5517
|
1080
|
|
|
|
|
3812
|
return $x; |
|
5518
|
|
|
|
|
|
|
} |
|
5519
|
|
|
|
|
|
|
|
|
5520
|
5305
|
100
|
|
|
|
15097
|
my @N = map { ref($_) eq $REF ? $_ : $REF->new("$_") } @_; |
|
|
10611
|
|
|
|
|
112454
|
|
|
5521
|
5305
|
|
|
|
|
488379
|
my $gcd; |
|
5522
|
|
|
|
|
|
|
|
|
5523
|
5305
|
50
|
|
|
|
17374
|
if ($REF eq 'Math::BigInt') { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
5524
|
5305
|
|
|
|
|
26554
|
$gcd = Math::BigInt::bgcd(@N); |
|
5525
|
|
|
|
|
|
|
} elsif ($REF eq 'Math::GMPz') { |
|
5526
|
0
|
|
|
|
|
0
|
$gcd = Math::GMPz->new(shift(@N)); |
|
5527
|
0
|
|
|
|
|
0
|
Math::GMPz::Rmpz_gcd($gcd,$gcd,$_) for @N; |
|
5528
|
|
|
|
|
|
|
} elsif ($REF eq 'Math::GMP') { |
|
5529
|
0
|
|
|
|
|
0
|
$gcd = Math::GMP->new(shift(@N)); |
|
5530
|
0
|
|
|
|
|
0
|
$gcd = Math::GMP::gcd($gcd,$_) for @N; |
|
5531
|
|
|
|
|
|
|
} else { |
|
5532
|
0
|
|
|
|
|
0
|
$gcd = Math::BigInt::bgcd(map { Math::BigInt->new("$_") } @N); |
|
|
0
|
|
|
|
|
0
|
|
|
5533
|
0
|
|
|
|
|
0
|
$gcd = tobigint($gcd); |
|
5534
|
|
|
|
|
|
|
} |
|
5535
|
5305
|
100
|
|
|
|
6346188
|
$gcd = _bigint_to_int($gcd) if $gcd <= INTMAX; |
|
5536
|
5305
|
|
|
|
|
265934
|
$gcd; |
|
5537
|
|
|
|
|
|
|
} |
|
5538
|
|
|
|
|
|
|
sub lcm { |
|
5539
|
19
|
|
|
19
|
0
|
3629
|
my(@v) = @_; |
|
5540
|
19
|
50
|
|
|
|
74
|
return 1 unless @v > 0; |
|
5541
|
19
|
|
|
|
|
36
|
my $lcm; |
|
5542
|
19
|
|
|
|
|
82
|
for my $y (@v) { |
|
5543
|
56
|
|
|
|
|
1941
|
validate_integer($y); |
|
5544
|
56
|
0
|
|
|
|
1014
|
if ($y <= 0) { return 0 if $y == 0; $y = Mabsint($y); } |
|
|
0
|
50
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
5545
|
56
|
100
|
|
|
|
3084
|
$lcm = defined $lcm ? Mmulint($lcm, Mdivint($y, Mgcd($lcm,$y))) : $y; |
|
5546
|
|
|
|
|
|
|
} |
|
5547
|
19
|
|
|
|
|
2082
|
return $lcm; |
|
5548
|
|
|
|
|
|
|
} |
|
5549
|
|
|
|
|
|
|
sub gcdext { |
|
5550
|
4
|
|
|
4
|
0
|
12268
|
my($x,$y) = @_; |
|
5551
|
4
|
|
|
|
|
30
|
validate_integer($x); |
|
5552
|
4
|
|
|
|
|
83
|
validate_integer($y); |
|
5553
|
4
|
50
|
|
|
|
79
|
if ($x == 0) { return (0, (-1,0,1)[($y>=0)+($y>0)], abs($y)); } |
|
|
0
|
|
|
|
|
0
|
|
|
5554
|
4
|
50
|
|
|
|
329
|
if ($y == 0) { return ((-1,0,1)[($x>=0)+($x>0)], 0, abs($x)); } |
|
|
0
|
|
|
|
|
0
|
|
|
5555
|
|
|
|
|
|
|
|
|
5556
|
4
|
50
|
|
|
|
286
|
if ($Math::Prime::Util::_GMPfunc{"gcdext"}) { |
|
5557
|
0
|
|
|
|
|
0
|
my($a,$b,$g) = Math::Prime::Util::GMP::gcdext($x,$y); |
|
5558
|
0
|
|
|
|
|
0
|
$a = reftyped($_[0], $a); |
|
5559
|
0
|
|
|
|
|
0
|
$b = reftyped($_[0], $b); |
|
5560
|
0
|
|
|
|
|
0
|
$g = reftyped($_[0], $g); |
|
5561
|
0
|
|
|
|
|
0
|
return ($a,$b,$g); |
|
5562
|
|
|
|
|
|
|
} |
|
5563
|
|
|
|
|
|
|
|
|
5564
|
4
|
|
|
|
|
21
|
my($a,$b,$g,$u,$v,$w); |
|
5565
|
4
|
100
|
66
|
|
|
27
|
if (abs($x) < (~0>>1) && abs($y) < (~0>>1)) { |
|
5566
|
2
|
50
|
|
|
|
7
|
$x = _bigint_to_int($x) if ref($x); |
|
5567
|
2
|
50
|
|
|
|
9
|
$y = _bigint_to_int($y) if ref($y); |
|
5568
|
2
|
|
|
|
|
16
|
($a,$b,$g,$u,$v,$w) = (1,0,$x,0,1,$y); |
|
5569
|
2
|
|
|
|
|
8
|
while ($w != 0) { |
|
5570
|
14
|
|
|
|
|
26
|
my $r = $g % $w; |
|
5571
|
14
|
|
|
|
|
32
|
my $q = int(($g-$r)/$w); |
|
5572
|
14
|
|
|
|
|
46
|
($a,$b,$g,$u,$v,$w) = ($u,$v,$w,$a-$q*$u,$b-$q*$v,$r); |
|
5573
|
|
|
|
|
|
|
} |
|
5574
|
|
|
|
|
|
|
} else { |
|
5575
|
2
|
|
|
|
|
469
|
($a,$b,$g,$u,$v,$w) = (1,0,$x,0,1,$y); |
|
5576
|
2
|
|
|
|
|
10
|
while ($w != 0) { |
|
5577
|
109
|
|
|
|
|
22741
|
my($q,$r) = Mdivrem($g,$w); |
|
5578
|
109
|
|
|
|
|
1203
|
($a,$b,$g,$u,$v,$w) = ($u, $v, $w, |
|
5579
|
|
|
|
|
|
|
Msubint($a,Mmulint($q,$u)), |
|
5580
|
|
|
|
|
|
|
Msubint($b,Mmulint($q,$v)), $r); |
|
5581
|
|
|
|
|
|
|
} |
|
5582
|
|
|
|
|
|
|
} |
|
5583
|
4
|
50
|
|
|
|
700
|
if ($g < 0) { ($a,$b,$g) = (-$a,-$b,-$g); } |
|
|
0
|
|
|
|
|
0
|
|
|
5584
|
4
|
|
|
|
|
42
|
return ($a,$b,$g); |
|
5585
|
|
|
|
|
|
|
} |
|
5586
|
|
|
|
|
|
|
|
|
5587
|
|
|
|
|
|
|
sub chinese2 { |
|
5588
|
94
|
50
|
|
94
|
0
|
2077
|
return (0,0) unless scalar @_; |
|
5589
|
94
|
|
|
|
|
166
|
my($lcm, $sum); |
|
5590
|
|
|
|
|
|
|
|
|
5591
|
94
|
50
|
33
|
|
|
263
|
if ($Math::Prime::Util::_GMPfunc{"chinese2"} && $Math::Prime::Util::GMP::VERSION >= 0.53) { |
|
5592
|
0
|
|
|
|
|
0
|
return maybetobigintall( |
|
5593
|
|
|
|
|
|
|
Math::Prime::Util::GMP::chinese2(@_) |
|
5594
|
|
|
|
|
|
|
); |
|
5595
|
|
|
|
|
|
|
} |
|
5596
|
|
|
|
|
|
|
|
|
5597
|
|
|
|
|
|
|
# Validate, copy, and do abs on the inputs. |
|
5598
|
94
|
|
|
|
|
153
|
my @items; |
|
5599
|
94
|
|
|
|
|
174
|
foreach my $aref (@_) { |
|
5600
|
194
|
50
|
33
|
|
|
755
|
die "chinese arguments are two-element array references" |
|
5601
|
|
|
|
|
|
|
unless ref($aref) eq 'ARRAY' && scalar @$aref == 2; |
|
5602
|
194
|
|
|
|
|
370
|
my($a,$n) = @$aref; |
|
5603
|
194
|
|
|
|
|
438
|
validate_integer($a); |
|
5604
|
194
|
|
|
|
|
619
|
validate_integer($n); |
|
5605
|
194
|
50
|
|
|
|
442
|
return (undef,undef) if $n == 0; |
|
5606
|
194
|
|
|
|
|
449
|
$n = Mabsint($n); |
|
5607
|
194
|
|
|
|
|
416
|
$a = Mmodint($a,$n); |
|
5608
|
194
|
|
|
|
|
238
|
if (OLD_PERL_VERSION) { ($a,$n) = ("$a","$n"); } |
|
5609
|
194
|
|
|
|
|
593
|
push @items, [$a,$n]; |
|
5610
|
|
|
|
|
|
|
} |
|
5611
|
94
|
50
|
|
|
|
199
|
return @{$items[0]} if scalar @items == 1; |
|
|
0
|
|
|
|
|
0
|
|
|
5612
|
94
|
|
|
|
|
384
|
@items = sort { $b->[1] <=> $a->[1] } @items; |
|
|
103
|
|
|
|
|
312
|
|
|
5613
|
|
|
|
|
|
|
|
|
5614
|
94
|
|
|
|
|
119
|
($sum, $lcm) = @{shift @items}; |
|
|
94
|
|
|
|
|
229
|
|
|
5615
|
|
|
|
|
|
|
|
|
5616
|
94
|
|
|
|
|
186
|
foreach my $aref (@items) { |
|
5617
|
100
|
|
|
|
|
517
|
my($ai, $ni) = @$aref; |
|
5618
|
|
|
|
|
|
|
# gcdext |
|
5619
|
100
|
|
|
|
|
222
|
my($u,$v,$g,$s,$t,$w) = (1,0,$lcm,0,1,$ni); |
|
5620
|
100
|
|
|
|
|
211
|
while ($w != 0) { |
|
5621
|
571
|
|
|
|
|
1791
|
my($q,$r) = Mdivrem($g,$w); |
|
5622
|
571
|
|
|
|
|
2220
|
($u,$v,$g,$s,$t,$w) = ($s, $t, $w, |
|
5623
|
|
|
|
|
|
|
Msubint($u,Mmulint($q,$s)), |
|
5624
|
|
|
|
|
|
|
Msubint($v,Mmulint($q,$t)), $r); |
|
5625
|
|
|
|
|
|
|
} |
|
5626
|
|
|
|
|
|
|
#($u,$v,$g) = (-$u,-$v,-$g) if $g < 0; |
|
5627
|
100
|
50
|
|
|
|
604
|
($u,$v,$g) = map { Mnegint($_) } ($u,$v,$g) if $g < 0; |
|
|
0
|
|
|
|
|
0
|
|
|
5628
|
100
|
50
|
66
|
|
|
241
|
return (undef,undef) if $g != 1 && ($sum % $g) != ($ai % $g); # Not co-prime |
|
5629
|
100
|
100
|
|
|
|
388
|
$s = Mnegint($s) if "$s" < 0; |
|
5630
|
100
|
100
|
|
|
|
301
|
$t = Mnegint($t) if "$t" < 0; |
|
5631
|
100
|
|
|
|
|
1322
|
$lcm = Mmulint($lcm, $s); |
|
5632
|
100
|
100
|
|
|
|
3455
|
$u = Maddint($u, $lcm) if "$u" < 0; |
|
5633
|
100
|
100
|
|
|
|
1147
|
$v = Maddint($v, $lcm) if "$v" < 0; |
|
5634
|
100
|
|
|
|
|
2523
|
my $vs = Mmulmod($v,$s,$lcm); |
|
5635
|
100
|
|
|
|
|
3525
|
my $ut = Mmulmod($u,$t,$lcm); |
|
5636
|
100
|
|
|
|
|
3194
|
my $m1 = Mmulmod($sum,$vs,$lcm); |
|
5637
|
100
|
|
|
|
|
3428
|
my $m2 = Mmulmod($ut,$ai,$lcm); |
|
5638
|
100
|
|
|
|
|
3440
|
$sum = Maddmod($m1, $m2, $lcm); |
|
5639
|
|
|
|
|
|
|
} |
|
5640
|
94
|
|
|
|
|
3348
|
($sum,$lcm); |
|
5641
|
|
|
|
|
|
|
} |
|
5642
|
|
|
|
|
|
|
|
|
5643
|
|
|
|
|
|
|
sub chinese { |
|
5644
|
88
|
|
|
88
|
0
|
2146
|
(chinese2(@_))[0]; |
|
5645
|
|
|
|
|
|
|
} |
|
5646
|
|
|
|
|
|
|
|
|
5647
|
|
|
|
|
|
|
sub _from_128 { |
|
5648
|
0
|
|
|
0
|
|
0
|
my($hi, $lo) = @_; |
|
5649
|
0
|
0
|
0
|
|
|
0
|
return 0 unless defined $hi && defined $lo; |
|
5650
|
0
|
|
|
|
|
0
|
Maddint(Mlshiftint($hi,MPU_MAXBITS), $lo); |
|
5651
|
|
|
|
|
|
|
} |
|
5652
|
|
|
|
|
|
|
|
|
5653
|
|
|
|
|
|
|
sub vecsum { |
|
5654
|
852
|
50
|
|
852
|
0
|
3916
|
return reftyped($_[0], @_ ? $_[0] : 0) if @_ <= 1; |
|
|
|
100
|
|
|
|
|
|
|
5655
|
|
|
|
|
|
|
|
|
5656
|
|
|
|
|
|
|
return reftyped($_[0], Math::Prime::Util::GMP::vecsum(@_)) |
|
5657
|
808
|
50
|
|
|
|
2523
|
if $Math::Prime::Util::_GMPfunc{"vecsum"}; |
|
5658
|
808
|
|
|
|
|
1520
|
my $sum = 0; |
|
5659
|
808
|
|
|
|
|
1437
|
if (OLD_PERL_VERSION) { $_="$_" for @_ }; |
|
5660
|
808
|
|
|
|
|
2013
|
foreach my $v (@_) { |
|
5661
|
18433
|
|
|
|
|
28054
|
$sum += $v; |
|
5662
|
18433
|
100
|
100
|
|
|
102715
|
if ($sum > (INTMAX-250) || $sum < (INTMIN+250)) { |
|
5663
|
|
|
|
|
|
|
# Sum again from the start using bigint sum |
|
5664
|
122
|
|
|
|
|
41429
|
$sum = tobigint(0); |
|
5665
|
122
|
50
|
|
|
|
737
|
if (ref($sum) eq 'Math::Pari') { $sum += "$_" for @_; } |
|
|
0
|
|
|
|
|
0
|
|
|
5666
|
122
|
|
|
|
|
715
|
else { $sum += $_ for @_; } |
|
5667
|
122
|
100
|
66
|
|
|
20383692
|
$sum = _bigint_to_int($sum) if $sum <= INTMAX && $sum >= INTMIN; |
|
5668
|
122
|
|
|
|
|
35618
|
return $sum; |
|
5669
|
|
|
|
|
|
|
} |
|
5670
|
|
|
|
|
|
|
} |
|
5671
|
686
|
|
|
|
|
6597
|
$sum; |
|
5672
|
|
|
|
|
|
|
} |
|
5673
|
|
|
|
|
|
|
|
|
5674
|
|
|
|
|
|
|
sub _product_mulint { |
|
5675
|
0
|
|
|
0
|
|
0
|
my($a, $b, $r) = @_; |
|
5676
|
0
|
0
|
|
|
|
0
|
return $r->[$a] if $b <= $a; |
|
5677
|
0
|
0
|
|
|
|
0
|
return Mmulint($r->[$a], $r->[$b]) if $b == $a+1; |
|
5678
|
0
|
0
|
|
|
|
0
|
return Mmulint(Mmulint($r->[$a], $r->[$a+1]), $r->[$a+2]) if $b == $a+2; |
|
5679
|
0
|
|
|
|
|
0
|
my $c = $a + (($b-$a+1)>>1); |
|
5680
|
0
|
|
|
|
|
0
|
Mmulint( _product_mulint($a, $c-1, $r), _product_mulint($c, $b, $r) ); |
|
5681
|
|
|
|
|
|
|
} |
|
5682
|
|
|
|
|
|
|
sub _product_mult { |
|
5683
|
1375
|
|
|
1375
|
|
151797
|
my($a, $b, $r) = @_; |
|
5684
|
1375
|
50
|
|
|
|
3978
|
return $r->[$a] if $b <= $a; |
|
5685
|
1375
|
100
|
|
|
|
3411
|
return $r->[$a] * $r->[$a+1] if $b == $a+1; |
|
5686
|
1044
|
100
|
|
|
|
3288
|
return $r->[$a] * $r->[$a+1] * $r->[$a+2] if $b == $a+2; |
|
5687
|
543
|
|
|
|
|
1016
|
my $c = $a + (($b-$a+1)>>1); |
|
5688
|
543
|
|
|
|
|
1288
|
_product_mult($a, $c-1, $r) * _product_mult($c, $b, $r); |
|
5689
|
|
|
|
|
|
|
} |
|
5690
|
|
|
|
|
|
|
|
|
5691
|
|
|
|
|
|
|
sub vecprod { |
|
5692
|
816
|
50
|
|
816
|
0
|
15399
|
return 1 unless @_; |
|
5693
|
|
|
|
|
|
|
return reftyped($_[0], Math::Prime::Util::GMP::vecprod(@_)) |
|
5694
|
816
|
50
|
|
|
|
2276
|
if $Math::Prime::Util::_GMPfunc{"vecprod"}; |
|
5695
|
|
|
|
|
|
|
|
|
5696
|
816
|
100
|
|
|
|
2131
|
return $_[0] if @_ == 1; |
|
5697
|
|
|
|
|
|
|
|
|
5698
|
|
|
|
|
|
|
# Argh, Perl 5.6.2. |
|
5699
|
698
|
|
|
|
|
1016
|
if (OLD_PERL_VERSION) { |
|
5700
|
|
|
|
|
|
|
my $prod = _product_mult(0, $#_, [map { tobigint($_) } @_]); |
|
5701
|
|
|
|
|
|
|
$prod = _bigint_to_int($prod) if ref($prod) && $prod <= INTMAX && $prod >= INTMIN; |
|
5702
|
|
|
|
|
|
|
return $prod; |
|
5703
|
|
|
|
|
|
|
} |
|
5704
|
|
|
|
|
|
|
|
|
5705
|
|
|
|
|
|
|
# Try native for non-negative/non-zero inputs |
|
5706
|
698
|
100
|
100
|
|
|
4003
|
if ($_[0] > 0 && $_[0] <= INTMAX && $_[1] > 0 && $_[1] <= INTMAX) { |
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
5707
|
318
|
|
|
|
|
667
|
my $prod = shift @_; |
|
5708
|
318
|
|
66
|
|
|
7926
|
$prod *= shift @_ |
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
5709
|
|
|
|
|
|
|
while @_ && $_[0] > 0 && $_[0] <= INTMAX && int(INTMAX/$prod) > $_[0]; |
|
5710
|
318
|
100
|
|
|
|
2103
|
return $prod if @_ == 0; |
|
5711
|
242
|
50
|
|
|
|
941
|
unshift @_, $prod if $prod > 1; |
|
5712
|
|
|
|
|
|
|
} |
|
5713
|
|
|
|
|
|
|
|
|
5714
|
622
|
100
|
|
|
|
46224
|
return mulint($_[0], $_[1]) if @_ == 2; |
|
5715
|
|
|
|
|
|
|
|
|
5716
|
|
|
|
|
|
|
# Product tree |
|
5717
|
|
|
|
|
|
|
# my $prod = _product_mulint(0, $#_, \@_); |
|
5718
|
289
|
|
|
|
|
1327
|
my $prod = _product_mult(0, $#_, [map { tobigint($_) } @_]); |
|
|
2165
|
|
|
|
|
5047
|
|
|
5719
|
|
|
|
|
|
|
|
|
5720
|
289
|
100
|
66
|
|
|
173384
|
$prod = _bigint_to_int($prod) if ref($prod) && $prod <= INTMAX && $prod >= INTMIN; |
|
|
|
|
100
|
|
|
|
|
|
5721
|
289
|
|
|
|
|
72242
|
$prod; |
|
5722
|
|
|
|
|
|
|
} |
|
5723
|
|
|
|
|
|
|
|
|
5724
|
|
|
|
|
|
|
sub vecmin { |
|
5725
|
6
|
50
|
|
6
|
0
|
45
|
return unless @_; |
|
5726
|
6
|
|
|
|
|
22
|
my $min = shift; |
|
5727
|
6
|
100
|
|
|
|
18
|
for (@_) { $min = $_ if $_ < $min; } |
|
|
13
|
|
|
|
|
53
|
|
|
5728
|
6
|
|
|
|
|
210
|
$min; |
|
5729
|
|
|
|
|
|
|
} |
|
5730
|
|
|
|
|
|
|
sub vecmax { |
|
5731
|
96
|
50
|
|
96
|
0
|
281
|
return unless @_; |
|
5732
|
96
|
|
|
|
|
235
|
my $max = shift; |
|
5733
|
96
|
100
|
|
|
|
241
|
for (@_) { $max = $_ if $_ > $max; } |
|
|
106
|
|
|
|
|
317
|
|
|
5734
|
96
|
|
|
|
|
755
|
$max; |
|
5735
|
|
|
|
|
|
|
} |
|
5736
|
|
|
|
|
|
|
|
|
5737
|
|
|
|
|
|
|
sub vecextract { |
|
5738
|
1
|
|
|
1
|
0
|
4
|
my($aref, $mask) = @_; |
|
5739
|
|
|
|
|
|
|
|
|
5740
|
1
|
50
|
|
|
|
15
|
return @$aref[@$mask] if ref($mask) eq 'ARRAY'; |
|
5741
|
|
|
|
|
|
|
|
|
5742
|
|
|
|
|
|
|
# This is concise but very slow. |
|
5743
|
|
|
|
|
|
|
# map { $aref->[$_] } grep { $mask & (1 << $_) } 0 .. $#$aref; |
|
5744
|
|
|
|
|
|
|
|
|
5745
|
0
|
|
|
|
|
0
|
my($i, @v) = (0); |
|
5746
|
0
|
|
|
|
|
0
|
while ($mask) { |
|
5747
|
0
|
0
|
|
|
|
0
|
push @v, $i if $mask & 1; |
|
5748
|
0
|
|
|
|
|
0
|
$mask >>= 1; |
|
5749
|
0
|
|
|
|
|
0
|
$i++; |
|
5750
|
|
|
|
|
|
|
} |
|
5751
|
0
|
|
|
|
|
0
|
@$aref[@v]; |
|
5752
|
|
|
|
|
|
|
} |
|
5753
|
|
|
|
|
|
|
|
|
5754
|
|
|
|
|
|
|
sub vecequal { |
|
5755
|
2
|
|
|
2
|
0
|
8
|
my($aref, $bref) = @_; |
|
5756
|
2
|
50
|
33
|
|
|
20
|
croak "vecequal element not scalar or array reference" |
|
5757
|
|
|
|
|
|
|
unless ref($aref) eq 'ARRAY' && ref($bref) eq 'ARRAY'; |
|
5758
|
2
|
50
|
|
|
|
9
|
return 0 unless $#$aref == $#$bref; |
|
5759
|
2
|
|
|
|
|
25
|
my $i = 0; |
|
5760
|
2
|
|
|
|
|
8
|
for my $av (@$aref) { |
|
5761
|
4
|
|
|
|
|
19
|
my $bv = $bref->[$i++]; |
|
5762
|
4
|
0
|
33
|
|
|
12
|
next if !defined $av && !defined $bv; |
|
5763
|
4
|
50
|
33
|
|
|
21
|
return 0 if !defined $av || !defined $bv; |
|
5764
|
4
|
0
|
33
|
|
|
14
|
if (ref($av) && ref($bv) && |
|
|
|
|
0
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
5765
|
|
|
|
|
|
|
(ref($av) =~ /^(ARRAY|HASH|CODE|FORMAT|IO|REGEXP)$/i || |
|
5766
|
|
|
|
|
|
|
ref($bv) =~ /^(ARRAY|HASH|CODE|FORMAT|IO|REGEXP)$/i) ) { |
|
5767
|
0
|
0
|
0
|
|
|
0
|
next if (ref($av) eq ref($bv)) && vecequal($av, $bv); |
|
5768
|
0
|
|
|
|
|
0
|
return 0; |
|
5769
|
|
|
|
|
|
|
} |
|
5770
|
|
|
|
|
|
|
# About 7x faster if we skip the validates. |
|
5771
|
|
|
|
|
|
|
# validate_integer($av); |
|
5772
|
|
|
|
|
|
|
# validate_integer($bv); |
|
5773
|
4
|
100
|
|
|
|
27
|
return 0 unless "$av" eq "$bv"; |
|
5774
|
|
|
|
|
|
|
} |
|
5775
|
1
|
|
|
|
|
8
|
1; |
|
5776
|
|
|
|
|
|
|
} |
|
5777
|
|
|
|
|
|
|
|
|
5778
|
|
|
|
|
|
|
sub vecmex { |
|
5779
|
1
|
|
|
1
|
0
|
5
|
my $items = scalar(@_); |
|
5780
|
1
|
|
|
|
|
4
|
my @seen; |
|
5781
|
1
|
|
|
|
|
15
|
for (@_) { |
|
5782
|
4
|
100
|
|
|
|
26
|
$seen[$_] = 0 if $_ < $items; |
|
5783
|
|
|
|
|
|
|
} |
|
5784
|
1
|
|
|
|
|
5
|
for (0 .. $items-1) { |
|
5785
|
4
|
100
|
|
|
|
21
|
return $_ unless defined $seen[$_]; |
|
5786
|
|
|
|
|
|
|
} |
|
5787
|
0
|
|
|
|
|
0
|
return $items; |
|
5788
|
|
|
|
|
|
|
} |
|
5789
|
|
|
|
|
|
|
|
|
5790
|
|
|
|
|
|
|
sub vecpmex { |
|
5791
|
1
|
|
|
1
|
0
|
4
|
my $items = scalar(@_); |
|
5792
|
1
|
|
|
|
|
3
|
my @seen; |
|
5793
|
1
|
|
|
|
|
3
|
for (@_) { |
|
5794
|
4
|
100
|
|
|
|
13
|
$seen[$_] = 0 if $_ <= $items; |
|
5795
|
|
|
|
|
|
|
} |
|
5796
|
1
|
|
|
|
|
5
|
for (1 .. $items) { |
|
5797
|
3
|
100
|
|
|
|
14
|
return $_ unless defined $seen[$_]; |
|
5798
|
|
|
|
|
|
|
} |
|
5799
|
0
|
|
|
|
|
0
|
return $items+1; |
|
5800
|
|
|
|
|
|
|
} |
|
5801
|
|
|
|
|
|
|
|
|
5802
|
|
|
|
|
|
|
sub sumdigits { |
|
5803
|
4
|
|
|
4
|
0
|
1669
|
my($n,$base) = @_; |
|
5804
|
4
|
|
|
|
|
10
|
my $sum = 0; |
|
5805
|
4
|
100
|
100
|
|
|
68
|
$base = 2 if !defined $base && $n =~ s/^0b//; |
|
5806
|
4
|
50
|
66
|
|
|
42
|
$base = 16 if !defined $base && $n =~ s/^0x//; |
|
5807
|
4
|
100
|
66
|
|
|
31
|
if (!defined $base || $base == 10) { |
|
5808
|
1
|
|
|
|
|
3
|
$n =~ tr/0123456789//cd; |
|
5809
|
1
|
|
|
|
|
9
|
$sum += $_ for (split(//,$n)); |
|
5810
|
|
|
|
|
|
|
} else { |
|
5811
|
3
|
50
|
|
|
|
25
|
croak "sumdigits: invalid base $base" if $base < 2; |
|
5812
|
3
|
|
|
|
|
11
|
my $cmap = substr("0123456789abcdefghijklmnopqrstuvwxyz",0,$base); |
|
5813
|
3
|
|
|
|
|
25
|
for my $c (split(//,lc($n))) { |
|
5814
|
21
|
|
|
|
|
45
|
my $p = index($cmap,$c); |
|
5815
|
21
|
100
|
|
|
|
52
|
$sum += $p if $p > 0; |
|
5816
|
|
|
|
|
|
|
} |
|
5817
|
|
|
|
|
|
|
} |
|
5818
|
4
|
|
|
|
|
39
|
$sum; |
|
5819
|
|
|
|
|
|
|
} |
|
5820
|
|
|
|
|
|
|
|
|
5821
|
|
|
|
|
|
|
sub is_happy { |
|
5822
|
4
|
|
|
4
|
0
|
1417
|
my($n, $base, $k) = @_; |
|
5823
|
4
|
|
|
|
|
18
|
validate_integer_nonneg($n); |
|
5824
|
|
|
|
|
|
|
|
|
5825
|
4
|
|
|
|
|
9
|
my $h = 1; |
|
5826
|
|
|
|
|
|
|
|
|
5827
|
4
|
50
|
66
|
|
|
31
|
if (!defined $base && !defined $k) { # default base 10 exponent 2 |
|
5828
|
1
|
|
66
|
|
|
11
|
while ($n > 1 && $n != 4) { |
|
5829
|
6
|
|
|
|
|
10
|
my $sum = 0; |
|
5830
|
6
|
|
|
|
|
26
|
$sum += $_*$_ for (split(//,$n)); |
|
5831
|
6
|
|
|
|
|
10
|
$n = $sum; |
|
5832
|
6
|
|
|
|
|
22
|
$h++; |
|
5833
|
|
|
|
|
|
|
} |
|
5834
|
1
|
50
|
|
|
|
13
|
return ($n == 1) ? $h : 0; |
|
5835
|
|
|
|
|
|
|
} |
|
5836
|
|
|
|
|
|
|
|
|
5837
|
3
|
50
|
|
|
|
26
|
if (defined $base) { |
|
5838
|
3
|
|
|
|
|
12
|
validate_integer_nonneg($base); |
|
5839
|
3
|
50
|
33
|
|
|
19
|
croak "is_happy: invalid base $base" if $base < 2 || $base > 36; |
|
5840
|
|
|
|
|
|
|
} else { |
|
5841
|
0
|
|
|
|
|
0
|
$base = 10; |
|
5842
|
|
|
|
|
|
|
} |
|
5843
|
3
|
100
|
|
|
|
22
|
if (defined $k) { |
|
5844
|
1
|
|
|
|
|
6
|
validate_integer_nonneg($k); |
|
5845
|
1
|
50
|
|
|
|
19
|
croak "is_happy: invalid exponent $k" if $k > 10; |
|
5846
|
|
|
|
|
|
|
} else { |
|
5847
|
2
|
|
|
|
|
5
|
$k = 2; |
|
5848
|
|
|
|
|
|
|
} |
|
5849
|
|
|
|
|
|
|
|
|
5850
|
3
|
|
|
|
|
14
|
my %seen; |
|
5851
|
3
|
|
66
|
|
|
24
|
while ($n > 1 && !exists $seen{$n}) { |
|
5852
|
7
|
|
|
|
|
35
|
$seen{$n} = undef; |
|
5853
|
7
|
50
|
|
|
|
18
|
if ($base == 10) { |
|
5854
|
0
|
|
|
|
|
0
|
my $sum = 0; |
|
5855
|
0
|
|
|
|
|
0
|
$sum += $_ ** $k for (split(//,$n)); |
|
5856
|
0
|
|
|
|
|
0
|
$n = $sum; |
|
5857
|
|
|
|
|
|
|
} else { |
|
5858
|
7
|
|
|
|
|
14
|
my @d; |
|
5859
|
7
|
|
|
|
|
22
|
while ($n >= 1) { |
|
5860
|
21
|
|
|
|
|
33
|
my $rem = $n % $base; |
|
5861
|
21
|
50
|
|
|
|
72
|
push @d, ($k <= 6) ? int($rem ** $k) : Mpowint($rem,$k); |
|
5862
|
|
|
|
|
|
|
#push @d, Mpowint($rem,$k); |
|
5863
|
21
|
|
|
|
|
56
|
$n = ($n-$rem)/$base; # Always an exact division |
|
5864
|
|
|
|
|
|
|
} |
|
5865
|
7
|
|
|
|
|
29
|
$n = Mvecsum(@d); |
|
5866
|
|
|
|
|
|
|
} |
|
5867
|
7
|
|
|
|
|
32
|
$h++; |
|
5868
|
|
|
|
|
|
|
} |
|
5869
|
3
|
50
|
|
|
|
45
|
return ($n == 1) ? $h : 0; |
|
5870
|
|
|
|
|
|
|
} |
|
5871
|
|
|
|
|
|
|
|
|
5872
|
|
|
|
|
|
|
|
|
5873
|
|
|
|
|
|
|
|
|
5874
|
|
|
|
|
|
|
# Tonelli-Shanks |
|
5875
|
|
|
|
|
|
|
sub _sqrtmod_prime { |
|
5876
|
47
|
|
|
47
|
|
352
|
my($a, $p) = @_; |
|
5877
|
47
|
|
|
|
|
110
|
my($x, $q, $e, $t, $z, $r, $m, $b); |
|
5878
|
47
|
|
|
|
|
179
|
my $Q = Msub1int($p); |
|
5879
|
|
|
|
|
|
|
|
|
5880
|
47
|
100
|
|
|
|
1095
|
if (($p % 4) == 3) { |
|
5881
|
24
|
|
|
|
|
1072
|
$r = Mpowmod($a, Mrshiftint(Madd1int($p),2), $p); |
|
5882
|
24
|
100
|
|
|
|
914
|
return undef unless Mmulmod($r,$r,$p) == $a; |
|
5883
|
18
|
|
|
|
|
937
|
return $r; |
|
5884
|
|
|
|
|
|
|
} |
|
5885
|
23
|
100
|
|
|
|
1086
|
if (($p % 8) == 5) { |
|
5886
|
17
|
|
|
|
|
1092
|
$m = Maddmod($a,$a,$p); |
|
5887
|
17
|
|
|
|
|
638
|
$t = Mpowmod($m, Mrshiftint(Msubint($p,5),3), $p); |
|
5888
|
17
|
|
|
|
|
270
|
$z = Mmulmod($m, Mmulmod($t,$t,$p), $p); |
|
5889
|
17
|
|
|
|
|
521
|
$r = Mmulmod($t, Mmulmod($a, Msubmod($z,1,$p), $p), $p); |
|
5890
|
17
|
100
|
|
|
|
511
|
return undef unless Mmulmod($r,$r,$p) == $a; |
|
5891
|
13
|
|
|
|
|
738
|
return $r; |
|
5892
|
|
|
|
|
|
|
} |
|
5893
|
|
|
|
|
|
|
|
|
5894
|
|
|
|
|
|
|
# Verify Euler's criterion for odd p |
|
5895
|
6
|
100
|
66
|
|
|
48
|
return undef if $p != 2 && Mpowmod($a, Mrshiftint($Q), $p) != 1; |
|
5896
|
|
|
|
|
|
|
|
|
5897
|
|
|
|
|
|
|
# Cohen Algorithm 1.5.1. Tonelli-Shanks. |
|
5898
|
4
|
|
|
|
|
169
|
$e = Mvaluation($Q, 2); |
|
5899
|
4
|
|
|
|
|
40
|
$q = Mdivint($Q, Mpowint(2,$e)); |
|
5900
|
4
|
|
|
|
|
28
|
$t = 3; |
|
5901
|
4
|
|
|
|
|
25
|
while (Mkronecker($t,$p) != -1) { |
|
5902
|
2
|
|
|
|
|
5
|
$t += 2; |
|
5903
|
2
|
50
|
33
|
|
|
10
|
return undef if $t == 201 && !Mis_prime($p); |
|
5904
|
|
|
|
|
|
|
} |
|
5905
|
4
|
|
|
|
|
24
|
$z = Mpowmod($t, $q, $p); |
|
5906
|
4
|
|
|
|
|
64
|
$b = Mpowmod($a, $q, $p); |
|
5907
|
4
|
|
|
|
|
52
|
$r = $e; |
|
5908
|
4
|
|
|
|
|
13
|
$q = ($q+1) >> 1; |
|
5909
|
4
|
|
|
|
|
20
|
$x = Mpowmod($a, $q, $p); |
|
5910
|
4
|
|
|
|
|
68
|
while ($b != 1) { |
|
5911
|
6
|
|
|
|
|
13
|
$t = $b; |
|
5912
|
6
|
|
66
|
|
|
37
|
for ($m = 0; $m < $r && $t != 1; $m++) { |
|
5913
|
12
|
|
|
|
|
49
|
$t = Mmulmod($t, $t, $p); |
|
5914
|
|
|
|
|
|
|
} |
|
5915
|
6
|
|
|
|
|
31
|
$t = Mpowmod($z, Mlshiftint(1, $r-$m-1), $p); |
|
5916
|
6
|
|
|
|
|
38
|
$x = Mmulmod($x, $t, $p); |
|
5917
|
6
|
|
|
|
|
19
|
$z = Mmulmod($t, $t, $p); |
|
5918
|
6
|
|
|
|
|
21
|
$b = Mmulmod($b, $z, $p); |
|
5919
|
6
|
|
|
|
|
20
|
$r = $m; |
|
5920
|
|
|
|
|
|
|
} |
|
5921
|
|
|
|
|
|
|
# Expected to always be true. |
|
5922
|
4
|
50
|
|
|
|
31
|
return undef unless Mmulmod($x,$x,$p) == $a; |
|
5923
|
4
|
|
|
|
|
16
|
return $x; |
|
5924
|
|
|
|
|
|
|
} |
|
5925
|
|
|
|
|
|
|
|
|
5926
|
|
|
|
|
|
|
sub _sqrtmod_prime_power { |
|
5927
|
97
|
|
|
97
|
|
204
|
my($a,$p,$e) = @_; |
|
5928
|
97
|
|
|
|
|
153
|
my($r,$s); |
|
5929
|
|
|
|
|
|
|
|
|
5930
|
97
|
100
|
|
|
|
202
|
if ($e == 1) { |
|
5931
|
47
|
100
|
|
|
|
128
|
$a %= $p if $a >= $p; |
|
5932
|
47
|
100
|
100
|
|
|
3801
|
return $a if $p == 2 || $a == 0; |
|
5933
|
39
|
|
|
|
|
1426
|
$r = _sqrtmod_prime($a,$p); |
|
5934
|
39
|
100
|
66
|
|
|
277
|
return (defined $r && (Mmulmod($r,$r,$p) == $a) ? $r : undef); |
|
5935
|
|
|
|
|
|
|
} |
|
5936
|
|
|
|
|
|
|
|
|
5937
|
50
|
|
|
|
|
134
|
my $n = Mpowint($p,$e); |
|
5938
|
50
|
|
|
|
|
155
|
my $pk = Mmulint($p,$p); |
|
5939
|
|
|
|
|
|
|
|
|
5940
|
50
|
50
|
|
|
|
170
|
return 0 if ($a % $n) == 0; |
|
5941
|
|
|
|
|
|
|
|
|
5942
|
50
|
100
|
|
|
|
1713
|
if (($a % $pk) == 0) { |
|
5943
|
1
|
|
|
|
|
8
|
my $apk = Mdivint($a, $pk); |
|
5944
|
1
|
|
|
|
|
7
|
$s = _sqrtmod_prime_power($apk, $p, $e-2); |
|
5945
|
1
|
50
|
|
|
|
7
|
return undef unless defined $s; |
|
5946
|
1
|
|
|
|
|
5
|
return Mmulint($s,$p); |
|
5947
|
|
|
|
|
|
|
} |
|
5948
|
|
|
|
|
|
|
|
|
5949
|
49
|
50
|
|
|
|
1106
|
return undef if ($a % $p) == 0; |
|
5950
|
|
|
|
|
|
|
|
|
5951
|
49
|
50
|
66
|
|
|
1282
|
my $ered = ($p > 2 || $e < 5) ? ($e+1) >> 1 : ($e+3) >> 1; |
|
5952
|
49
|
|
|
|
|
128
|
$s = _sqrtmod_prime_power($a,$p,$ered); |
|
5953
|
49
|
100
|
|
|
|
301
|
return undef unless defined $s; |
|
5954
|
|
|
|
|
|
|
|
|
5955
|
33
|
100
|
|
|
|
97
|
my $np = ($p == 2) ? Mmulint($n,$p) : $n; |
|
5956
|
33
|
|
|
|
|
122
|
my $t1 = Msubmod($a, Mmulmod($s,$s,$np), $np); |
|
5957
|
33
|
|
|
|
|
241
|
my $t2 = Maddmod($s, $s, $np); |
|
5958
|
33
|
|
|
|
|
352
|
my $gcd = Mgcd($t1, $t2); |
|
5959
|
33
|
|
|
|
|
146
|
$r = Maddmod($s, Mdivmod(Mdivint($t1,$gcd),Mdivint($t2,$gcd),$n), $n); |
|
5960
|
33
|
100
|
|
|
|
195
|
return ((Mmulmod($r,$r,$n) == ($a % $n)) ? $r : undef); |
|
5961
|
|
|
|
|
|
|
} |
|
5962
|
|
|
|
|
|
|
|
|
5963
|
|
|
|
|
|
|
sub _sqrtmod_composite { |
|
5964
|
2
|
|
|
2
|
|
426
|
my($a,$n) = @_; |
|
5965
|
|
|
|
|
|
|
|
|
5966
|
2
|
50
|
|
|
|
8
|
return undef if $n <= 0; |
|
5967
|
2
|
50
|
|
|
|
247
|
$a %= $n if $a >= $n; |
|
5968
|
2
|
50
|
33
|
|
|
65
|
return $a if $n <= 2 || $a <= 1; |
|
5969
|
2
|
50
|
|
|
|
453
|
return Msqrtint($a) if _is_perfect_square($a); |
|
5970
|
|
|
|
|
|
|
|
|
5971
|
2
|
|
|
|
|
5
|
my $N = 1; |
|
5972
|
2
|
|
|
|
|
5
|
my $r = 0; |
|
5973
|
2
|
|
|
|
|
168
|
foreach my $F (Mfactor_exp($n)) { |
|
5974
|
6
|
|
|
|
|
21
|
my($f,$e) = @$F; |
|
5975
|
6
|
|
|
|
|
22
|
my $fe = Mpowint($f, $e); |
|
5976
|
6
|
|
|
|
|
35
|
my $s = _sqrtmod_prime_power($a, $f, $e); |
|
5977
|
6
|
50
|
|
|
|
827
|
return undef unless defined $s; |
|
5978
|
6
|
|
|
|
|
52
|
my $inv = Minvmod($N, $fe); |
|
5979
|
6
|
|
|
|
|
27
|
my $t = Mmulmod($inv, Msubmod($s % $fe, $r % $fe, $fe), $fe); |
|
5980
|
6
|
|
|
|
|
707
|
$r = Mmuladdmod($N, $t, $r, $n); |
|
5981
|
6
|
|
|
|
|
340
|
$N = Mmulint($N, $fe); |
|
5982
|
|
|
|
|
|
|
} |
|
5983
|
|
|
|
|
|
|
#croak "Bad _sqrtmod_composite root $a,$n" unless Mmulmod($r,$r,$n) == $a; |
|
5984
|
2
|
|
|
|
|
147
|
$r; |
|
5985
|
|
|
|
|
|
|
} |
|
5986
|
|
|
|
|
|
|
|
|
5987
|
|
|
|
|
|
|
sub sqrtmod { |
|
5988
|
6
|
|
|
6
|
0
|
2015
|
my($a,$n) = @_; |
|
5989
|
6
|
|
|
|
|
41
|
validate_integer($a); |
|
5990
|
6
|
|
|
|
|
135
|
validate_integer_abs($n); |
|
5991
|
6
|
50
|
|
|
|
731
|
return (undef,0)[$n] if $n <= 1; |
|
5992
|
|
|
|
|
|
|
#return Mmodint(Msqrtint($a),$n) if _is_perfect_square($a); |
|
5993
|
6
|
|
|
|
|
634
|
$a = Mmodint($a,$n); |
|
5994
|
6
|
50
|
|
|
|
21
|
return $a if $a <= 1; |
|
5995
|
|
|
|
|
|
|
|
|
5996
|
6
|
100
|
|
|
|
753
|
my $r = Mis_prime($n) ? _sqrtmod_prime($a,$n) : _sqrtmod_composite($a,$n); |
|
5997
|
6
|
100
|
|
|
|
84
|
if (defined $r) { |
|
5998
|
5
|
100
|
|
|
|
16
|
$r = $n-$r if $n-$r < $r; |
|
5999
|
5
|
100
|
100
|
|
|
1209
|
$r = _bigint_to_int($r) if ref($r) && $r <= INTMAX; |
|
6000
|
|
|
|
|
|
|
} |
|
6001
|
|
|
|
|
|
|
#croak "Bad _sqrtmod_composite root $a,$n" unless Mmulmod($r,$r,$n) == $a; |
|
6002
|
6
|
|
|
|
|
286
|
$r; |
|
6003
|
|
|
|
|
|
|
} |
|
6004
|
|
|
|
|
|
|
|
|
6005
|
|
|
|
|
|
|
|
|
6006
|
|
|
|
|
|
|
|
|
6007
|
|
|
|
|
|
|
|
|
6008
|
|
|
|
|
|
|
# helper function for allsqrtmod() - return list of all square roots of |
|
6009
|
|
|
|
|
|
|
# a (mod p^k), assuming a integer, p prime, k positive integer. |
|
6010
|
|
|
|
|
|
|
sub _allsqrtmodpk { |
|
6011
|
62
|
|
|
62
|
|
488
|
my($a,$p,$k) = @_; |
|
6012
|
62
|
|
|
|
|
145
|
my $pk = Mpowint($p,$k); |
|
6013
|
62
|
100
|
|
|
|
196
|
unless ($a % $p) { |
|
6014
|
27
|
100
|
|
|
|
66
|
unless ($a % ($pk)) { |
|
6015
|
|
|
|
|
|
|
# if p^k divides a, we need the square roots of zero, satisfied by |
|
6016
|
|
|
|
|
|
|
# ip^j with 0 <= i < p^{floor(k/2)}, j = p^{ceil(k/2)} |
|
6017
|
26
|
|
|
|
|
84
|
my $low = Mpowint($p,$k >> 1); |
|
6018
|
26
|
50
|
|
|
|
120
|
my $high = ($k % 2) ? Mmulint($low, $p) : $low; |
|
6019
|
26
|
|
|
|
|
105
|
return map Mmulint($high, $_), 0 .. $low - 1; |
|
6020
|
|
|
|
|
|
|
} |
|
6021
|
|
|
|
|
|
|
# p divides a, p^2 does not |
|
6022
|
1
|
|
|
|
|
3
|
my $a2 = Mdivint($a,$p); |
|
6023
|
1
|
50
|
|
|
|
17
|
return () if $a2 % $p; |
|
6024
|
1
|
|
|
|
|
3
|
my $pj = Mdivint($pk, $p); |
|
6025
|
|
|
|
|
|
|
return map { |
|
6026
|
1
|
|
|
|
|
3
|
my $qp = Mmulint($_,$p); |
|
|
1
|
|
|
|
|
2
|
|
|
6027
|
1
|
|
|
|
|
4
|
map Maddint($qp,Mmulint($_,$pj)), 0 .. $p - 1; |
|
6028
|
|
|
|
|
|
|
} _allsqrtmodpk(Mdivint($a2,$p), $p, $k - 2); |
|
6029
|
|
|
|
|
|
|
} |
|
6030
|
35
|
|
|
|
|
578
|
my $q = _sqrtmod_prime_power($a,$p,$k); |
|
6031
|
35
|
100
|
|
|
|
648
|
return () unless defined $q; |
|
6032
|
25
|
100
|
|
|
|
73
|
return ($q, $pk - $q) if $p != 2; |
|
6033
|
1
|
50
|
|
|
|
3
|
return ($q) if $k == 1; |
|
6034
|
0
|
0
|
|
|
|
0
|
return ($q, $pk - $q) if $k == 2; |
|
6035
|
0
|
|
|
|
|
0
|
my $pj = Mdivint($pk,$p); |
|
6036
|
0
|
|
|
|
|
0
|
my $q2 = ($q * ($pj - 1)) % $pk; |
|
6037
|
0
|
|
|
|
|
0
|
return ($q, $pk - $q, $q2, $pk - $q2); |
|
6038
|
|
|
|
|
|
|
} |
|
6039
|
|
|
|
|
|
|
|
|
6040
|
|
|
|
|
|
|
# helper function for allsqrtmod() - return list of all square roots of |
|
6041
|
|
|
|
|
|
|
# a (mod p^k), assuming a integer, n positive integer > 1, f arrayref |
|
6042
|
|
|
|
|
|
|
# of [ p, k ] pairs representing factorization of n. Destroys f. |
|
6043
|
|
|
|
|
|
|
sub _allsqrtmodfact { |
|
6044
|
59
|
|
|
59
|
|
113
|
my($a,$n,$f) = @_; |
|
6045
|
59
|
|
|
|
|
83
|
my($p,$k) = @{ shift @$f }; |
|
|
59
|
|
|
|
|
148
|
|
|
6046
|
59
|
|
|
|
|
134
|
my @q = _allsqrtmodpk($a, $p, $k); |
|
6047
|
59
|
100
|
|
|
|
166
|
return @q unless @$f; |
|
6048
|
43
|
|
|
|
|
96
|
my $pk = Mpowint($p, $k); |
|
6049
|
43
|
|
|
|
|
105
|
my $n2 = Mdivint($n, $pk); |
|
6050
|
|
|
|
|
|
|
return map { |
|
6051
|
43
|
|
|
|
|
118
|
my $q2 = $_; |
|
|
61
|
|
|
|
|
94
|
|
|
6052
|
61
|
|
|
|
|
230
|
map Mchinese([ $q2, $n2 ], [ $_, $pk ]), @q; |
|
6053
|
|
|
|
|
|
|
} _allsqrtmodfact($a, $n2, $f); |
|
6054
|
|
|
|
|
|
|
} |
|
6055
|
|
|
|
|
|
|
|
|
6056
|
|
|
|
|
|
|
sub allsqrtmod { |
|
6057
|
5
|
|
|
5
|
0
|
2318
|
my($A,$n) = @_; |
|
6058
|
5
|
|
|
|
|
31
|
validate_integer($A); |
|
6059
|
5
|
|
|
|
|
76
|
validate_integer_abs($n); |
|
6060
|
5
|
0
|
|
|
|
415
|
return $n ? (0) : () if $n <= 1; |
|
|
|
50
|
|
|
|
|
|
|
6061
|
5
|
|
|
|
|
385
|
$A = Mmodint($A,$n); |
|
6062
|
5
|
100
|
|
|
|
24
|
my @R = Mis_prime($n) ? _allsqrtmodpk($A,$n,1) |
|
6063
|
|
|
|
|
|
|
: _allsqrtmodfact($A, $n, [Mfactor_exp($n)]); |
|
6064
|
5
|
|
|
|
|
833
|
Mvecsort(@R); |
|
6065
|
|
|
|
|
|
|
} |
|
6066
|
|
|
|
|
|
|
|
|
6067
|
|
|
|
|
|
|
|
|
6068
|
|
|
|
|
|
|
############################################################################### |
|
6069
|
|
|
|
|
|
|
# Tonelli-Shanks kth roots |
|
6070
|
|
|
|
|
|
|
############################################################################### |
|
6071
|
|
|
|
|
|
|
|
|
6072
|
|
|
|
|
|
|
# Algorithm 3.3, step 2 "Find generator" |
|
6073
|
|
|
|
|
|
|
sub _find_ts_generator { |
|
6074
|
1
|
|
|
1
|
|
3
|
my ($a, $k, $p) = @_; |
|
6075
|
|
|
|
|
|
|
# Assume: k > 2, 1 < a < p, p > 2, k prime, p prime |
|
6076
|
|
|
|
|
|
|
|
|
6077
|
1
|
|
|
|
|
17
|
my($e,$r) = (0, $p-1); |
|
6078
|
1
|
|
|
|
|
423
|
while (!($r % $k)) { |
|
6079
|
2
|
|
|
|
|
1326
|
$e++; |
|
6080
|
2
|
|
|
|
|
9
|
$r /= $k; |
|
6081
|
|
|
|
|
|
|
} |
|
6082
|
1
|
|
|
|
|
917
|
my $ke1 = Mpowint($k, $e-1); |
|
6083
|
1
|
|
|
|
|
3
|
my($x,$m,$y) = (2,1); |
|
6084
|
1
|
|
|
|
|
5
|
while ($m == 1) { |
|
6085
|
1
|
|
|
|
|
8
|
$y = Mpowmod($x, $r, $p); |
|
6086
|
1
|
50
|
|
|
|
363
|
$m = Mpowmod($y, $ke1, $p) if $y != 1; |
|
6087
|
1
|
50
|
|
|
|
305
|
croak "bad T-S input" if $x >= $p; |
|
6088
|
1
|
|
|
|
|
168
|
$x++; |
|
6089
|
|
|
|
|
|
|
} |
|
6090
|
1
|
|
|
|
|
233
|
($y, $m); |
|
6091
|
|
|
|
|
|
|
} |
|
6092
|
|
|
|
|
|
|
|
|
6093
|
|
|
|
|
|
|
sub _ts_rootmod { |
|
6094
|
1
|
|
|
1
|
|
5
|
my($a, $k, $p, $y, $m) = @_; |
|
6095
|
|
|
|
|
|
|
|
|
6096
|
1
|
|
|
|
|
5
|
my($e,$r) = (0, $p-1); |
|
6097
|
1
|
|
|
|
|
458
|
while (!($r % $k)) { |
|
6098
|
2
|
|
|
|
|
2093
|
$e++; |
|
6099
|
2
|
|
|
|
|
8
|
$r /= $k; |
|
6100
|
|
|
|
|
|
|
} |
|
6101
|
|
|
|
|
|
|
# p-1 = r * k^e |
|
6102
|
1
|
|
|
|
|
900
|
my $x = Mpowmod($a, Minvmod($k % $r, $r), $p); |
|
6103
|
1
|
50
|
|
|
|
387
|
my $A = ($a == 0) ? 0 : Mmulmod(Mpowmod($x,$k,$p), Minvmod($a,$p), $p); |
|
6104
|
|
|
|
|
|
|
|
|
6105
|
1
|
50
|
33
|
|
|
392
|
($y,$m) = _find_ts_generator($a,$k,$p) if $y == 0 && $A != 1; |
|
6106
|
|
|
|
|
|
|
|
|
6107
|
1
|
|
|
|
|
269
|
while ($A != 1) { |
|
6108
|
1
|
|
|
|
|
232
|
my ($l,$T,$z) = (1,$A); |
|
6109
|
1
|
|
|
|
|
5
|
while ($T != 1) { |
|
6110
|
1
|
50
|
|
|
|
248
|
return 0 if $l >= $e; |
|
6111
|
1
|
|
|
|
|
4
|
$z = $T; |
|
6112
|
1
|
|
|
|
|
8
|
$T = Mpowmod($T, $k, $p); |
|
6113
|
1
|
|
|
|
|
60
|
$l++; |
|
6114
|
|
|
|
|
|
|
} |
|
6115
|
|
|
|
|
|
|
# We want a znlog that takes gorder as well (k=znorder(m,p)) |
|
6116
|
1
|
|
|
|
|
9
|
my $kz = _negmod(znlog($z, $m, $p), $k); |
|
6117
|
1
|
|
|
|
|
8
|
$m = Mpowmod($m, $kz, $p); |
|
6118
|
1
|
|
|
|
|
16
|
$T = Mpowmod($y, Mmulint($kz,Mpowint($k,$e-$l)), $p); |
|
6119
|
|
|
|
|
|
|
# In the loop we always end with l < e, so e always gets smaller |
|
6120
|
1
|
|
|
|
|
37
|
$e = $l-1; |
|
6121
|
1
|
|
|
|
|
12
|
$x = Mmulmod($x, $T, $p); |
|
6122
|
1
|
|
|
|
|
297
|
$y = Mpowmod($T, $k, $p); |
|
6123
|
1
|
50
|
|
|
|
274
|
return 0 if $y <= 1; # In theory this will never be hit. |
|
6124
|
1
|
|
|
|
|
259
|
$A = Mmulmod($A, $y, $p); |
|
6125
|
|
|
|
|
|
|
} |
|
6126
|
1
|
|
|
|
|
66
|
$x; |
|
6127
|
|
|
|
|
|
|
} |
|
6128
|
|
|
|
|
|
|
|
|
6129
|
|
|
|
|
|
|
sub _compute_generator { |
|
6130
|
|
|
|
|
|
|
# uncoverable subroutine |
|
6131
|
0
|
|
|
0
|
|
0
|
my($l, $e, $r, $p) = @_; |
|
6132
|
0
|
|
|
|
|
0
|
my($m, $lem1, $y) = (1, Mpowint($l, $e-1)); |
|
6133
|
0
|
|
|
|
|
0
|
for (my $x = 2; $m == 1; $x++) { |
|
6134
|
0
|
|
|
|
|
0
|
$y = Mpowmod($x, $r, $p); |
|
6135
|
0
|
0
|
|
|
|
0
|
next if $y == 1; |
|
6136
|
0
|
|
|
|
|
0
|
$m = Mpowmod($y, $lem1, $p); |
|
6137
|
|
|
|
|
|
|
} |
|
6138
|
0
|
|
|
|
|
0
|
$y; |
|
6139
|
|
|
|
|
|
|
} |
|
6140
|
|
|
|
|
|
|
|
|
6141
|
|
|
|
|
|
|
sub _rootmod_prime_splitk { |
|
6142
|
8
|
|
|
8
|
|
33
|
my($a, $k, $p, $refzeta) = @_; |
|
6143
|
|
|
|
|
|
|
|
|
6144
|
8
|
50
|
|
|
|
32
|
$$refzeta = 1 if defined $refzeta; |
|
6145
|
8
|
50
|
|
|
|
31
|
$a = Mmodint($a, $p) if $a >= $p; |
|
6146
|
8
|
100
|
66
|
|
|
1203
|
return $a if $a == 0 || ($a == 1 && !defined $refzeta); |
|
|
|
|
66
|
|
|
|
|
|
6147
|
7
|
|
|
|
|
1523
|
my $p1 = Msub1int($p); |
|
6148
|
|
|
|
|
|
|
|
|
6149
|
7
|
50
|
|
|
|
587
|
if ($k == 2) { |
|
6150
|
0
|
|
|
|
|
0
|
my $r = _sqrtmod_prime($a,$p); |
|
6151
|
0
|
0
|
|
|
|
0
|
$$refzeta = (defined $r) ? $p1 : 0 if defined $refzeta; |
|
|
|
0
|
|
|
|
|
|
|
6152
|
0
|
|
|
|
|
0
|
return $r; |
|
6153
|
|
|
|
|
|
|
} |
|
6154
|
|
|
|
|
|
|
|
|
6155
|
|
|
|
|
|
|
# See Algorithm 2.1 of van de Woestijne (2006), or Lindhurst (1997). |
|
6156
|
|
|
|
|
|
|
# The latter's proposition 7 generalizes to composite p. |
|
6157
|
|
|
|
|
|
|
|
|
6158
|
7
|
|
|
|
|
62
|
my $g = Mgcd($k, $p1); |
|
6159
|
7
|
|
|
|
|
22
|
my $r = $a; |
|
6160
|
|
|
|
|
|
|
|
|
6161
|
7
|
100
|
|
|
|
27
|
if ($g != 1) { |
|
6162
|
1
|
|
|
|
|
47
|
foreach my $fac (Mfactor_exp($g)) { |
|
6163
|
1
|
|
|
|
|
5
|
my($F,$E) = @$fac; |
|
6164
|
1
|
50
|
|
|
|
6
|
last if $r == 0; |
|
6165
|
|
|
|
|
|
|
# uncoverable branch true |
|
6166
|
1
|
50
|
|
|
|
7
|
if (defined $refzeta) { |
|
6167
|
0
|
|
|
|
|
0
|
my $V = Mvaluation($p1, $F); |
|
6168
|
0
|
|
|
|
|
0
|
my $REM = Mdivint($p1, Mpowint($F,$V)); |
|
6169
|
0
|
|
|
|
|
0
|
my $Y = _compute_generator($F, $V, $REM, $p); |
|
6170
|
0
|
|
|
|
|
0
|
$$refzeta = Mmulmod($$refzeta, Mpowmod($Y, Mpowint($F, $V-$E), $p), $p); |
|
6171
|
|
|
|
|
|
|
} |
|
6172
|
1
|
|
|
|
|
6
|
my ($y,$m) = _find_ts_generator($r, $F, $p); |
|
6173
|
1
|
|
|
|
|
7
|
while ($E-- > 0) { |
|
6174
|
1
|
|
|
|
|
7
|
$r = _ts_rootmod($r, $F, $p, $y, $m); |
|
6175
|
|
|
|
|
|
|
} |
|
6176
|
|
|
|
|
|
|
} |
|
6177
|
|
|
|
|
|
|
} |
|
6178
|
7
|
100
|
|
|
|
42
|
if ($g != $k) { |
|
6179
|
6
|
|
|
|
|
31
|
my($kg, $pg) = (Mdivint($k,$g), Mdivint($p1,$g)); |
|
6180
|
6
|
|
|
|
|
39
|
$r = Mpowmod($r, Minvmod($kg % $pg, $pg), $p); |
|
6181
|
|
|
|
|
|
|
} |
|
6182
|
7
|
50
|
|
|
|
1194
|
return $r if Mpowmod($r, $k, $p) == $a; |
|
6183
|
0
|
0
|
|
|
|
0
|
$$refzeta = 0 if defined $refzeta; |
|
6184
|
0
|
|
|
|
|
0
|
undef; |
|
6185
|
|
|
|
|
|
|
} |
|
6186
|
|
|
|
|
|
|
|
|
6187
|
|
|
|
|
|
|
sub _rootmod_composite1 { |
|
6188
|
6
|
|
|
6
|
|
25
|
my($a,$k,$n) = @_; |
|
6189
|
6
|
|
|
|
|
13
|
my $r; |
|
6190
|
|
|
|
|
|
|
|
|
6191
|
6
|
50
|
33
|
|
|
62
|
croak "_rootmod_composite1 bad parameters" if $a < 1 || $k < 2 || $n < 2; |
|
|
|
|
33
|
|
|
|
|
|
6192
|
|
|
|
|
|
|
|
|
6193
|
6
|
50
|
|
|
|
1366
|
if (Mis_power($a, $k, \$r)) { |
|
6194
|
0
|
|
|
|
|
0
|
return $r; |
|
6195
|
|
|
|
|
|
|
} |
|
6196
|
|
|
|
|
|
|
|
|
6197
|
6
|
100
|
|
|
|
269
|
if (Mis_prime($n)) { |
|
6198
|
3
|
|
|
|
|
786
|
return _rootmod_prime_splitk($a,$k,$n,undef); |
|
6199
|
|
|
|
|
|
|
} |
|
6200
|
|
|
|
|
|
|
|
|
6201
|
|
|
|
|
|
|
# We should do this iteratively using cprod |
|
6202
|
3
|
|
|
|
|
424
|
my @rootmap; |
|
6203
|
3
|
|
|
|
|
20
|
foreach my $fac (Mfactor_exp($n)) { |
|
6204
|
10
|
|
|
|
|
38
|
my($F,$E) = @$fac; |
|
6205
|
10
|
|
|
|
|
44
|
my $FE = Mpowint($F,$E); |
|
6206
|
10
|
|
|
|
|
41
|
my $A = $a % $FE; |
|
6207
|
10
|
100
|
|
|
|
1965
|
if ($E == 1) { |
|
6208
|
5
|
|
|
|
|
26
|
$r = _rootmod_prime_splitk($A,$k,$F,undef) |
|
6209
|
|
|
|
|
|
|
} else { |
|
6210
|
|
|
|
|
|
|
# TODO: Fix this. We should do this directly. |
|
6211
|
5
|
|
|
|
|
79
|
$r = (allrootmod($A, $k, $FE))[0]; |
|
6212
|
|
|
|
|
|
|
} |
|
6213
|
10
|
50
|
33
|
|
|
1250
|
return undef unless defined $r && Mpowmod($r, $k, $FE) == $A; |
|
6214
|
10
|
|
|
|
|
1512
|
push @rootmap, [ $r, $FE ]; |
|
6215
|
|
|
|
|
|
|
} |
|
6216
|
3
|
50
|
|
|
|
66
|
$r = Mchinese(@rootmap) if @rootmap > 1; |
|
6217
|
|
|
|
|
|
|
|
|
6218
|
|
|
|
|
|
|
#return (defined $r && Mpowmod($r, $k, $n) == ($a % $n)) ? $r : undef; |
|
6219
|
3
|
50
|
33
|
|
|
58
|
croak "Bad _rootmod_composite1 root $a,$k,$n" unless defined $r && Mpowmod($r,$k,$n) == ($a % $n); |
|
6220
|
3
|
|
|
|
|
676
|
$r; |
|
6221
|
|
|
|
|
|
|
} |
|
6222
|
|
|
|
|
|
|
|
|
6223
|
|
|
|
|
|
|
############################################################################### |
|
6224
|
|
|
|
|
|
|
# Tonelli-Shanks kth roots alternate version |
|
6225
|
|
|
|
|
|
|
############################################################################### |
|
6226
|
|
|
|
|
|
|
|
|
6227
|
|
|
|
|
|
|
sub _ts_prime { |
|
6228
|
2
|
|
|
2
|
|
7
|
my($a, $k, $p, $refzeta) = @_; |
|
6229
|
|
|
|
|
|
|
|
|
6230
|
2
|
|
|
|
|
7
|
my($e,$r) = (0, $p-1); |
|
6231
|
2
|
|
|
|
|
426
|
while (!($r % $k)) { |
|
6232
|
4
|
|
|
|
|
1423
|
$e++; |
|
6233
|
4
|
|
|
|
|
12
|
$r /= $k; |
|
6234
|
|
|
|
|
|
|
} |
|
6235
|
2
|
|
|
|
|
777
|
my $ke = Mdivint($p-1, $r); |
|
6236
|
|
|
|
|
|
|
|
|
6237
|
2
|
|
|
|
|
10
|
my $x = Mpowmod($a, Minvmod($k % $r, $r), $p); |
|
6238
|
2
|
|
|
|
|
382
|
my $B = Mmulmod(Mpowmod($x, $k, $p), Minvmod($a, $p), $p); |
|
6239
|
|
|
|
|
|
|
|
|
6240
|
2
|
|
|
|
|
171
|
my($T,$y,$t,$A) = (2,1); |
|
6241
|
2
|
|
|
|
|
6
|
while ($y == 1) { |
|
6242
|
3
|
|
|
|
|
9
|
$t = Mpowmod($T, $r, $p); |
|
6243
|
3
|
|
|
|
|
388
|
$y = Mpowmod($t, Mdivint($ke,$k), $p); |
|
6244
|
3
|
|
|
|
|
284
|
$T++; |
|
6245
|
|
|
|
|
|
|
} |
|
6246
|
2
|
|
|
|
|
256
|
while ($ke != $k) { |
|
6247
|
2
|
|
|
|
|
10
|
$ke = Mdivint($ke, $k); |
|
6248
|
2
|
|
|
|
|
5
|
$T = $t; |
|
6249
|
2
|
|
|
|
|
11
|
$t = Mpowmod($t, $k, $p); |
|
6250
|
2
|
|
|
|
|
297
|
$A = Mpowmod($B, Mdivint($ke,$k), $p); |
|
6251
|
2
|
|
|
|
|
16
|
while ($A != 1) { |
|
6252
|
4
|
|
|
|
|
271
|
$x = Mmulmod($x, $T, $p); |
|
6253
|
4
|
|
|
|
|
268
|
$B = Mmulmod($B, $t, $p); |
|
6254
|
4
|
|
|
|
|
52
|
$A = Mmulmod($A, $y, $p); |
|
6255
|
|
|
|
|
|
|
} |
|
6256
|
|
|
|
|
|
|
} |
|
6257
|
2
|
50
|
|
|
|
57
|
$$refzeta = $t if defined $refzeta; |
|
6258
|
2
|
|
|
|
|
11
|
$x; |
|
6259
|
|
|
|
|
|
|
} |
|
6260
|
|
|
|
|
|
|
|
|
6261
|
|
|
|
|
|
|
sub _rootmod_prime { |
|
6262
|
|
|
|
|
|
|
# uncoverable subroutine |
|
6263
|
0
|
|
|
0
|
|
0
|
my($a, $k, $p) = @_; |
|
6264
|
|
|
|
|
|
|
|
|
6265
|
|
|
|
|
|
|
# p must be a prime, k must be a prime. Otherwise UNDEFINED. |
|
6266
|
0
|
0
|
|
|
|
0
|
$a %= $p if $a >= $p; |
|
6267
|
|
|
|
|
|
|
|
|
6268
|
0
|
0
|
0
|
|
|
0
|
return $a if $p == 2 || $a == 0; |
|
6269
|
0
|
0
|
|
|
|
0
|
return _sqrtmod_prime($a, $p) if $k == 2; |
|
6270
|
|
|
|
|
|
|
|
|
6271
|
|
|
|
|
|
|
# If co-prime, there is exactly one root. |
|
6272
|
0
|
|
|
|
|
0
|
my $g = Mgcd($k, $p-1); |
|
6273
|
0
|
0
|
|
|
|
0
|
return Mpowmod($a, Minvmod($k % ($p-1), $p-1), $p) if $g == 1; |
|
6274
|
|
|
|
|
|
|
# Check generalized Euler's criterion |
|
6275
|
0
|
0
|
|
|
|
0
|
return undef if Mpowmod($a, Mdivint($p-1, $g), $p) != 1; |
|
6276
|
|
|
|
|
|
|
|
|
6277
|
0
|
|
|
|
|
0
|
_ts_prime($a, $k, $p); |
|
6278
|
|
|
|
|
|
|
} |
|
6279
|
|
|
|
|
|
|
|
|
6280
|
|
|
|
|
|
|
sub _rootmod_prime_power { |
|
6281
|
|
|
|
|
|
|
# uncoverable subroutine |
|
6282
|
0
|
|
|
0
|
|
0
|
my($a,$k,$p,$e) = @_; # prime k, prime p |
|
6283
|
|
|
|
|
|
|
|
|
6284
|
0
|
0
|
|
|
|
0
|
return _sqrtmod_prime_power($a, $p, $e) if $k == 2; |
|
6285
|
0
|
0
|
|
|
|
0
|
return _rootmod_prime($a, $k, $p) if $e == 1; |
|
6286
|
|
|
|
|
|
|
|
|
6287
|
0
|
|
|
|
|
0
|
my $n = Mpowint($p,$e); |
|
6288
|
0
|
|
|
|
|
0
|
my $pk = Mpowint($p,$k); |
|
6289
|
|
|
|
|
|
|
|
|
6290
|
0
|
0
|
|
|
|
0
|
return 0 if ($a % $n) == 0; |
|
6291
|
|
|
|
|
|
|
|
|
6292
|
0
|
0
|
|
|
|
0
|
if (($a % $pk) == 0) { |
|
6293
|
0
|
|
|
|
|
0
|
my $apk = Mdivint($a, $pk); |
|
6294
|
0
|
|
|
|
|
0
|
my $s = _rootmod_prime_power($apk, $k, $p, $e-$k); |
|
6295
|
0
|
0
|
|
|
|
0
|
return (defined $s) ? Mmulint($s,$p) : undef; |
|
6296
|
|
|
|
|
|
|
} |
|
6297
|
|
|
|
|
|
|
|
|
6298
|
0
|
0
|
|
|
|
0
|
return undef if ($a % $p) == 0; |
|
6299
|
|
|
|
|
|
|
|
|
6300
|
0
|
0
|
0
|
|
|
0
|
my $ered = ($p > 2 || $e < 5) ? ($e+1) >> 1 : ($e+3) >> 1; |
|
6301
|
0
|
|
|
|
|
0
|
my $s = _rootmod_prime_power($a, $k, $p, $ered); |
|
6302
|
0
|
0
|
|
|
|
0
|
return undef if !defined $s; |
|
6303
|
|
|
|
|
|
|
|
|
6304
|
0
|
0
|
|
|
|
0
|
my $np = ($p == $k) ? Mmulint($n,$p) : $n; |
|
6305
|
0
|
|
|
|
|
0
|
my $t = Mpowmod($s, $k-1, $np); |
|
6306
|
0
|
|
|
|
|
0
|
my $t1 = Msubmod($a, Mmulmod($t,$s,$np), $np); |
|
6307
|
0
|
|
|
|
|
0
|
my $t2 = Mmulmod($k, $t, $np); |
|
6308
|
0
|
|
|
|
|
0
|
my $gcd = Mgcd($t1, $t2); |
|
6309
|
0
|
|
|
|
|
0
|
my $r = Maddmod($s,Mdivmod(Mdivint($t1,$gcd),Mdivint($t2,$gcd),$n),$n); |
|
6310
|
0
|
0
|
|
|
|
0
|
return ((Mpowmod($r,$k,$n) == ($a % $n)) ? $r : undef); |
|
6311
|
|
|
|
|
|
|
} |
|
6312
|
|
|
|
|
|
|
|
|
6313
|
|
|
|
|
|
|
sub _rootmod_kprime { |
|
6314
|
|
|
|
|
|
|
# uncoverable subroutine |
|
6315
|
0
|
|
|
0
|
|
0
|
my($a,$k,$n,@nf) = @_; # k prime, n factored into f^e,f^e,... |
|
6316
|
|
|
|
|
|
|
|
|
6317
|
0
|
|
|
|
|
0
|
my($N,$r) = (1,0); |
|
6318
|
0
|
|
|
|
|
0
|
foreach my $F (@nf) { |
|
6319
|
0
|
|
|
|
|
0
|
my($f,$e) = @$F; |
|
6320
|
0
|
|
|
|
|
0
|
my $fe = Mpowint($f, $e); |
|
6321
|
0
|
|
|
|
|
0
|
my $s = _rootmod_prime_power($a, $k, $f, $e); |
|
6322
|
0
|
0
|
|
|
|
0
|
return undef unless defined $s; |
|
6323
|
0
|
|
|
|
|
0
|
my $inv = Minvmod($N, $fe); |
|
6324
|
0
|
|
|
|
|
0
|
my $t = Mmulmod($inv, Msubmod($s % $fe, $r % $fe, $fe), $fe); |
|
6325
|
0
|
|
|
|
|
0
|
$r = Mmuladdmod($N, $t, $r, $n); |
|
6326
|
0
|
|
|
|
|
0
|
$N = Mmulint($N, $fe); |
|
6327
|
|
|
|
|
|
|
} |
|
6328
|
0
|
|
|
|
|
0
|
$r; |
|
6329
|
|
|
|
|
|
|
} |
|
6330
|
|
|
|
|
|
|
|
|
6331
|
|
|
|
|
|
|
sub _rootmod_composite2 { |
|
6332
|
|
|
|
|
|
|
# uncoverable subroutine |
|
6333
|
0
|
|
|
0
|
|
0
|
my($a,$k,$n) = @_; |
|
6334
|
|
|
|
|
|
|
|
|
6335
|
0
|
0
|
0
|
|
|
0
|
croak "_rootmod_composite2 bad parameters" if $a < 1 || $k < 2 || $n < 2; |
|
|
|
|
0
|
|
|
|
|
|
6336
|
|
|
|
|
|
|
|
|
6337
|
0
|
|
|
|
|
0
|
my @nf = Mfactor_exp($n); |
|
6338
|
|
|
|
|
|
|
|
|
6339
|
0
|
0
|
|
|
|
0
|
return _rootmod_kprime($a, $k, $n, @nf) if Mis_prime($k); |
|
6340
|
|
|
|
|
|
|
|
|
6341
|
0
|
|
|
|
|
0
|
my $r = $a; |
|
6342
|
0
|
|
|
|
|
0
|
foreach my $kf (Mfactor($k)) { |
|
6343
|
0
|
|
|
|
|
0
|
$r = _rootmod_kprime($r, $kf, $n, @nf); |
|
6344
|
0
|
0
|
|
|
|
0
|
if (!defined $r) { |
|
6345
|
|
|
|
|
|
|
# Choose one. The former is faster but makes more intertwined code. |
|
6346
|
0
|
|
|
|
|
0
|
return _rootmod_composite1($a,$k,$n); |
|
6347
|
|
|
|
|
|
|
#return (allrootmod($a,$k,$n))[0]; |
|
6348
|
|
|
|
|
|
|
} |
|
6349
|
|
|
|
|
|
|
} |
|
6350
|
0
|
0
|
0
|
|
|
0
|
croak "Bad _rootmod_composite2 root $a,$k,$n" unless defined $r && Mpowmod($r,$k,$n) == ($a % $n); |
|
6351
|
0
|
|
|
|
|
0
|
$r; |
|
6352
|
|
|
|
|
|
|
} |
|
6353
|
|
|
|
|
|
|
|
|
6354
|
|
|
|
|
|
|
|
|
6355
|
|
|
|
|
|
|
############################################################################### |
|
6356
|
|
|
|
|
|
|
# Modular k-th root |
|
6357
|
|
|
|
|
|
|
############################################################################### |
|
6358
|
|
|
|
|
|
|
|
|
6359
|
|
|
|
|
|
|
sub rootmod { |
|
6360
|
8
|
|
|
8
|
0
|
66007
|
my($a,$k,$n) = @_; |
|
6361
|
8
|
|
|
|
|
48
|
validate_integer($a); |
|
6362
|
8
|
|
|
|
|
135
|
validate_integer($k); |
|
6363
|
8
|
|
|
|
|
220
|
validate_integer_abs($n); |
|
6364
|
8
|
50
|
|
|
|
888
|
return (undef,0)[$n] if $n <= 1; |
|
6365
|
8
|
|
|
|
|
825
|
$a = Mmodint($a,$n); |
|
6366
|
|
|
|
|
|
|
|
|
6367
|
|
|
|
|
|
|
# Be careful with zeros, as we can't divide or invert them. |
|
6368
|
8
|
100
|
|
|
|
32
|
if ($a == 0) { |
|
6369
|
1
|
50
|
|
|
|
10
|
return ($k <= 0) ? undef : 0; |
|
6370
|
|
|
|
|
|
|
} |
|
6371
|
7
|
100
|
|
|
|
564
|
if ($k < 0) { |
|
6372
|
1
|
|
|
|
|
7
|
$a = Minvmod($a, $n); |
|
6373
|
1
|
50
|
33
|
|
|
9
|
return undef unless defined $a && $a > 0; |
|
6374
|
1
|
|
|
|
|
2
|
$k = -$k; |
|
6375
|
|
|
|
|
|
|
} |
|
6376
|
7
|
100
|
66
|
|
|
36
|
return undef if $k == 0 && $a != 1; |
|
6377
|
6
|
50
|
33
|
|
|
47
|
return 1 if $k == 0 || $a == 1; |
|
6378
|
6
|
50
|
|
|
|
530
|
return $a if $k == 1; |
|
6379
|
|
|
|
|
|
|
|
|
6380
|
|
|
|
|
|
|
# Choose either one based on performance. |
|
6381
|
6
|
|
|
|
|
28
|
my $r = _rootmod_composite1($a, $k, $n); |
|
6382
|
|
|
|
|
|
|
#my $r = _rootmod_composite2($a, $k, $n); |
|
6383
|
6
|
50
|
33
|
|
|
646
|
$r = $n-$r if defined $r && $k == 2 && ($n-$r) < $r; # Select smallest root |
|
|
|
|
33
|
|
|
|
|
|
6384
|
6
|
|
|
|
|
56
|
$r; |
|
6385
|
|
|
|
|
|
|
} |
|
6386
|
|
|
|
|
|
|
|
|
6387
|
|
|
|
|
|
|
############################################################################### |
|
6388
|
|
|
|
|
|
|
# All modular k-th roots |
|
6389
|
|
|
|
|
|
|
############################################################################### |
|
6390
|
|
|
|
|
|
|
|
|
6391
|
|
|
|
|
|
|
sub _allrootmod_cprod { |
|
6392
|
102
|
|
|
102
|
|
320
|
my($aroots1, $p1, $aroots2, $p2) = @_; |
|
6393
|
102
|
|
|
|
|
259
|
my($t, $n, $inv); |
|
6394
|
|
|
|
|
|
|
|
|
6395
|
102
|
|
|
|
|
421
|
$n = mulint($p1, $p2); |
|
6396
|
102
|
|
|
|
|
733
|
$inv = Minvmod($p1, $p2); |
|
6397
|
102
|
50
|
|
|
|
272
|
croak("CRT has undefined inverse") unless defined $inv; |
|
6398
|
|
|
|
|
|
|
|
|
6399
|
102
|
|
|
|
|
177
|
my @roots; |
|
6400
|
102
|
|
|
|
|
253
|
for my $q1 (@$aroots1) { |
|
6401
|
236
|
|
|
|
|
444
|
for my $q2 (@$aroots2) { |
|
6402
|
306
|
|
|
|
|
870
|
$t = Mmulmod($inv, Msubmod($q2, $q1, $p2), $p2); |
|
6403
|
306
|
|
|
|
|
852
|
$t = Mmuladdmod($p1, $t, $q1, $n); |
|
6404
|
306
|
|
|
|
|
1956
|
push @roots, $t; |
|
6405
|
|
|
|
|
|
|
} |
|
6406
|
|
|
|
|
|
|
} |
|
6407
|
102
|
|
|
|
|
444
|
return @roots; |
|
6408
|
|
|
|
|
|
|
} |
|
6409
|
|
|
|
|
|
|
|
|
6410
|
|
|
|
|
|
|
sub _allrootmod_prime { |
|
6411
|
144
|
|
|
144
|
|
320
|
my($a,$k,$p) = @_; # prime k, prime p |
|
6412
|
144
|
100
|
|
|
|
407
|
$a %= $p if $a >= $p; #$a = Mmodint($a,$p) if $a >= $p; |
|
6413
|
|
|
|
|
|
|
|
|
6414
|
144
|
100
|
100
|
|
|
2483
|
return ($a) if $p == 2 || $a == 0; |
|
6415
|
|
|
|
|
|
|
|
|
6416
|
|
|
|
|
|
|
# If co-prime, there is exactly one root. |
|
6417
|
78
|
|
|
|
|
1060
|
my $g = Mgcd($k, $p-1); |
|
6418
|
78
|
100
|
|
|
|
250
|
if ($g == 1) { |
|
6419
|
76
|
|
|
|
|
354
|
my $r = Mpowmod($a, Minvmod($k % ($p-1), $p-1), $p); |
|
6420
|
76
|
|
|
|
|
486
|
return ($r); |
|
6421
|
|
|
|
|
|
|
} |
|
6422
|
|
|
|
|
|
|
|
|
6423
|
|
|
|
|
|
|
# Check generalized Euler's criterion |
|
6424
|
2
|
50
|
|
|
|
10
|
return () if Mpowmod($a, Mdivint($p-1, $g), $p) != 1; |
|
6425
|
|
|
|
|
|
|
|
|
6426
|
|
|
|
|
|
|
# Special case for p=3 for performance |
|
6427
|
2
|
50
|
|
|
|
135
|
return (1,2) if $p == 3; |
|
6428
|
|
|
|
|
|
|
|
|
6429
|
|
|
|
|
|
|
# A trivial brute force search: |
|
6430
|
|
|
|
|
|
|
# return grep { Mpowmod($_,$k,$p) == $a } 0 .. $p-1; |
|
6431
|
|
|
|
|
|
|
|
|
6432
|
|
|
|
|
|
|
# Call one of the general TS solvers that also allow us to get all the roots. |
|
6433
|
2
|
|
|
|
|
245
|
my $z; |
|
6434
|
|
|
|
|
|
|
#my $r = _rootmod_prime_splitk($a, $k, $p, \$z); |
|
6435
|
2
|
|
|
|
|
11
|
my $r = _ts_prime($a, $k, $p, \$z); |
|
6436
|
2
|
50
|
33
|
|
|
8
|
croak "allrootmod: failed to find root" if $z==0 || Mpowmod($r,$k,$p) != $a; |
|
6437
|
2
|
|
|
|
|
57
|
my @roots = ($r); |
|
6438
|
2
|
|
|
|
|
10
|
my $r2 = Mmulmod($r,$z,$p); |
|
6439
|
2
|
|
66
|
|
|
307
|
while ($r2 != $r && @roots < $k) { |
|
6440
|
6
|
|
|
|
|
448
|
push @roots, $r2; |
|
6441
|
6
|
|
|
|
|
18
|
$r2 = Mmulmod($r2, $z, $p); |
|
6442
|
|
|
|
|
|
|
} |
|
6443
|
2
|
50
|
|
|
|
332
|
croak "allrootmod: excess roots found" if $r2 != $r; |
|
6444
|
2
|
|
|
|
|
65
|
return @roots; |
|
6445
|
|
|
|
|
|
|
} |
|
6446
|
|
|
|
|
|
|
|
|
6447
|
|
|
|
|
|
|
sub _allrootmod_prime_power { |
|
6448
|
178
|
|
|
178
|
|
472
|
my($a,$k,$p,$e) = @_; # prime k, prime p |
|
6449
|
|
|
|
|
|
|
|
|
6450
|
178
|
100
|
|
|
|
591
|
return _allrootmod_prime($a, $k, $p) if $e == 1; |
|
6451
|
|
|
|
|
|
|
|
|
6452
|
106
|
50
|
33
|
|
|
631
|
my $n = ($e<=13 && $p<=13)||($e<=5 && $p<=1000) ?int($p**$e):Mpowint($p,$e); |
|
6453
|
106
|
50
|
33
|
|
|
511
|
my $pk = ($k<=13 && $p<=13)||($k<=5 && $p<=1000) ?int($p**$k):Mpowint($p,$k); |
|
6454
|
106
|
|
|
|
|
180
|
my @roots; |
|
6455
|
|
|
|
|
|
|
|
|
6456
|
106
|
50
|
|
|
|
289
|
if (($a % $n) == 0) { |
|
6457
|
0
|
|
|
|
|
0
|
my $t = Mdivint($e-1, $k) + 1; |
|
6458
|
0
|
|
|
|
|
0
|
my $nt = Mpowint($p, $t); |
|
6459
|
0
|
|
|
|
|
0
|
my $nr = Mpowint($p, $e-$t); |
|
6460
|
0
|
|
|
|
|
0
|
@roots = map { Mmulmod($_, $nt, $n) } 0 .. $nr-1; |
|
|
0
|
|
|
|
|
0
|
|
|
6461
|
0
|
|
|
|
|
0
|
return @roots; |
|
6462
|
|
|
|
|
|
|
} |
|
6463
|
|
|
|
|
|
|
|
|
6464
|
106
|
50
|
|
|
|
737
|
if (($a % $pk) == 0) { |
|
6465
|
0
|
|
|
|
|
0
|
my $apk = Mdivint($a, $pk); |
|
6466
|
0
|
|
|
|
|
0
|
my $pe1 = Mpowint($p, $k-1); |
|
6467
|
0
|
|
|
|
|
0
|
my $pek = Mpowint($p, $e-$k+1); |
|
6468
|
0
|
|
|
|
|
0
|
my @roots2 = _allrootmod_prime_power($apk, $k, $p, $e-$k); |
|
6469
|
0
|
|
|
|
|
0
|
for my $r (@roots2) { |
|
6470
|
0
|
|
|
|
|
0
|
my $rp = Mmulmod($r, $p, $n); |
|
6471
|
0
|
|
|
|
|
0
|
push @roots, Mmuladdmod($_, $pek, $rp, $n) for 0 .. $pe1-1; |
|
6472
|
|
|
|
|
|
|
} |
|
6473
|
0
|
|
|
|
|
0
|
return @roots; |
|
6474
|
|
|
|
|
|
|
} |
|
6475
|
|
|
|
|
|
|
|
|
6476
|
106
|
50
|
|
|
|
602
|
return () if ($a % $p) == 0; |
|
6477
|
|
|
|
|
|
|
|
|
6478
|
106
|
|
|
|
|
628
|
my $np = Mmulint($n,$p); |
|
6479
|
106
|
50
|
33
|
|
|
450
|
my $ered = ($p > 2 || $e < 5) ? ($e+1) >> 1 : ($e+3) >> 1; |
|
6480
|
106
|
|
|
|
|
369
|
my @roots2 = _allrootmod_prime_power($a, $k, $p, $ered); |
|
6481
|
|
|
|
|
|
|
|
|
6482
|
106
|
100
|
|
|
|
324
|
if ($k != $p) { |
|
6483
|
40
|
|
|
|
|
113
|
for my $s (@roots2) { |
|
6484
|
40
|
|
|
|
|
205
|
my $t = Mpowmod($s, $k-1, $n); |
|
6485
|
40
|
|
|
|
|
421
|
my $t1 = Msubmod($a, Mmulmod($t,$s,$n), $n); |
|
6486
|
40
|
|
|
|
|
151
|
my $t2 = Mmulmod($k, $t, $n); |
|
6487
|
40
|
|
|
|
|
142
|
my $gcd = Mgcd($t1, $t2); |
|
6488
|
40
|
|
|
|
|
282
|
my $r = Maddmod($s,Mdivmod(Mdivint($t1,$gcd),Mdivint($t2,$gcd),$n),$n); |
|
6489
|
40
|
|
|
|
|
177
|
push @roots, $r; |
|
6490
|
|
|
|
|
|
|
} |
|
6491
|
|
|
|
|
|
|
} else { |
|
6492
|
66
|
|
|
|
|
156
|
my @rootst; |
|
6493
|
66
|
|
|
|
|
200
|
for my $s (@roots2) { |
|
6494
|
130
|
|
|
|
|
467
|
my $t = Mpowmod($s, $k-1, $np); |
|
6495
|
130
|
|
|
|
|
375
|
my $t1 = Msubmod($a, Mmulmod($t,$s,$np), $np); |
|
6496
|
130
|
|
|
|
|
421
|
my $t2 = Mmulmod($k, $t, $np); |
|
6497
|
130
|
|
|
|
|
429
|
my $gcd = Mgcd($t1, $t2); |
|
6498
|
130
|
|
|
|
|
523
|
my $r = Maddmod($s,Mdivmod(Mdivint($t1,$gcd), Mdivint($t2,$gcd),$n),$n); |
|
6499
|
130
|
50
|
|
|
|
468
|
push @rootst, $r if Mpowmod($r, $k, $n) == ($a % $n); |
|
6500
|
|
|
|
|
|
|
} |
|
6501
|
66
|
|
|
|
|
220
|
my $ndivp = Mdivint($n,$p); |
|
6502
|
66
|
|
|
|
|
226
|
my $rset = []; |
|
6503
|
66
|
|
|
|
|
171
|
for my $r (@rootst) { |
|
6504
|
|
|
|
|
|
|
Msetinsert($rset, Mmulmod($r, Mmuladdmod($_, $ndivp, 1, $n), $n)) |
|
6505
|
130
|
|
|
|
|
773
|
for 0 .. $k-1; |
|
6506
|
|
|
|
|
|
|
} |
|
6507
|
66
|
|
|
|
|
264
|
@roots = @$rset; |
|
6508
|
|
|
|
|
|
|
} |
|
6509
|
106
|
|
|
|
|
477
|
return @roots; |
|
6510
|
|
|
|
|
|
|
} |
|
6511
|
|
|
|
|
|
|
|
|
6512
|
|
|
|
|
|
|
sub _allrootmod_kprime { |
|
6513
|
55
|
|
|
55
|
|
217
|
my($a,$k,$n,@nf) = @_; # k prime, n factored into f^e,f^e,... |
|
6514
|
|
|
|
|
|
|
|
|
6515
|
55
|
100
|
|
|
|
192
|
return _allsqrtmodfact($a, $n, \@nf) if $k == 2; |
|
6516
|
|
|
|
|
|
|
|
|
6517
|
42
|
|
|
|
|
80
|
my $N = 1; |
|
6518
|
42
|
|
|
|
|
76
|
my @roots; |
|
6519
|
42
|
|
|
|
|
90
|
foreach my $F (@nf) { |
|
6520
|
144
|
|
|
|
|
545
|
my($f,$e) = @$F; |
|
6521
|
144
|
100
|
|
|
|
666
|
my @roots2 = ($e==1) ? _allrootmod_prime($a, $k, $f) |
|
6522
|
|
|
|
|
|
|
: _allrootmod_prime_power($a, $k, $f, $e); |
|
6523
|
144
|
50
|
|
|
|
445
|
return () unless @roots2; |
|
6524
|
144
|
100
|
66
|
|
|
786
|
my $fe = ($e <= 13 && $f <= 13) ? int($f**$e) : Mpowint($f, $e); |
|
6525
|
144
|
100
|
|
|
|
422
|
if (scalar(@roots) == 0) { |
|
6526
|
42
|
|
|
|
|
108
|
@roots = @roots2; |
|
6527
|
|
|
|
|
|
|
} else { |
|
6528
|
102
|
|
|
|
|
493
|
@roots = _allrootmod_cprod(\@roots, $N, \@roots2, $fe); |
|
6529
|
|
|
|
|
|
|
} |
|
6530
|
144
|
|
|
|
|
843
|
$N = Mmulint($N, $fe); |
|
6531
|
|
|
|
|
|
|
} |
|
6532
|
|
|
|
|
|
|
|
|
6533
|
42
|
|
|
|
|
968
|
return @roots; |
|
6534
|
|
|
|
|
|
|
} |
|
6535
|
|
|
|
|
|
|
|
|
6536
|
|
|
|
|
|
|
sub allrootmod { |
|
6537
|
9
|
|
|
9
|
0
|
2499
|
my($A,$k,$n) = @_; |
|
6538
|
9
|
|
|
|
|
39
|
validate_integer($A); |
|
6539
|
9
|
|
|
|
|
139
|
validate_integer($k); |
|
6540
|
9
|
|
|
|
|
79
|
validate_integer_abs($n); |
|
6541
|
|
|
|
|
|
|
|
|
6542
|
9
|
50
|
|
|
|
417
|
return () if $n == 0; |
|
6543
|
9
|
|
|
|
|
461
|
$A = Mmodint($A,$n); |
|
6544
|
|
|
|
|
|
|
|
|
6545
|
9
|
50
|
33
|
|
|
56
|
return () if $k <= 0 && $A == 0; |
|
6546
|
|
|
|
|
|
|
|
|
6547
|
9
|
50
|
|
|
|
33
|
if ($k < 0) { |
|
6548
|
0
|
|
|
|
|
0
|
$A = Minvmod($A, $n); |
|
6549
|
0
|
0
|
0
|
|
|
0
|
return () unless defined $A && $A > 0; |
|
6550
|
0
|
|
|
|
|
0
|
$k = -$k; |
|
6551
|
|
|
|
|
|
|
} |
|
6552
|
|
|
|
|
|
|
|
|
6553
|
|
|
|
|
|
|
# TODO: For testing |
|
6554
|
|
|
|
|
|
|
#my @roots = sort { $a <=> $b } |
|
6555
|
|
|
|
|
|
|
# grep { Mpowmod($_,$k,$n) == $A } 0 .. $n-1; |
|
6556
|
|
|
|
|
|
|
#return @roots; |
|
6557
|
|
|
|
|
|
|
|
|
6558
|
9
|
50
|
33
|
|
|
47
|
return ($A) if $n <= 2 || $k == 1; |
|
6559
|
9
|
0
|
|
|
|
429
|
return ($A == 1) ? (0..$n-1) : () if $k == 0; |
|
|
|
50
|
|
|
|
|
|
|
6560
|
|
|
|
|
|
|
|
|
6561
|
9
|
|
|
|
|
19
|
my @roots; |
|
6562
|
9
|
100
|
|
|
|
54
|
my @nf = Mis_prime($n) ? ([$n,1]) : Mfactor_exp($n); |
|
6563
|
|
|
|
|
|
|
|
|
6564
|
9
|
100
|
|
|
|
392
|
if (Mis_prime($k)) { |
|
6565
|
6
|
|
|
|
|
24
|
@roots = _allrootmod_kprime($A, $k, $n, @nf); |
|
6566
|
|
|
|
|
|
|
} else { |
|
6567
|
3
|
|
|
|
|
9
|
@roots = ($A); |
|
6568
|
3
|
|
|
|
|
31
|
for my $primek (Mfactor($k)) { |
|
6569
|
9
|
|
|
|
|
21
|
my @rootsnew = (); |
|
6570
|
9
|
|
|
|
|
20
|
for my $r (@roots) { |
|
6571
|
49
|
|
|
|
|
254
|
push @rootsnew, _allrootmod_kprime($r, $primek, $n, @nf); |
|
6572
|
|
|
|
|
|
|
} |
|
6573
|
9
|
|
|
|
|
74
|
@roots = @rootsnew; |
|
6574
|
|
|
|
|
|
|
} |
|
6575
|
|
|
|
|
|
|
} |
|
6576
|
|
|
|
|
|
|
|
|
6577
|
9
|
|
|
|
|
62
|
Mvecsort(@roots); |
|
6578
|
|
|
|
|
|
|
} |
|
6579
|
|
|
|
|
|
|
|
|
6580
|
|
|
|
|
|
|
################################################################################ |
|
6581
|
|
|
|
|
|
|
################################################################################ |
|
6582
|
|
|
|
|
|
|
|
|
6583
|
|
|
|
|
|
|
sub _modabsint { |
|
6584
|
516
|
|
|
516
|
|
2080
|
my($a, $n) = @_; |
|
6585
|
516
|
50
|
|
|
|
1307
|
if ($n <= 1) { |
|
6586
|
0
|
0
|
0
|
|
|
0
|
if ($n < 0) { $n = tobigint($n) if $n <= INTMIN && !ref($n); $n = -$n; } |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
6587
|
0
|
0
|
|
|
|
0
|
return (undef,0)[$n] if $n <= 1; |
|
6588
|
|
|
|
|
|
|
} |
|
6589
|
516
|
100
|
66
|
|
|
3488
|
if ($n < INTMAX && $a < INTMAX && $a > INTMIN) { |
|
|
|
|
100
|
|
|
|
|
|
6590
|
512
|
50
|
|
|
|
1298
|
$a = $n - ((-$a) % $n) if $a < 0; |
|
6591
|
512
|
100
|
|
|
|
1403
|
$a %= $n if $a >= $n; |
|
6592
|
|
|
|
|
|
|
} else { |
|
6593
|
4
|
|
|
|
|
837
|
$a = tobigint($a) % $n; |
|
6594
|
4
|
100
|
|
|
|
1310
|
$a = _bigint_to_int($a) if $a <= INTMAX; |
|
6595
|
|
|
|
|
|
|
} |
|
6596
|
516
|
|
|
|
|
2408
|
$a; |
|
6597
|
|
|
|
|
|
|
} |
|
6598
|
|
|
|
|
|
|
|
|
6599
|
|
|
|
|
|
|
sub addmod { |
|
6600
|
1454
|
|
|
1454
|
0
|
7409
|
my($a, $b, $n) = @_; |
|
6601
|
1454
|
100
|
|
|
|
3928
|
if ($n <= 1) { |
|
6602
|
1
|
50
|
33
|
|
|
3
|
if ($n < 0) { $n = tobigint($n) if $n <= INTMIN && !ref($n); $n = -$n; } |
|
|
1
|
50
|
|
|
|
8
|
|
|
|
1
|
|
|
|
|
4
|
|
|
6603
|
1
|
50
|
|
|
|
78
|
return (undef,0)[$n] if $n <= 1; |
|
6604
|
|
|
|
|
|
|
} |
|
6605
|
1454
|
100
|
100
|
|
|
108053
|
if ($n <= INTMAX && $a <= INTMAX && $b <= INTMAX && $a >= INTMIN && $b >= INTMIN) { |
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
6606
|
987
|
50
|
|
|
|
1761
|
$a = $n - ((-$a) % $n) if $a < 0; |
|
6607
|
987
|
50
|
|
|
|
2122
|
$b = $n - ((-$b) % $n) if $b < 0; |
|
6608
|
987
|
100
|
|
|
|
2142
|
$a %= $n if $a >= $n; |
|
6609
|
987
|
100
|
|
|
|
1780
|
$b %= $n if $b >= $n; |
|
6610
|
987
|
100
|
|
|
|
3137
|
return $n-$a > $b ? $a+$b |
|
|
|
100
|
|
|
|
|
|
|
6611
|
|
|
|
|
|
|
: $a > $b ? ($a-$n)+$b |
|
6612
|
|
|
|
|
|
|
: ($b-$n)+$a; |
|
6613
|
|
|
|
|
|
|
} |
|
6614
|
|
|
|
|
|
|
# Impl 1. Make $a a bigint and let things promote. Fastest. |
|
6615
|
467
|
|
|
|
|
103155
|
$a = tobigint($a); |
|
6616
|
467
|
50
|
|
|
|
1973
|
if (ref($a) eq 'Math::Pari') { $b = tobigint($b); $n = tobigint($n); } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
6617
|
467
|
|
|
|
|
2001
|
my $r = ($a + $b) % $n; |
|
6618
|
467
|
100
|
|
|
|
208374
|
return $r <= INTMAX ? _bigint_to_int($r) : $r; |
|
6619
|
|
|
|
|
|
|
|
|
6620
|
|
|
|
|
|
|
# Impl 2. Use Maddint but mod with a $n as a bigint. |
|
6621
|
|
|
|
|
|
|
#my $r = Maddint($a,$b) % tobigint($n); |
|
6622
|
|
|
|
|
|
|
#return $r <= INTMAX ? _bigint_to_int($r) : $r; |
|
6623
|
|
|
|
|
|
|
|
|
6624
|
|
|
|
|
|
|
# Impl 3. Prefered, but slowest. Probably fine when we use amagic in XS. |
|
6625
|
|
|
|
|
|
|
#Mmodint(Maddint($a,$b),$n); |
|
6626
|
|
|
|
|
|
|
} |
|
6627
|
|
|
|
|
|
|
sub submod { |
|
6628
|
731
|
|
|
731
|
0
|
5396
|
my($a, $b, $n) = @_; |
|
6629
|
731
|
100
|
|
|
|
1902
|
if ($n <= 1) { |
|
6630
|
1
|
50
|
33
|
|
|
4
|
if ($n < 0) { $n = tobigint($n) if $n <= INTMIN && !ref($n); $n = -$n; } |
|
|
1
|
50
|
|
|
|
8
|
|
|
|
1
|
|
|
|
|
4
|
|
|
6631
|
1
|
50
|
|
|
|
72
|
return (undef,0)[$n] if $n <= 1; |
|
6632
|
|
|
|
|
|
|
} |
|
6633
|
731
|
100
|
100
|
|
|
28533
|
if ($n <= INTMAX && $a <= INTMAX && $b <= INTMAX && $a >= INTMIN && $b >= INTMIN) { |
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
6634
|
614
|
50
|
|
|
|
1262
|
$a = $n - ((-$a) % $n) if $a < 0; |
|
6635
|
614
|
50
|
|
|
|
1100
|
$b = $n - ((-$b) % $n) if $b < 0; |
|
6636
|
614
|
100
|
|
|
|
1213
|
$a %= $n if $a >= $n; |
|
6637
|
614
|
100
|
|
|
|
1226
|
$b %= $n if $b >= $n; |
|
6638
|
614
|
|
|
|
|
1077
|
$b = $n-$b; # negate b then we add as above |
|
6639
|
614
|
100
|
|
|
|
2614
|
return $n-$a > $b ? $a+$b |
|
|
|
100
|
|
|
|
|
|
|
6640
|
|
|
|
|
|
|
: $a > $b ? ($a-$n)+$b |
|
6641
|
|
|
|
|
|
|
: ($b-$n)+$a; |
|
6642
|
|
|
|
|
|
|
} |
|
6643
|
117
|
|
|
|
|
26374
|
$a = tobigint($a); |
|
6644
|
117
|
50
|
|
|
|
609
|
if (ref($a) eq 'Math::Pari') { $b = tobigint($b); $n = tobigint($n); } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
6645
|
117
|
|
|
|
|
536
|
my $r = ($a - $b) % $n; |
|
6646
|
117
|
100
|
|
|
|
49622
|
return $r <= INTMAX ? _bigint_to_int($r) : $r; |
|
6647
|
|
|
|
|
|
|
} |
|
6648
|
|
|
|
|
|
|
|
|
6649
|
|
|
|
|
|
|
sub mulmod { |
|
6650
|
16364
|
|
|
16364
|
0
|
62776
|
my($a, $b, $n) = @_; |
|
6651
|
|
|
|
|
|
|
#if ($n <= 1) { # ABS(n) and handle mod 0 | mod 1. |
|
6652
|
|
|
|
|
|
|
# if ($n < 0) { $n = tobigint($n) if $n <= INTMIN && !ref($n); $n = -$n; } |
|
6653
|
|
|
|
|
|
|
# return (undef,0)[$n] if $n <= 1; |
|
6654
|
|
|
|
|
|
|
#} |
|
6655
|
16364
|
100
|
|
|
|
58119
|
if ($n <= 1) { |
|
6656
|
1
|
50
|
|
|
|
4
|
return (undef,0)[$n] if $n >= 0; |
|
6657
|
1
|
50
|
33
|
|
|
8
|
$n = tobigint($n) if $n <= INTMIN && !ref($n); |
|
6658
|
1
|
|
|
|
|
4
|
$n = -$n; |
|
6659
|
1
|
50
|
|
|
|
70
|
return 0 if $n == 1; |
|
6660
|
|
|
|
|
|
|
} |
|
6661
|
|
|
|
|
|
|
|
|
6662
|
|
|
|
|
|
|
# If n is a native int, we can reduce a and b then do everything native |
|
6663
|
16364
|
100
|
|
|
|
2766242
|
if ($n < INTMAX) { |
|
6664
|
4156
|
100
|
33
|
|
|
25720
|
if ($a >= INTMAX || $a < 0 || $b >= INTMAX || $b < 0) { |
|
|
|
|
33
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
6665
|
1
|
50
|
33
|
|
|
7
|
$a = _bigint_to_int(tobigint($a) % $n) if $a >= INTMAX || $a < 0; |
|
6666
|
1
|
50
|
33
|
|
|
12
|
$b = _bigint_to_int(tobigint($b) % $n) if $b >= INTMAX || $b < 0; |
|
6667
|
|
|
|
|
|
|
} |
|
6668
|
4156
|
|
|
|
|
9551
|
return _mulmod($a,$b,$n); |
|
6669
|
|
|
|
|
|
|
} |
|
6670
|
|
|
|
|
|
|
|
|
6671
|
|
|
|
|
|
|
# Try GMP |
|
6672
|
|
|
|
|
|
|
return reftyped($_[0], Math::Prime::Util::GMP::mulmod($a,$b,$n)) |
|
6673
|
12208
|
50
|
|
|
|
2849987
|
if $Math::Prime::Util::_GMPfunc{"mulmod"}; |
|
6674
|
|
|
|
|
|
|
|
|
6675
|
12208
|
|
|
|
|
29051
|
my $refn = ref($n); |
|
6676
|
12208
|
100
|
|
|
|
33159
|
if (!$refn) { |
|
6677
|
2
|
|
|
|
|
10
|
$n = tobigint($n); |
|
6678
|
2
|
|
|
|
|
6
|
$refn = ref($n); |
|
6679
|
|
|
|
|
|
|
} |
|
6680
|
12208
|
100
|
|
|
|
51426
|
$a = $refn->new("$a") unless ref($a) eq $refn; |
|
6681
|
12208
|
100
|
|
|
|
798089
|
$b = $refn->new("$b") unless ref($b) eq $refn; |
|
6682
|
12208
|
|
|
|
|
644361
|
my $r = ($a * $b) % $n; |
|
6683
|
12208
|
100
|
|
|
|
6736522
|
return $r <= INTMAX ? _bigint_to_int($r) : $r; |
|
6684
|
|
|
|
|
|
|
} |
|
6685
|
|
|
|
|
|
|
|
|
6686
|
|
|
|
|
|
|
sub _bi_powmod { |
|
6687
|
979
|
|
|
979
|
|
3400
|
my($a, $b, $n) = @_; |
|
6688
|
979
|
50
|
|
|
|
3470
|
croak "_bi_powmod must have positive exponent" if $b < 0; |
|
6689
|
979
|
50
|
|
|
|
137143
|
croak "_bi_powmod must have n > 1" if $n <= 1; |
|
6690
|
|
|
|
|
|
|
|
|
6691
|
979
|
|
|
|
|
166339
|
my $refn = ref($n); |
|
6692
|
979
|
100
|
|
|
|
3715
|
if (!$refn) { |
|
6693
|
155
|
|
|
|
|
5403
|
$n = tobigint($n); |
|
6694
|
155
|
|
|
|
|
429
|
$refn = ref($n); |
|
6695
|
|
|
|
|
|
|
} |
|
6696
|
979
|
100
|
|
|
|
4118
|
$b = $refn->new($b) unless ref($b) eq $refn; |
|
6697
|
|
|
|
|
|
|
|
|
6698
|
979
|
|
|
|
|
34958
|
my $r = $refn->new($a); |
|
6699
|
|
|
|
|
|
|
|
|
6700
|
979
|
50
|
|
|
|
97300
|
if ($refn eq 'Math::GMPz') { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
6701
|
0
|
|
|
|
|
0
|
Math::GMPz::Rmpz_powm($r, $r, $b, $n); |
|
6702
|
|
|
|
|
|
|
} elsif ($refn eq 'Math::GMP') { |
|
6703
|
0
|
|
|
|
|
0
|
$r = $r->powm_gmp($b,$n); |
|
6704
|
|
|
|
|
|
|
} elsif ($refn eq 'Math::BigInt') { |
|
6705
|
979
|
50
|
|
|
|
6923
|
$r->bmod($n) if $BIGINTVERSION < 1.999; |
|
6706
|
979
|
|
|
|
|
164437
|
$r->bmodpow($b,$n); |
|
6707
|
|
|
|
|
|
|
} elsif ($refn eq 'Math::Pari') { |
|
6708
|
0
|
0
|
|
|
|
0
|
$a = $refn->new("$a") unless ref($a) eq $refn; |
|
6709
|
0
|
0
|
|
|
|
0
|
$b = $refn->new("$b") unless ref($b) eq $refn; |
|
6710
|
0
|
0
|
0
|
|
|
0
|
if ($n <= 4294967295 && $b > 4294967295) { |
|
6711
|
0
|
|
|
|
|
0
|
$b = $b % Math::Prime::Util::carmichael_lambda($n); |
|
6712
|
|
|
|
|
|
|
} |
|
6713
|
0
|
|
|
|
|
0
|
$r = Math::Pari::lift(Math::Pari::gpow(Math::Pari::Mod($a,$n),$b)); |
|
6714
|
|
|
|
|
|
|
} else { |
|
6715
|
0
|
|
|
|
|
0
|
$r->bmodpow("$b","$n"); |
|
6716
|
|
|
|
|
|
|
} |
|
6717
|
979
|
|
|
|
|
53637639
|
$r; |
|
6718
|
|
|
|
|
|
|
} |
|
6719
|
|
|
|
|
|
|
|
|
6720
|
|
|
|
|
|
|
sub powmod { |
|
6721
|
988
|
|
|
988
|
0
|
5160
|
my($a, $b, $n) = @_; |
|
6722
|
988
|
50
|
|
|
|
4844
|
if ($n <= 1) { |
|
6723
|
0
|
0
|
0
|
|
|
0
|
if ($n < 0) { $n = tobigint($n) if $n <= INTMIN && !ref($n); $n = -$n; } |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
6724
|
0
|
0
|
|
|
|
0
|
return (undef,0)[$n] if $n <= 1; |
|
6725
|
|
|
|
|
|
|
} |
|
6726
|
988
|
0
|
|
|
|
77664
|
return ($b > 0) ? 0 : 1 if $a == 0; |
|
|
|
50
|
|
|
|
|
|
|
6727
|
|
|
|
|
|
|
|
|
6728
|
988
|
50
|
|
|
|
13435
|
if ($Math::Prime::Util::_GMPfunc{"powmod"}) { |
|
6729
|
0
|
|
|
|
|
0
|
my $r = Math::Prime::Util::GMP::powmod($a,$b,$n); |
|
6730
|
0
|
0
|
|
|
|
0
|
return (defined $r) ? reftyped($_[0], $r) : undef; |
|
6731
|
|
|
|
|
|
|
} |
|
6732
|
|
|
|
|
|
|
|
|
6733
|
|
|
|
|
|
|
# If the exponent is negative: a=1/a ; b=-b |
|
6734
|
988
|
100
|
|
|
|
2896
|
if ($b < 0) { |
|
6735
|
1
|
|
|
|
|
6
|
$a = Minvmod($a,$n); |
|
6736
|
1
|
50
|
|
|
|
4
|
return undef unless defined $a; |
|
6737
|
1
|
50
|
33
|
|
|
12
|
$b = tobigint($b) if $b <= INTMIN && !ref($b); |
|
6738
|
1
|
|
|
|
|
7
|
$b = -$b; |
|
6739
|
|
|
|
|
|
|
} |
|
6740
|
|
|
|
|
|
|
|
|
6741
|
988
|
100
|
|
|
|
48527
|
if ($b <= 8) { |
|
6742
|
565
|
100
|
|
|
|
1379
|
return 1 if $b == 0; |
|
6743
|
551
|
100
|
|
|
|
1314
|
return _modabsint($a,$n) if $b == 1; |
|
6744
|
483
|
100
|
|
|
|
5706
|
return Mmulmod($a,$a,$n) if $b == 2; |
|
6745
|
|
|
|
|
|
|
# For exponents 3-8, this can be 20x faster for native n |
|
6746
|
266
|
50
|
66
|
|
|
1490
|
if (!ref($n) && $a <= 31622776 && $a >= -31622776) { |
|
|
|
|
66
|
|
|
|
|
|
6747
|
224
|
|
|
|
|
512
|
my $a2 = int($a*$a); |
|
6748
|
224
|
100
|
|
|
|
757
|
return Mmulmod($a2,$a,$n) if $b == 3; |
|
6749
|
44
|
|
|
|
|
168
|
my $a4 = Mmulmod($a2,$a2,$n); |
|
6750
|
44
|
100
|
|
|
|
165
|
return $a4 if $b == 4; |
|
6751
|
32
|
100
|
|
|
|
83
|
return Mmulmod($a4,$a,$n) if $b == 5; |
|
6752
|
17
|
100
|
|
|
|
76
|
return Mmulmod($a4,$a2,$n) if $b == 6; |
|
6753
|
11
|
100
|
|
|
|
51
|
return Mmulmod($a4,Mmulmod($a2,$a,$n),$n) if $b == 7; |
|
6754
|
6
|
50
|
|
|
|
47
|
return Mmulmod($a4,$a4,$n) if $b == 8; |
|
6755
|
|
|
|
|
|
|
} |
|
6756
|
|
|
|
|
|
|
} |
|
6757
|
|
|
|
|
|
|
|
|
6758
|
465
|
|
|
|
|
41823
|
my $r = _bi_powmod($a,$b,$n); |
|
6759
|
465
|
100
|
|
|
|
5866
|
return $r <= INTMAX ? _bigint_to_int($r) : $r; |
|
6760
|
|
|
|
|
|
|
} |
|
6761
|
|
|
|
|
|
|
|
|
6762
|
|
|
|
|
|
|
sub muladdmod { |
|
6763
|
12556
|
|
|
12556
|
0
|
105974
|
my($a, $b, $c, $n) = @_; |
|
6764
|
12556
|
50
|
|
|
|
43055
|
if ($n <= 1) { |
|
6765
|
0
|
0
|
|
|
|
0
|
$n = Mnegint($n) if $n < 0; |
|
6766
|
0
|
0
|
|
|
|
0
|
return (undef,0)[$n] if $n <= 1; |
|
6767
|
|
|
|
|
|
|
} |
|
6768
|
|
|
|
|
|
|
|
|
6769
|
12556
|
50
|
100
|
|
|
2424858
|
if (!ref($n) && $n <= INTMAX |
|
|
|
|
66
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
6770
|
|
|
|
|
|
|
&& $a <= INTMAX && $b <= INTMAX && $c <= INTMAX |
|
6771
|
|
|
|
|
|
|
&& $a >= INTMIN && $b >= INTMIN && $c >= INTMIN) { |
|
6772
|
2161
|
50
|
|
|
|
4380
|
$a = $n - ((-$a) % $n) if $a < 0; |
|
6773
|
2161
|
50
|
|
|
|
3984
|
$b = $n - ((-$b) % $n) if $b < 0; |
|
6774
|
2161
|
50
|
|
|
|
4030
|
$c = $n - ((-$c) % $n) if $c < 0; |
|
6775
|
|
|
|
|
|
|
#$c %= $n if $c >= $n; # For mulsubmod |
|
6776
|
2161
|
|
|
|
|
4850
|
return _addmod(_mulmod($a,$b,$n),$c,$n); |
|
6777
|
|
|
|
|
|
|
} |
|
6778
|
|
|
|
|
|
|
return reftyped($_[0], Math::Prime::Util::GMP::muladdmod($a,$b,$c,$n)) |
|
6779
|
10395
|
50
|
|
|
|
35381
|
if $Math::Prime::Util::_GMPfunc{"muladdmod"}; |
|
6780
|
|
|
|
|
|
|
|
|
6781
|
10395
|
100
|
|
|
|
27346
|
$n = tobigint($n) unless ref($n); |
|
6782
|
10395
|
50
|
|
|
|
29176
|
if (ref($n) eq 'Math::Pari') { |
|
6783
|
0
|
0
|
|
|
|
0
|
$a = tobigint("$a") unless ref($a) eq 'Math::Pari'; |
|
6784
|
0
|
0
|
|
|
|
0
|
$b = tobigint("$b") unless ref($b) eq 'Math::Pari'; |
|
6785
|
|
|
|
|
|
|
} else { |
|
6786
|
10395
|
100
|
66
|
|
|
53960
|
$a = tobigint($a) unless ref($a) || ref($b); |
|
6787
|
|
|
|
|
|
|
} |
|
6788
|
10395
|
100
|
|
|
|
41260
|
$c = tobigint($c) unless ref($c); |
|
6789
|
10395
|
|
|
|
|
40364
|
my $r = (($a * $b) + $c) % $n; |
|
6790
|
10395
|
100
|
|
|
|
8776892
|
return $r <= INTMAX ? _bigint_to_int($r) : $r; |
|
6791
|
|
|
|
|
|
|
} |
|
6792
|
|
|
|
|
|
|
sub mulsubmod { |
|
6793
|
19456
|
|
|
19456
|
0
|
83222
|
my($a, $b, $c, $n) = @_; |
|
6794
|
19456
|
50
|
|
|
|
76730
|
if ($n <= 1) { |
|
6795
|
0
|
0
|
|
|
|
0
|
$n = Mnegint($n) if $n < 0; |
|
6796
|
0
|
0
|
|
|
|
0
|
return (undef,0)[$n] if $n <= 1; |
|
6797
|
|
|
|
|
|
|
} |
|
6798
|
|
|
|
|
|
|
|
|
6799
|
19456
|
50
|
100
|
|
|
4191833
|
if (!ref($n) && $n <= INTMAX |
|
|
|
|
66
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
6800
|
|
|
|
|
|
|
&& $a <= INTMAX && $b <= INTMAX && $c <= INTMAX |
|
6801
|
|
|
|
|
|
|
&& $a >= INTMIN && $b >= INTMIN && $c >= INTMIN) { |
|
6802
|
1275
|
50
|
|
|
|
2567
|
$a = $n - ((-$a) % $n) if $a < 0; |
|
6803
|
1275
|
50
|
|
|
|
2223
|
$b = $n - ((-$b) % $n) if $b < 0; |
|
6804
|
1275
|
50
|
|
|
|
2326
|
$c = $n - ((-$c) % $n) if $c < 0; |
|
6805
|
1275
|
50
|
|
|
|
2570
|
$c = ($c < $n) ? $n-$c : $n-($c % $n); # $c = -$c (mod n) |
|
6806
|
1275
|
|
|
|
|
2595
|
return _addmod(_mulmod($a,$b,$n),$c,$n); |
|
6807
|
|
|
|
|
|
|
} |
|
6808
|
|
|
|
|
|
|
return reftyped($_[0], Math::Prime::Util::GMP::mulsubmod($a,$b,$c,$n)) |
|
6809
|
18181
|
50
|
|
|
|
58660
|
if $Math::Prime::Util::_GMPfunc{"mulsubmod"}; |
|
6810
|
|
|
|
|
|
|
|
|
6811
|
|
|
|
|
|
|
# return Msubmod(Mmulmod($a,$b,$n),$c,$n); |
|
6812
|
|
|
|
|
|
|
|
|
6813
|
18181
|
100
|
|
|
|
49263
|
$n = tobigint($n) unless ref($n); |
|
6814
|
18181
|
50
|
|
|
|
49991
|
if (ref($n) eq 'Math::Pari') { |
|
6815
|
0
|
0
|
|
|
|
0
|
$a = tobigint("$a") unless ref($a) eq 'Math::Pari'; |
|
6816
|
0
|
0
|
|
|
|
0
|
$b = tobigint("$b") unless ref($b) eq 'Math::Pari'; |
|
6817
|
|
|
|
|
|
|
} else { |
|
6818
|
18181
|
100
|
100
|
|
|
64931
|
$a = tobigint($a) unless ref($a) || ref($b); |
|
6819
|
|
|
|
|
|
|
} |
|
6820
|
18181
|
100
|
|
|
|
77190
|
$c = tobigint($c) unless ref($c); |
|
6821
|
18181
|
|
|
|
|
67452
|
my $r = (($a * $b) - $c) % $n; |
|
6822
|
18181
|
100
|
|
|
|
18468422
|
return $r <= INTMAX ? _bigint_to_int($r) : $r; |
|
6823
|
|
|
|
|
|
|
} |
|
6824
|
|
|
|
|
|
|
|
|
6825
|
|
|
|
|
|
|
sub invmod { |
|
6826
|
684
|
|
|
684
|
0
|
3320
|
my($a,$n) = @_; |
|
6827
|
684
|
100
|
|
|
|
2145
|
if ($n <= 1) { |
|
6828
|
1
|
50
|
33
|
|
|
5
|
if ($n < 0) { $n = tobigint($n) if $n <= INTMIN && !ref($n); $n = -$n; } |
|
|
1
|
50
|
|
|
|
5
|
|
|
|
1
|
|
|
|
|
2
|
|
|
6829
|
1
|
50
|
|
|
|
4
|
return (undef,0)[$n] if $n <= 1; |
|
6830
|
|
|
|
|
|
|
} |
|
6831
|
684
|
50
|
|
|
|
53819
|
return if $a == 0; |
|
6832
|
|
|
|
|
|
|
|
|
6833
|
684
|
100
|
|
|
|
28930
|
if ($n < INTMAX) { # Fast all native math |
|
6834
|
448
|
|
|
|
|
1478
|
my($t,$nt,$r,$nr) = (0, 1, $n, _modabsint($a,$n)); |
|
6835
|
448
|
|
|
|
|
1270
|
while ($nr != 0) { |
|
6836
|
|
|
|
|
|
|
# Use mod before divide to force correct behavior with high bit set |
|
6837
|
1598
|
|
|
|
|
5235
|
my $quot = int( ($r-($r % $nr))/$nr ); |
|
6838
|
1598
|
|
|
|
|
3393
|
($nt,$t) = ($t-$quot*$nt,$nt); |
|
6839
|
1598
|
|
|
|
|
4479
|
($nr,$r) = ($r-$quot*$nr,$nr); |
|
6840
|
|
|
|
|
|
|
} |
|
6841
|
448
|
100
|
|
|
|
1961
|
return $r > 1 ? undef |
|
|
|
100
|
|
|
|
|
|
|
6842
|
|
|
|
|
|
|
: $t < 0 ? $t+$n |
|
6843
|
|
|
|
|
|
|
: $t; |
|
6844
|
|
|
|
|
|
|
} |
|
6845
|
|
|
|
|
|
|
|
|
6846
|
236
|
|
|
|
|
57343
|
$n = tobigint($n); |
|
6847
|
236
|
|
|
|
|
697
|
$a = tobigint($a) % $n; |
|
6848
|
236
|
|
|
|
|
44725
|
my $refn = ref($n); |
|
6849
|
236
|
|
|
|
|
582
|
my $I; |
|
6850
|
|
|
|
|
|
|
|
|
6851
|
236
|
50
|
|
|
|
886
|
if ($refn eq 'Math::BigInt') { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
6852
|
236
|
|
|
|
|
853
|
$I = $a->copy->bmodinv($n); |
|
6853
|
236
|
100
|
66
|
|
|
804242
|
$I = undef if defined $I && !$I->is_int(); |
|
6854
|
|
|
|
|
|
|
} elsif ($refn eq 'Math::GMPz') { |
|
6855
|
0
|
|
|
|
|
0
|
$I = Math::GMPz->new(); |
|
6856
|
0
|
|
|
|
|
0
|
Math::GMPz::Rmpz_invert($I, $a, $n); |
|
6857
|
0
|
0
|
0
|
|
|
0
|
$I = undef if defined $I && $I == 0; |
|
6858
|
|
|
|
|
|
|
} elsif ($refn eq 'Math::GMP') { |
|
6859
|
0
|
|
|
|
|
0
|
$I = $a->gmp_copy->bmodinv($n); |
|
6860
|
0
|
0
|
0
|
|
|
0
|
$I = undef if defined $I && $I == 0; |
|
6861
|
|
|
|
|
|
|
} elsif ($refn eq 'Math::Pari') { |
|
6862
|
0
|
|
|
|
|
0
|
$I = eval{1/Math::Pari::Mod($a,$n)}; |
|
|
0
|
|
|
|
|
0
|
|
|
6863
|
0
|
0
|
0
|
|
|
0
|
$I = defined $I && $I != 0 ? Math::Pari::lift($I) : undef; |
|
6864
|
|
|
|
|
|
|
} else { |
|
6865
|
0
|
|
|
|
|
0
|
$I = Math::BigInt->new("$a")->bmodinv("$n"); |
|
6866
|
0
|
0
|
0
|
|
|
0
|
$I = undef if defined $I && !$I->is_int(); |
|
6867
|
0
|
0
|
|
|
|
0
|
$I = tobigint("$I") if defined $I; |
|
6868
|
|
|
|
|
|
|
} |
|
6869
|
236
|
100
|
100
|
|
|
4535
|
$I = _bigint_to_int($I) if defined $I && $I <= INTMAX; |
|
6870
|
236
|
|
|
|
|
58994
|
return $I; |
|
6871
|
|
|
|
|
|
|
} |
|
6872
|
|
|
|
|
|
|
|
|
6873
|
|
|
|
|
|
|
sub divmod { |
|
6874
|
199
|
|
|
199
|
0
|
1535
|
my($a, $b, $n) = @_; |
|
6875
|
199
|
50
|
|
|
|
650
|
if ($n <= 1) { |
|
6876
|
0
|
0
|
0
|
|
|
0
|
if ($n < 0) { $n = tobigint($n) if $n <= INTMIN && !ref($n); $n = -$n; } |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
6877
|
0
|
0
|
|
|
|
0
|
return (undef,0)[$n] if $n <= 1; |
|
6878
|
|
|
|
|
|
|
} |
|
6879
|
|
|
|
|
|
|
|
|
6880
|
199
|
|
|
|
|
907
|
my $invb = Minvmod($b,$n); |
|
6881
|
199
|
50
|
|
|
|
506
|
return undef unless defined $invb; |
|
6882
|
199
|
|
|
|
|
570
|
return Mmulmod($a,$invb,$n); |
|
6883
|
|
|
|
|
|
|
} |
|
6884
|
|
|
|
|
|
|
|
|
6885
|
|
|
|
|
|
|
sub negmod { |
|
6886
|
2
|
|
|
2
|
0
|
5487
|
my($a,$n) = @_; |
|
6887
|
2
|
|
|
|
|
9
|
validate_integer($a); |
|
6888
|
2
|
|
|
|
|
44
|
validate_integer($n); |
|
6889
|
|
|
|
|
|
|
|
|
6890
|
2
|
50
|
|
|
|
28
|
if ($n <= 0) { |
|
6891
|
0
|
0
|
|
|
|
0
|
return undef if $n == 0; # standard mod behavior with n = 0 |
|
6892
|
0
|
0
|
0
|
|
|
0
|
$n = tobigint($n) if $n <= INTMIN && !ref($n); |
|
6893
|
0
|
|
|
|
|
0
|
$n = -$n; # we use |n|, unlike modint |
|
6894
|
|
|
|
|
|
|
} |
|
6895
|
|
|
|
|
|
|
# Easy: |
|
6896
|
|
|
|
|
|
|
# Msubmod(0, $a, $n); |
|
6897
|
|
|
|
|
|
|
|
|
6898
|
2
|
50
|
33
|
|
|
191
|
$a = Mmodint($a,$n) if $a >= $n || $a < 0; |
|
6899
|
2
|
50
|
|
|
|
14
|
return $a ? $n-$a : 0; |
|
6900
|
|
|
|
|
|
|
} |
|
6901
|
|
|
|
|
|
|
|
|
6902
|
|
|
|
|
|
|
# No validation. |
|
6903
|
|
|
|
|
|
|
sub _negmod { |
|
6904
|
5
|
|
|
5
|
|
21
|
my($a,$n) = @_; |
|
6905
|
5
|
50
|
|
|
|
25
|
if ($n <= 0) { |
|
6906
|
0
|
0
|
|
|
|
0
|
return undef if $n == 0; |
|
6907
|
0
|
0
|
0
|
|
|
0
|
$n = tobigint($n) if $n <= INTMIN && !ref($n); |
|
6908
|
0
|
|
|
|
|
0
|
$n = -$n; |
|
6909
|
|
|
|
|
|
|
} |
|
6910
|
5
|
50
|
33
|
|
|
31
|
$a = Mmodint($a,$n) if $a >= $n || $a < 0; |
|
6911
|
5
|
50
|
|
|
|
21
|
return $a ? $n-$a : 0; |
|
6912
|
|
|
|
|
|
|
} |
|
6913
|
|
|
|
|
|
|
|
|
6914
|
|
|
|
|
|
|
################################################################################ |
|
6915
|
|
|
|
|
|
|
################################################################################ |
|
6916
|
|
|
|
|
|
|
|
|
6917
|
|
|
|
|
|
|
# no validation, x is allowed to be negative, y must be >= 0 |
|
6918
|
|
|
|
|
|
|
sub _gcd_ui { |
|
6919
|
1339
|
|
|
1339
|
|
2847
|
my($x, $y) = @_; |
|
6920
|
1339
|
100
|
|
|
|
2849
|
if ($y < $x) { ($x, $y) = ($y, $x); } |
|
|
918
|
50
|
|
|
|
1964
|
|
|
6921
|
0
|
|
|
|
|
0
|
elsif ($x < 0) { $x = -$x; } |
|
6922
|
1339
|
|
|
|
|
3076
|
while ($y > 0) { |
|
6923
|
10763
|
|
|
|
|
27021
|
($x, $y) = ($y, $x % $y); |
|
6924
|
|
|
|
|
|
|
} |
|
6925
|
1339
|
|
|
|
|
2668
|
$x; |
|
6926
|
|
|
|
|
|
|
} |
|
6927
|
|
|
|
|
|
|
|
|
6928
|
|
|
|
|
|
|
sub _powerof_ret { |
|
6929
|
1031
|
|
|
1031
|
|
3067
|
my($n, $refp) = @_; |
|
6930
|
|
|
|
|
|
|
|
|
6931
|
1031
|
|
|
|
|
2002
|
my $k = 2; |
|
6932
|
1031
|
|
|
|
|
1665
|
while (1) { |
|
6933
|
4713
|
|
|
|
|
8391
|
my $rk; |
|
6934
|
4713
|
|
|
|
|
21810
|
my $r = Mrootint($n, $k, \$rk); |
|
6935
|
4713
|
100
|
|
|
|
17373
|
return 0 if $r == 1; |
|
6936
|
4378
|
100
|
|
|
|
104656
|
if ($rk == $n) { |
|
6937
|
696
|
|
|
|
|
30689
|
my $next = _powerof_ret($r, $refp); |
|
6938
|
696
|
100
|
100
|
|
|
3230
|
$$refp = $r if !$next && defined $refp; |
|
6939
|
696
|
100
|
|
|
|
1633
|
$k *= $next if $next != 0; |
|
6940
|
696
|
|
|
|
|
3201
|
return $k; |
|
6941
|
|
|
|
|
|
|
} |
|
6942
|
3682
|
|
|
|
|
195835
|
$k = Mnext_prime($k); |
|
6943
|
|
|
|
|
|
|
} |
|
6944
|
0
|
|
|
|
|
0
|
0; |
|
6945
|
|
|
|
|
|
|
} |
|
6946
|
|
|
|
|
|
|
|
|
6947
|
|
|
|
|
|
|
sub is_power { |
|
6948
|
345
|
|
|
345
|
0
|
326781
|
my ($n, $a, $refp) = @_; |
|
6949
|
345
|
|
|
|
|
3332
|
validate_integer($n); |
|
6950
|
345
|
100
|
|
|
|
3298
|
if (!defined $a) { $a = 0; } else { validate_integer_nonneg($a); } |
|
|
147
|
|
|
|
|
492
|
|
|
|
198
|
|
|
|
|
699
|
|
|
6951
|
345
|
50
|
66
|
|
|
2141
|
croak("is_power third argument not a scalar reference") if defined($refp) && !ref($refp); |
|
6952
|
345
|
100
|
100
|
|
|
1574
|
return 0 if abs($n) <= 3 && !$a; |
|
6953
|
|
|
|
|
|
|
|
|
6954
|
343
|
0
|
0
|
|
|
108815
|
if ($Math::Prime::Util::_GMPfunc{"is_power"} && |
|
|
|
|
33
|
|
|
|
|
|
6955
|
|
|
|
|
|
|
($Math::Prime::Util::GMP::VERSION >= 0.42 || |
|
6956
|
|
|
|
|
|
|
($Math::Prime::Util::GMP::VERSION >= 0.28 && $n > 0))) { |
|
6957
|
0
|
|
|
|
|
0
|
my $k = Math::Prime::Util::GMP::is_power($n,$a); |
|
6958
|
0
|
0
|
|
|
|
0
|
return 0 unless $k > 0; |
|
6959
|
0
|
0
|
|
|
|
0
|
if (defined $refp) { |
|
6960
|
0
|
0
|
|
|
|
0
|
$a = $k unless $a; |
|
6961
|
0
|
|
|
|
|
0
|
my $isneg = ($n < 0); |
|
6962
|
0
|
0
|
|
|
|
0
|
$n =~ s/^-// if $isneg; |
|
6963
|
0
|
|
|
|
|
0
|
$$refp = Mrootint($n, $a); |
|
6964
|
0
|
0
|
|
|
|
0
|
$$refp = reftyped($_[0], $$refp) if $$refp > INTMAX; |
|
6965
|
0
|
0
|
|
|
|
0
|
$$refp = Mnegint($$refp) if $isneg; |
|
6966
|
|
|
|
|
|
|
} |
|
6967
|
0
|
|
|
|
|
0
|
return $k; |
|
6968
|
|
|
|
|
|
|
} |
|
6969
|
|
|
|
|
|
|
|
|
6970
|
343
|
100
|
|
|
|
1185
|
if ($a != 0) { |
|
6971
|
8
|
50
|
|
|
|
28
|
if ($a == 1) { |
|
6972
|
0
|
0
|
|
|
|
0
|
$$refp = $n if defined $refp; |
|
6973
|
0
|
|
|
|
|
0
|
return 1; # Everything is a 1st power |
|
6974
|
|
|
|
|
|
|
} |
|
6975
|
8
|
50
|
33
|
|
|
31
|
return 0 if $n < 0 && $a % 2 == 0; # Negative n never an even power |
|
6976
|
8
|
100
|
|
|
|
528
|
if ($a == 2) { |
|
6977
|
3
|
50
|
|
|
|
55
|
if (_is_perfect_square($n)) { |
|
6978
|
3
|
50
|
|
|
|
41
|
$$refp = Msqrtint($n) if defined $refp; |
|
6979
|
3
|
|
|
|
|
17
|
return 1; |
|
6980
|
|
|
|
|
|
|
} |
|
6981
|
|
|
|
|
|
|
} else { |
|
6982
|
|
|
|
|
|
|
|
|
6983
|
5
|
|
|
|
|
63
|
my @rootmask = ( |
|
6984
|
|
|
|
|
|
|
0x00000000,0x00000000,0xfdfcfdec,0x54555454,0xfffcfffc, # 0-4 |
|
6985
|
|
|
|
|
|
|
0x55555554,0xfdfdfdfc,0x55555554,0xfffffffc,0x55555554,0xfdfdfdfc,# 5-10 |
|
6986
|
|
|
|
|
|
|
0x55555554,0xfffdfffc,0xd5555556,0xfdfdfdfc,0xf57d57d6,0xfffffffc,# 11-16 |
|
6987
|
|
|
|
|
|
|
0xffffd556,0xfdfdfdfe,0xd57ffffe,0xfffdfffc,0xffd7ff7e,0xfdfdfdfe,# 17-22 |
|
6988
|
|
|
|
|
|
|
0xffffd7fe,0xfffffffc,0xffffffd6,0xfdfffdfe,0xd7fffffe,0xfffdfffe,# 23-28 |
|
6989
|
|
|
|
|
|
|
0xfff7fffe,0xfdfffffe,0xfffff7fe,0xfffffffc,0xfffffff6,0xfffffdfe,# 29-34 |
|
6990
|
|
|
|
|
|
|
0xf7fffffe,0xfffdfffe,0xfff7fffe,0xfdfffffe,0xfffff7fe,0xfffffffc # 35-40 |
|
6991
|
|
|
|
|
|
|
); |
|
6992
|
5
|
50
|
|
|
|
20
|
if ($a <= 40) { |
|
6993
|
5
|
100
|
|
|
|
29
|
my $n32 = 1 << (ref($n) ? Mmodint($n,32) : $n & 31); |
|
6994
|
5
|
100
|
|
|
|
32
|
return 0 if $n32 & $rootmask[$a]; |
|
6995
|
|
|
|
|
|
|
} |
|
6996
|
3
|
|
|
|
|
9
|
my $RK; |
|
6997
|
3
|
50
|
|
|
|
10
|
if ($n >= 0) { |
|
6998
|
3
|
|
|
|
|
266
|
my $root = Mrootint($n, $a, \$RK); |
|
6999
|
3
|
0
|
|
|
|
18
|
if ($RK == $n) { $$refp = $root if defined $refp; return 1; } |
|
|
0
|
50
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
7000
|
|
|
|
|
|
|
} else { |
|
7001
|
0
|
|
|
|
|
0
|
my $N = Mnegint($n); |
|
7002
|
0
|
|
|
|
|
0
|
my $root = Mrootint($N, $a, \$RK); |
|
7003
|
0
|
0
|
|
|
|
0
|
if ($RK == $N) { $$refp = Mnegint($root) if defined $refp; return 1; } |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
7004
|
|
|
|
|
|
|
} |
|
7005
|
|
|
|
|
|
|
} |
|
7006
|
3
|
|
|
|
|
77
|
return 0; |
|
7007
|
|
|
|
|
|
|
} |
|
7008
|
|
|
|
|
|
|
|
|
7009
|
335
|
|
|
|
|
1366
|
my $negn = $n < 0; |
|
7010
|
335
|
100
|
|
|
|
66419
|
$n = Mnegint($n) if $negn; |
|
7011
|
335
|
|
|
|
|
34088
|
my $r; |
|
7012
|
335
|
100
|
|
|
|
1674
|
my $k = _powerof_ret($n, defined $refp ? \$r : undef); |
|
7013
|
335
|
100
|
|
|
|
1593
|
return 0 if $k < 2; |
|
7014
|
278
|
100
|
100
|
|
|
1945
|
if ($negn && $k % 2 == 0) { |
|
7015
|
128
|
|
|
|
|
699
|
my $v = Mvaluation($k, 2); |
|
7016
|
128
|
|
|
|
|
328
|
$k >>= $v; |
|
7017
|
128
|
100
|
|
|
|
437
|
return 0 if $k < 2; |
|
7018
|
122
|
100
|
|
|
|
913
|
$r = Mpowint($r, Mpowint(2,$v)) if defined $r; |
|
7019
|
|
|
|
|
|
|
} |
|
7020
|
272
|
100
|
66
|
|
|
3968
|
$$refp = $negn ? Mnegint($r) : $r if defined $refp && $k > 0; |
|
|
|
100
|
|
|
|
|
|
|
7021
|
272
|
|
|
|
|
2853
|
$k; |
|
7022
|
|
|
|
|
|
|
} |
|
7023
|
|
|
|
|
|
|
|
|
7024
|
|
|
|
|
|
|
sub is_square { |
|
7025
|
2
|
|
|
2
|
0
|
1143
|
my($n) = @_; |
|
7026
|
2
|
50
|
|
|
|
47
|
return 0 if $n < 0; |
|
7027
|
|
|
|
|
|
|
#Mis_power($n,2); |
|
7028
|
2
|
|
|
|
|
30
|
validate_integer($n); |
|
7029
|
2
|
|
|
|
|
14
|
_is_perfect_square($n); |
|
7030
|
|
|
|
|
|
|
} |
|
7031
|
|
|
|
|
|
|
|
|
7032
|
|
|
|
|
|
|
sub is_prime_power { |
|
7033
|
60
|
|
|
60
|
0
|
208
|
my ($n, $refp) = @_; |
|
7034
|
60
|
|
|
|
|
212
|
validate_integer($n); |
|
7035
|
60
|
50
|
66
|
|
|
889
|
croak("is_prime_power second argument not a scalar reference") if defined($refp) && !ref($refp); |
|
7036
|
60
|
50
|
|
|
|
147
|
return 0 if $n <= 1; |
|
7037
|
|
|
|
|
|
|
|
|
7038
|
60
|
100
|
|
|
|
2615
|
if (Mis_prime($n)) { $$refp = $n if defined $refp; return 1; } |
|
|
18
|
100
|
|
|
|
87
|
|
|
|
18
|
|
|
|
|
81
|
|
|
7039
|
42
|
|
|
|
|
84
|
my $r; |
|
7040
|
42
|
|
|
|
|
169
|
my $k = Mis_power($n,0,\$r); |
|
7041
|
42
|
100
|
|
|
|
141
|
if ($k) { |
|
7042
|
13
|
50
|
66
|
|
|
76
|
$r = _bigint_to_int($r) if ref($r) && $r <= INTMAX; |
|
7043
|
13
|
50
|
|
|
|
2198
|
return 0 unless Mis_prime($r); |
|
7044
|
13
|
100
|
|
|
|
1344
|
$$refp = $r if defined $refp; |
|
7045
|
|
|
|
|
|
|
} |
|
7046
|
42
|
|
|
|
|
152
|
$k; |
|
7047
|
|
|
|
|
|
|
} |
|
7048
|
|
|
|
|
|
|
|
|
7049
|
|
|
|
|
|
|
sub is_gaussian_prime { |
|
7050
|
7
|
|
|
7
|
0
|
1668
|
my($a,$b) = @_; |
|
7051
|
7
|
|
|
|
|
48
|
validate_integer_abs($a); |
|
7052
|
7
|
|
|
|
|
27
|
validate_integer_abs($b); |
|
7053
|
7
|
100
|
|
|
|
58
|
return ((($b % 4) == 3) ? Mis_prime($b) : 0) if $a == 0; |
|
|
|
100
|
|
|
|
|
|
|
7054
|
5
|
100
|
|
|
|
44
|
return ((($a % 4) == 3) ? Mis_prime($a) : 0) if $b == 0; |
|
|
|
100
|
|
|
|
|
|
|
7055
|
3
|
|
|
|
|
22
|
Mis_prime( Maddint( Mmulint($a,$a), Mmulint($b,$b) ) ); |
|
7056
|
|
|
|
|
|
|
} |
|
7057
|
|
|
|
|
|
|
|
|
7058
|
|
|
|
|
|
|
sub is_polygonal { |
|
7059
|
4
|
|
|
4
|
0
|
40
|
my ($n, $k, $refp) = @_; |
|
7060
|
4
|
|
|
|
|
38
|
validate_integer($n); |
|
7061
|
4
|
|
|
|
|
23
|
validate_integer_nonneg($k); |
|
7062
|
4
|
50
|
33
|
|
|
19
|
croak("is_polygonal third argument not a scalar reference") if defined($refp) && !ref($refp); |
|
7063
|
4
|
50
|
|
|
|
15
|
croak("is_polygonal: k must be >= 3") if $k < 3; |
|
7064
|
4
|
50
|
|
|
|
38
|
return 0 if $n < 0; |
|
7065
|
4
|
0
|
|
|
|
657
|
if ($n <= 1) { $$refp = $n if defined $refp; return 1; } |
|
|
0
|
50
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
7066
|
|
|
|
|
|
|
|
|
7067
|
4
|
50
|
|
|
|
567
|
if ($Math::Prime::Util::_GMPfunc{"polygonal_nth"}) { |
|
7068
|
0
|
|
|
|
|
0
|
my $nth = Math::Prime::Util::GMP::polygonal_nth($n, $k); |
|
7069
|
0
|
0
|
|
|
|
0
|
return 0 unless $nth; |
|
7070
|
0
|
0
|
|
|
|
0
|
$$refp = reftyped($_[0], $nth) if defined $refp; |
|
7071
|
0
|
|
|
|
|
0
|
return 1; |
|
7072
|
|
|
|
|
|
|
} |
|
7073
|
|
|
|
|
|
|
|
|
7074
|
4
|
|
|
|
|
21
|
my($D,$R); |
|
7075
|
4
|
100
|
|
|
|
27
|
if ($k == 4) { |
|
7076
|
1
|
50
|
|
|
|
5
|
return 0 unless _is_perfect_square($n); |
|
7077
|
1
|
50
|
|
|
|
34
|
$$refp = Msqrtint($n) if defined $refp; |
|
7078
|
1
|
|
|
|
|
9
|
return 1; |
|
7079
|
|
|
|
|
|
|
} |
|
7080
|
3
|
100
|
66
|
|
|
18
|
if ($n <= MPU_HALFWORD && $k <= MPU_HALFWORD) { |
|
7081
|
1
|
50
|
|
|
|
6
|
$D = ($k==3) ? 1+($n<<3) : (8*$k-16)*$n + ($k-4)*($k-4); |
|
7082
|
1
|
50
|
|
|
|
7
|
return 0 unless _is_perfect_square($D); |
|
7083
|
1
|
|
|
|
|
9
|
$D = $k-4 + Msqrtint($D); |
|
7084
|
1
|
|
|
|
|
5
|
$R = 2*$k-4; |
|
7085
|
|
|
|
|
|
|
} else { |
|
7086
|
2
|
50
|
|
|
|
516
|
if ($k == 3) { |
|
7087
|
2
|
|
|
|
|
53
|
$D = Maddint(1, Mmulint($n, 8)); |
|
7088
|
|
|
|
|
|
|
} else { |
|
7089
|
0
|
|
|
|
|
0
|
$D = Maddint(Mmulint($n, Mmulint(8, $k) - 16), Mmulint($k-4,$k-4)); |
|
7090
|
|
|
|
|
|
|
} |
|
7091
|
2
|
100
|
|
|
|
553
|
return 0 unless _is_perfect_square($D); |
|
7092
|
1
|
|
|
|
|
373
|
$D = Maddint( Msqrtint($D), $k-4 ); |
|
7093
|
1
|
|
|
|
|
265
|
$R = Mmulint(2, $k) - 4; |
|
7094
|
|
|
|
|
|
|
} |
|
7095
|
2
|
50
|
|
|
|
25
|
return 0 if ($D % $R) != 0; |
|
7096
|
2
|
50
|
|
|
|
642
|
$$refp = $D / $R if defined $refp; |
|
7097
|
2
|
|
|
|
|
21
|
1; |
|
7098
|
|
|
|
|
|
|
} |
|
7099
|
|
|
|
|
|
|
|
|
7100
|
|
|
|
|
|
|
sub is_sum_of_squares { |
|
7101
|
23
|
|
|
23
|
0
|
117
|
my($n, $k) = @_; |
|
7102
|
23
|
|
|
|
|
94
|
validate_integer_abs($n); |
|
7103
|
23
|
100
|
|
|
|
309
|
if (defined $k) { validate_integer_nonneg($k); } |
|
|
1
|
|
|
|
|
5
|
|
|
7104
|
22
|
|
|
|
|
35
|
else { $k = 2; } |
|
7105
|
|
|
|
|
|
|
|
|
7106
|
23
|
0
|
|
|
|
1125
|
return ($n == 0) ? 1 : 0 if $k == 0; |
|
|
|
50
|
|
|
|
|
|
|
7107
|
23
|
50
|
|
|
|
72
|
return 1 if $k > 3; |
|
7108
|
23
|
50
|
|
|
|
65
|
return _is_perfect_square($n) if $k == 1; |
|
7109
|
|
|
|
|
|
|
|
|
7110
|
23
|
100
|
|
|
|
103
|
return 1 if $n < 3; |
|
7111
|
|
|
|
|
|
|
|
|
7112
|
18
|
100
|
|
|
|
289
|
if ($k == 3) { |
|
7113
|
1
|
|
|
|
|
9
|
my $tz = Mvaluation($n,2); |
|
7114
|
1
|
50
|
|
|
|
7
|
return 1 if ($tz & 1) == 1; |
|
7115
|
1
|
50
|
|
|
|
9
|
return 1 unless Mis_congruent(Mrshiftint($n,$tz), 7, 8); |
|
7116
|
1
|
|
|
|
|
13
|
return 0; |
|
7117
|
|
|
|
|
|
|
} |
|
7118
|
|
|
|
|
|
|
|
|
7119
|
|
|
|
|
|
|
# k = 2 |
|
7120
|
17
|
|
|
|
|
51
|
while (($n % 2) == 0) { $n >>= 1; } |
|
|
14
|
|
|
|
|
34
|
|
|
7121
|
17
|
100
|
|
|
|
60
|
return 0 if ($n % 4) == 3; |
|
7122
|
|
|
|
|
|
|
|
|
7123
|
11
|
|
|
|
|
64
|
foreach my $F (Mfactor_exp($n)) { |
|
7124
|
7
|
|
|
|
|
23
|
my($f,$e) = @$F; |
|
7125
|
7
|
100
|
100
|
|
|
74
|
return 0 if ($e & 1) == 1 && ($f % 4) == 3; |
|
7126
|
|
|
|
|
|
|
} |
|
7127
|
10
|
|
|
|
|
72
|
1; |
|
7128
|
|
|
|
|
|
|
} |
|
7129
|
|
|
|
|
|
|
|
|
7130
|
|
|
|
|
|
|
sub cornacchia { |
|
7131
|
3
|
|
|
3
|
0
|
10
|
my($d, $n) = @_; |
|
7132
|
3
|
|
|
|
|
47
|
validate_integer_nonneg($d); |
|
7133
|
3
|
|
|
|
|
10
|
validate_integer_nonneg($n); |
|
7134
|
|
|
|
|
|
|
|
|
7135
|
3
|
50
|
|
|
|
22
|
return (0,0) if $n == 0; |
|
7136
|
3
|
50
|
|
|
|
17
|
if ($d == 0) { |
|
7137
|
0
|
0
|
|
|
|
0
|
return undef unless _is_perfect_square($n); |
|
7138
|
0
|
|
|
|
|
0
|
return (Msqrtint($n), 0); |
|
7139
|
|
|
|
|
|
|
} |
|
7140
|
|
|
|
|
|
|
|
|
7141
|
3
|
100
|
|
|
|
35
|
if (Mis_prime($n)) { |
|
7142
|
2
|
|
|
|
|
5
|
my ($u,$rk); |
|
7143
|
2
|
|
|
|
|
39
|
my $negd = _negmod($d,$n); |
|
7144
|
2
|
50
|
|
|
|
19
|
return undef if Mkronecker($negd, $n) == -1; |
|
7145
|
2
|
|
|
|
|
56
|
$u = _sqrtmod_prime($negd, $n); |
|
7146
|
2
|
50
|
|
|
|
28
|
return undef unless defined $u; |
|
7147
|
2
|
100
|
|
|
|
18
|
$u = $n-$u if $u > ($n>>1); |
|
7148
|
|
|
|
|
|
|
{ |
|
7149
|
2
|
|
|
|
|
5
|
my $l = Msqrtint($n); |
|
|
2
|
|
|
|
|
10
|
|
|
7150
|
2
|
|
|
|
|
19
|
my($a, $b) = ($n, $u); |
|
7151
|
2
|
|
|
|
|
18
|
while ($a > $l) { |
|
7152
|
5
|
|
|
|
|
15
|
($a,$b) = ($b, $a % $b); |
|
7153
|
|
|
|
|
|
|
} |
|
7154
|
2
|
|
|
|
|
5
|
$rk = $a; |
|
7155
|
|
|
|
|
|
|
} |
|
7156
|
2
|
|
|
|
|
9
|
$u = _negmod(Mmulmod($rk,$rk,$n),$n); |
|
7157
|
2
|
100
|
|
|
|
14
|
$u = (($u % $d) == 0) ? Mdivint($u,$d) : 0; |
|
7158
|
2
|
100
|
66
|
|
|
44
|
return ($rk, Msqrtint($u)) if $u && _is_perfect_square($u); |
|
7159
|
1
|
|
|
|
|
6
|
return undef; |
|
7160
|
|
|
|
|
|
|
} |
|
7161
|
|
|
|
|
|
|
|
|
7162
|
1
|
|
|
|
|
6
|
my $limu = Msqrtint(Mdivint($n,$d)); |
|
7163
|
1
|
|
|
|
|
6
|
for my $u (0 .. $limu) { |
|
7164
|
7
|
|
|
|
|
53
|
my $t = $n - Mvecprod($d,$u,$u); |
|
7165
|
7
|
100
|
|
|
|
22
|
return (Msqrtint($t), $u) if _is_perfect_square($t); |
|
7166
|
|
|
|
|
|
|
} |
|
7167
|
0
|
|
|
|
|
0
|
undef; |
|
7168
|
|
|
|
|
|
|
} |
|
7169
|
|
|
|
|
|
|
|
|
7170
|
|
|
|
|
|
|
sub is_congruent_number { |
|
7171
|
17
|
|
|
17
|
0
|
1490
|
my($n) = @_; |
|
7172
|
17
|
|
|
|
|
57
|
validate_integer_nonneg($n); |
|
7173
|
|
|
|
|
|
|
|
|
7174
|
17
|
50
|
0
|
|
|
47
|
return ($n >= 5 && $n <= 7) if $n < 13; |
|
7175
|
|
|
|
|
|
|
|
|
7176
|
17
|
|
|
|
|
31
|
my $n8 = $n % 8; |
|
7177
|
17
|
100
|
100
|
|
|
126
|
return 1 if $n8 == 5 || $n8 == 6 || $n8 == 7; |
|
|
|
|
100
|
|
|
|
|
|
7178
|
|
|
|
|
|
|
|
|
7179
|
14
|
100
|
|
|
|
51
|
if (!Mis_square_free($n)) { |
|
7180
|
1
|
|
|
|
|
5
|
my $N = 1; |
|
7181
|
1
|
|
|
|
|
6
|
foreach my $f (Mfactor_exp($n)) { |
|
7182
|
2
|
|
|
|
|
6
|
my($p,$e) = @$f; |
|
7183
|
2
|
100
|
|
|
|
13
|
$N = Mmulint($N,$p) if ($e % 2) == 1; |
|
7184
|
|
|
|
|
|
|
} |
|
7185
|
1
|
|
|
|
|
49
|
return is_congruent_number($N); |
|
7186
|
|
|
|
|
|
|
} |
|
7187
|
|
|
|
|
|
|
|
|
7188
|
13
|
|
|
|
|
45
|
my $ndiv2 = Mrshiftint($n); |
|
7189
|
|
|
|
|
|
|
|
|
7190
|
13
|
100
|
100
|
|
|
46
|
if (Mis_even($n) && Mis_prime($ndiv2)) { |
|
|
|
100
|
|
|
|
|
|
|
7191
|
2
|
|
|
|
|
6
|
my $p = $ndiv2; |
|
7192
|
2
|
|
|
|
|
7
|
my $p8 = $p % 8; |
|
7193
|
2
|
50
|
33
|
|
|
31
|
return 1 if $p8 == 3 || $p8 == 7; |
|
7194
|
2
|
100
|
66
|
|
|
30
|
return 0 if $p8 == 5 || ($p % 16) == 9; |
|
7195
|
|
|
|
|
|
|
} elsif (Mis_prime($n)) { |
|
7196
|
3
|
100
|
|
|
|
16
|
return 0 if $n8 == 3; |
|
7197
|
2
|
50
|
33
|
|
|
14
|
return 1 if $n8 == 5 || $n8 == 7; |
|
7198
|
|
|
|
|
|
|
|
|
7199
|
2
|
|
|
|
|
11
|
my $r = _sqrtmod_prime(2, $n); |
|
7200
|
2
|
100
|
66
|
|
|
18
|
return 0 if defined $r && Mkronecker(1+$r, $n) == -1; |
|
7201
|
|
|
|
|
|
|
} elsif (1) { |
|
7202
|
8
|
|
|
|
|
26
|
my @factors = Mfactor($n); |
|
7203
|
8
|
100
|
33
|
|
|
57
|
if (scalar(@factors) == 2) { |
|
|
|
50
|
|
|
|
|
|
|
7204
|
4
|
|
|
|
|
14
|
my($p, $q) = ($factors[0], $factors[1]); |
|
7205
|
4
|
|
|
|
|
10
|
my($p8, $q8) = ($p % 8, $q %8); |
|
7206
|
4
|
100
|
100
|
|
|
51
|
return 0 if $p8 == 3 && $q8 == 3; |
|
7207
|
3
|
50
|
66
|
|
|
24
|
return 0 if $p8 == 1 && $q8 == 3 && kronecker($p,$q) == -1; |
|
|
|
|
66
|
|
|
|
|
|
7208
|
2
|
50
|
66
|
|
|
27
|
return 0 if $p8 == 3 && $q8 == 1 && kronecker($q,$p) == -1; |
|
|
|
|
66
|
|
|
|
|
|
7209
|
|
|
|
|
|
|
} elsif (scalar(@factors) == 3 && $factors[0] == 2) { |
|
7210
|
4
|
|
|
|
|
27
|
my($p, $q) = ($factors[1], $factors[2]); |
|
7211
|
4
|
|
|
|
|
10
|
my($p8, $q8) = ($p % 8, $q %8); |
|
7212
|
4
|
100
|
100
|
|
|
24
|
return 0 if $p8 == 5 && $q8 == 5; |
|
7213
|
3
|
50
|
66
|
|
|
23
|
return 0 if $p8 == 1 && $q8 == 5 && kronecker($p,$q) == -1; |
|
|
|
|
66
|
|
|
|
|
|
7214
|
2
|
50
|
66
|
|
|
34
|
return 0 if $p8 == 5 && $q8 == 1 && kronecker($q,$p) == -1; |
|
|
|
|
66
|
|
|
|
|
|
7215
|
|
|
|
|
|
|
} |
|
7216
|
|
|
|
|
|
|
} |
|
7217
|
|
|
|
|
|
|
|
|
7218
|
|
|
|
|
|
|
# General test |
|
7219
|
4
|
|
|
|
|
31
|
my @sols = (0,0); |
|
7220
|
4
|
100
|
|
|
|
21
|
if (Mis_odd($n)) { |
|
7221
|
2
|
|
|
|
|
29
|
my $limz = Msqrtint($n >> 3); |
|
7222
|
2
|
|
|
|
|
9
|
foreach my $z (0 .. $limz) { |
|
7223
|
6
|
|
|
|
|
12
|
my $zsols = 0; |
|
7224
|
6
|
|
|
|
|
54
|
my $n8z = $n - 8*$z*$z; |
|
7225
|
6
|
|
|
|
|
21
|
my $limy = Msqrtint($n8z >> 1); |
|
7226
|
6
|
|
|
|
|
16
|
foreach my $y (0 .. $limy) { |
|
7227
|
24
|
|
|
|
|
42
|
my $x = $n8z - 2*$y*$y; |
|
7228
|
24
|
100
|
|
|
|
65
|
$zsols += 1 << (1 + ($y>0) + ($z>0)) |
|
7229
|
|
|
|
|
|
|
if _is_perfect_square($x); |
|
7230
|
|
|
|
|
|
|
} |
|
7231
|
6
|
|
|
|
|
20
|
$sols[$z % 2] += $zsols; |
|
7232
|
|
|
|
|
|
|
} |
|
7233
|
|
|
|
|
|
|
} else { |
|
7234
|
2
|
|
|
|
|
14
|
my $limz = Msqrtint($ndiv2 >> 3); |
|
7235
|
2
|
|
|
|
|
10
|
foreach my $z (0 .. $limz) { |
|
7236
|
4
|
|
|
|
|
8
|
my $zsols = 0; |
|
7237
|
4
|
|
|
|
|
30
|
my $n8z = $ndiv2 - 8*$z*$z; # ndiv2 odd => n8z is odd |
|
7238
|
4
|
|
|
|
|
12
|
my $limx = Msqrtint($n8z); |
|
7239
|
4
|
|
|
|
|
16
|
for (my $x = 1; $x <= $limx; $x += 2) { |
|
7240
|
8
|
|
|
|
|
16
|
my $y = $n8z - $x*$x; |
|
7241
|
8
|
100
|
100
|
|
|
33
|
$zsols += 1 << (1 + ($y>0) + ($z>0)) |
|
7242
|
|
|
|
|
|
|
if $y == 0 || _is_perfect_square($y); |
|
7243
|
|
|
|
|
|
|
} |
|
7244
|
4
|
|
|
|
|
30
|
$sols[$z % 2] += $zsols; |
|
7245
|
|
|
|
|
|
|
} |
|
7246
|
|
|
|
|
|
|
} |
|
7247
|
4
|
100
|
|
|
|
31
|
return ($sols[0] == $sols[1]) ? 1 : 0; |
|
7248
|
|
|
|
|
|
|
} |
|
7249
|
|
|
|
|
|
|
|
|
7250
|
|
|
|
|
|
|
sub is_perfect_number { |
|
7251
|
4
|
|
|
4
|
0
|
1211
|
my($n) = @_; |
|
7252
|
4
|
|
|
|
|
39
|
validate_integer($n); |
|
7253
|
4
|
50
|
|
|
|
18
|
return 0 if $n <= 0; |
|
7254
|
|
|
|
|
|
|
|
|
7255
|
4
|
50
|
|
|
|
683
|
if (Mis_even($n)) { |
|
7256
|
4
|
|
|
|
|
242
|
my $v = Mvaluation($n,2); |
|
7257
|
4
|
|
|
|
|
759
|
my $m = Mrshiftint($n, $v); |
|
7258
|
4
|
100
|
|
|
|
166
|
return 0 if Mrshiftint($m,$v) != 1; |
|
7259
|
3
|
50
|
|
|
|
43
|
return 0 if Math::Prime::Util::hammingweight($m) != $v+1; |
|
7260
|
3
|
|
|
|
|
53
|
return Math::Prime::Util::is_mersenne_prime($v+1); |
|
7261
|
|
|
|
|
|
|
} |
|
7262
|
|
|
|
|
|
|
|
|
7263
|
|
|
|
|
|
|
# N is odd. See https://www.lirmm.fr/~ochem/opn/ |
|
7264
|
0
|
0
|
|
|
|
0
|
return 0 if length($n) <= 2200; |
|
7265
|
0
|
0
|
|
|
|
0
|
return 0 unless Mis_divisible($n, 105); |
|
7266
|
0
|
0
|
0
|
|
|
0
|
return 0 unless Mis_congruent($n, 1, 12) |
|
|
|
|
0
|
|
|
|
|
|
7267
|
|
|
|
|
|
|
|| Mis_congruent($n,117,468) |
|
7268
|
|
|
|
|
|
|
|| Mis_congruent($n, 81, 324); |
|
7269
|
0
|
|
|
|
|
0
|
Mcmpint($n,Msubint(Mdivisor_sum($n),$n)) == 0; |
|
7270
|
|
|
|
|
|
|
} |
|
7271
|
|
|
|
|
|
|
|
|
7272
|
|
|
|
|
|
|
sub valuation { |
|
7273
|
507
|
|
|
507
|
0
|
1985
|
my($n, $k) = @_; |
|
7274
|
|
|
|
|
|
|
# The validation in PP is 2x more time than our actual work. |
|
7275
|
507
|
|
|
|
|
3240
|
validate_integer_abs($n); |
|
7276
|
507
|
|
|
|
|
126815
|
validate_integer_positive($k); |
|
7277
|
507
|
50
|
|
|
|
2125
|
croak "valuation: k must be > 1" if $k <= 1; |
|
7278
|
|
|
|
|
|
|
|
|
7279
|
507
|
50
|
|
|
|
1808
|
return if $k < 2; |
|
7280
|
507
|
50
|
|
|
|
1694
|
return (undef,0)[$n] if $n <= 1; |
|
7281
|
507
|
|
|
|
|
103068
|
my $v = 0; |
|
7282
|
507
|
100
|
|
|
|
2019
|
if ($k == 2) { # Accelerate power of 2 |
|
7283
|
499
|
|
|
|
|
1060
|
my $s; |
|
7284
|
499
|
100
|
|
|
|
2942
|
if (!ref($n)) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
7285
|
8
|
50
|
|
|
|
68
|
return 0 if $n & 1; |
|
7286
|
8
|
100
|
|
|
|
36
|
return 1 if $n & 2; |
|
7287
|
6
|
50
|
|
|
|
26
|
return 2 if $n & 4; |
|
7288
|
6
|
|
|
|
|
36
|
$s = sprintf("%b","$n"); |
|
7289
|
|
|
|
|
|
|
} elsif (ref($n) eq 'Math::BigInt') { |
|
7290
|
491
|
|
|
|
|
2911
|
$s = $n->as_bin; |
|
7291
|
|
|
|
|
|
|
} elsif (ref($n) eq 'Math::GMPz') { |
|
7292
|
0
|
|
|
|
|
0
|
return Math::GMPz::Rmpz_scan1($n,0); |
|
7293
|
|
|
|
|
|
|
} else { |
|
7294
|
0
|
|
|
|
|
0
|
$s = Math::BigInt->new("$n")->as_bin; |
|
7295
|
|
|
|
|
|
|
} |
|
7296
|
497
|
|
|
|
|
190673
|
return length($s) - rindex($s,'1') - 1; |
|
7297
|
|
|
|
|
|
|
} |
|
7298
|
8
|
|
|
|
|
30
|
while ( !($n % $k) ) { |
|
7299
|
12
|
|
|
|
|
1779
|
$n /= $k; |
|
7300
|
12
|
|
|
|
|
2890
|
$v++; |
|
7301
|
|
|
|
|
|
|
} |
|
7302
|
8
|
|
|
|
|
444
|
$v; |
|
7303
|
|
|
|
|
|
|
} |
|
7304
|
|
|
|
|
|
|
|
|
7305
|
|
|
|
|
|
|
sub hammingweight { |
|
7306
|
2
|
|
|
2
|
0
|
26
|
return 0 + (Mtodigitstring($_[0],2) =~ tr/1//); |
|
7307
|
|
|
|
|
|
|
} |
|
7308
|
|
|
|
|
|
|
|
|
7309
|
|
|
|
|
|
|
my @_digitmap = (0..9, 'a'..'z'); |
|
7310
|
|
|
|
|
|
|
my %_mapdigit = map { $_digitmap[$_] => $_ } 0 .. $#_digitmap; |
|
7311
|
|
|
|
|
|
|
sub _splitdigits { |
|
7312
|
176
|
|
|
176
|
|
6855
|
my($n, $base, $len) = @_; # n is num or bigint, base is in range |
|
7313
|
176
|
|
|
|
|
951
|
validate_integer_nonneg($n); |
|
7314
|
176
|
|
|
|
|
6233
|
my @d; |
|
7315
|
176
|
100
|
|
|
|
876
|
if ($base == 10) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
7316
|
1
|
|
|
|
|
7
|
@d = split(//,"$n"); |
|
7317
|
|
|
|
|
|
|
} elsif ($base == 2) { |
|
7318
|
145
|
|
|
|
|
831
|
@d = split(//,substr(Math::BigInt->new("$n")->as_bin,2)); |
|
7319
|
|
|
|
|
|
|
} elsif ($base == 16) { |
|
7320
|
27
|
|
|
|
|
128
|
@d = map { $_mapdigit{$_} } split(//,substr(Math::BigInt->new("$n")->as_hex,2)); |
|
|
523
|
|
|
|
|
14337
|
|
|
7321
|
|
|
|
|
|
|
} else { |
|
7322
|
|
|
|
|
|
|
# The validation turned n into a bigint if necessary |
|
7323
|
3
|
|
|
|
|
7
|
while ($n >= 1) { |
|
7324
|
98
|
|
|
|
|
43039
|
my $rem = $n % $base; |
|
7325
|
98
|
|
|
|
|
17167
|
unshift @d, $rem; |
|
7326
|
98
|
|
|
|
|
184
|
$n = ($n-$rem)/$base; # Always an exact division |
|
7327
|
|
|
|
|
|
|
} |
|
7328
|
|
|
|
|
|
|
} |
|
7329
|
176
|
50
|
33
|
|
|
66082
|
if ($len >= 0 && $len != scalar(@d)) { |
|
7330
|
0
|
|
|
|
|
0
|
while (@d < $len) { unshift @d, 0; } |
|
|
0
|
|
|
|
|
0
|
|
|
7331
|
0
|
|
|
|
|
0
|
while (@d > $len) { shift @d; } |
|
|
0
|
|
|
|
|
0
|
|
|
7332
|
|
|
|
|
|
|
} |
|
7333
|
176
|
|
|
|
|
4812
|
@d; |
|
7334
|
|
|
|
|
|
|
} |
|
7335
|
|
|
|
|
|
|
|
|
7336
|
|
|
|
|
|
|
sub todigits { |
|
7337
|
141
|
|
|
141
|
0
|
617
|
my($n,$base,$len) = @_; |
|
7338
|
141
|
|
|
|
|
924
|
validate_integer_abs($n); |
|
7339
|
141
|
100
|
|
|
|
20932
|
$base = 10 unless defined $base; |
|
7340
|
141
|
50
|
|
|
|
552
|
$len = -1 unless defined $len; |
|
7341
|
141
|
50
|
|
|
|
483
|
die "Invalid base: $base" if $base < 2; |
|
7342
|
141
|
50
|
|
|
|
475
|
return if $n == 0; |
|
7343
|
141
|
|
|
|
|
19342
|
_splitdigits($n, $base, $len); |
|
7344
|
|
|
|
|
|
|
} |
|
7345
|
|
|
|
|
|
|
|
|
7346
|
|
|
|
|
|
|
sub _tobinarystring { |
|
7347
|
14
|
|
|
14
|
|
41
|
my($n) = @_; |
|
7348
|
14
|
|
|
|
|
75
|
$n =~ s/^-//; |
|
7349
|
14
|
50
|
|
|
|
329
|
return "" if $n == 0; |
|
7350
|
14
|
100
|
|
|
|
1705
|
return sprintf("%b",$n) if $n < INTMAX; |
|
7351
|
6
|
50
|
|
|
|
1697
|
$n = tobigint($n) unless ref($n); |
|
7352
|
6
|
|
|
|
|
15
|
my $refn = ref($n); |
|
7353
|
6
|
50
|
|
|
|
20
|
return Math::GMPz::Rmpz_get_str($n,2) if $refn eq 'Math::GMPz'; |
|
7354
|
6
|
50
|
|
|
|
15
|
return Math::GMP::get_str_gmp($n,2) if $refn eq 'Math::GMP'; |
|
7355
|
6
|
50
|
|
|
|
17
|
if ($BIGINTVERSION >= 1.999814) { |
|
7356
|
0
|
0
|
|
|
|
0
|
$n = Math::BigInt->new("$n") if $refn ne 'Math::BigInt'; |
|
7357
|
0
|
|
|
|
|
0
|
return $n->to_base(2); |
|
7358
|
|
|
|
|
|
|
} |
|
7359
|
6
|
|
|
|
|
25
|
return join("", _splitdigits($n, 2, -1)); |
|
7360
|
|
|
|
|
|
|
} |
|
7361
|
|
|
|
|
|
|
|
|
7362
|
|
|
|
|
|
|
sub todigitstring { |
|
7363
|
44
|
|
|
44
|
0
|
6783
|
my($n,$base,$len) = @_; |
|
7364
|
44
|
|
|
|
|
342
|
validate_integer($n); |
|
7365
|
44
|
50
|
|
|
|
1619
|
$base = 10 unless defined $base; |
|
7366
|
44
|
100
|
66
|
|
|
294
|
return _tobinarystring($n) if $base == 2 && !defined $len; |
|
7367
|
30
|
50
|
33
|
|
|
184
|
croak "Invalid base for string: $base" if $base < 2 || $base > 36; |
|
7368
|
30
|
50
|
|
|
|
118
|
$len = -1 unless defined $len; |
|
7369
|
30
|
|
|
|
|
103
|
$n =~ s/^-//; |
|
7370
|
|
|
|
|
|
|
|
|
7371
|
30
|
50
|
33
|
|
|
1623
|
return "" if $len == 0 || $n == 0; |
|
7372
|
|
|
|
|
|
|
|
|
7373
|
30
|
100
|
|
|
|
6636
|
if ($n < INTMAX) { |
|
7374
|
1
|
50
|
33
|
|
|
16
|
if ($base != 2 && $base != 8 && $base != 16) { |
|
|
|
|
33
|
|
|
|
|
|
7375
|
0
|
0
|
|
|
|
0
|
return join "", _splitdigits($n, $base, $len) if $base <= 10; |
|
7376
|
0
|
|
|
|
|
0
|
return join "", map { $_digitmap[$_] } _splitdigits($n, $base, $len); |
|
|
0
|
|
|
|
|
0
|
|
|
7377
|
|
|
|
|
|
|
} |
|
7378
|
1
|
|
|
|
|
2
|
my $s; |
|
7379
|
1
|
50
|
|
|
|
7
|
$s = sprintf("%b",$n) if $base == 2; |
|
7380
|
1
|
50
|
|
|
|
5
|
$s = sprintf("%o",$n) if $base == 8; |
|
7381
|
1
|
50
|
|
|
|
8
|
$s = sprintf("%x",$n) if $base == 16; |
|
7382
|
1
|
50
|
|
|
|
5
|
if ($len > 0) { |
|
7383
|
0
|
|
|
|
|
0
|
$s = substr($s,0,$len); |
|
7384
|
0
|
0
|
|
|
|
0
|
$s = '0' x ($len-length($s)) . $s if length($s) < $len; |
|
7385
|
|
|
|
|
|
|
} |
|
7386
|
1
|
|
|
|
|
9
|
return $s; |
|
7387
|
|
|
|
|
|
|
} |
|
7388
|
|
|
|
|
|
|
|
|
7389
|
29
|
50
|
|
|
|
6651
|
$n = tobigint($n) unless ref($n); |
|
7390
|
29
|
|
|
|
|
121
|
my $refn = ref($n); |
|
7391
|
29
|
|
|
|
|
64
|
my $s; |
|
7392
|
|
|
|
|
|
|
|
|
7393
|
29
|
50
|
|
|
|
179
|
if ($refn eq 'Math::GMPz') { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
7394
|
0
|
|
|
|
|
0
|
$s = Math::GMPz::Rmpz_get_str($n,$base); |
|
7395
|
|
|
|
|
|
|
} elsif ($refn eq 'Math::GMP') { |
|
7396
|
0
|
|
|
|
|
0
|
$s = Math::GMP::get_str_gmp($n,$base); |
|
7397
|
|
|
|
|
|
|
} elsif ($BIGINTVERSION >= 1.999814) { |
|
7398
|
0
|
0
|
|
|
|
0
|
$n = Math::BigInt->new("$n") if $refn ne 'Math::BigInt'; |
|
7399
|
0
|
|
|
|
|
0
|
$s = $n->to_base($base); |
|
7400
|
|
|
|
|
|
|
} else { |
|
7401
|
29
|
50
|
|
|
|
115
|
my @d = ($n == 0) ? () : _splitdigits($n, $base, -1); |
|
7402
|
29
|
100
|
|
|
|
121
|
if ($base <= 10) { |
|
7403
|
2
|
|
|
|
|
9
|
$s = join("", @d); |
|
7404
|
|
|
|
|
|
|
} else { |
|
7405
|
27
|
50
|
|
|
|
89
|
die "Invalid base for string: $base" if $base > 36; |
|
7406
|
27
|
|
|
|
|
76
|
$s = join("", map { $_digitmap[$_] } @d); |
|
|
544
|
|
|
|
|
1654
|
|
|
7407
|
|
|
|
|
|
|
} |
|
7408
|
|
|
|
|
|
|
} |
|
7409
|
29
|
50
|
|
|
|
1406
|
if ($len > 0) { |
|
7410
|
0
|
|
|
|
|
0
|
$s = substr($s,0,$len); |
|
7411
|
0
|
0
|
|
|
|
0
|
$s = '0' x ($len-length($s)) . $s if length($s) < $len; |
|
7412
|
|
|
|
|
|
|
} |
|
7413
|
29
|
|
|
|
|
168
|
return lc($s); |
|
7414
|
|
|
|
|
|
|
} |
|
7415
|
|
|
|
|
|
|
|
|
7416
|
|
|
|
|
|
|
sub _FastIntegerInput { |
|
7417
|
93
|
|
|
93
|
|
212
|
my($digits, $B) = @_; |
|
7418
|
93
|
50
|
|
|
|
259
|
return 0 if scalar(@$digits) == 0; |
|
7419
|
93
|
50
|
|
|
|
217
|
return $digits->[0] if scalar(@$digits) == 1; |
|
7420
|
93
|
|
|
|
|
418
|
my $L = [reverse @$digits]; |
|
7421
|
93
|
|
|
|
|
191
|
my $k = scalar(@$L); |
|
7422
|
93
|
|
|
|
|
257
|
while ($k > 1) { |
|
7423
|
326
|
|
|
|
|
568
|
my @T; |
|
7424
|
326
|
|
|
|
|
958
|
for my $i (1 .. $k>>1) { |
|
7425
|
1111
|
|
|
|
|
3225
|
my $x = $L->[2*$i-2]; |
|
7426
|
1111
|
|
|
|
|
1890
|
my $y = $L->[2*$i-1]; |
|
7427
|
1111
|
|
|
|
|
3349
|
push(@T, Maddint($x, Mmulint($B, $y))); |
|
7428
|
|
|
|
|
|
|
} |
|
7429
|
326
|
100
|
|
|
|
5030
|
push(@T, $L->[$k-1]) if ($k&1); |
|
7430
|
326
|
|
|
|
|
862
|
$L = \@T; |
|
7431
|
326
|
|
|
|
|
2024
|
$B = Mmulint($B, $B); |
|
7432
|
326
|
|
|
|
|
8242
|
$k = ($k+1) >> 1; |
|
7433
|
|
|
|
|
|
|
} |
|
7434
|
93
|
|
|
|
|
553
|
$L->[0]; |
|
7435
|
|
|
|
|
|
|
} |
|
7436
|
|
|
|
|
|
|
|
|
7437
|
|
|
|
|
|
|
sub fromdigits { |
|
7438
|
93
|
|
|
93
|
0
|
221
|
my($r, $base) = @_; |
|
7439
|
93
|
50
|
|
|
|
248
|
$base = 10 unless defined $base; |
|
7440
|
93
|
|
|
|
|
237
|
my $refr = ref($r); |
|
7441
|
|
|
|
|
|
|
|
|
7442
|
93
|
100
|
66
|
|
|
399
|
if ($refr && $refr !~ /^Math::/) { |
|
7443
|
77
|
50
|
|
|
|
183
|
croak "fromdigits: first argument must be a string or array reference" |
|
7444
|
|
|
|
|
|
|
unless $refr eq 'ARRAY'; |
|
7445
|
|
|
|
|
|
|
# Math::BigInt->from_base_num is identical but slower |
|
7446
|
77
|
|
|
|
|
219
|
return _FastIntegerInput($r,$base); |
|
7447
|
|
|
|
|
|
|
} |
|
7448
|
|
|
|
|
|
|
|
|
7449
|
16
|
|
|
|
|
53
|
my $n; |
|
7450
|
16
|
|
|
|
|
158
|
$r =~ s/^0*//; |
|
7451
|
16
|
50
|
|
|
|
66
|
return 0 if $r eq ""; |
|
7452
|
|
|
|
|
|
|
{ # Validate string |
|
7453
|
16
|
|
|
|
|
55
|
my $cmap = substr("0123456789abcdefghijklmnopqrstuvwxyz",0,$base); |
|
|
16
|
|
|
|
|
57
|
|
|
7454
|
16
|
50
|
|
|
|
321
|
croak "Invalid digit for base $base" if $r =~ /[^$cmap]/i; |
|
7455
|
|
|
|
|
|
|
} |
|
7456
|
16
|
50
|
66
|
|
|
162
|
if (defined $_BIGINT && $_BIGINT =~ /^Math::(GMPz|GMP)$/) { |
|
|
|
50
|
|
|
|
|
|
|
7457
|
0
|
|
|
|
|
0
|
$n = $_BIGINT->new($r, $base); |
|
7458
|
|
|
|
|
|
|
} elsif ($BIGINTVERSION < 1.999814) { |
|
7459
|
16
|
|
|
|
|
246
|
$n=_FastIntegerInput([map{index("0123456789abcdefghijklmnopqrstuvwxyz",$_)}split(//,lc($r))],$base); |
|
|
820
|
|
|
|
|
1685
|
|
|
7460
|
|
|
|
|
|
|
} else { |
|
7461
|
|
|
|
|
|
|
# from_base is 2x slower than calling the method directly (TODO file an RT) |
|
7462
|
0
|
0
|
|
|
|
0
|
if ($base == 2) { $n = Math::BigInt->from_bin($r); } |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
7463
|
0
|
|
|
|
|
0
|
elsif ($base == 8) { $n = Math::BigInt->from_oct($r); } |
|
7464
|
0
|
|
|
|
|
0
|
elsif ($base == 10) { $n = Math::BigInt->new($r); } |
|
7465
|
0
|
|
|
|
|
0
|
elsif ($base == 16) { $n = Math::BigInt->from_hex($r); } |
|
7466
|
0
|
|
|
|
|
0
|
else { $n = Math::BigInt->from_base($r,$base); } |
|
7467
|
0
|
0
|
0
|
|
|
0
|
$n = tobigint($n) if defined $_BIGINT && $_BIGINT ne 'Math::BigInt'; |
|
7468
|
|
|
|
|
|
|
} |
|
7469
|
16
|
100
|
|
|
|
277
|
return $n <= INTMAX ? _bigint_to_int($n) : $n; |
|
7470
|
|
|
|
|
|
|
} |
|
7471
|
|
|
|
|
|
|
|
|
7472
|
|
|
|
|
|
|
sub _validate_zeckendorf { |
|
7473
|
2
|
|
|
2
|
|
6
|
my($s) = @_; |
|
7474
|
2
|
50
|
|
|
|
11
|
if ($s ne '0') { |
|
7475
|
2
|
50
|
|
|
|
15
|
croak "fromzeckendorf: expected binary string" |
|
7476
|
|
|
|
|
|
|
unless $s =~ /^1[01]*\z/; |
|
7477
|
2
|
50
|
|
|
|
10
|
croak "fromzeckendorf: expected binary string in canonical Zeckendorf form" |
|
7478
|
|
|
|
|
|
|
if $s =~ /11/; |
|
7479
|
|
|
|
|
|
|
} |
|
7480
|
2
|
|
|
|
|
5
|
1; |
|
7481
|
|
|
|
|
|
|
} |
|
7482
|
|
|
|
|
|
|
|
|
7483
|
|
|
|
|
|
|
sub fromzeckendorf { |
|
7484
|
2
|
|
|
2
|
0
|
4140
|
my($s) = @_; |
|
7485
|
2
|
|
|
|
|
10
|
_validate_zeckendorf($s); |
|
7486
|
|
|
|
|
|
|
|
|
7487
|
2
|
|
|
|
|
5
|
my($n, $fb, $fc) = (0, 1, 1); |
|
7488
|
2
|
|
|
|
|
39
|
for my $c (split(//,reverse $s)) { |
|
7489
|
153
|
100
|
|
|
|
13268
|
$n = Maddint($n,$fc) if $c eq '1'; |
|
7490
|
153
|
|
|
|
|
5676
|
($fb, $fc) = ($fc, Maddint($fb,$fc)); |
|
7491
|
|
|
|
|
|
|
} |
|
7492
|
2
|
|
|
|
|
355
|
$n; |
|
7493
|
|
|
|
|
|
|
} |
|
7494
|
|
|
|
|
|
|
|
|
7495
|
|
|
|
|
|
|
sub tozeckendorf { |
|
7496
|
2
|
|
|
2
|
0
|
11
|
my($n) = @_; |
|
7497
|
2
|
|
|
|
|
25
|
validate_integer_nonneg($n); |
|
7498
|
2
|
50
|
|
|
|
9
|
return '0' if $n == 0; |
|
7499
|
|
|
|
|
|
|
|
|
7500
|
2
|
|
|
|
|
274
|
my($rn, $s, $fa, $fb, $fc) = ($n, '', 0, 1, 1); |
|
7501
|
2
|
|
|
|
|
31
|
my($i, $k); |
|
7502
|
2
|
|
|
|
|
11
|
for ($k = 2; $fc <= $rn; $k++) { |
|
7503
|
153
|
|
|
|
|
30428
|
($fa, $fb, $fc) = ($fb, $fc, Maddint($fb,$fc)); |
|
7504
|
|
|
|
|
|
|
} |
|
7505
|
2
|
|
|
|
|
183
|
for ($i = $k-1; $i >= 2; $i--) { |
|
7506
|
153
|
|
|
|
|
291
|
($fc, $fb, $fa) = ($fb, $fa, Msubint($fb,$fa)); |
|
7507
|
153
|
100
|
|
|
|
7720
|
if ($fc <= $rn) { |
|
7508
|
48
|
|
|
|
|
698
|
$rn = Msubint($rn, $fc); |
|
7509
|
48
|
|
|
|
|
3174
|
$s .= '1'; |
|
7510
|
|
|
|
|
|
|
} else { |
|
7511
|
105
|
|
|
|
|
1123
|
$s .= '0'; |
|
7512
|
|
|
|
|
|
|
} |
|
7513
|
|
|
|
|
|
|
} |
|
7514
|
|
|
|
|
|
|
# croak "wrong tozeckendorf $n" unless $n == fromzeckendorf($s); |
|
7515
|
2
|
|
|
|
|
21
|
$s; |
|
7516
|
|
|
|
|
|
|
} |
|
7517
|
|
|
|
|
|
|
|
|
7518
|
|
|
|
|
|
|
|
|
7519
|
|
|
|
|
|
|
sub sqrtint { |
|
7520
|
2212
|
|
|
2212
|
0
|
10642
|
my($n) = @_; |
|
7521
|
2212
|
|
|
|
|
6439
|
validate_integer_nonneg($n); |
|
7522
|
2212
|
100
|
|
|
|
15501
|
return int(sqrt("$n")) if $n <= 562949953421312; # 2^49 safe everywhere |
|
7523
|
|
|
|
|
|
|
|
|
7524
|
61
|
|
|
|
|
13950
|
my $refn = ref($n); |
|
7525
|
61
|
|
|
|
|
165
|
my $R; |
|
7526
|
|
|
|
|
|
|
|
|
7527
|
61
|
100
|
|
|
|
293
|
if ($refn eq 'Math::BigInt') { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
7528
|
58
|
|
|
|
|
233
|
$R = $n->copy->bsqrt; |
|
7529
|
|
|
|
|
|
|
} elsif ($refn eq 'Math::GMPz') { |
|
7530
|
0
|
|
|
|
|
0
|
$R = Math::GMPz->new(); |
|
7531
|
0
|
|
|
|
|
0
|
Math::GMPz::Rmpz_sqrt($R, $n); |
|
7532
|
|
|
|
|
|
|
} elsif ($refn eq 'Math::GMP') { |
|
7533
|
0
|
|
|
|
|
0
|
$R = $n->bsqrt(); |
|
7534
|
|
|
|
|
|
|
} else { |
|
7535
|
3
|
|
|
|
|
71
|
$R = Math::BigInt->new("$n")->bsqrt; |
|
7536
|
|
|
|
|
|
|
} |
|
7537
|
61
|
100
|
|
|
|
89465
|
$R = _bigint_to_int($R) if $R <= INTMAX; |
|
7538
|
61
|
|
|
|
|
4543
|
$R; |
|
7539
|
|
|
|
|
|
|
} |
|
7540
|
|
|
|
|
|
|
|
|
7541
|
|
|
|
|
|
|
sub rootint { |
|
7542
|
9724
|
|
|
9724
|
0
|
33450
|
my ($n, $k, $refp) = @_; |
|
7543
|
9724
|
|
|
|
|
36069
|
validate_integer_nonneg($n); |
|
7544
|
9724
|
|
|
|
|
230550
|
validate_integer_positive($k); |
|
7545
|
9724
|
50
|
66
|
|
|
34973
|
croak("rootint: third argument not a scalar reference") if defined $refp && !ref($refp); |
|
7546
|
|
|
|
|
|
|
|
|
7547
|
9724
|
100
|
|
|
|
21966
|
if ($k == 1) { |
|
7548
|
75
|
50
|
|
|
|
234
|
$$refp = $n if defined $refp; |
|
7549
|
75
|
|
|
|
|
312
|
return $n; |
|
7550
|
|
|
|
|
|
|
} |
|
7551
|
9649
|
100
|
|
|
|
31645
|
if (!ref($n)) { # native integer |
|
7552
|
5886
|
50
|
|
|
|
12350
|
if ($n == 0) { |
|
7553
|
0
|
0
|
|
|
|
0
|
$$refp = 0 if defined $refp; |
|
7554
|
0
|
|
|
|
|
0
|
return 0; |
|
7555
|
|
|
|
|
|
|
} |
|
7556
|
5886
|
100
|
100
|
|
|
13186
|
if ($k == 2 && $n <= 562949953421312) { |
|
7557
|
559
|
|
|
|
|
1190
|
my $R = int(sqrt($n)); |
|
7558
|
559
|
100
|
|
|
|
1279
|
$$refp = $R*$R if defined $refp; |
|
7559
|
559
|
|
|
|
|
1364
|
return $R; |
|
7560
|
|
|
|
|
|
|
} |
|
7561
|
5327
|
100
|
66
|
|
|
18598
|
if ($k >= MPU_MAXBITS || $n >> $k == 0) { |
|
7562
|
675
|
100
|
|
|
|
1526
|
$$refp = 1 if defined $refp; |
|
7563
|
675
|
|
|
|
|
1389
|
return 1; |
|
7564
|
|
|
|
|
|
|
} |
|
7565
|
4652
|
|
|
|
|
14431
|
my $R = int($n ** (1/$k)); # Could be off by +/-1. |
|
7566
|
4652
|
100
|
|
|
|
10101
|
my $F = $n <= 562949953421312 ? $R**$k : powint($R,$k); |
|
7567
|
4652
|
50
|
|
|
|
7945
|
if ($F > $n) { |
|
7568
|
0
|
|
|
|
|
0
|
$R--; |
|
7569
|
0
|
0
|
|
|
|
0
|
$F = $n <= 562949953421312 ? $R**$k : powint($R,$k); |
|
7570
|
|
|
|
|
|
|
} else { |
|
7571
|
4652
|
100
|
|
|
|
10440
|
my $F1 = $n <= 562949953421312 ? ($R+1)**$k : powint($R+1,$k); |
|
7572
|
4652
|
100
|
|
|
|
20459
|
if ($F1 <= $n) { |
|
7573
|
24
|
|
|
|
|
43
|
$R++; |
|
7574
|
24
|
|
|
|
|
42
|
$F = $F1; |
|
7575
|
|
|
|
|
|
|
} |
|
7576
|
|
|
|
|
|
|
} |
|
7577
|
4652
|
100
|
|
|
|
10461
|
$$refp = $F if defined $refp; |
|
7578
|
4652
|
|
|
|
|
11380
|
return $R; |
|
7579
|
|
|
|
|
|
|
} |
|
7580
|
|
|
|
|
|
|
|
|
7581
|
|
|
|
|
|
|
# It's unclear whether we should add GMPfunc here. We want it in logint |
|
7582
|
|
|
|
|
|
|
# because it's slow or not included in Perl bigint classes. |
|
7583
|
|
|
|
|
|
|
|
|
7584
|
3763
|
|
|
|
|
7690
|
my $refn = ref($n); |
|
7585
|
3763
|
|
|
|
|
7247
|
my $R; |
|
7586
|
3763
|
50
|
|
|
|
10499
|
if ($refn eq 'Math::BigInt') { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
7587
|
3763
|
|
|
|
|
13856
|
$R = $n->copy->broot($k); |
|
7588
|
|
|
|
|
|
|
} elsif ($refn eq 'Math::GMPz') { |
|
7589
|
0
|
|
|
|
|
0
|
$R = Math::GMPz->new(); |
|
7590
|
0
|
|
|
|
|
0
|
Math::GMPz::Rmpz_root($R, $n, $k); |
|
7591
|
|
|
|
|
|
|
} elsif ($refn eq 'Math::GMP') { |
|
7592
|
0
|
|
|
|
|
0
|
$R = $n->broot($k); |
|
7593
|
|
|
|
|
|
|
} else { |
|
7594
|
0
|
|
|
|
|
0
|
$R = Math::BigInt->new("$n")->broot($k); |
|
7595
|
|
|
|
|
|
|
} |
|
7596
|
3763
|
100
|
|
|
|
9657904
|
$R = _bigint_to_int($R) if $R <= INTMAX; |
|
7597
|
3763
|
100
|
|
|
|
517493
|
$$refp = Mpowint($R,$k) if defined $refp; |
|
7598
|
3763
|
|
|
|
|
754159
|
$R; |
|
7599
|
|
|
|
|
|
|
} |
|
7600
|
|
|
|
|
|
|
|
|
7601
|
|
|
|
|
|
|
sub _logint { |
|
7602
|
4868
|
|
|
4868
|
|
8632
|
my($n,$b) = @_; |
|
7603
|
4868
|
50
|
|
|
|
8565
|
return 0 if $n < $b; |
|
7604
|
4868
|
100
|
|
|
|
92494
|
return length("$n")-1 if $b == 10; |
|
7605
|
4867
|
100
|
|
|
|
8423
|
if ($n < INTMAX) { |
|
7606
|
4484
|
100
|
|
|
|
14325
|
return length(sprintf("%b",$n))-1 if $b == 2; |
|
7607
|
5
|
50
|
|
|
|
26
|
return length(sprintf("%o",$n))-1 if $b == 8; |
|
7608
|
5
|
50
|
|
|
|
18
|
return length(sprintf("%x",$n))-1 if $b == 16; |
|
7609
|
|
|
|
|
|
|
} |
|
7610
|
388
|
|
|
|
|
86029
|
my $l; |
|
7611
|
388
|
50
|
|
|
|
1297
|
if (length("$n") > 150) { |
|
7612
|
|
|
|
|
|
|
# Reduce size so native log works |
|
7613
|
0
|
|
|
|
|
0
|
my $N = substr($n,0,80); |
|
7614
|
0
|
|
|
|
|
0
|
my $reddigits = length("$n") - length($N); |
|
7615
|
0
|
|
|
|
|
0
|
$l = log($N) + 2.302585092994045684*$reddigits; |
|
7616
|
|
|
|
|
|
|
} else { |
|
7617
|
388
|
|
|
|
|
18954
|
$l = log("$n"); |
|
7618
|
|
|
|
|
|
|
} |
|
7619
|
388
|
|
|
|
|
17807
|
$l /= log($b); |
|
7620
|
|
|
|
|
|
|
|
|
7621
|
|
|
|
|
|
|
# Just in case something failed, escape via using Math::BigInt's blog |
|
7622
|
388
|
50
|
33
|
|
|
2691
|
if ($l == MPU_INFINITY || !defined($l<=>MPU_INFINITY)) { |
|
7623
|
0
|
|
|
|
|
0
|
my $R = Math::BigInt->new("$n")->copy->blog($b); |
|
7624
|
0
|
0
|
|
|
|
0
|
$R = _bigint_to_int($R) if $R <= INTMAX; |
|
7625
|
0
|
|
|
|
|
0
|
return $R; |
|
7626
|
|
|
|
|
|
|
} |
|
7627
|
|
|
|
|
|
|
|
|
7628
|
388
|
|
|
|
|
2889
|
my $R = int($l); |
|
7629
|
388
|
100
|
66
|
|
|
2653
|
if ($R != int($l+1e-7) || $R != int($l-1e-7)) { |
|
7630
|
9
|
|
|
|
|
892
|
my $BR = Mpowint($b,$R); |
|
7631
|
9
|
50
|
|
|
|
2310
|
if ($BR > $n) { |
|
|
|
100
|
|
|
|
|
|
|
7632
|
0
|
|
|
|
|
0
|
$R--; |
|
7633
|
|
|
|
|
|
|
} elsif ($BR < $n) { |
|
7634
|
7
|
|
|
|
|
817
|
my $BRB = Mmulint($BR, $b); |
|
7635
|
7
|
50
|
|
|
|
1832
|
$R++ if $BRB <= $n; |
|
7636
|
|
|
|
|
|
|
} |
|
7637
|
|
|
|
|
|
|
} |
|
7638
|
388
|
|
|
|
|
1772
|
$R; |
|
7639
|
|
|
|
|
|
|
} |
|
7640
|
|
|
|
|
|
|
|
|
7641
|
|
|
|
|
|
|
sub logint { |
|
7642
|
4868
|
|
|
4868
|
0
|
14427
|
my ($n, $b, $refp) = @_; |
|
7643
|
4868
|
|
|
|
|
12095
|
validate_integer_positive($n); |
|
7644
|
4868
|
|
|
|
|
31177
|
validate_integer_nonneg($b); |
|
7645
|
4868
|
50
|
|
|
|
9867
|
croak "logint: base must be > 1" if $b <= 1; |
|
7646
|
4868
|
50
|
66
|
|
|
10751
|
croak("logint third argument not a scalar reference") if defined($refp) && !ref($refp); |
|
7647
|
|
|
|
|
|
|
|
|
7648
|
4868
|
50
|
|
|
|
9049
|
if ($Math::Prime::Util::_GMPfunc{"logint"}) { |
|
7649
|
0
|
|
|
|
|
0
|
my $e = Math::Prime::Util::GMP::logint($n, $b); |
|
7650
|
0
|
0
|
|
|
|
0
|
if (defined $refp) { |
|
7651
|
|
|
|
|
|
|
# logint in 0.47, powmod in 0.36, powint in 0.52 |
|
7652
|
0
|
|
|
|
|
0
|
my $r = Math::Prime::Util::GMP::powmod($b, $e, $n); |
|
7653
|
0
|
0
|
|
|
|
0
|
$r = $n if $r == 0; |
|
7654
|
0
|
|
|
|
|
0
|
$$refp = reftyped($_[0], $r); |
|
7655
|
|
|
|
|
|
|
} |
|
7656
|
0
|
|
|
|
|
0
|
return reftyped($_[0], $e); |
|
7657
|
|
|
|
|
|
|
} |
|
7658
|
|
|
|
|
|
|
|
|
7659
|
4868
|
|
|
|
|
10939
|
my $log = _logint($n,$b); |
|
7660
|
4868
|
100
|
|
|
|
16531
|
$$refp = Mpowint($b,$log) if defined $refp; |
|
7661
|
4868
|
|
|
|
|
9715
|
return $log; |
|
7662
|
|
|
|
|
|
|
} |
|
7663
|
|
|
|
|
|
|
|
|
7664
|
|
|
|
|
|
|
# Seidel (Luschny), core using Trizen's simplications from Math::AnyNum. |
|
7665
|
|
|
|
|
|
|
# http://oeis.org/wiki/User:Peter_Luschny/ComputationAndAsymptoticsOfBernoulliNumbers#Bernoulli_numbers__after_Seidel |
|
7666
|
|
|
|
|
|
|
sub _bernoulli_seidel { |
|
7667
|
22
|
|
|
22
|
|
50
|
my($n) = @_; |
|
7668
|
22
|
50
|
|
|
|
79
|
return (1,1) if $n == 0; |
|
7669
|
22
|
50
|
33
|
|
|
145
|
return (0,1) if $n > 1 && $n % 2; |
|
7670
|
|
|
|
|
|
|
|
|
7671
|
22
|
|
|
|
|
116
|
my @D = (0, 1, map { 0} 1 .. ($n>>1)-1); |
|
|
421
|
|
|
|
|
573
|
|
|
7672
|
22
|
|
|
|
|
68
|
my ($h, $w) = (1, 1); |
|
7673
|
|
|
|
|
|
|
|
|
7674
|
22
|
|
|
|
|
76
|
foreach my $i (0 .. $n-1) { |
|
7675
|
886
|
100
|
|
|
|
57442
|
if ($w ^= 1) { |
|
7676
|
443
|
|
|
|
|
3941
|
$D[$_] = Maddint($D[$_],$D[$_-1]) for 1.. $h-1; |
|
7677
|
|
|
|
|
|
|
} else { |
|
7678
|
443
|
|
|
|
|
703
|
$w = $h++; |
|
7679
|
443
|
|
|
|
|
3689
|
$D[$w] = Maddint($D[$w],$D[$w+1]) while --$w; |
|
7680
|
|
|
|
|
|
|
} |
|
7681
|
|
|
|
|
|
|
} |
|
7682
|
22
|
|
|
|
|
3311
|
my $num = $D[$h-1]; |
|
7683
|
22
|
|
|
|
|
153
|
my $den = Msubint(Mpowint(2,$n+1),2); |
|
7684
|
22
|
|
|
|
|
185
|
my $gcd = Mgcd($num,$den); |
|
7685
|
22
|
100
|
|
|
|
110
|
($num,$den) = map { Mdivint($_,$gcd) } ($num,$den) if $gcd > 1; |
|
|
42
|
|
|
|
|
184
|
|
|
7686
|
22
|
100
|
|
|
|
111
|
$num = Mnegint($num) if ($n % 4) == 0; |
|
7687
|
22
|
|
|
|
|
1674
|
($num,$den); |
|
7688
|
|
|
|
|
|
|
} |
|
7689
|
|
|
|
|
|
|
|
|
7690
|
|
|
|
|
|
|
sub bernfrac { |
|
7691
|
26
|
|
|
26
|
0
|
4341
|
my($n) = @_; |
|
7692
|
26
|
|
|
|
|
106
|
validate_integer_nonneg($n); |
|
7693
|
26
|
100
|
|
|
|
105
|
return (1,1) if $n == 0; |
|
7694
|
25
|
100
|
|
|
|
73
|
return (1,2) if $n == 1; # We're choosing 1/2 instead of -1/2 |
|
7695
|
24
|
100
|
66
|
|
|
187
|
return (0,1) if $n < 0 || $n & 1; |
|
7696
|
|
|
|
|
|
|
|
|
7697
|
|
|
|
|
|
|
# We should have used one of the GMP functions before coming here. |
|
7698
|
|
|
|
|
|
|
|
|
7699
|
22
|
|
|
|
|
69
|
_bernoulli_seidel($n); |
|
7700
|
|
|
|
|
|
|
} |
|
7701
|
|
|
|
|
|
|
|
|
7702
|
|
|
|
|
|
|
sub stirling { |
|
7703
|
184
|
|
|
184
|
0
|
98820
|
my($n, $m, $type) = @_; |
|
7704
|
184
|
100
|
|
|
|
670
|
return 1 if $m == $n; |
|
7705
|
181
|
50
|
33
|
|
|
1582
|
return 0 if $n == 0 || $m == 0 || $m > $n; |
|
|
|
|
33
|
|
|
|
|
|
7706
|
181
|
100
|
|
|
|
644
|
$type = 1 unless defined $type; |
|
7707
|
181
|
50
|
100
|
|
|
1048
|
croak "stirling type must be 1, 2, or 3" unless $type == 1 || $type == 2 || $type == 3; |
|
|
|
|
66
|
|
|
|
|
|
7708
|
181
|
100
|
|
|
|
677
|
if ($m == 1) { |
|
7709
|
3
|
50
|
|
|
|
13
|
return 1 if $type == 2; |
|
7710
|
0
|
0
|
|
|
|
0
|
return Mfactorial($n) if $type == 3; |
|
7711
|
0
|
0
|
|
|
|
0
|
return Mfactorial($n-1) if $n & 1; |
|
7712
|
0
|
|
|
|
|
0
|
return Mvecprod(-1, Mfactorial($n-1)); |
|
7713
|
|
|
|
|
|
|
} |
|
7714
|
|
|
|
|
|
|
return reftyped($_[0], Math::Prime::Util::GMP::stirling($n,$m,$type)) |
|
7715
|
178
|
50
|
|
|
|
630
|
if $Math::Prime::Util::_GMPfunc{"stirling"}; |
|
7716
|
|
|
|
|
|
|
# Go through vecsum with quoted negatives to make sure we don't overflow. |
|
7717
|
178
|
|
|
|
|
392
|
my $s; |
|
7718
|
178
|
100
|
|
|
|
752
|
if ($type == 3) { |
|
|
|
100
|
|
|
|
|
|
|
7719
|
5
|
|
|
|
|
519
|
$s = Mvecprod( Mbinomial($n,$m), Mbinomial($n-1,$m-1), Mfactorial($n-$m) ); |
|
7720
|
|
|
|
|
|
|
} elsif ($type == 2) { |
|
7721
|
125
|
100
|
|
|
|
487
|
return Mbinomial($n,2) if $m==$n-1; |
|
7722
|
116
|
|
|
|
|
245
|
my @terms; |
|
7723
|
116
|
|
|
|
|
381
|
for my $j (1 .. $m) { |
|
7724
|
2791
|
|
|
|
|
209250
|
my $t = Mmulint( |
|
7725
|
|
|
|
|
|
|
Mpowint($j,$n), |
|
7726
|
|
|
|
|
|
|
Mbinomial($m,$j) |
|
7727
|
|
|
|
|
|
|
); |
|
7728
|
2791
|
100
|
|
|
|
591576
|
$t = Mnegint($t) if ($m-$j) & 1; |
|
7729
|
2791
|
|
|
|
|
174908
|
push @terms, $t; |
|
7730
|
|
|
|
|
|
|
} |
|
7731
|
116
|
|
|
|
|
743
|
$s = Mdivint(vecsum(@terms),Mfactorial($m)); |
|
7732
|
|
|
|
|
|
|
} else { |
|
7733
|
48
|
|
|
|
|
134
|
my $M = $n-$m; |
|
7734
|
|
|
|
|
|
|
# Both work on all inputs, but perform differently. Select one. |
|
7735
|
48
|
100
|
100
|
|
|
128
|
if ($n <= 21 || $m < $M) { # Simple direct (see Arndt) |
|
7736
|
47
|
|
|
|
|
199
|
my @S = (0)x($n+1); |
|
7737
|
47
|
|
|
|
|
94
|
$S[1]=1; |
|
7738
|
47
|
|
|
|
|
123
|
for my $k (2 .. $n) { |
|
7739
|
979
|
|
|
|
|
63491
|
$S[$_] = addint($S[$_-1],mulint($k-1,$S[$_])) for reverse(1..$k); |
|
7740
|
|
|
|
|
|
|
} |
|
7741
|
47
|
|
|
|
|
3712
|
$s = $S[$m]; |
|
7742
|
|
|
|
|
|
|
} else { # Concrete Mathematics, eq 6.27 |
|
7743
|
1
|
|
|
|
|
7
|
my @terms = map { Mvecprod( Mbinomial($M-$n, $M+$_), |
|
|
65
|
|
|
|
|
5963
|
|
|
7744
|
|
|
|
|
|
|
Mbinomial($M+$n, $M-$_), |
|
7745
|
|
|
|
|
|
|
Mstirling($M+$_, $_, 2) ) } 1 .. $M; |
|
7746
|
1
|
|
|
|
|
13
|
$s = vecsum(@terms); |
|
7747
|
|
|
|
|
|
|
} |
|
7748
|
48
|
100
|
|
|
|
204
|
$s = Mnegint($s) if is_odd($n-$m); |
|
7749
|
|
|
|
|
|
|
} |
|
7750
|
169
|
|
|
|
|
3723
|
$s; |
|
7751
|
|
|
|
|
|
|
} |
|
7752
|
|
|
|
|
|
|
|
|
7753
|
|
|
|
|
|
|
sub _harmonic_split { # From Fredrik Johansson |
|
7754
|
144
|
|
|
144
|
|
222
|
my($a,$b) = @_; |
|
7755
|
144
|
100
|
|
|
|
264
|
return (1, $a) if $b-$a == 1; |
|
7756
|
119
|
100
|
|
|
|
324
|
return (Mvecsum($a,$a,1), Maddint(Mmulint($a,$a),$a)) if $b-$a == 2; |
|
7757
|
68
|
|
|
|
|
180
|
my $m = Mrshiftint(Maddint($a,$b)); |
|
7758
|
68
|
|
|
|
|
155
|
my ($p,$q) = _harmonic_split($a, $m); |
|
7759
|
68
|
|
|
|
|
275
|
my ($r,$s) = _harmonic_split($m, $b); |
|
7760
|
68
|
|
|
|
|
869
|
(Maddint(Mmulint($p,$s),Mmulint($q,$r)), Mmulint($q,$s)); |
|
7761
|
|
|
|
|
|
|
} |
|
7762
|
|
|
|
|
|
|
|
|
7763
|
|
|
|
|
|
|
sub harmfrac { |
|
7764
|
9
|
|
|
9
|
0
|
13242
|
my($n) = @_; |
|
7765
|
9
|
|
|
|
|
34
|
validate_integer_nonneg($n); |
|
7766
|
9
|
100
|
|
|
|
29
|
return (0,1) if $n <= 0; |
|
7767
|
8
|
|
|
|
|
31
|
my($p,$q) = _harmonic_split(1, Madd1int($n)); |
|
7768
|
8
|
|
|
|
|
409
|
my $gcd = Mgcd($p,$q); |
|
7769
|
8
|
100
|
|
|
|
32
|
($p,$q) = map { Mdivint($_,$gcd) } ($p,$q) if $gcd > 1; |
|
|
10
|
|
|
|
|
551
|
|
|
7770
|
8
|
|
|
|
|
88
|
($p,$q); |
|
7771
|
|
|
|
|
|
|
} |
|
7772
|
|
|
|
|
|
|
|
|
7773
|
|
|
|
|
|
|
sub harmreal { |
|
7774
|
22
|
|
|
22
|
0
|
34
|
my($n, $precision) = @_; |
|
7775
|
|
|
|
|
|
|
|
|
7776
|
22
|
50
|
|
|
|
42
|
do { require Math::BigFloat; Math::BigFloat->import(); } unless defined $Math::BigFloat::VERSION; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
7777
|
22
|
50
|
|
|
|
36
|
return Math::BigFloat->bzero if $n <= 0; |
|
7778
|
|
|
|
|
|
|
|
|
7779
|
|
|
|
|
|
|
# Use asymptotic formula for larger $n if possible. Saves lots of time if |
|
7780
|
|
|
|
|
|
|
# the default Calc backend is being used. |
|
7781
|
|
|
|
|
|
|
{ |
|
7782
|
22
|
|
|
|
|
24
|
my $sprec = $precision; |
|
|
22
|
|
|
|
|
26
|
|
|
7783
|
22
|
50
|
|
|
|
65
|
$sprec = Math::BigFloat->precision unless defined $sprec; |
|
7784
|
22
|
50
|
|
|
|
238
|
$sprec = 40 unless defined $sprec; |
|
7785
|
22
|
50
|
33
|
|
|
213
|
if ( ($sprec <= 23 && $n > 54) || |
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
7786
|
|
|
|
|
|
|
($sprec <= 30 && $n > 348) || |
|
7787
|
|
|
|
|
|
|
($sprec <= 40 && $n > 2002) || |
|
7788
|
|
|
|
|
|
|
($sprec <= 50 && $n > 12644) ) { |
|
7789
|
0
|
|
|
|
|
0
|
$n = Math::BigFloat->new($n, $sprec+5); |
|
7790
|
0
|
|
|
|
|
0
|
my($n2, $one, $h) = ($n*$n, Math::BigFloat->bone, Math::BigFloat->bzero); |
|
7791
|
0
|
|
|
|
|
0
|
my $nt = $n2; |
|
7792
|
0
|
|
|
|
|
0
|
my $eps = Math::BigFloat->new(10)->bpow(-$sprec-4); |
|
7793
|
0
|
|
|
|
|
0
|
foreach my $d (-12, 120, -252, 240, -132, 32760, -12, 8160, -14364, 6600, -276, 65520, -12) { # OEIS A006593 |
|
7794
|
0
|
|
|
|
|
0
|
my $term = $one/($d * $nt); |
|
7795
|
0
|
0
|
|
|
|
0
|
last if $term->bacmp($eps) < 0; |
|
7796
|
0
|
|
|
|
|
0
|
$h += $term; |
|
7797
|
0
|
|
|
|
|
0
|
$nt *= $n2; |
|
7798
|
|
|
|
|
|
|
} |
|
7799
|
0
|
|
|
|
|
0
|
$h->badd(scalar $one->copy->bdiv(2*$n)); |
|
7800
|
0
|
|
|
|
|
0
|
$h->badd(_Euler($sprec)); |
|
7801
|
0
|
|
|
|
|
0
|
$h->badd($n->copy->blog); |
|
7802
|
0
|
|
|
|
|
0
|
$h->round($sprec); |
|
7803
|
0
|
|
|
|
|
0
|
return $h; |
|
7804
|
|
|
|
|
|
|
} |
|
7805
|
|
|
|
|
|
|
} |
|
7806
|
|
|
|
|
|
|
|
|
7807
|
22
|
|
|
|
|
172
|
my($num,$den) = Math::Prime::Util::harmfrac($n); |
|
7808
|
|
|
|
|
|
|
# Note, with Calc backend this can be very, very slow |
|
7809
|
22
|
|
|
|
|
86
|
scalar Math::BigFloat->new($num)->bdiv($den, $precision); |
|
7810
|
|
|
|
|
|
|
} |
|
7811
|
|
|
|
|
|
|
|
|
7812
|
|
|
|
|
|
|
sub is_pseudoprime { |
|
7813
|
86
|
|
|
86
|
0
|
404
|
my($n, @bases) = @_; |
|
7814
|
86
|
|
|
|
|
617
|
validate_integer($n); |
|
7815
|
86
|
50
|
|
|
|
4033
|
return 0 if $n < 0; |
|
7816
|
86
|
50
|
|
|
|
17327
|
@bases = (2) if scalar(@bases) == 0; |
|
7817
|
86
|
50
|
|
|
|
281
|
return 0+($n >= 2) if $n < 3; |
|
7818
|
|
|
|
|
|
|
|
|
7819
|
86
|
|
|
|
|
16707
|
foreach my $a (@bases) { |
|
7820
|
86
|
50
|
|
|
|
344
|
croak "Base $a is invalid" if $a < 2; |
|
7821
|
86
|
50
|
|
|
|
343
|
$a = $a % $n if $a >= $n; |
|
7822
|
86
|
100
|
66
|
|
|
11167
|
return 0 unless $a == 1 || Mpowmod($a, $n-1, $n) == 1; |
|
7823
|
|
|
|
|
|
|
} |
|
7824
|
20
|
|
|
|
|
1280
|
1; |
|
7825
|
|
|
|
|
|
|
} |
|
7826
|
|
|
|
|
|
|
|
|
7827
|
|
|
|
|
|
|
sub is_euler_pseudoprime { |
|
7828
|
1
|
|
|
1
|
0
|
1310
|
my($n, @bases) = @_; |
|
7829
|
1
|
|
|
|
|
8
|
validate_integer($n); |
|
7830
|
1
|
50
|
|
|
|
4
|
return 0 if $n < 0; |
|
7831
|
1
|
50
|
|
|
|
3
|
@bases = (2) if scalar(@bases) == 0; |
|
7832
|
1
|
50
|
|
|
|
3
|
return 0+($n >= 2) if $n < 3; |
|
7833
|
1
|
50
|
|
|
|
4
|
return 0 if ($n % 2) == 0; |
|
7834
|
|
|
|
|
|
|
|
|
7835
|
1
|
|
|
|
|
2
|
foreach my $a (@bases) { |
|
7836
|
1
|
50
|
|
|
|
3
|
croak "Base $a is invalid" if $a < 2; |
|
7837
|
1
|
50
|
|
|
|
4
|
$a = $a % $n if $a >= $n; |
|
7838
|
1
|
|
|
|
|
15
|
my $j = Mkronecker($a, $n); |
|
7839
|
1
|
50
|
|
|
|
5
|
return 0 if $j == 0; # gcd(a,n) != 1 |
|
7840
|
1
|
50
|
|
|
|
9
|
$j = ($j > 0) ? 1 : $n-1; |
|
7841
|
1
|
50
|
|
|
|
50
|
return 0 unless Mpowmod($a, ($n-1)>>1, $n) == $j; |
|
7842
|
|
|
|
|
|
|
} |
|
7843
|
1
|
|
|
|
|
93
|
1; |
|
7844
|
|
|
|
|
|
|
} |
|
7845
|
|
|
|
|
|
|
|
|
7846
|
|
|
|
|
|
|
sub is_euler_plumb_pseudoprime { |
|
7847
|
1
|
|
|
1
|
0
|
3
|
my($n) = @_; |
|
7848
|
1
|
|
|
|
|
4
|
validate_integer($n); |
|
7849
|
1
|
50
|
|
|
|
4
|
return 0 if $n < 0; |
|
7850
|
1
|
50
|
|
|
|
4
|
return 0+($n >= 2) if $n < 4; |
|
7851
|
1
|
50
|
|
|
|
3
|
return 0 if ($n % 2) == 0; |
|
7852
|
1
|
|
|
|
|
4
|
my $nmod8 = $n % 8; |
|
7853
|
1
|
|
|
|
|
2
|
my $exp = 1 + ($nmod8 == 1); |
|
7854
|
1
|
|
|
|
|
6
|
my $ap = Mpowmod(2, ($n-1) >> $exp, $n); |
|
7855
|
1
|
50
|
0
|
|
|
36
|
if ($ap == 1) { return ($nmod8 == 1 || $nmod8 == 7); } |
|
|
0
|
|
|
|
|
0
|
|
|
7856
|
1
|
50
|
33
|
|
|
4
|
if ($ap == $n-1) { return ($nmod8 == 1 || $nmod8 == 3 || $nmod8 == 5); } |
|
|
1
|
|
|
|
|
11
|
|
|
7857
|
0
|
|
|
|
|
0
|
0; |
|
7858
|
|
|
|
|
|
|
} |
|
7859
|
|
|
|
|
|
|
|
|
7860
|
|
|
|
|
|
|
sub _miller_rabin_2 { |
|
7861
|
3730
|
|
|
3730
|
|
26630
|
my($n, $nm1, $s, $d) = @_; |
|
7862
|
3730
|
50
|
|
|
|
7228
|
return 0 if $n < 0; |
|
7863
|
3730
|
50
|
|
|
|
102007
|
return 0+($n >= 2) if $n < 4; |
|
7864
|
3730
|
50
|
|
|
|
102602
|
return 0 if ($n % 2) == 0; |
|
7865
|
|
|
|
|
|
|
|
|
7866
|
3730
|
100
|
|
|
|
249112
|
if (ref($n)) { |
|
7867
|
|
|
|
|
|
|
|
|
7868
|
449
|
50
|
|
|
|
1864
|
if (!defined $nm1) { |
|
7869
|
449
|
|
|
|
|
3891
|
$nm1 = Msub1int($n); |
|
7870
|
449
|
|
|
|
|
108592
|
$s = valuation($nm1,2); |
|
7871
|
449
|
|
|
|
|
2593
|
$d = rshiftint($nm1,$s); |
|
7872
|
|
|
|
|
|
|
} |
|
7873
|
449
|
|
|
|
|
102448
|
my $x = _bi_powmod(2,$d,$n); |
|
7874
|
449
|
100
|
100
|
|
|
2979
|
return 1 if $x == 1 || $x == $nm1; |
|
7875
|
368
|
|
|
|
|
127414
|
foreach my $r (1 .. $s-1) { |
|
7876
|
363
|
|
|
|
|
14494
|
$x = Mmulmod($x,$x,$n); |
|
7877
|
363
|
50
|
|
|
|
81580
|
last if $x == 1; |
|
7878
|
363
|
100
|
|
|
|
69782
|
return 1 if $x == $nm1; |
|
7879
|
|
|
|
|
|
|
} |
|
7880
|
|
|
|
|
|
|
|
|
7881
|
|
|
|
|
|
|
} else { |
|
7882
|
|
|
|
|
|
|
|
|
7883
|
3281
|
50
|
|
|
|
6250
|
if (!defined $nm1) { |
|
7884
|
3281
|
|
|
|
|
4319
|
$nm1 = $n-1; |
|
7885
|
3281
|
|
|
|
|
4218
|
$s = 0; |
|
7886
|
3281
|
|
|
|
|
4377
|
$d = $nm1; |
|
7887
|
3281
|
|
|
|
|
6638
|
while ( ($d & 1) == 0 ) { |
|
7888
|
7639
|
|
|
|
|
9015
|
$s++; |
|
7889
|
7639
|
|
|
|
|
13396
|
$d >>= 1; |
|
7890
|
|
|
|
|
|
|
} |
|
7891
|
|
|
|
|
|
|
} |
|
7892
|
|
|
|
|
|
|
|
|
7893
|
3281
|
100
|
|
|
|
5559
|
if ($n < MPU_HALFWORD) { |
|
7894
|
3225
|
|
|
|
|
10172
|
my $x = _native_powmod(2, $d, $n); |
|
7895
|
3225
|
100
|
100
|
|
|
11066
|
return 1 if $x == 1 || $x == $nm1; |
|
7896
|
3194
|
|
|
|
|
7416
|
foreach my $r (1 .. $s-1) { |
|
7897
|
3812
|
|
|
|
|
5046
|
$x = ($x*$x) % $n; |
|
7898
|
3812
|
100
|
|
|
|
5866
|
last if $x == 1; |
|
7899
|
3809
|
100
|
|
|
|
7644
|
return 1 if $x == $n-1; |
|
7900
|
|
|
|
|
|
|
} |
|
7901
|
|
|
|
|
|
|
} else { |
|
7902
|
56
|
|
|
|
|
278
|
my $x = _powmod(2, $d, $n); |
|
7903
|
56
|
100
|
100
|
|
|
614
|
return 1 if $x == 1 || $x == $nm1; |
|
7904
|
33
|
|
|
|
|
187
|
foreach my $r (1 .. $s-1) { |
|
7905
|
39
|
100
|
|
|
|
211
|
$x = ($x < MPU_HALFWORD) ? ($x*$x) % $n : _mulmod($x, $x, $n); |
|
7906
|
39
|
50
|
|
|
|
162
|
last if $x == 1; |
|
7907
|
39
|
100
|
|
|
|
317
|
return 1 if $x == $n-1; |
|
7908
|
|
|
|
|
|
|
} |
|
7909
|
|
|
|
|
|
|
} |
|
7910
|
|
|
|
|
|
|
} |
|
7911
|
3222
|
|
|
|
|
29913
|
0; |
|
7912
|
|
|
|
|
|
|
} |
|
7913
|
|
|
|
|
|
|
|
|
7914
|
|
|
|
|
|
|
sub is_strong_pseudoprime { |
|
7915
|
3313
|
|
|
3313
|
0
|
9270
|
my($n, @bases) = @_; |
|
7916
|
3313
|
|
|
|
|
8843
|
validate_integer($n); |
|
7917
|
3313
|
50
|
|
|
|
8005
|
return 0 if $n < 0; |
|
7918
|
3313
|
100
|
|
|
|
15633
|
return _miller_rabin_2($n) if scalar(@bases) == 0; |
|
7919
|
|
|
|
|
|
|
|
|
7920
|
3312
|
100
|
|
|
|
6041
|
return 0+($n >= 2) if $n < 4; |
|
7921
|
3308
|
50
|
|
|
|
14119
|
return 0 if ($n % 2) == 0; |
|
7922
|
|
|
|
|
|
|
|
|
7923
|
3308
|
|
|
|
|
29467
|
my @newbases; |
|
7924
|
3308
|
|
|
|
|
5616
|
for my $a (@bases) { |
|
7925
|
3733
|
50
|
|
|
|
6600
|
croak "Base $a is invalid" if $a < 2; |
|
7926
|
3733
|
100
|
|
|
|
14946
|
$a %= $n if $a >= $n; |
|
7927
|
3733
|
100
|
66
|
|
|
19315
|
next if $a <= 1 || $a == $n-1; |
|
7928
|
3732
|
100
|
|
|
|
49134
|
if ($a == 2) { |
|
7929
|
3237
|
100
|
|
|
|
5670
|
return 0 unless _miller_rabin_2($n); |
|
7930
|
351
|
|
|
|
|
2012
|
next; |
|
7931
|
|
|
|
|
|
|
} |
|
7932
|
495
|
|
|
|
|
6002
|
push @newbases, $a; |
|
7933
|
|
|
|
|
|
|
} |
|
7934
|
422
|
100
|
|
|
|
1059
|
return 1 if scalar(@newbases) == 0; |
|
7935
|
414
|
|
|
|
|
908
|
@bases = @newbases; |
|
7936
|
|
|
|
|
|
|
|
|
7937
|
414
|
100
|
|
|
|
1182
|
if (ref($n)) { |
|
7938
|
|
|
|
|
|
|
|
|
7939
|
37
|
|
|
|
|
241
|
my $nm1 = Msub1int($n); |
|
7940
|
37
|
|
|
|
|
7097
|
my $s = Mvaluation($nm1,2); |
|
7941
|
37
|
|
|
|
|
223
|
my $d = Mrshiftint($nm1,$s); |
|
7942
|
|
|
|
|
|
|
|
|
7943
|
37
|
|
|
|
|
6031
|
foreach my $ma (@bases) { |
|
7944
|
69
|
|
|
|
|
4965
|
my $x = Mpowmod($ma,$d,$n); |
|
7945
|
69
|
100
|
100
|
|
|
14990
|
next if $x == 1 || $x == $nm1; |
|
7946
|
30
|
|
|
|
|
5921
|
foreach my $r (1 .. $s-1) { |
|
7947
|
26
|
|
|
|
|
645
|
$x = Mmulmod($x,$x,$n); |
|
7948
|
26
|
50
|
|
|
|
4080
|
return 0 if $x == 1; |
|
7949
|
26
|
100
|
|
|
|
3393
|
last if $x == $nm1; |
|
7950
|
|
|
|
|
|
|
} |
|
7951
|
30
|
100
|
|
|
|
882
|
return 0 if $x != $nm1; |
|
7952
|
|
|
|
|
|
|
} |
|
7953
|
|
|
|
|
|
|
|
|
7954
|
|
|
|
|
|
|
} else { |
|
7955
|
|
|
|
|
|
|
|
|
7956
|
377
|
|
|
|
|
598
|
my $s = 0; |
|
7957
|
377
|
|
|
|
|
755
|
my $d = $n - 1; |
|
7958
|
377
|
|
|
|
|
975
|
while ( ($d & 1) == 0 ) { |
|
7959
|
1673
|
|
|
|
|
2200
|
$s++; |
|
7960
|
1673
|
|
|
|
|
2901
|
$d >>= 1; |
|
7961
|
|
|
|
|
|
|
} |
|
7962
|
|
|
|
|
|
|
|
|
7963
|
377
|
100
|
|
|
|
897
|
if ($n < MPU_HALFWORD) { |
|
7964
|
363
|
|
|
|
|
655
|
foreach my $ma (@bases) { |
|
7965
|
382
|
|
|
|
|
988
|
my $x = _native_powmod($ma, $d, $n); |
|
7966
|
382
|
100
|
100
|
|
|
1653
|
next if ($x == 1) || ($x == ($n-1)); |
|
7967
|
329
|
|
|
|
|
992
|
foreach my $r (1 .. $s-1) { |
|
7968
|
960
|
|
|
|
|
1400
|
$x = ($x*$x) % $n; |
|
7969
|
960
|
100
|
|
|
|
4340
|
return 0 if $x == 1; |
|
7970
|
959
|
100
|
|
|
|
1919
|
last if $x == $n-1; |
|
7971
|
|
|
|
|
|
|
} |
|
7972
|
328
|
100
|
|
|
|
1069
|
return 0 if $x != $n-1; |
|
7973
|
|
|
|
|
|
|
} |
|
7974
|
|
|
|
|
|
|
} else { |
|
7975
|
14
|
|
|
|
|
58
|
foreach my $ma (@bases) { |
|
7976
|
27
|
|
|
|
|
107
|
my $x = _powmod($ma, $d, $n); |
|
7977
|
27
|
100
|
100
|
|
|
341
|
next if ($x == 1) || ($x == ($n-1)); |
|
7978
|
20
|
|
|
|
|
110
|
foreach my $r (1 .. $s-1) { |
|
7979
|
17
|
100
|
|
|
|
118
|
$x = ($x < MPU_HALFWORD) ? ($x*$x) % $n : _mulmod($x, $x, $n); |
|
7980
|
17
|
50
|
|
|
|
89
|
return 0 if $x == 1; |
|
7981
|
17
|
100
|
|
|
|
79
|
last if $x == $n-1; |
|
7982
|
|
|
|
|
|
|
} |
|
7983
|
20
|
100
|
|
|
|
171
|
return 0 if $x != $n-1; |
|
7984
|
|
|
|
|
|
|
} |
|
7985
|
|
|
|
|
|
|
} |
|
7986
|
|
|
|
|
|
|
|
|
7987
|
|
|
|
|
|
|
} |
|
7988
|
376
|
|
|
|
|
4434
|
1; |
|
7989
|
|
|
|
|
|
|
} |
|
7990
|
|
|
|
|
|
|
|
|
7991
|
|
|
|
|
|
|
|
|
7992
|
|
|
|
|
|
|
# Calculate Kronecker symbol (a|b). Cohen Algorithm 1.4.10. |
|
7993
|
|
|
|
|
|
|
# Extension of the Jacobi symbol, itself an extension of the Legendre symbol. |
|
7994
|
|
|
|
|
|
|
sub kronecker { |
|
7995
|
829
|
|
|
829
|
0
|
12724
|
my($a, $b) = @_; |
|
7996
|
829
|
0
|
|
|
|
2564
|
return (abs($a) == 1) ? 1 : 0 if $b == 0; |
|
|
|
50
|
|
|
|
|
|
|
7997
|
829
|
|
|
|
|
69469
|
my $k = 1; |
|
7998
|
829
|
100
|
|
|
|
2449
|
if ($b % 2 == 0) { |
|
7999
|
4
|
100
|
|
|
|
399
|
return 0 if $a % 2 == 0; |
|
8000
|
2
|
|
|
|
|
6
|
my $v = 0; |
|
8001
|
2
|
|
|
|
|
15
|
do { $v++; $b /= 2; } while $b % 2 == 0; |
|
|
2
|
|
|
|
|
5
|
|
|
|
2
|
|
|
|
|
10
|
|
|
8002
|
2
|
50
|
33
|
|
|
16
|
$k = -$k if $v % 2 == 1 && ($a % 8 == 3 || $a % 8 == 5); |
|
|
|
|
33
|
|
|
|
|
|
8003
|
|
|
|
|
|
|
} |
|
8004
|
827
|
50
|
|
|
|
159815
|
if ($b < 0) { |
|
8005
|
0
|
|
|
|
|
0
|
$b = -$b; |
|
8006
|
0
|
0
|
|
|
|
0
|
$k = -$k if $a < 0; |
|
8007
|
|
|
|
|
|
|
} |
|
8008
|
827
|
100
|
|
|
|
63763
|
if ($a < 0) { $a = -$a; $k = -$k if $b % 4 == 3; } |
|
|
11
|
100
|
|
|
|
29
|
|
|
|
11
|
|
|
|
|
43
|
|
|
8009
|
827
|
100
|
100
|
|
|
4276
|
$b = _bigint_to_int($b) if ref($b) && $b <= INTMAX; |
|
8010
|
827
|
50
|
66
|
|
|
72850
|
$a = _bigint_to_int($a) if ref($a) && $a <= INTMAX; |
|
8011
|
|
|
|
|
|
|
# Now: b > 0, b odd, a >= 0 |
|
8012
|
827
|
|
|
|
|
3520
|
while ($a != 0) { |
|
8013
|
1388
|
100
|
|
|
|
133445
|
if ($a % 2 == 0) { |
|
8014
|
618
|
|
|
|
|
72688
|
my $v = 0; |
|
8015
|
618
|
|
|
|
|
1079
|
do { $v++; $a /= 2; } while $a % 2 == 0; |
|
|
1130
|
|
|
|
|
65414
|
|
|
|
1130
|
|
|
|
|
3268
|
|
|
8016
|
618
|
100
|
100
|
|
|
139157
|
$k = -$k if $v % 2 == 1 && ($b % 8 == 3 || $b % 8 == 5); |
|
|
|
|
100
|
|
|
|
|
|
8017
|
|
|
|
|
|
|
} |
|
8018
|
1388
|
100
|
100
|
|
|
112827
|
$k = -$k if $a % 4 == 3 && $b % 4 == 3; |
|
8019
|
1388
|
|
|
|
|
206367
|
($a, $b) = ($b % $a, $a); |
|
8020
|
|
|
|
|
|
|
# If a,b are bigints and now small enough, finish as native. |
|
8021
|
1388
|
100
|
100
|
|
|
172482
|
return $k * kronecker(_bigint_to_int($a),_bigint_to_int($b)) |
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
8022
|
|
|
|
|
|
|
if $a <= INTMAX && $b <= INTMAX && ref($a) && ref($b); |
|
8023
|
|
|
|
|
|
|
} |
|
8024
|
527
|
100
|
|
|
|
11808
|
return ($b == 1) ? $k : 0; |
|
8025
|
|
|
|
|
|
|
} |
|
8026
|
|
|
|
|
|
|
|
|
8027
|
|
|
|
|
|
|
sub is_qr { |
|
8028
|
4
|
|
|
4
|
0
|
1898
|
my($a, $n) = @_; |
|
8029
|
4
|
|
|
|
|
42
|
validate_integer($a); |
|
8030
|
4
|
|
|
|
|
141
|
validate_integer_abs($n); |
|
8031
|
|
|
|
|
|
|
|
|
8032
|
|
|
|
|
|
|
# return (defined Math::Prime::Util::sqrtmod($a,$n)) ? 1 : 0; |
|
8033
|
|
|
|
|
|
|
|
|
8034
|
4
|
50
|
|
|
|
511
|
return (undef,1,1)[$n] if $n <= 2; |
|
8035
|
4
|
100
|
66
|
|
|
373
|
$a = Mmodint($a,$n) if $a >= $n || $a < 0;; |
|
8036
|
4
|
50
|
|
|
|
31
|
return 1 if $a <= 1; |
|
8037
|
|
|
|
|
|
|
|
|
8038
|
4
|
|
|
|
|
386
|
foreach my $f (Mfactor_exp($n)) { |
|
8039
|
11
|
|
|
|
|
603
|
my($p,$e) = @$f; |
|
8040
|
11
|
100
|
100
|
|
|
113
|
next if $e == 1 && Mkronecker($a,$p) == 1; |
|
8041
|
6
|
100
|
|
|
|
47
|
return 0 unless defined _sqrtmod_prime_power($a,$p,$e); |
|
8042
|
|
|
|
|
|
|
} |
|
8043
|
2
|
|
|
|
|
27
|
1; |
|
8044
|
|
|
|
|
|
|
} |
|
8045
|
|
|
|
|
|
|
|
|
8046
|
|
|
|
|
|
|
sub _binomialu { |
|
8047
|
262
|
|
|
262
|
|
807
|
my($r, $n, $k) = (1, @_); |
|
8048
|
262
|
50
|
|
|
|
840
|
return ($k == $n) ? 1 : 0 if $k >= $n; |
|
|
|
100
|
|
|
|
|
|
|
8049
|
249
|
100
|
|
|
|
798
|
$k = $n - $k if $k > ($n >> 1); |
|
8050
|
249
|
|
|
|
|
833
|
foreach my $d (1 .. $k) { |
|
8051
|
2949
|
100
|
|
|
|
6074
|
if ($r >= int(INTMAX/$n)) { |
|
8052
|
459
|
|
|
|
|
835
|
my($g, $nr, $dr); |
|
8053
|
459
|
|
|
|
|
1423
|
$g = _gcd_ui($n, $d); $nr = int($n/$g); $dr = int($d/$g); |
|
|
459
|
|
|
|
|
981
|
|
|
|
459
|
|
|
|
|
930
|
|
|
8054
|
459
|
|
|
|
|
924
|
$g = _gcd_ui($r, $dr); $r = int($r/$g); $dr = int($dr/$g); |
|
|
459
|
|
|
|
|
954
|
|
|
|
459
|
|
|
|
|
877
|
|
|
8055
|
459
|
100
|
|
|
|
1530
|
return 0 if $r >= int(INTMAX/$nr); |
|
8056
|
266
|
|
|
|
|
580
|
$r *= $nr; |
|
8057
|
266
|
|
|
|
|
584
|
$r = int($r/$dr); |
|
8058
|
|
|
|
|
|
|
} else { |
|
8059
|
2490
|
|
|
|
|
3889
|
$r *= $n; |
|
8060
|
2490
|
|
|
|
|
4012
|
$r = int($r/$d); |
|
8061
|
|
|
|
|
|
|
} |
|
8062
|
2756
|
|
|
|
|
4503
|
$n--; |
|
8063
|
|
|
|
|
|
|
} |
|
8064
|
56
|
|
|
|
|
127
|
$r; |
|
8065
|
|
|
|
|
|
|
} |
|
8066
|
|
|
|
|
|
|
|
|
8067
|
|
|
|
|
|
|
sub binomial { |
|
8068
|
272
|
|
|
272
|
0
|
28100
|
my($n, $k) = @_; |
|
8069
|
272
|
|
|
|
|
1245
|
validate_integer($n); |
|
8070
|
272
|
|
|
|
|
1212
|
validate_integer($k); |
|
8071
|
|
|
|
|
|
|
|
|
8072
|
|
|
|
|
|
|
# 1. Try GMP |
|
8073
|
|
|
|
|
|
|
return reftyped($_[0], Math::Prime::Util::GMP::binomial($n,$k)) |
|
8074
|
272
|
0
|
0
|
|
|
1105
|
if $Math::Prime::Util::_GMPfunc{"binomial"} && |
|
|
|
|
33
|
|
|
|
|
|
8075
|
|
|
|
|
|
|
($Math::Prime::Util::GMP::VERSION >= 0.53 || ($n >= 0 && $k >= 0 && $n < 4294967296 && $k < 4294967296)); |
|
8076
|
|
|
|
|
|
|
|
|
8077
|
|
|
|
|
|
|
# 2. Exit early for known 0 cases, and adjust k to be positive. |
|
8078
|
272
|
50
|
33
|
|
|
778
|
if ($n >= 0) { return 0 if $k < 0 || $k > $n; } |
|
|
206
|
100
|
|
|
|
3884
|
|
|
8079
|
66
|
50
|
66
|
|
|
268
|
else { return 0 if $k < 0 && $k > $n; } |
|
8080
|
272
|
100
|
|
|
|
2362
|
$k = $n - $k if $k < 0; |
|
8081
|
|
|
|
|
|
|
|
|
8082
|
|
|
|
|
|
|
# TODO: consider reflection for large k (e.g. k=n-2 => k=2) |
|
8083
|
|
|
|
|
|
|
# Also, be careful with large n and k with bigints. |
|
8084
|
|
|
|
|
|
|
|
|
8085
|
272
|
|
|
|
|
488
|
my $r; |
|
8086
|
|
|
|
|
|
|
|
|
8087
|
|
|
|
|
|
|
# 3. Try to do in integer Perl |
|
8088
|
272
|
100
|
|
|
|
781
|
if (!ref($n)) { |
|
8089
|
262
|
100
|
|
|
|
723
|
if ($n >= 0) { |
|
8090
|
196
|
|
|
|
|
647
|
$r = _binomialu($n, $k); |
|
8091
|
196
|
100
|
66
|
|
|
990
|
return $r if $r > 0 && $r eq int($r); |
|
8092
|
|
|
|
|
|
|
} else { |
|
8093
|
66
|
|
|
|
|
326
|
$r = _binomialu(-$n+$k-1, $k); |
|
8094
|
66
|
100
|
66
|
|
|
287
|
if ($r > 0 && $r eq int($r)) { |
|
8095
|
1
|
50
|
|
|
|
8
|
return $r if !($k & 1); |
|
8096
|
1
|
|
|
|
|
46
|
return Mnegint($r); |
|
8097
|
|
|
|
|
|
|
} |
|
8098
|
|
|
|
|
|
|
} |
|
8099
|
|
|
|
|
|
|
} |
|
8100
|
|
|
|
|
|
|
|
|
8101
|
|
|
|
|
|
|
# 4. Overflow. Solve using Math::BigInt |
|
8102
|
203
|
50
|
|
|
|
599
|
return 1 if $k == 0; # Work around bug in old |
|
8103
|
203
|
100
|
66
|
|
|
1219
|
return $n if $k == 1 || $k == $n-1; # Math::BigInt (fixed in 1.90) |
|
8104
|
|
|
|
|
|
|
|
|
8105
|
202
|
|
|
|
|
5918
|
my $R; |
|
8106
|
202
|
100
|
|
|
|
1109
|
$n = tobigint($n) unless ref($n); |
|
8107
|
|
|
|
|
|
|
|
|
8108
|
|
|
|
|
|
|
# Older Math::BigInt isn't right for negative n. Adjust now. |
|
8109
|
202
|
|
|
|
|
475
|
my $negate = 0; |
|
8110
|
202
|
100
|
|
|
|
808
|
if ($n < 0) { |
|
8111
|
65
|
|
|
|
|
13126
|
$n = -$n + ($k-1); |
|
8112
|
65
|
100
|
|
|
|
28891
|
$negate = 1 if $k & 1; |
|
8113
|
|
|
|
|
|
|
} |
|
8114
|
|
|
|
|
|
|
|
|
8115
|
202
|
50
|
33
|
|
|
35078
|
if (defined $Math::GMPz::VERSION) { |
|
|
|
50
|
33
|
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
8116
|
0
|
|
|
|
|
0
|
$R = Math::GMPz->new(); |
|
8117
|
0
|
|
|
|
|
0
|
Math::GMPz::Rmpz_bin_ui($R, Math::GMPz->new($n), $k); |
|
8118
|
|
|
|
|
|
|
} elsif (defined $Math::GMP::VERSION && $Math::GMP::VERSION >= 2.23 && $n < 4294967296) { |
|
8119
|
|
|
|
|
|
|
# This will silently coerce inputs to C 'long' type. |
|
8120
|
0
|
|
|
|
|
0
|
$R = Math::GMP::bnok("$n","$k"); |
|
8121
|
|
|
|
|
|
|
} elsif ($n > INTMAX && $k < 100) { |
|
8122
|
|
|
|
|
|
|
# Incomplete work around problem with Math::BigInt not liking bigint n. |
|
8123
|
|
|
|
|
|
|
# Fixed in 2.003003. |
|
8124
|
9
|
|
|
|
|
2405
|
$R = Mdivint(Mfalling_factorial($n,$k),Mfactorial($k)); |
|
8125
|
|
|
|
|
|
|
} else { |
|
8126
|
193
|
|
|
|
|
47669
|
$R = Math::BigInt::bnok("$n","$k"); |
|
8127
|
|
|
|
|
|
|
} |
|
8128
|
202
|
100
|
|
|
|
3125678
|
$R = -$R if $negate; |
|
8129
|
202
|
50
|
66
|
|
|
5008
|
return $R <= INTMAX && $R >= INTMIN ? _bigint_to_int($R) |
|
|
|
50
|
33
|
|
|
|
|
|
8130
|
|
|
|
|
|
|
: defined $_BIGINT && $_BIGINT eq ref($R) ? $R |
|
8131
|
|
|
|
|
|
|
: tobigint($R); |
|
8132
|
|
|
|
|
|
|
} |
|
8133
|
|
|
|
|
|
|
|
|
8134
|
|
|
|
|
|
|
sub binomialmod { |
|
8135
|
8
|
|
|
8
|
0
|
299
|
my($n,$k,$m) = @_; |
|
8136
|
8
|
|
|
|
|
31
|
validate_integer($n); |
|
8137
|
8
|
|
|
|
|
59
|
validate_integer($k); |
|
8138
|
8
|
|
|
|
|
65
|
validate_integer_abs($m); |
|
8139
|
8
|
50
|
|
|
|
242
|
return (undef,0)[$m] if $m <= 1; |
|
8140
|
|
|
|
|
|
|
|
|
8141
|
|
|
|
|
|
|
return reftyped($_[0], Math::Prime::Util::GMP::binomialmod($n,$k,$m)) |
|
8142
|
8
|
50
|
|
|
|
154
|
if $Math::Prime::Util::_GMPfunc{"binomialmod"}; |
|
8143
|
|
|
|
|
|
|
|
|
8144
|
|
|
|
|
|
|
# Avoid the possible enormously slow bigint creation. |
|
8145
|
8
|
0
|
33
|
|
|
21
|
if ($Math::Prime::Util::_GMPfunc{"binomial"} && $Math::Prime::Util::_GMPfunc{"modint"}) { |
|
8146
|
0
|
0
|
0
|
|
|
0
|
if ($Math::Prime::Util::GMP::VERSION >= 0.53 || ($n >= 0 && $k >= 0 && $n < 4294967296 && $k < 4294967296)) { |
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
8147
|
0
|
|
|
|
|
0
|
return reftyped($_[2], Math::Prime::Util::GMP::modint(Math::Prime::Util::GMP::binomial($n,$k),$m)); |
|
8148
|
|
|
|
|
|
|
} |
|
8149
|
|
|
|
|
|
|
} |
|
8150
|
|
|
|
|
|
|
|
|
8151
|
8
|
100
|
66
|
|
|
31
|
return 1 if $k == 0 || $k == $n; |
|
8152
|
7
|
50
|
33
|
|
|
193
|
return 0 if $n >= 0 && ($k < 0 || $k > $n); |
|
|
|
|
33
|
|
|
|
|
|
8153
|
7
|
0
|
0
|
|
|
256
|
return 0 if $n < 0 && ($k < 0 && $k > $n); |
|
|
|
|
33
|
|
|
|
|
|
8154
|
7
|
50
|
|
|
|
144
|
return 0+!(($n-$k) & $k) if $m == 2; |
|
8155
|
|
|
|
|
|
|
|
|
8156
|
|
|
|
|
|
|
# TODO: Lucas split, etc. |
|
8157
|
|
|
|
|
|
|
# 1. factorexp |
|
8158
|
|
|
|
|
|
|
# 2. bin[i] = _binomial_lucas_mod_prime_power(n, k, $f, $e) |
|
8159
|
|
|
|
|
|
|
# 2a. _factorialmod_without_prime |
|
8160
|
|
|
|
|
|
|
# 3. chinese(bin, p^e) |
|
8161
|
|
|
|
|
|
|
# we can just run the more general code path. |
|
8162
|
|
|
|
|
|
|
|
|
8163
|
|
|
|
|
|
|
# Give up. |
|
8164
|
7
|
|
|
|
|
397
|
return Mmodint(Mbinomial($n,$k),$m); |
|
8165
|
|
|
|
|
|
|
} |
|
8166
|
|
|
|
|
|
|
|
|
8167
|
|
|
|
|
|
|
sub _falling_factorial { |
|
8168
|
16
|
|
|
16
|
|
50
|
my($n,$m) = @_; |
|
8169
|
16
|
0
|
|
|
|
69
|
if ($m <= 1) { return ($m == 0) ? 1 : $n } |
|
|
0
|
50
|
|
|
|
0
|
|
|
8170
|
16
|
50
|
33
|
|
|
88
|
return 0 if $n >= 0 && $m > $n; |
|
8171
|
16
|
50
|
|
|
|
4118
|
return Mvecprod($n,map { Msubint($n,$_) } 1 .. Msubint($m,1)) if $m < 250; |
|
|
323
|
|
|
|
|
17514
|
|
|
8172
|
0
|
|
|
|
|
0
|
Mmulint(Mbinomial($n,$m),Mfactorial($m)); |
|
8173
|
|
|
|
|
|
|
} |
|
8174
|
|
|
|
|
|
|
sub falling_factorial { |
|
8175
|
13
|
|
|
13
|
0
|
8124
|
my($n,$m) = @_; |
|
8176
|
13
|
|
|
|
|
90
|
validate_integer($n); |
|
8177
|
13
|
|
|
|
|
562
|
validate_integer_nonneg($m); |
|
8178
|
13
|
|
|
|
|
66
|
_falling_factorial($n,$m); |
|
8179
|
|
|
|
|
|
|
} |
|
8180
|
|
|
|
|
|
|
sub rising_factorial { |
|
8181
|
3
|
|
|
3
|
0
|
10187
|
my($n,$m) = @_; |
|
8182
|
3
|
|
|
|
|
15
|
validate_integer($n); |
|
8183
|
3
|
|
|
|
|
12
|
validate_integer_nonneg($m); |
|
8184
|
3
|
|
|
|
|
26
|
_falling_factorial(Mvecsum($n,$m,-1),$m); |
|
8185
|
|
|
|
|
|
|
} |
|
8186
|
|
|
|
|
|
|
|
|
8187
|
|
|
|
|
|
|
sub factorial { |
|
8188
|
388
|
|
|
388
|
0
|
127166
|
my($n) = @_; |
|
8189
|
388
|
100
|
|
|
|
1536
|
return (1,1,2,6,24,120,720,5040,40320,362880,3628800,39916800,479001600)[$n] if $n <= 12; |
|
8190
|
352
|
50
|
|
|
|
1029
|
return Math::GMP::bfac($n) if ref($n) eq 'Math::GMP'; |
|
8191
|
352
|
50
|
|
|
|
898
|
do { my $r = Math::GMPz->new(); Math::GMPz::Rmpz_fac_ui($r,$n); return $r; } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
8192
|
|
|
|
|
|
|
if ref($n) eq 'Math::GMPz'; |
|
8193
|
352
|
50
|
|
|
|
1380
|
if (Math::BigInt->config()->{lib} !~ /GMP|Pari/) { |
|
8194
|
|
|
|
|
|
|
# It's not a GMP or GMPz object, and we have a slow bigint library. |
|
8195
|
352
|
|
|
|
|
51376
|
my $r; |
|
8196
|
352
|
50
|
33
|
|
|
1991
|
if (defined $Math::GMPz::VERSION) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
8197
|
0
|
|
|
|
|
0
|
$r = Math::GMPz->new(); Math::GMPz::Rmpz_fac_ui($r,$n); |
|
|
0
|
|
|
|
|
0
|
|
|
8198
|
|
|
|
|
|
|
} elsif (defined $Math::GMP::VERSION) { |
|
8199
|
0
|
|
|
|
|
0
|
$r = Math::GMP::bfac($n); |
|
8200
|
|
|
|
|
|
|
} elsif (defined &Math::Prime::Util::GMP::factorial && getconfig()->{'gmp'}) { |
|
8201
|
0
|
|
|
|
|
0
|
$r = Math::Prime::Util::GMP::factorial($n); |
|
8202
|
|
|
|
|
|
|
} |
|
8203
|
352
|
50
|
|
|
|
895
|
return reftyped($_[0], $r) if defined $r; |
|
8204
|
|
|
|
|
|
|
} |
|
8205
|
|
|
|
|
|
|
# maybe roll our own: https://oeis.org/A000142/a000142.pdf |
|
8206
|
352
|
|
|
|
|
1867
|
my $r = Math::BigInt->new($n)->bfac(); |
|
8207
|
352
|
50
|
|
|
|
19718269
|
$r = _bigint_to_int($r) if $r <= INTMAX; |
|
8208
|
352
|
|
|
|
|
83618
|
$r; |
|
8209
|
|
|
|
|
|
|
} |
|
8210
|
|
|
|
|
|
|
|
|
8211
|
|
|
|
|
|
|
sub factorialmod { |
|
8212
|
4
|
|
|
4
|
0
|
2923
|
my($n,$m) = @_; |
|
8213
|
4
|
|
|
|
|
34
|
validate_integer($n); |
|
8214
|
4
|
|
|
|
|
164
|
validate_integer_abs($m); |
|
8215
|
4
|
50
|
|
|
|
482
|
return (undef,0)[$m] if $m <= 1; |
|
8216
|
|
|
|
|
|
|
|
|
8217
|
|
|
|
|
|
|
return reftyped($_[1], Math::Prime::Util::GMP::factorialmod($n,$m)) |
|
8218
|
4
|
50
|
33
|
|
|
503
|
if $Math::Prime::Util::_GMPfunc{"factorialmod"} && $n < ~0; |
|
8219
|
|
|
|
|
|
|
|
|
8220
|
4
|
50
|
33
|
|
|
31
|
return 0 if $n >= $m || $m == 1; |
|
8221
|
|
|
|
|
|
|
|
|
8222
|
4
|
50
|
|
|
|
678
|
return factorial($n) % $m if $n <= 10; |
|
8223
|
|
|
|
|
|
|
|
|
8224
|
4
|
|
|
|
|
179
|
my($F, $N, $m_prime) = (1, $n, Mis_prime($m)); |
|
8225
|
|
|
|
|
|
|
|
|
8226
|
|
|
|
|
|
|
# Check for Wilson's theorem letting us go backwards |
|
8227
|
4
|
50
|
66
|
|
|
689
|
$n = $m-$n-1 if $m_prime && $n > Mrshiftint($m); |
|
8228
|
4
|
0
|
|
|
|
30
|
return ($n == 0) ? ($m-1) : 1 if $n < 2; |
|
|
|
50
|
|
|
|
|
|
|
8229
|
|
|
|
|
|
|
|
|
8230
|
4
|
100
|
100
|
|
|
190
|
if ($n > 100 && !$m_prime) { # Check for a composite that leads to zero |
|
8231
|
2
|
|
|
|
|
126
|
my $maxpk = 0; |
|
8232
|
2
|
|
|
|
|
16
|
foreach my $f (Mfactor_exp($m)) { |
|
8233
|
12
|
|
|
|
|
30
|
my $pk = Mmulint($f->[0],$f->[1]); |
|
8234
|
12
|
50
|
|
|
|
24
|
$maxpk = $pk if $pk > $maxpk; |
|
8235
|
|
|
|
|
|
|
} |
|
8236
|
2
|
100
|
|
|
|
23
|
return 0 if $n >= $maxpk; |
|
8237
|
|
|
|
|
|
|
} |
|
8238
|
|
|
|
|
|
|
|
|
8239
|
3
|
|
|
|
|
8
|
my($t,$e); |
|
8240
|
|
|
|
|
|
|
Mforprimes( sub { |
|
8241
|
165
|
|
|
165
|
|
12122
|
($t,$e) = ($n,0); |
|
8242
|
165
|
|
|
|
|
425
|
while ($t > 0) { |
|
8243
|
384
|
|
|
|
|
719
|
$t = int($t/$_); |
|
8244
|
384
|
|
|
|
|
788
|
$e += $t; |
|
8245
|
|
|
|
|
|
|
} |
|
8246
|
165
|
|
|
|
|
662
|
$F = Mmulmod($F,Mpowmod($_,$e,$m),$m); |
|
8247
|
3
|
|
|
|
|
110
|
}, 2, $n >> 1); |
|
8248
|
|
|
|
|
|
|
Mforprimes( sub { |
|
8249
|
133
|
|
|
133
|
|
9841
|
$F = Mmulmod($F, $_, $m); |
|
8250
|
3
|
|
|
|
|
235
|
}, ($n >> 1)+1, $n); |
|
8251
|
|
|
|
|
|
|
|
|
8252
|
|
|
|
|
|
|
# Adjust for Wilson's theorem if we used it |
|
8253
|
3
|
50
|
33
|
|
|
208
|
if ($n != $N && $F != 0) { |
|
8254
|
0
|
0
|
|
|
|
0
|
$F = Msubmod($m, $F, $m) if !($n & 1); |
|
8255
|
0
|
|
|
|
|
0
|
$F = Minvmod($F, $m); |
|
8256
|
|
|
|
|
|
|
} |
|
8257
|
|
|
|
|
|
|
|
|
8258
|
3
|
|
|
|
|
34
|
$F; |
|
8259
|
|
|
|
|
|
|
} |
|
8260
|
|
|
|
|
|
|
|
|
8261
|
|
|
|
|
|
|
sub subfactorial { |
|
8262
|
6
|
|
|
6
|
0
|
73382
|
my($n) = @_; |
|
8263
|
6
|
|
|
|
|
36
|
validate_integer_nonneg($n); |
|
8264
|
6
|
50
|
|
|
|
24
|
if ($n <= 3) { return ($n == 0) ? 1 : $n-1; } |
|
|
1
|
100
|
|
|
|
9
|
|
|
8265
|
5
|
|
|
|
|
9
|
my $r = 0; |
|
8266
|
5
|
|
|
|
|
21
|
for my $k (2..$n) { |
|
8267
|
186
|
|
|
|
|
8797
|
$r = Mmulint($r,$k); |
|
8268
|
186
|
100
|
|
|
|
24362
|
if ($k&1) { $r--; } else { $r++; } |
|
|
92
|
|
|
|
|
241
|
|
|
|
94
|
|
|
|
|
240
|
|
|
8269
|
|
|
|
|
|
|
} |
|
8270
|
5
|
|
|
|
|
336
|
$r; |
|
8271
|
|
|
|
|
|
|
} |
|
8272
|
|
|
|
|
|
|
|
|
8273
|
|
|
|
|
|
|
my $_fubinis = [1,1,3,13,75]; |
|
8274
|
|
|
|
|
|
|
sub _add_fubini { # Add the next Fubini sequence term to an array reference. |
|
8275
|
33
|
|
|
33
|
|
78
|
my($A)= @_; |
|
8276
|
33
|
|
|
|
|
70
|
my $N = @$A; |
|
8277
|
|
|
|
|
|
|
|
|
8278
|
|
|
|
|
|
|
# Faster method from Daniel Șuteu. |
|
8279
|
|
|
|
|
|
|
# 1..400 no-GMP GMP Math::GMPz |
|
8280
|
|
|
|
|
|
|
# old 51.82 13.95 0.804 |
|
8281
|
|
|
|
|
|
|
# new 35.73 3.79 0.380 |
|
8282
|
|
|
|
|
|
|
|
|
8283
|
33
|
|
|
|
|
66
|
my($t,$x) = (1); |
|
8284
|
33
|
|
|
|
|
118
|
push @$A, Mvecsum(map { $x = Smulint($t, $A->[$_]); |
|
|
427
|
|
|
|
|
2325
|
|
|
8285
|
427
|
|
|
|
|
8034
|
$t = Smulint($t, $N - $_); |
|
8286
|
427
|
|
|
|
|
1052
|
$t = Sdivint($t, $_+1); |
|
8287
|
427
|
|
|
|
|
1006
|
$x } 0..$N-1); |
|
8288
|
|
|
|
|
|
|
} |
|
8289
|
|
|
|
|
|
|
_register_free_sub(sub { $_fubinis = [1,1,3,13,75]; }); |
|
8290
|
|
|
|
|
|
|
sub fubini { |
|
8291
|
16
|
|
|
16
|
0
|
4811
|
my($n) = @_; |
|
8292
|
16
|
|
|
|
|
64
|
validate_integer_nonneg($n); |
|
8293
|
|
|
|
|
|
|
|
|
8294
|
16
|
50
|
|
|
|
49
|
my $cmax = $n < 500 ? $n : 500; |
|
8295
|
16
|
|
|
|
|
104
|
_add_fubini($_fubinis) until defined $_fubinis->[$cmax]; |
|
8296
|
16
|
50
|
|
|
|
127
|
return $_fubinis->[$n] if defined $_fubinis->[$n]; |
|
8297
|
|
|
|
|
|
|
|
|
8298
|
0
|
|
|
|
|
0
|
my @F = @$_fubinis; # copy the cached values to our own. |
|
8299
|
0
|
|
|
|
|
0
|
_add_fubini(\@F) until defined $F[$n]; |
|
8300
|
0
|
|
|
|
|
0
|
return $F[$n]; |
|
8301
|
|
|
|
|
|
|
} |
|
8302
|
|
|
|
|
|
|
|
|
8303
|
|
|
|
|
|
|
|
|
8304
|
|
|
|
|
|
|
# Rational maps |
|
8305
|
|
|
|
|
|
|
|
|
8306
|
|
|
|
|
|
|
sub _rational_cfrac { |
|
8307
|
27
|
|
|
27
|
|
1004
|
my($num,$den,$non_reduce_ok) = @_; |
|
8308
|
27
|
|
|
|
|
48
|
my @CF; |
|
8309
|
27
|
|
|
|
|
96
|
while ($den > 0) { |
|
8310
|
476
|
|
|
|
|
34364
|
my($quo,$rem) = Mtdivrem($num,$den); |
|
8311
|
476
|
|
|
|
|
1244
|
($num,$den) = ($den,$rem); |
|
8312
|
476
|
|
|
|
|
1802
|
push @CF, $quo; |
|
8313
|
|
|
|
|
|
|
} |
|
8314
|
27
|
50
|
33
|
|
|
106
|
croak "Rational must be reduced" unless $num == 1 || $non_reduce_ok; |
|
8315
|
27
|
|
|
|
|
148
|
@CF; |
|
8316
|
|
|
|
|
|
|
} |
|
8317
|
|
|
|
|
|
|
|
|
8318
|
|
|
|
|
|
|
# https://kconrad.math.uconn.edu/blurbs/ugradnumthy/contfrac-neg-invert.pdf |
|
8319
|
|
|
|
|
|
|
sub _negcfrac { |
|
8320
|
11
|
|
|
11
|
|
29
|
my(@CF) = @_; |
|
8321
|
11
|
|
|
|
|
33
|
my $neg0 = Mnegint($CF[0]); |
|
8322
|
11
|
100
|
|
|
|
40
|
if (@CF == 1) { |
|
|
|
100
|
|
|
|
|
|
|
8323
|
3
|
|
|
|
|
5
|
$CF[0] = $neg0; |
|
8324
|
|
|
|
|
|
|
} elsif ($CF[1] == 1) { |
|
8325
|
2
|
|
|
|
|
16
|
splice(@CF, 0, 3, Msub1int($neg0), Madd1int($CF[2])); |
|
8326
|
|
|
|
|
|
|
} else { |
|
8327
|
6
|
|
|
|
|
31
|
splice(@CF, 0, 2, Msub1int($neg0), 1, Msub1int($CF[1])); |
|
8328
|
|
|
|
|
|
|
} |
|
8329
|
11
|
|
|
|
|
106
|
@CF; |
|
8330
|
|
|
|
|
|
|
} |
|
8331
|
|
|
|
|
|
|
|
|
8332
|
|
|
|
|
|
|
sub contfrac { |
|
8333
|
16
|
|
|
16
|
0
|
66056
|
my($num,$den) = @_; |
|
8334
|
16
|
|
|
|
|
136
|
validate_integer($num); |
|
8335
|
16
|
|
|
|
|
3134
|
validate_integer_positive($den); |
|
8336
|
|
|
|
|
|
|
|
|
8337
|
16
|
|
|
|
|
139
|
my @CF = _rational_cfrac(Mabsint($num),$den,1); |
|
8338
|
16
|
100
|
|
|
|
91
|
return ($num >= 0) ? @CF : _negcfrac(@CF); |
|
8339
|
|
|
|
|
|
|
} |
|
8340
|
|
|
|
|
|
|
|
|
8341
|
|
|
|
|
|
|
sub from_contfrac { |
|
8342
|
18
|
50
|
|
18
|
0
|
19511
|
return (0,1) unless @_; |
|
8343
|
|
|
|
|
|
|
|
|
8344
|
18
|
|
|
|
|
47
|
my $b0 = shift @_; |
|
8345
|
18
|
|
|
|
|
68
|
validate_integer($b0); |
|
8346
|
|
|
|
|
|
|
|
|
8347
|
18
|
|
|
|
|
49
|
my($A0,$A1,$B0,$B1) = (1,$b0,0,1); |
|
8348
|
|
|
|
|
|
|
|
|
8349
|
18
|
|
|
|
|
54
|
while (@_) { |
|
8350
|
330
|
|
|
|
|
37906
|
my $bi = shift @_; |
|
8351
|
330
|
|
|
|
|
1089
|
validate_integer_positive($bi); |
|
8352
|
330
|
|
|
|
|
1528
|
($A0,$A1) = ($A1, Maddint(Mmulint($bi,$A1),$A0)); |
|
8353
|
330
|
|
|
|
|
43608
|
($B0,$B1) = ($B1, Maddint(Mmulint($bi,$B1),$B0)); |
|
8354
|
|
|
|
|
|
|
} |
|
8355
|
18
|
|
|
|
|
1017
|
return ($A1,$B1); |
|
8356
|
|
|
|
|
|
|
} |
|
8357
|
|
|
|
|
|
|
|
|
8358
|
|
|
|
|
|
|
sub next_calkin_wilf { |
|
8359
|
1
|
|
|
1
|
0
|
4
|
my($num,$den) = @_; |
|
8360
|
1
|
|
|
|
|
4
|
validate_integer_positive($num); |
|
8361
|
1
|
|
|
|
|
3
|
validate_integer_positive($den); |
|
8362
|
|
|
|
|
|
|
# Check gcd to ensure a valid CW entry? |
|
8363
|
1
|
|
|
|
|
6
|
($den, Mvecprod(2,$den,Mdivint($num,$den)) + $den - $num); |
|
8364
|
|
|
|
|
|
|
} |
|
8365
|
|
|
|
|
|
|
sub next_stern_brocot { |
|
8366
|
1
|
|
|
1
|
0
|
4
|
my($num,$den) = @_; |
|
8367
|
1
|
|
|
|
|
7
|
validate_integer_positive($num); |
|
8368
|
1
|
|
|
|
|
4
|
validate_integer_positive($den); |
|
8369
|
|
|
|
|
|
|
# There should be a better solution |
|
8370
|
1
|
|
|
|
|
4
|
nth_stern_brocot(Madd1int(stern_brocot_n($num,$den))); |
|
8371
|
|
|
|
|
|
|
} |
|
8372
|
|
|
|
|
|
|
|
|
8373
|
|
|
|
|
|
|
sub calkin_wilf_n { |
|
8374
|
5
|
|
|
5
|
0
|
6367
|
my($num,$den) = @_; |
|
8375
|
5
|
|
|
|
|
27
|
validate_integer_positive($num); |
|
8376
|
5
|
|
|
|
|
20
|
validate_integer_positive($den); |
|
8377
|
|
|
|
|
|
|
|
|
8378
|
5
|
|
|
|
|
19
|
my @CF = _rational_cfrac($num,$den); |
|
8379
|
|
|
|
|
|
|
# Note: vecsum(@CF) gives the number of bits in the output |
|
8380
|
|
|
|
|
|
|
|
|
8381
|
5
|
|
|
|
|
13
|
$CF[-1]--; |
|
8382
|
5
|
|
|
|
|
29
|
my $bitstr = '1'; |
|
8383
|
5
|
|
|
|
|
78
|
$bitstr .= (1-($_%2)) x $CF[$_] for reverse 0 .. $#CF; |
|
8384
|
5
|
|
|
|
|
375
|
return Mfromdigits($bitstr,2); |
|
8385
|
|
|
|
|
|
|
} |
|
8386
|
|
|
|
|
|
|
sub stern_brocot_n { |
|
8387
|
6
|
|
|
6
|
0
|
84318
|
my($num,$den) = @_; |
|
8388
|
6
|
|
|
|
|
33
|
validate_integer_positive($num); |
|
8389
|
6
|
|
|
|
|
21
|
validate_integer_positive($den); |
|
8390
|
6
|
|
|
|
|
28
|
my @CF = _rational_cfrac($num,$den); |
|
8391
|
6
|
|
|
|
|
20
|
$CF[-1]--; |
|
8392
|
6
|
|
|
|
|
19
|
my $bitstr = '1'; |
|
8393
|
6
|
|
|
|
|
91
|
$bitstr .= (1-($_%2)) x $CF[$_] for 0 .. $#CF; |
|
8394
|
6
|
|
|
|
|
296
|
return Mfromdigits($bitstr,2); |
|
8395
|
|
|
|
|
|
|
} |
|
8396
|
|
|
|
|
|
|
|
|
8397
|
|
|
|
|
|
|
sub nth_calkin_wilf { |
|
8398
|
5
|
|
|
5
|
0
|
5088
|
my($n) = @_; |
|
8399
|
5
|
|
|
|
|
47
|
validate_integer_positive($n); |
|
8400
|
|
|
|
|
|
|
|
|
8401
|
5
|
|
|
|
|
34
|
my @M = (1,0); |
|
8402
|
5
|
|
|
|
|
33
|
$M[$_] = Mvecsum(@M) for split(//, Mtodigitstring($n,2)); |
|
8403
|
5
|
|
|
|
|
105
|
($M[1],$M[0]); |
|
8404
|
|
|
|
|
|
|
} |
|
8405
|
|
|
|
|
|
|
sub nth_stern_brocot { |
|
8406
|
5
|
|
|
5
|
0
|
4627
|
my($n) = @_; |
|
8407
|
5
|
|
|
|
|
42
|
validate_integer_positive($n); |
|
8408
|
|
|
|
|
|
|
|
|
8409
|
5
|
|
|
|
|
16
|
my @M = (1,0); |
|
8410
|
5
|
|
|
|
|
32
|
my @bits = split(//,Mtodigitstring($n,2)); |
|
8411
|
5
|
|
|
|
|
231
|
$M[$_] = Mvecsum(@M) for 1,reverse(@bits[1..$#bits]); |
|
8412
|
5
|
|
|
|
|
86
|
($M[1],$M[0]); |
|
8413
|
|
|
|
|
|
|
} |
|
8414
|
|
|
|
|
|
|
|
|
8415
|
|
|
|
|
|
|
sub nth_stern_diatomic { |
|
8416
|
1
|
|
|
1
|
0
|
5
|
my ($n) = @_; |
|
8417
|
1
|
|
|
|
|
8
|
validate_integer_nonneg($n); |
|
8418
|
1
|
|
|
|
|
5
|
my @M = (1,0); |
|
8419
|
1
|
|
|
|
|
7
|
$M[$_] = Mvecsum(@M) for split(//, Mtodigitstring($n,2)); |
|
8420
|
1
|
|
|
|
|
14
|
$M[1]; |
|
8421
|
|
|
|
|
|
|
} |
|
8422
|
|
|
|
|
|
|
|
|
8423
|
|
|
|
|
|
|
sub farey { |
|
8424
|
3
|
|
|
3
|
0
|
12
|
my($n,$k) = @_; |
|
8425
|
3
|
|
|
|
|
14
|
validate_integer_positive($n); |
|
8426
|
3
|
|
|
|
|
14
|
my $len = Madd1int(Math::Prime::Util::sumtotient($n)); |
|
8427
|
|
|
|
|
|
|
|
|
8428
|
3
|
|
|
|
|
48
|
my($p0, $q0, $p1, $q1, $p2, $q2, $j) = (0,1,1,$n); |
|
8429
|
|
|
|
|
|
|
|
|
8430
|
3
|
100
|
|
|
|
13
|
if (defined $k) { |
|
8431
|
1
|
|
|
|
|
3
|
validate_integer_nonneg($k); |
|
8432
|
1
|
50
|
|
|
|
3
|
return undef if $k >= $len; |
|
8433
|
1
|
|
|
|
|
4
|
for (1 .. $k) { |
|
8434
|
146
|
|
|
|
|
290
|
$j = Mdivint(($q0 + $n), $q1); |
|
8435
|
146
|
|
|
|
|
268
|
$p2 = Mmulint($j, $p1) - $p0; |
|
8436
|
146
|
|
|
|
|
318
|
$q2 = Mmulint($j, $q1) - $q0; |
|
8437
|
146
|
|
|
|
|
340
|
($p0, $q0, $p1, $q1) = ($p1, $q1, $p2, $q2); |
|
8438
|
|
|
|
|
|
|
} |
|
8439
|
1
|
|
|
|
|
33
|
return [$p0,$q0]; |
|
8440
|
|
|
|
|
|
|
} |
|
8441
|
|
|
|
|
|
|
|
|
8442
|
2
|
100
|
|
|
|
16
|
return $len unless wantarray; |
|
8443
|
|
|
|
|
|
|
|
|
8444
|
1
|
|
|
|
|
12
|
my @V; |
|
8445
|
1
|
|
|
|
|
5
|
for (1 .. $len) { |
|
8446
|
13
|
|
|
|
|
32
|
push @V, [$p0, $q0]; |
|
8447
|
13
|
|
|
|
|
30
|
$j = Mdivint(($q0 + $n), $q1); |
|
8448
|
13
|
|
|
|
|
23
|
$p2 = Mmulint($j, $p1) - $p0; |
|
8449
|
13
|
|
|
|
|
21
|
$q2 = Mmulint($j, $q1) - $q0; |
|
8450
|
13
|
|
|
|
|
24
|
($p0, $q0, $p1, $q1) = ($p1, $q1, $p2, $q2); |
|
8451
|
|
|
|
|
|
|
} |
|
8452
|
1
|
|
|
|
|
46
|
@V; |
|
8453
|
|
|
|
|
|
|
} |
|
8454
|
|
|
|
|
|
|
|
|
8455
|
|
|
|
|
|
|
# Uses gcdext to find next entry with only one point. |
|
8456
|
|
|
|
|
|
|
sub next_farey { |
|
8457
|
1
|
|
|
1
|
0
|
6
|
my($n,$frac) = @_; |
|
8458
|
1
|
|
|
|
|
5
|
validate_integer_positive($n); |
|
8459
|
1
|
50
|
|
|
|
8
|
croak "next_farey second argument not an array reference" unless ref($frac) eq 'ARRAY'; |
|
8460
|
1
|
|
|
|
|
3
|
my($p,$q) = @$frac; |
|
8461
|
1
|
|
|
|
|
5
|
validate_integer_nonneg($p); |
|
8462
|
1
|
|
|
|
|
4
|
validate_integer_positive($q); |
|
8463
|
1
|
50
|
|
|
|
5
|
return undef if $p >= $q; |
|
8464
|
1
|
|
|
|
|
6
|
my($u,$v,$g) = Mgcdext($p,$q); |
|
8465
|
1
|
50
|
|
|
|
6
|
($p,$q) = (Mdivint($p,$g),Mdivint($q,$g)) if $g != 1; |
|
8466
|
1
|
|
|
|
|
5
|
my $d = Mmulint(Mdivint(($n+$u),$q),$q) - $u; |
|
8467
|
1
|
|
|
|
|
6
|
my $c = Mdivint((Mmulint($d,$p)+1),$q); |
|
8468
|
1
|
|
|
|
|
11
|
[$c,$d]; |
|
8469
|
|
|
|
|
|
|
} |
|
8470
|
|
|
|
|
|
|
|
|
8471
|
|
|
|
|
|
|
sub farey_rank { |
|
8472
|
2
|
|
|
2
|
0
|
6
|
my($n,$frac) = @_; |
|
8473
|
2
|
|
|
|
|
29
|
validate_integer_positive($n); |
|
8474
|
2
|
50
|
|
|
|
9
|
croak "next_farey second argument not an array reference" unless ref($frac) eq 'ARRAY'; |
|
8475
|
2
|
|
|
|
|
7
|
my($p,$q) = @$frac; |
|
8476
|
2
|
|
|
|
|
7
|
validate_integer_nonneg($p); |
|
8477
|
2
|
|
|
|
|
20
|
validate_integer_positive($q); |
|
8478
|
|
|
|
|
|
|
|
|
8479
|
2
|
50
|
|
|
|
8
|
return 0 if $p == 0; |
|
8480
|
|
|
|
|
|
|
|
|
8481
|
2
|
|
|
|
|
19
|
my $g = Mgcd($p,$q); |
|
8482
|
2
|
50
|
|
|
|
8
|
($p,$q) = (Mdivint($p,$g),Mdivint($q,$g)) if $g != 1; |
|
8483
|
|
|
|
|
|
|
|
|
8484
|
2
|
|
|
|
|
16
|
my @count = (0,0,map { Mdivint(Mmulint($p,$_)-1,$q); } 2..$n); |
|
|
374
|
|
|
|
|
715
|
|
|
8485
|
2
|
|
|
|
|
32
|
my $sum = 1; |
|
8486
|
2
|
|
|
|
|
10
|
for my $i (2 .. $n) { |
|
8487
|
374
|
|
|
|
|
601
|
my $icount = $count[$i]; |
|
8488
|
374
|
|
|
|
|
799
|
for (my $j = Mmulint($i,2); $j <= $n; $j = Maddint($j,$i)) { |
|
8489
|
1280
|
|
|
|
|
2634
|
$count[$j] -= $icount; |
|
8490
|
|
|
|
|
|
|
} |
|
8491
|
374
|
|
|
|
|
704
|
$sum += $icount; |
|
8492
|
|
|
|
|
|
|
} |
|
8493
|
2
|
|
|
|
|
100
|
$sum; |
|
8494
|
|
|
|
|
|
|
} |
|
8495
|
|
|
|
|
|
|
|
|
8496
|
|
|
|
|
|
|
# End of Rational maps |
|
8497
|
|
|
|
|
|
|
|
|
8498
|
|
|
|
|
|
|
|
|
8499
|
|
|
|
|
|
|
sub _is_perfect_square { |
|
8500
|
260
|
|
|
260
|
|
59739
|
my($n) = @_; |
|
8501
|
260
|
100
|
|
|
|
1070
|
return (1,1,0,0,1)[$n] if $n <= 4; |
|
8502
|
|
|
|
|
|
|
|
|
8503
|
244
|
100
|
|
|
|
24048
|
if (ref($n)) { |
|
8504
|
110
|
100
|
|
|
|
1134
|
return 0 if ((1 << Mmodint($n,32)) & 0xfdfcfdec); |
|
8505
|
35
|
|
|
|
|
402
|
my $sq = Msqrtint($n); |
|
8506
|
35
|
100
|
|
|
|
2963
|
return 1 if Mmulint($sq,$sq) == $n; |
|
8507
|
|
|
|
|
|
|
} else { |
|
8508
|
134
|
100
|
|
|
|
702
|
return 0 if (1 << ($n & 31)) & 0xfdfcfdec; |
|
8509
|
51
|
100
|
|
|
|
266
|
my $sq = $n < 562949953421312 ? int(sqrt($n)) : Msqrtint($n); |
|
8510
|
51
|
100
|
|
|
|
279
|
return 1 if ($sq*$sq) == $n; |
|
8511
|
|
|
|
|
|
|
} |
|
8512
|
67
|
|
|
|
|
10052
|
0; |
|
8513
|
|
|
|
|
|
|
} |
|
8514
|
|
|
|
|
|
|
|
|
8515
|
|
|
|
|
|
|
sub is_primitive_root { |
|
8516
|
22
|
|
|
22
|
0
|
33244
|
my($a, $n) = @_; |
|
8517
|
22
|
|
|
|
|
2243
|
validate_integer($a); |
|
8518
|
22
|
|
|
|
|
300
|
validate_integer_abs($n); |
|
8519
|
|
|
|
|
|
|
|
|
8520
|
22
|
50
|
|
|
|
1672
|
return (undef,1)[$n] if $n <= 1; |
|
8521
|
22
|
100
|
66
|
|
|
1534
|
$a = Mmodint($a, $n) if $a < 0 || $a >= $n; |
|
8522
|
22
|
100
|
|
|
|
1054
|
return 0+($a == $n-1) if $n <= 4; |
|
8523
|
17
|
100
|
|
|
|
1434
|
return 0 if $a <= 1; |
|
8524
|
|
|
|
|
|
|
|
|
8525
|
|
|
|
|
|
|
return Math::Prime::Util::GMP::is_primitive_root($a,$n) |
|
8526
|
16
|
50
|
|
|
|
109
|
if $Math::Prime::Util::_GMPfunc{"is_primitive_root"}; |
|
8527
|
|
|
|
|
|
|
|
|
8528
|
|
|
|
|
|
|
# my $order = Mznorder($a,$n); return 0 unless defined $order; return 0+($order == Mtotient($n)); |
|
8529
|
|
|
|
|
|
|
|
|
8530
|
16
|
100
|
|
|
|
96
|
if (Mis_even($n)) { |
|
8531
|
2
|
50
|
|
|
|
263
|
return 0 if ($n % 4) == 0; # n can't still be even after we shift it |
|
8532
|
2
|
50
|
|
|
|
1352
|
return 0 if Mis_even($a); # n and a cannot both be even |
|
8533
|
2
|
|
|
|
|
13
|
$n = Mrshiftint($n); # a is odd, so it is a primroot of p^k also |
|
8534
|
|
|
|
|
|
|
} |
|
8535
|
16
|
100
|
|
|
|
1052
|
return 0 if Mgcd($a, $n) != 1; |
|
8536
|
15
|
100
|
|
|
|
84
|
return 0 if _is_perfect_square($a); |
|
8537
|
|
|
|
|
|
|
|
|
8538
|
14
|
|
|
|
|
39
|
my ($p,$k,$phi); |
|
8539
|
14
|
|
|
|
|
159
|
$k = Mis_prime_power($n,\$p); |
|
8540
|
14
|
50
|
|
|
|
78
|
return 0 if !$k; |
|
8541
|
14
|
|
|
|
|
36
|
$n = $p; |
|
8542
|
14
|
|
|
|
|
89
|
$phi = Msub1int($n); |
|
8543
|
14
|
50
|
66
|
|
|
1176
|
return 0 if $k > 1 && Mpowmod($a, $phi, Mmulint($p,$p)) == 1; |
|
8544
|
|
|
|
|
|
|
|
|
8545
|
14
|
100
|
|
|
|
2319
|
return 0 if Mkronecker($a,$n) != -1; |
|
8546
|
13
|
50
|
66
|
|
|
136
|
return 0 if ($phi % 3) == 0 && Mpowmod($a,Mdivint($phi,3),$n) == 1; |
|
8547
|
13
|
50
|
66
|
|
|
2350
|
return 0 if ($phi % 5) == 0 && Mpowmod($a,Mdivint($phi,5),$n) == 1; |
|
8548
|
13
|
|
|
|
|
2299
|
foreach my $f (Mfactor_exp($phi)) { |
|
8549
|
39
|
|
|
|
|
5965
|
my $fp = $f->[0]; |
|
8550
|
39
|
50
|
66
|
|
|
299
|
return 0 if $fp > 5 && Mpowmod($a, Mdivint($phi,$fp), $n) == 1; |
|
8551
|
|
|
|
|
|
|
} |
|
8552
|
13
|
|
|
|
|
1399
|
1; |
|
8553
|
|
|
|
|
|
|
} |
|
8554
|
|
|
|
|
|
|
|
|
8555
|
|
|
|
|
|
|
sub znorder { |
|
8556
|
6
|
|
|
6
|
0
|
6181
|
my($a, $n) = @_; |
|
8557
|
6
|
|
|
|
|
37
|
validate_integer_abs($n); |
|
8558
|
6
|
50
|
|
|
|
431
|
return (undef,1)[$n] if $n <= 1; |
|
8559
|
6
|
|
|
|
|
672
|
$a = Mmodint($a, $n); |
|
8560
|
6
|
50
|
|
|
|
27
|
return undef if $a <= 0; |
|
8561
|
6
|
50
|
|
|
|
35
|
return 1 if $a == 1; |
|
8562
|
|
|
|
|
|
|
|
|
8563
|
|
|
|
|
|
|
return reftyped($_[0], Math::Prime::Util::GMP::znorder($a,$n)) |
|
8564
|
6
|
50
|
|
|
|
25
|
if $Math::Prime::Util::_GMPfunc{"znorder"}; |
|
8565
|
|
|
|
|
|
|
|
|
8566
|
6
|
100
|
|
|
|
32
|
return undef if Mgcd($a, $n) > 1; |
|
8567
|
|
|
|
|
|
|
|
|
8568
|
|
|
|
|
|
|
# Factor n, compute znorder mod each prime power, LCM the results. |
|
8569
|
|
|
|
|
|
|
# This is much faster than working mod n because each p^e is smaller. |
|
8570
|
4
|
|
|
|
|
24
|
my $order = 1; |
|
8571
|
4
|
|
|
|
|
24
|
foreach my $fn (Mfactor_exp($n)) { |
|
8572
|
12
|
|
|
|
|
54
|
my($p, $e) = @$fn; |
|
8573
|
12
|
100
|
|
|
|
47
|
my $pe = ($e == 1) ? $p : Mpowint($p, $e); |
|
8574
|
12
|
|
|
|
|
42
|
my $amod = Mmodint($a, $pe); |
|
8575
|
12
|
100
|
|
|
|
37
|
next if $amod <= 1; |
|
8576
|
|
|
|
|
|
|
# phi(p^e) = (p-1) * p^(e-1) |
|
8577
|
11
|
|
|
|
|
36
|
my $pm1 = Msubint($p, 1); |
|
8578
|
11
|
100
|
|
|
|
53
|
my $phi = ($e == 1) ? $pm1 : Mmulint($pm1, Mpowint($p, $e-1)); |
|
8579
|
|
|
|
|
|
|
|
|
8580
|
|
|
|
|
|
|
# For small phi, enumerate sorted divisors directly. |
|
8581
|
11
|
50
|
|
|
|
42
|
if ($phi < 2 ** MPU_MAXBITS) { |
|
8582
|
11
|
|
|
|
|
21
|
my $found = 0; |
|
8583
|
11
|
|
|
|
|
70
|
foreach my $d (Mdivisors($phi)) { |
|
8584
|
86
|
100
|
|
|
|
2968
|
if (Mpowmod($amod, $d, $pe) == 1) { |
|
8585
|
11
|
|
|
|
|
373
|
$order = Mlcm($order, $d); |
|
8586
|
11
|
|
|
|
|
30
|
$found = 1; |
|
8587
|
11
|
|
|
|
|
26
|
last; |
|
8588
|
|
|
|
|
|
|
} |
|
8589
|
|
|
|
|
|
|
} |
|
8590
|
11
|
50
|
|
|
|
50
|
return undef unless $found; |
|
8591
|
11
|
|
|
|
|
31
|
next; |
|
8592
|
|
|
|
|
|
|
} |
|
8593
|
|
|
|
|
|
|
|
|
8594
|
|
|
|
|
|
|
# Algorithm 1.7 from A. Das applied to phi(p^e). |
|
8595
|
0
|
|
|
|
|
0
|
my $k = 1; |
|
8596
|
0
|
|
|
|
|
0
|
foreach my $f (Mfactor_exp($phi)) { |
|
8597
|
0
|
|
|
|
|
0
|
my($pi, $ei, $enum) = ($f->[0], $f->[1], 0); |
|
8598
|
0
|
|
|
|
|
0
|
my $phidiv = Mdivint($phi, Mpowint($pi, $ei)); |
|
8599
|
0
|
|
|
|
|
0
|
my $b = Mpowmod($amod, $phidiv, $pe); |
|
8600
|
0
|
|
|
|
|
0
|
while ($b != 1) { |
|
8601
|
0
|
0
|
|
|
|
0
|
return undef if $enum++ >= $ei; |
|
8602
|
0
|
|
|
|
|
0
|
$b = Mpowmod($b, $pi, $pe); |
|
8603
|
0
|
|
|
|
|
0
|
$k = Mmulint($k, $pi); |
|
8604
|
|
|
|
|
|
|
} |
|
8605
|
|
|
|
|
|
|
} |
|
8606
|
0
|
|
|
|
|
0
|
$order = Mlcm($order, $k); |
|
8607
|
|
|
|
|
|
|
} |
|
8608
|
4
|
|
|
|
|
80
|
$order; |
|
8609
|
|
|
|
|
|
|
} |
|
8610
|
|
|
|
|
|
|
|
|
8611
|
|
|
|
|
|
|
sub _dlp_trial { |
|
8612
|
3
|
|
|
3
|
|
12
|
my ($a,$g,$p,$limit) = @_; |
|
8613
|
3
|
50
|
33
|
|
|
24
|
$limit = $p if !defined $limit || $limit > $p; |
|
8614
|
|
|
|
|
|
|
|
|
8615
|
3
|
50
|
|
|
|
338
|
if ($limit < 1_000_000_000) { |
|
8616
|
3
|
|
|
|
|
26
|
my $t = $g; |
|
8617
|
3
|
|
|
|
|
12
|
for my $k (1 .. $limit) { |
|
8618
|
215
|
100
|
|
|
|
5022
|
return $k if $t == $a; |
|
8619
|
213
|
|
|
|
|
1193
|
$t = Mmulmod($t, $g, $p); |
|
8620
|
|
|
|
|
|
|
} |
|
8621
|
1
|
|
|
|
|
6
|
return 0; |
|
8622
|
|
|
|
|
|
|
} |
|
8623
|
|
|
|
|
|
|
|
|
8624
|
0
|
|
|
|
|
0
|
($a, $g, $p, $limit) = map { tobigint($_) } ($a, $g, $p, $limit); |
|
|
0
|
|
|
|
|
0
|
|
|
8625
|
0
|
|
|
|
|
0
|
my $t = tobigint($g); |
|
8626
|
0
|
|
|
|
|
0
|
for (my $k = tobigint(1); $k < $limit; $k++) { |
|
8627
|
0
|
0
|
|
|
|
0
|
return Maddint($k,0) if $t == $a; |
|
8628
|
0
|
|
|
|
|
0
|
$t *= $g; |
|
8629
|
0
|
|
|
|
|
0
|
$t %= $p; |
|
8630
|
|
|
|
|
|
|
} |
|
8631
|
0
|
|
|
|
|
0
|
0; |
|
8632
|
|
|
|
|
|
|
} |
|
8633
|
|
|
|
|
|
|
sub _dlp_bsgs { |
|
8634
|
1
|
|
|
1
|
|
5
|
my ($a,$g,$p,$_verbose) = @_; |
|
8635
|
1
|
|
|
|
|
20
|
my $invg = Minvmod($g, $p); |
|
8636
|
1
|
50
|
|
|
|
9
|
return 0 unless defined $invg; |
|
8637
|
1
|
|
|
|
|
9
|
my $N = Madd1int(Msqrtint($p-1)); |
|
8638
|
|
|
|
|
|
|
# Limit for time and space. |
|
8639
|
1
|
50
|
|
|
|
9
|
my $b = $N > 4_000_000 ? 4_000_000 : $N; |
|
8640
|
|
|
|
|
|
|
|
|
8641
|
1
|
|
|
|
|
4
|
my %hash; |
|
8642
|
1
|
|
|
|
|
3
|
my $am = 1; |
|
8643
|
1
|
|
|
|
|
22
|
my $gm = Mpowmod($invg, $N, $p); |
|
8644
|
1
|
|
|
|
|
47
|
my $key = $a; |
|
8645
|
1
|
|
|
|
|
20
|
my $r; |
|
8646
|
|
|
|
|
|
|
|
|
8647
|
1
|
50
|
|
|
|
8
|
print " BSGS starting $b loops\n" if $_verbose > 1; |
|
8648
|
1
|
|
|
|
|
5
|
foreach my $m (0 .. $b) { |
|
8649
|
|
|
|
|
|
|
# Baby Step |
|
8650
|
86
|
50
|
|
|
|
229
|
if ($m <= $N) { |
|
8651
|
86
|
|
|
|
|
237
|
$r = $hash{"$am"}; |
|
8652
|
86
|
50
|
|
|
|
249
|
if (defined $r) { |
|
8653
|
0
|
0
|
|
|
|
0
|
print " bsgs found in stage 1 after $m tries\n" if $_verbose; |
|
8654
|
0
|
|
|
|
|
0
|
$r = Mmuladdmod($r, $N, $m, $p); |
|
8655
|
0
|
|
|
|
|
0
|
return $r; |
|
8656
|
|
|
|
|
|
|
} |
|
8657
|
86
|
|
|
|
|
345
|
$hash{"$am"} = $m; |
|
8658
|
86
|
|
|
|
|
223
|
$am = Mmulmod($am,$g,$p); |
|
8659
|
86
|
50
|
|
|
|
313
|
if ($am == $a) { |
|
8660
|
0
|
0
|
|
|
|
0
|
print " bsgs found during bs\n" if $_verbose; |
|
8661
|
0
|
|
|
|
|
0
|
return $m+1; |
|
8662
|
|
|
|
|
|
|
} |
|
8663
|
|
|
|
|
|
|
} |
|
8664
|
|
|
|
|
|
|
|
|
8665
|
|
|
|
|
|
|
# Giant Step |
|
8666
|
86
|
|
|
|
|
16003
|
$r = $hash{"$key"}; |
|
8667
|
86
|
100
|
|
|
|
223
|
if (defined $r) { |
|
8668
|
1
|
50
|
|
|
|
23
|
print " bsgs found in stage 2 after $m tries\n" if $_verbose; |
|
8669
|
1
|
|
|
|
|
49
|
$r = Mmuladdmod($m, $N, $r, $p); |
|
8670
|
1
|
|
|
|
|
97
|
return $r; |
|
8671
|
|
|
|
|
|
|
} |
|
8672
|
85
|
|
|
|
|
822
|
$hash{"$key"} = $m; |
|
8673
|
85
|
|
|
|
|
301
|
$key = Mmulmod($key,$gm,$p); |
|
8674
|
|
|
|
|
|
|
} |
|
8675
|
0
|
|
|
|
|
0
|
0; |
|
8676
|
|
|
|
|
|
|
} |
|
8677
|
|
|
|
|
|
|
|
|
8678
|
|
|
|
|
|
|
sub znlog { |
|
8679
|
3
|
|
|
3
|
0
|
1840
|
my($a, $g, $n) = @_; |
|
8680
|
3
|
|
|
|
|
27
|
validate_integer($a); |
|
8681
|
3
|
|
|
|
|
148
|
validate_integer($g); |
|
8682
|
3
|
|
|
|
|
113
|
validate_integer_abs($n); |
|
8683
|
3
|
50
|
|
|
|
514
|
return (undef,0,1)[$n] if $n <= 1; |
|
8684
|
3
|
|
|
|
|
557
|
$a = Mmodint($a, $n); |
|
8685
|
3
|
|
|
|
|
20
|
$g = Mmodint($g, $n); |
|
8686
|
3
|
50
|
33
|
|
|
26
|
return 0 if $a == 1 || $g == 0 || $n < 2; |
|
|
|
|
33
|
|
|
|
|
|
8687
|
|
|
|
|
|
|
|
|
8688
|
3
|
|
|
|
|
1498
|
my $_verbose = getconfig()->{'verbose'}; |
|
8689
|
|
|
|
|
|
|
|
|
8690
|
|
|
|
|
|
|
# For large p, znorder can be very slow. Do a small trial test first. |
|
8691
|
3
|
|
|
|
|
27
|
my $x = _dlp_trial($a, $g, $n, 200); |
|
8692
|
|
|
|
|
|
|
|
|
8693
|
3
|
100
|
|
|
|
182
|
if ($x == 0) { |
|
8694
|
1
|
|
|
|
|
7
|
($a,$g,$n) = map { tobigint($_) } ($a,$g,$n); |
|
|
3
|
|
|
|
|
19
|
|
|
8695
|
1
|
|
|
|
|
25
|
$x = _dlp_bsgs($a, $g, $n, $_verbose); |
|
8696
|
1
|
50
|
33
|
|
|
8
|
$x = _bigint_to_int($x) if ref($x) && $x <= INTMAX; |
|
8697
|
1
|
50
|
33
|
|
|
11
|
return $x if $x > 0 && Mpowmod($g,$x,$n) == $a; |
|
8698
|
0
|
0
|
0
|
|
|
0
|
print " BSGS giving up\n" if $x == 0 && $_verbose; |
|
8699
|
0
|
0
|
0
|
|
|
0
|
print " BSGS incorrect answer $x\n" if $x > 0 && $_verbose > 1; |
|
8700
|
0
|
|
|
|
|
0
|
$x = _dlp_trial($a,$g,$n); |
|
8701
|
|
|
|
|
|
|
} |
|
8702
|
2
|
50
|
33
|
|
|
15
|
$x = _bigint_to_int($x) if ref($x) && $x <= INTMAX; |
|
8703
|
2
|
50
|
|
|
|
26
|
return ($x == 0) ? undef : $x; |
|
8704
|
|
|
|
|
|
|
} |
|
8705
|
|
|
|
|
|
|
|
|
8706
|
|
|
|
|
|
|
sub znprimroot { |
|
8707
|
12
|
|
|
12
|
0
|
30373
|
my($n) = @_; |
|
8708
|
12
|
|
|
|
|
101
|
validate_integer_abs($n); |
|
8709
|
12
|
100
|
|
|
|
1357
|
return (undef,0,1,2,3)[$n] if $n <= 4; |
|
8710
|
10
|
100
|
|
|
|
1188
|
return if $n % 4 == 0; |
|
8711
|
|
|
|
|
|
|
|
|
8712
|
9
|
|
|
|
|
3061
|
my $iseven = Mis_even($n); |
|
8713
|
9
|
100
|
|
|
|
610
|
$n = Mrshiftint($n) if $iseven; |
|
8714
|
|
|
|
|
|
|
|
|
8715
|
9
|
|
|
|
|
515
|
my($k,$p); |
|
8716
|
9
|
|
|
|
|
83
|
$k = Mis_prime_power($n, \$p); |
|
8717
|
9
|
100
|
|
|
|
40
|
return if $k < 1; |
|
8718
|
8
|
50
|
33
|
|
|
31
|
return 5 if $p == 3 && $iseven; |
|
8719
|
8
|
|
|
|
|
1169
|
my $ispow = ($k > 1); |
|
8720
|
|
|
|
|
|
|
|
|
8721
|
8
|
|
|
|
|
27
|
my $phi = $p-1; |
|
8722
|
8
|
100
|
|
|
|
1953
|
my $psquared = $ispow ? Mmulint($p,$p) : 0; |
|
8723
|
|
|
|
|
|
|
|
|
8724
|
34
|
|
|
|
|
215
|
my @phidivfac = map { Mdivint($phi, $_) } |
|
8725
|
42
|
|
|
|
|
110
|
grep { $_ > 2 } |
|
8726
|
8
|
|
|
|
|
1049
|
map { $_->[0] } Mfactor_exp($phi); |
|
|
42
|
|
|
|
|
113
|
|
|
8727
|
8
|
|
|
|
|
55
|
my $a = 1; |
|
8728
|
8
|
|
|
|
|
17
|
while (1) { |
|
8729
|
127
|
100
|
|
|
|
2113
|
$a += $iseven ? 2 : 1; |
|
8730
|
127
|
50
|
|
|
|
339
|
return if $a >= $p; |
|
8731
|
127
|
100
|
100
|
|
|
4884
|
next if $a == 4 || $a == 8 || $a == 9; |
|
|
|
|
100
|
|
|
|
|
|
8732
|
119
|
100
|
|
|
|
441
|
next if Mkronecker($a,$p) != -1; |
|
8733
|
37
|
100
|
|
70
|
|
581
|
next if Mvecany(sub { Mpowmod($a,$_,$p) == 1 }, @phidivfac); |
|
|
70
|
|
|
|
|
13733
|
|
|
8734
|
8
|
50
|
66
|
|
|
2230
|
return $a unless $ispow && Mpowmod($a,$phi,$psquared) == 1; |
|
8735
|
|
|
|
|
|
|
} |
|
8736
|
|
|
|
|
|
|
} |
|
8737
|
|
|
|
|
|
|
|
|
8738
|
|
|
|
|
|
|
sub qnr { |
|
8739
|
3
|
|
|
3
|
0
|
226
|
my($n) = @_; |
|
8740
|
3
|
|
|
|
|
26
|
validate_integer_abs($n); |
|
8741
|
3
|
50
|
|
|
|
372
|
return (undef,1,2)[$n] if $n <= 2; |
|
8742
|
|
|
|
|
|
|
|
|
8743
|
3
|
50
|
|
|
|
463
|
return 2 if Mkronecker(2,$n) == -1; |
|
8744
|
|
|
|
|
|
|
|
|
8745
|
3
|
100
|
|
|
|
30
|
if (Mis_prime($n)) { |
|
8746
|
2
|
|
|
|
|
11
|
for (my $a = 3; $a < $n; $a = Mnext_prime($a)) { |
|
8747
|
14
|
100
|
|
|
|
1267
|
return $a if Mkronecker($a,$n) == -1; |
|
8748
|
|
|
|
|
|
|
} |
|
8749
|
|
|
|
|
|
|
} else { |
|
8750
|
1
|
50
|
|
|
|
244
|
if ($n % 2 == 0) { |
|
8751
|
1
|
|
|
|
|
368
|
my $e = Mvaluation($n, 2); |
|
8752
|
1
|
|
|
|
|
6
|
$n >>= $e; |
|
8753
|
1
|
50
|
33
|
|
|
399
|
return 2 if $n == 1 || $e >= 2; |
|
8754
|
|
|
|
|
|
|
} |
|
8755
|
0
|
0
|
0
|
|
|
0
|
return 2 if !($n%3) || !($n%5) || !($n%11) || !($n%13) || !($n%19); |
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
8756
|
0
|
|
|
|
|
0
|
my @F = Mfactor_exp($n); |
|
8757
|
0
|
|
|
|
|
0
|
for (my $a = 2; $a < $n; $a = Mnext_prime($a)) { |
|
8758
|
0
|
|
|
|
|
0
|
for my $pe (@F) { |
|
8759
|
0
|
|
|
|
|
0
|
my $p = $pe->[0]; |
|
8760
|
0
|
0
|
0
|
|
|
0
|
return $a if $a < $p && Mkronecker($a,$p) == -1; |
|
8761
|
|
|
|
|
|
|
} |
|
8762
|
|
|
|
|
|
|
} |
|
8763
|
|
|
|
|
|
|
} |
|
8764
|
0
|
|
|
|
|
0
|
0; |
|
8765
|
|
|
|
|
|
|
} |
|
8766
|
|
|
|
|
|
|
|
|
8767
|
|
|
|
|
|
|
|
|
8768
|
|
|
|
|
|
|
# Find first D in sequence (5,-7,9,-11,13,-15,...) where (D|N) == -1 |
|
8769
|
|
|
|
|
|
|
sub _lucas_selfridge_params { |
|
8770
|
8
|
|
|
8
|
|
29
|
my($n) = @_; |
|
8771
|
|
|
|
|
|
|
|
|
8772
|
|
|
|
|
|
|
# D is typically quite small: 67 max for N < 10^19. However, it is |
|
8773
|
|
|
|
|
|
|
# theoretically possible D could grow unreasonably. I'm giving up at 4000M. |
|
8774
|
8
|
|
|
|
|
22
|
my $d = 5; |
|
8775
|
8
|
|
|
|
|
18
|
my $sign = 1; |
|
8776
|
8
|
|
|
|
|
19
|
while (1) { |
|
8777
|
21
|
|
|
|
|
85
|
my $gcd = Mgcd($d, $n); |
|
8778
|
21
|
50
|
33
|
|
|
84
|
return (0,0,0) if $gcd > 1 && $gcd != $n; # Found divisor $d |
|
8779
|
21
|
|
|
|
|
76
|
my $j = Mkronecker($d * $sign, $n); |
|
8780
|
21
|
100
|
|
|
|
77
|
last if $j == -1; |
|
8781
|
13
|
|
|
|
|
30
|
$d += 2; |
|
8782
|
13
|
50
|
|
|
|
40
|
croak "Could not find Jacobi sequence for $n" if $d > 4_000_000_000; |
|
8783
|
13
|
|
|
|
|
29
|
$sign = -$sign; |
|
8784
|
|
|
|
|
|
|
} |
|
8785
|
8
|
|
|
|
|
21
|
my $D = $sign * $d; |
|
8786
|
8
|
|
|
|
|
19
|
my $P = 1; |
|
8787
|
8
|
|
|
|
|
29
|
my $Q = int( (1 - $D) / 4 ); |
|
8788
|
8
|
|
|
|
|
35
|
($P, $Q, $D) |
|
8789
|
|
|
|
|
|
|
} |
|
8790
|
|
|
|
|
|
|
|
|
8791
|
|
|
|
|
|
|
sub _lucas_extrastrong_params { |
|
8792
|
162
|
|
|
162
|
|
540
|
my($n, $increment) = @_; |
|
8793
|
162
|
100
|
|
|
|
753
|
$increment = 1 unless defined $increment; |
|
8794
|
162
|
50
|
|
|
|
606
|
croak "internal lucas, increment $increment" if $increment < 1; |
|
8795
|
|
|
|
|
|
|
|
|
8796
|
162
|
|
|
|
|
504
|
my ($P, $Q, $D) = (3, 1, 5); |
|
8797
|
162
|
|
|
|
|
361
|
while (1) { |
|
8798
|
382
|
|
|
|
|
2556
|
my $gcd = Mgcd($D, $n); |
|
8799
|
382
|
50
|
33
|
|
|
1669
|
return (0,0,0) if $gcd > 1 && $gcd != $n; # Found divisor $d |
|
8800
|
382
|
100
|
|
|
|
2096
|
last if Mkronecker($D, $n) == -1; |
|
8801
|
220
|
|
|
|
|
605
|
$P += $increment; |
|
8802
|
220
|
50
|
|
|
|
590
|
croak "Could not find Jacobi sequence for $n" if $P > 65535; |
|
8803
|
220
|
|
|
|
|
529
|
$D = $P*$P - 4; |
|
8804
|
|
|
|
|
|
|
} |
|
8805
|
162
|
|
|
|
|
976
|
($P, $Q, $D); |
|
8806
|
|
|
|
|
|
|
} |
|
8807
|
|
|
|
|
|
|
|
|
8808
|
|
|
|
|
|
|
# returns U_k, V_k, Q_k all mod n |
|
8809
|
|
|
|
|
|
|
sub lucas_sequence { |
|
8810
|
0
|
|
|
0
|
0
|
0
|
my($n, $P, $Q, $k) = @_; |
|
8811
|
|
|
|
|
|
|
|
|
8812
|
0
|
0
|
|
|
|
0
|
croak "lucas_sequence: n must be > 0" if $n < 1; |
|
8813
|
0
|
0
|
|
|
|
0
|
croak "lucas_sequence: k must be >= 0" if $k < 0; |
|
8814
|
0
|
0
|
|
|
|
0
|
return (0,0,0) if $n == 1; |
|
8815
|
|
|
|
|
|
|
|
|
8816
|
0
|
0
|
0
|
|
|
0
|
if ($Math::Prime::Util::_GMPfunc{"lucas_sequence"} && $Math::Prime::Util::GMP::VERSION >= 0.30 && !ref($P) && !ref($Q)) { |
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
8817
|
0
|
|
|
|
|
0
|
return maybetobigintall( |
|
8818
|
|
|
|
|
|
|
Math::Prime::Util::GMP::lucas_sequence($n, $P, $Q, $k) |
|
8819
|
|
|
|
|
|
|
); |
|
8820
|
|
|
|
|
|
|
} |
|
8821
|
|
|
|
|
|
|
|
|
8822
|
0
|
|
|
|
|
0
|
return (lucasuvmod($P,$Q,$k,$n), Mpowmod($Q,$k,$n)); |
|
8823
|
|
|
|
|
|
|
} |
|
8824
|
|
|
|
|
|
|
|
|
8825
|
|
|
|
|
|
|
sub lucasuv { |
|
8826
|
80
|
|
|
80
|
0
|
73166
|
my($P, $Q, $k) = @_; |
|
8827
|
|
|
|
|
|
|
|
|
8828
|
80
|
50
|
|
|
|
315
|
croak "lucasuv: k must be >= 0" if $k < 0; |
|
8829
|
80
|
50
|
|
|
|
281
|
return (0,2) if $k == 0; |
|
8830
|
|
|
|
|
|
|
|
|
8831
|
80
|
50
|
33
|
|
|
446
|
if ($Math::Prime::Util::_GMPfunc{"lucasuv"} && $Math::Prime::Util::GMP::VERSION >= 0.53) { |
|
8832
|
0
|
|
|
|
|
0
|
return maybetobigintall( |
|
8833
|
|
|
|
|
|
|
Math::Prime::Util::GMP::lucasuv($P, $Q, $k) |
|
8834
|
|
|
|
|
|
|
); |
|
8835
|
|
|
|
|
|
|
} |
|
8836
|
|
|
|
|
|
|
|
|
8837
|
|
|
|
|
|
|
# Do this very generic. Optimize later if needed (D=0,Q=1,Q=-1,n odd). |
|
8838
|
|
|
|
|
|
|
|
|
8839
|
80
|
|
|
|
|
218
|
($P,$Q) = map { tobigint($_) } ($P,$Q); |
|
|
160
|
|
|
|
|
606
|
|
|
8840
|
80
|
|
|
|
|
239
|
my($Uh, $Vl, $Vh, $Ql, $Qh) = map { tobigint($_) } (1, 2, $P, 1, 1); |
|
|
400
|
|
|
|
|
1003
|
|
|
8841
|
|
|
|
|
|
|
|
|
8842
|
80
|
|
|
|
|
245
|
my $s = 0; |
|
8843
|
80
|
|
|
|
|
618
|
my @kbits = Mtodigits($k, 2); |
|
8844
|
80
|
|
|
|
|
334
|
while ($kbits[-1] == 0) { $s++; pop @kbits; } # Remove trailing zeros. |
|
|
71
|
|
|
|
|
131
|
|
|
|
71
|
|
|
|
|
166
|
|
|
8845
|
80
|
|
|
|
|
170
|
pop @kbits; # Remove trailing 1. |
|
8846
|
|
|
|
|
|
|
|
|
8847
|
80
|
|
|
|
|
224
|
foreach my $bit (@kbits) { |
|
8848
|
394
|
|
|
|
|
174092
|
$Ql *= $Qh; |
|
8849
|
394
|
100
|
|
|
|
110067
|
if ($bit) { |
|
8850
|
205
|
|
|
|
|
604
|
$Qh = $Ql * $Q; |
|
8851
|
205
|
|
|
|
|
33762
|
$Uh = $Uh * $Vh; |
|
8852
|
205
|
|
|
|
|
94585
|
$Vl = $Vh * $Vl - $P * $Ql; |
|
8853
|
205
|
|
|
|
|
181658
|
$Vh = $Vh * $Vh - ($Qh+$Qh); |
|
8854
|
|
|
|
|
|
|
} else { |
|
8855
|
189
|
|
|
|
|
405
|
$Qh = $Ql; |
|
8856
|
189
|
|
|
|
|
747
|
$Uh = $Uh * $Vl - $Ql; |
|
8857
|
189
|
|
|
|
|
95163
|
$Vh = $Vh * $Vl - $P * $Ql; |
|
8858
|
189
|
|
|
|
|
121777
|
$Vl = $Vl * $Vl - ($Ql+$Ql); |
|
8859
|
|
|
|
|
|
|
} |
|
8860
|
|
|
|
|
|
|
} |
|
8861
|
80
|
|
|
|
|
105887
|
$Ql *= $Qh; |
|
8862
|
80
|
|
|
|
|
118957
|
$Qh = $Ql * $Q; |
|
8863
|
80
|
|
|
|
|
22462
|
$Uh = $Uh * $Vl - $Ql; |
|
8864
|
80
|
|
|
|
|
244025
|
$Vl = $Vh * $Vl - $P * $Ql; |
|
8865
|
80
|
|
|
|
|
271245
|
$Ql *= $Qh; |
|
8866
|
80
|
|
|
|
|
457775
|
for (1 .. $s) { |
|
8867
|
71
|
|
|
|
|
4077
|
$Uh *= $Vl; |
|
8868
|
71
|
|
|
|
|
752592
|
$Vl = $Vl * $Vl - ($Ql+$Ql); |
|
8869
|
71
|
|
|
|
|
1005208
|
$Ql *= $Ql; |
|
8870
|
|
|
|
|
|
|
} |
|
8871
|
80
|
100
|
66
|
|
|
1836903
|
$Uh = _bigint_to_int($Uh) if $Uh <= INTMAX && $Uh >= INTMIN; |
|
8872
|
80
|
100
|
100
|
|
|
18331
|
$Vl = _bigint_to_int($Vl) if $Vl <= INTMAX && $Vl >= INTMIN; |
|
8873
|
80
|
|
|
|
|
18426
|
($Uh, $Vl); |
|
8874
|
|
|
|
|
|
|
} |
|
8875
|
|
|
|
|
|
|
|
|
8876
|
|
|
|
|
|
|
sub lucasuvmod { |
|
8877
|
146
|
|
|
146
|
0
|
38081
|
my($P, $Q, $k, $n) = @_; |
|
8878
|
146
|
|
|
|
|
667
|
validate_integer($P); |
|
8879
|
146
|
|
|
|
|
696
|
validate_integer($Q); |
|
8880
|
146
|
|
|
|
|
1136
|
validate_integer_nonneg($k); |
|
8881
|
146
|
|
|
|
|
4448
|
validate_integer_abs($n); |
|
8882
|
146
|
50
|
|
|
|
27733
|
return if $n == 0; |
|
8883
|
146
|
50
|
|
|
|
25767
|
return (0,0) if $n == 1; |
|
8884
|
146
|
50
|
|
|
|
25534
|
return (0, Mmodint(2,$n)) if $k == 0; |
|
8885
|
|
|
|
|
|
|
|
|
8886
|
146
|
50
|
33
|
|
|
19256
|
if ($Math::Prime::Util::_GMPfunc{"lucasuvmod"} && $Math::Prime::Util::GMP::VERSION >= 0.53) { |
|
8887
|
0
|
|
|
|
|
0
|
return maybetobigintall( |
|
8888
|
|
|
|
|
|
|
Math::Prime::Util::GMP::lucasuvmod($P, $Q, $k, $n) |
|
8889
|
|
|
|
|
|
|
); |
|
8890
|
|
|
|
|
|
|
} |
|
8891
|
|
|
|
|
|
|
|
|
8892
|
146
|
50
|
33
|
|
|
950
|
$P = Mmodint($P,$n) if $P < 0 || $P >= $n; |
|
8893
|
146
|
100
|
66
|
|
|
18668
|
$Q = Mmodint($Q,$n) if $Q < 0 || $Q >= $n; |
|
8894
|
146
|
|
|
|
|
29926
|
my $D = Mmulsubmod($P, $P, Mmulmod(4,$Q,$n), $n); |
|
8895
|
|
|
|
|
|
|
|
|
8896
|
146
|
50
|
|
|
|
8687
|
if ($D == 0) { |
|
8897
|
0
|
|
|
|
|
0
|
my $S = Mdivmod($P, 2, $n); |
|
8898
|
0
|
0
|
|
|
|
0
|
if ($S) { |
|
8899
|
0
|
|
|
|
|
0
|
my $U = Mmulmod($k, Mpowmod($S, $k-1, $n), $n); |
|
8900
|
0
|
|
|
|
|
0
|
my $V = Mmulmod(2, Mpowmod($S, $k, $n), $n); |
|
8901
|
0
|
|
|
|
|
0
|
return ($U, $V); |
|
8902
|
|
|
|
|
|
|
} |
|
8903
|
|
|
|
|
|
|
} |
|
8904
|
|
|
|
|
|
|
|
|
8905
|
146
|
|
|
|
|
4799
|
my @kbits = Mtodigits($k, 2); |
|
8906
|
146
|
|
|
|
|
483
|
shift @kbits; # Remove leading 1 |
|
8907
|
146
|
|
|
|
|
429
|
my $U = 1; |
|
8908
|
146
|
|
|
|
|
446
|
my $V = $P; |
|
8909
|
146
|
|
|
|
|
1196
|
my $invD = Minvmod($D, $n); |
|
8910
|
146
|
|
|
|
|
1046
|
my $nisodd = Mis_odd($n); |
|
8911
|
|
|
|
|
|
|
|
|
8912
|
146
|
100
|
66
|
|
|
12531
|
if ($Q == 1 && $invD) { |
|
|
|
100
|
66
|
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
8913
|
113
|
|
|
|
|
4557
|
$U = Mmulsubmod($P, $P, 2, $n); |
|
8914
|
113
|
|
|
|
|
5097
|
foreach my $bit (@kbits) { |
|
8915
|
8120
|
|
|
|
|
1734416
|
my $T = Mmulsubmod($U, $V, $P, $n); |
|
8916
|
8120
|
100
|
|
|
|
1740985
|
if ($bit) { |
|
8917
|
3489
|
|
|
|
|
8329
|
$V = $T; |
|
8918
|
3489
|
|
|
|
|
22881
|
$U = Mmulsubmod($U, $U, 2, $n); |
|
8919
|
|
|
|
|
|
|
} else { |
|
8920
|
4631
|
|
|
|
|
10005
|
$U = $T; |
|
8921
|
4631
|
|
|
|
|
28503
|
$V = Mmulsubmod($V, $V, 2, $n); |
|
8922
|
|
|
|
|
|
|
} |
|
8923
|
|
|
|
|
|
|
} |
|
8924
|
113
|
|
|
|
|
23476
|
$V = Mmodint($V,$n); |
|
8925
|
113
|
|
|
|
|
969
|
$U = Maddmod($U, $U, $n); |
|
8926
|
113
|
|
|
|
|
22519
|
$U = Msubmod($U, Mmulmod($V, $P, $n), $n); |
|
8927
|
113
|
|
|
|
|
13385
|
$U = Mmulmod($U, $invD, $n); |
|
8928
|
|
|
|
|
|
|
} elsif ($nisodd && ($Q == 1 || $Q == ($n-1))) { |
|
8929
|
13
|
|
|
|
|
25
|
my $ps = ($P == 1); |
|
8930
|
13
|
|
|
|
|
23
|
my $qs = ($Q == 1); |
|
8931
|
13
|
|
|
|
|
43
|
my $halfn = Madd1int(Mrshiftint($n)); |
|
8932
|
13
|
|
|
|
|
47
|
foreach my $bit (@kbits) { |
|
8933
|
124
|
|
|
|
|
356
|
$U = Mmulmod($U, $V, $n); |
|
8934
|
124
|
100
|
|
|
|
402
|
$V = ($qs) ? Mmulsubmod($V,$V,2,$n) : Mmuladdmod($V,$V,2,$n); |
|
8935
|
124
|
|
|
|
|
205
|
$qs = 1; |
|
8936
|
124
|
100
|
|
|
|
285
|
if ($bit) { |
|
8937
|
70
|
|
|
|
|
187
|
my $t = Mmulmod($U, $D, $n); |
|
8938
|
70
|
50
|
|
|
|
267
|
$U = (!$ps) ? Mmuladdmod($U,$P,$V,$n) : Maddmod($U,$V,$n); |
|
8939
|
70
|
100
|
|
|
|
211
|
if (Mis_odd($U)) { |
|
8940
|
18
|
|
|
|
|
56
|
$U = Maddint(Mrshiftint($U), $halfn); |
|
8941
|
|
|
|
|
|
|
} else { |
|
8942
|
52
|
|
|
|
|
167
|
$U = Mrshiftint($U); |
|
8943
|
|
|
|
|
|
|
} |
|
8944
|
70
|
50
|
|
|
|
291
|
$V = (!$ps) ? Mmuladdmod($V,$P,$t,$n) : Maddmod($V,$t,$n); |
|
8945
|
70
|
100
|
|
|
|
177
|
if (Mis_odd($V)) { |
|
8946
|
18
|
|
|
|
|
55
|
$V = Maddint(Mrshiftint($V), $halfn); |
|
8947
|
|
|
|
|
|
|
} else { |
|
8948
|
52
|
|
|
|
|
168
|
$V = Mrshiftint($V); |
|
8949
|
|
|
|
|
|
|
} |
|
8950
|
70
|
|
|
|
|
205
|
$qs = ($Q==1); |
|
8951
|
|
|
|
|
|
|
} |
|
8952
|
|
|
|
|
|
|
} |
|
8953
|
|
|
|
|
|
|
} elsif ($nisodd) { |
|
8954
|
11
|
|
|
|
|
4784
|
my $Qk = $Q; |
|
8955
|
11
|
|
|
|
|
70
|
my $halfn = Madd1int(Mrshiftint($n)); |
|
8956
|
11
|
|
|
|
|
1468
|
foreach my $bit (@kbits) { |
|
8957
|
259
|
|
|
|
|
22174
|
$U = Mmulmod($U, $V, $n); |
|
8958
|
259
|
|
|
|
|
51085
|
$V = Mmulsubmod($V, $V, Maddmod($Qk, $Qk, $n), $n); |
|
8959
|
259
|
|
|
|
|
44564
|
$Qk = Mmulmod($Qk, $Qk, $n); |
|
8960
|
259
|
100
|
|
|
|
60200
|
if ($bit) { |
|
8961
|
130
|
|
|
|
|
618
|
my $t = Mmulmod($U, $D, $n); |
|
8962
|
130
|
|
|
|
|
24945
|
$U = Mmuladdmod($U, $P, $V, $n); |
|
8963
|
130
|
100
|
|
|
|
21736
|
if (Mis_odd($U)) { |
|
8964
|
54
|
|
|
|
|
3218
|
$U = Maddint(Mrshiftint($U), $halfn); |
|
8965
|
|
|
|
|
|
|
} else { |
|
8966
|
76
|
|
|
|
|
5087
|
$U = Mrshiftint($U); |
|
8967
|
|
|
|
|
|
|
} |
|
8968
|
130
|
|
|
|
|
21648
|
$V = Mmuladdmod($V, $P, $t, $n); |
|
8969
|
130
|
100
|
|
|
|
22671
|
if (Mis_odd($V)) { |
|
8970
|
66
|
|
|
|
|
5068
|
$V = Maddint(Mrshiftint($V), $halfn); |
|
8971
|
|
|
|
|
|
|
} else { |
|
8972
|
64
|
|
|
|
|
3541
|
$V = Mrshiftint($V); |
|
8973
|
|
|
|
|
|
|
} |
|
8974
|
130
|
|
|
|
|
21658
|
$Qk = Mmulmod($Qk, $Q, $n); |
|
8975
|
|
|
|
|
|
|
} |
|
8976
|
|
|
|
|
|
|
} |
|
8977
|
|
|
|
|
|
|
} else { |
|
8978
|
9
|
|
|
|
|
1977
|
my ($s, $Uh, $Vl, $Vh, $Ql, $Qh) = (0, 1, 2, $P, 1, 1); |
|
8979
|
9
|
|
|
|
|
48
|
unshift @kbits, 1; # Add back leading 1. |
|
8980
|
9
|
|
|
|
|
38
|
while ($kbits[-1] == 0) { $s++; pop @kbits; } # Remove trailing zeros. |
|
|
3
|
|
|
|
|
8
|
|
|
|
3
|
|
|
|
|
12
|
|
|
8981
|
9
|
|
|
|
|
22
|
pop @kbits; # Remove trailing 1. |
|
8982
|
9
|
|
|
|
|
27
|
foreach my $bit (@kbits) { |
|
8983
|
247
|
|
|
|
|
27621
|
$Ql = Mmulmod($Ql, $Qh, $n); |
|
8984
|
247
|
100
|
|
|
|
24239
|
if ($bit) { |
|
8985
|
138
|
|
|
|
|
561
|
$Qh = Mmulmod($Ql, $Q, $n); |
|
8986
|
138
|
|
|
|
|
11193
|
$Uh = Mmulmod($Uh, $Vh, $n); |
|
8987
|
138
|
|
|
|
|
15112
|
$Vl = Mmulsubmod($Vh, $Vl, Mmulmod($P, $Ql, $n), $n); |
|
8988
|
138
|
|
|
|
|
16589
|
$Vh = Mmulsubmod($Vh, $Vh, Maddmod($Qh, $Qh, $n), $n); |
|
8989
|
|
|
|
|
|
|
} else { |
|
8990
|
109
|
|
|
|
|
228
|
$Qh = $Ql; |
|
8991
|
109
|
|
|
|
|
482
|
$Uh = Mmulsubmod($Uh, $Vl, $Ql, $n); |
|
8992
|
109
|
|
|
|
|
13626
|
$Vh = Mmulsubmod($Vh, $Vl, Mmulmod($P, $Ql, $n), $n); |
|
8993
|
109
|
|
|
|
|
13569
|
$Vl = Mmulsubmod($Vl, $Vl, Maddmod($Ql, $Ql, $n), $n); |
|
8994
|
|
|
|
|
|
|
} |
|
8995
|
|
|
|
|
|
|
} |
|
8996
|
9
|
|
|
|
|
1868
|
$Ql = Mmulmod($Ql, $Qh, $n); |
|
8997
|
9
|
|
|
|
|
1943
|
$Qh = Mmulmod($Ql, $Q, $n); |
|
8998
|
9
|
|
|
|
|
1829
|
$Uh = Mmulsubmod($Uh, $Vl, $Ql, $n); |
|
8999
|
9
|
|
|
|
|
1727
|
$Vl = Mmulsubmod($Vh, $Vl, Mmulmod($P, $Ql, $n), $n); |
|
9000
|
9
|
|
|
|
|
2162
|
$Ql = Mmulmod($Ql, $Qh, $n); |
|
9001
|
9
|
|
|
|
|
2062
|
for (1 .. $s) { |
|
9002
|
3
|
|
|
|
|
21
|
$Uh = Mmulmod($Uh, $Vl, $n); |
|
9003
|
3
|
|
|
|
|
815
|
$Vl = Mmulsubmod($Vl, $Vl, Maddmod($Ql, $Ql, $n), $n); |
|
9004
|
3
|
|
|
|
|
792
|
$Ql = Mmulmod($Ql, $Ql, $n); |
|
9005
|
|
|
|
|
|
|
} |
|
9006
|
9
|
|
|
|
|
812
|
($U, $V) = ($Uh, $Vl); |
|
9007
|
|
|
|
|
|
|
} |
|
9008
|
146
|
|
|
|
|
17619
|
($U,$V); |
|
9009
|
|
|
|
|
|
|
} |
|
9010
|
|
|
|
|
|
|
|
|
9011
|
|
|
|
|
|
|
sub lucasu { |
|
9012
|
|
|
|
|
|
|
return maybetobigint( Math::Prime::Util::GMP::lucasu($_[0], $_[1], $_[2]) ) |
|
9013
|
27
|
50
|
|
27
|
0
|
105644
|
if $Math::Prime::Util::_GMPfunc{"lucasu"}; |
|
9014
|
27
|
|
|
|
|
113
|
(lucasuv(@_))[0]; |
|
9015
|
|
|
|
|
|
|
} |
|
9016
|
|
|
|
|
|
|
sub lucasv { |
|
9017
|
|
|
|
|
|
|
return maybetobigint( Math::Prime::Util::GMP::lucasv($_[0], $_[1], $_[2]) ) |
|
9018
|
27
|
50
|
|
27
|
0
|
48778
|
if $Math::Prime::Util::_GMPfunc{"lucasv"}; |
|
9019
|
27
|
|
|
|
|
119
|
(lucasuv(@_))[1]; |
|
9020
|
|
|
|
|
|
|
} |
|
9021
|
|
|
|
|
|
|
|
|
9022
|
|
|
|
|
|
|
sub lucasumod { |
|
9023
|
|
|
|
|
|
|
return maybetobigint( Math::Prime::Util::GMP::lucasumod($_[0], $_[1], $_[2], $_[3]) ) |
|
9024
|
15
|
50
|
|
15
|
0
|
5528
|
if $Math::Prime::Util::_GMPfunc{"lucasumod"}; |
|
9025
|
15
|
|
|
|
|
84
|
(lucasuvmod(@_))[0]; |
|
9026
|
|
|
|
|
|
|
} |
|
9027
|
|
|
|
|
|
|
sub lucasvmod { |
|
9028
|
9
|
|
|
9
|
0
|
6624
|
my($P, $Q, $k, $n) = @_; |
|
9029
|
|
|
|
|
|
|
return maybetobigint( Math::Prime::Util::GMP::lucasvmod($P, $Q, $k, $n) ) |
|
9030
|
9
|
50
|
|
|
|
57
|
if $Math::Prime::Util::_GMPfunc{"lucasvmod"}; |
|
9031
|
9
|
|
|
|
|
64
|
validate_integer($P); |
|
9032
|
9
|
|
|
|
|
272
|
validate_integer($Q); |
|
9033
|
9
|
|
|
|
|
253
|
validate_integer_nonneg($k); |
|
9034
|
9
|
|
|
|
|
293
|
validate_integer_abs($n); |
|
9035
|
9
|
50
|
|
|
|
1440
|
return if $n == 0; |
|
9036
|
|
|
|
|
|
|
|
|
9037
|
9
|
100
|
|
|
|
1586
|
return (lucasuvmod($P, $Q, $k, $n))[1] if $Q != 1; |
|
9038
|
|
|
|
|
|
|
|
|
9039
|
|
|
|
|
|
|
# Fast algorithm for Q=1 |
|
9040
|
3
|
|
|
|
|
18
|
$P = Mmodint($P, $n); |
|
9041
|
3
|
|
|
|
|
9
|
my $V = 2; |
|
9042
|
3
|
|
|
|
|
6
|
my $U = $P; |
|
9043
|
3
|
|
|
|
|
21
|
foreach my $bit (Mtodigits($k, 2)) { |
|
9044
|
74
|
|
|
|
|
8696
|
my $T = Mmulsubmod($U, $V, $P, $n); |
|
9045
|
74
|
100
|
|
|
|
8536
|
if ($bit) { |
|
9046
|
31
|
|
|
|
|
67
|
$V = $T; |
|
9047
|
31
|
|
|
|
|
172
|
$U = Mmulsubmod($U, $U, 2, $n); |
|
9048
|
|
|
|
|
|
|
} else { |
|
9049
|
43
|
|
|
|
|
97
|
$U = $T; |
|
9050
|
43
|
|
|
|
|
203
|
$V = Mmulsubmod($V, $V, 2, $n); |
|
9051
|
|
|
|
|
|
|
} |
|
9052
|
|
|
|
|
|
|
} |
|
9053
|
3
|
|
|
|
|
195
|
return $V; |
|
9054
|
|
|
|
|
|
|
} |
|
9055
|
|
|
|
|
|
|
|
|
9056
|
|
|
|
|
|
|
my %_ppc = (3 => 8, 5 => 20, 7 => 16, 11 => 10, 13 => 28, 17 => 36, 19 => 18); |
|
9057
|
|
|
|
|
|
|
_register_free_sub(sub { |
|
9058
|
|
|
|
|
|
|
%_ppc = (3 => 8, 5 => 20, 7 => 16, 11 => 10, 13 => 28, 17 => 36, 19 => 18); |
|
9059
|
|
|
|
|
|
|
}); |
|
9060
|
|
|
|
|
|
|
sub _pisano_pp { |
|
9061
|
15
|
|
|
15
|
|
26
|
my($p,$e) = @_; |
|
9062
|
15
|
50
|
|
|
|
33
|
return 1 if $e == 0; |
|
9063
|
15
|
100
|
66
|
|
|
65
|
return 3 << ($e-1) if $p == 2 && $e < 32; |
|
9064
|
12
|
50
|
|
|
|
36
|
return Mlshiftint(3,$e-1) if $p == 2; |
|
9065
|
12
|
|
|
|
|
39
|
my $k = $_ppc{$p}; |
|
9066
|
|
|
|
|
|
|
|
|
9067
|
12
|
100
|
|
|
|
24
|
if (!defined $k) { |
|
9068
|
3
|
|
|
|
|
16
|
$k = Msubint($p, Mkronecker(5,$p)); |
|
9069
|
3
|
|
|
|
|
18
|
for my $f (Mfactor_exp($k)) { |
|
9070
|
7
|
|
|
|
|
15
|
my($fac,$exp) = @$f; |
|
9071
|
7
|
|
|
|
|
15
|
for my $j (1 .. $exp) { |
|
9072
|
8
|
|
|
|
|
18
|
my $rk = Mdivint($k,$fac); |
|
9073
|
8
|
100
|
|
|
|
36
|
last if Mlucasumod(1, $p-1, $rk, $p) != 0; |
|
9074
|
2
|
|
|
|
|
8
|
$k = $rk; |
|
9075
|
|
|
|
|
|
|
} |
|
9076
|
|
|
|
|
|
|
} |
|
9077
|
3
|
|
|
|
|
13
|
$_ppc{$p} = $k; |
|
9078
|
|
|
|
|
|
|
} |
|
9079
|
12
|
100
|
|
|
|
285
|
$k = Mmulint($k, Mpowint($p, $e-1)) if $e > 1; |
|
9080
|
12
|
|
|
|
|
797
|
$k; |
|
9081
|
|
|
|
|
|
|
} |
|
9082
|
|
|
|
|
|
|
sub pisano_period { |
|
9083
|
4
|
|
|
4
|
0
|
1523
|
my($n) = @_; |
|
9084
|
4
|
|
|
|
|
38
|
validate_integer_nonneg($n); |
|
9085
|
4
|
50
|
|
|
|
68
|
return 0 if $n < 0; |
|
9086
|
4
|
50
|
|
|
|
419
|
return (0,1,3,8,6,20,24,16,12,24,60)[$n] if $n <= 10; |
|
9087
|
|
|
|
|
|
|
|
|
9088
|
4
|
|
|
|
|
398
|
my $k = Mlcm(map { _pisano_pp($_->[0],$_->[1]) } Mfactor_exp($n)); |
|
|
15
|
|
|
|
|
37
|
|
|
9089
|
|
|
|
|
|
|
|
|
9090
|
4
|
|
|
|
|
143
|
my $lim = Mmulint(6,$n); |
|
9091
|
4
|
|
|
|
|
657
|
for (my $ret = $k; $ret <= $lim; $ret = Maddint($ret,$k)) { |
|
9092
|
7
|
100
|
|
|
|
175
|
return $ret if Mlucasumod(1, -1, Msub1int($ret), $n) == 1; |
|
9093
|
|
|
|
|
|
|
} |
|
9094
|
0
|
|
|
|
|
0
|
undef; |
|
9095
|
|
|
|
|
|
|
} |
|
9096
|
|
|
|
|
|
|
|
|
9097
|
|
|
|
|
|
|
sub is_lucas_pseudoprime { |
|
9098
|
4
|
|
|
4
|
0
|
19
|
my($n) = @_; |
|
9099
|
|
|
|
|
|
|
|
|
9100
|
4
|
50
|
|
|
|
16
|
return 0+($n >= 2) if $n < 4; |
|
9101
|
4
|
50
|
33
|
|
|
42
|
return 0 if ($n % 2) == 0 || _is_perfect_square($n); |
|
9102
|
|
|
|
|
|
|
|
|
9103
|
4
|
|
|
|
|
31
|
my ($P, $Q, $D) = _lucas_selfridge_params($n); |
|
9104
|
4
|
50
|
|
|
|
21
|
return 0 if $D == 0; # We found a divisor in the sequence |
|
9105
|
4
|
50
|
|
|
|
25
|
die "Lucas parameter error: $D, $P, $Q\n" if ($D != $P*$P - 4*$Q); |
|
9106
|
|
|
|
|
|
|
|
|
9107
|
4
|
|
|
|
|
23
|
my($U, $V) = lucasuvmod($P, $Q, $n+1, $n); |
|
9108
|
4
|
50
|
|
|
|
66
|
return ($U == 0) ? 1 : 0; |
|
9109
|
|
|
|
|
|
|
} |
|
9110
|
|
|
|
|
|
|
|
|
9111
|
|
|
|
|
|
|
sub is_strong_lucas_pseudoprime { |
|
9112
|
4
|
|
|
4
|
0
|
9
|
my($n) = @_; |
|
9113
|
|
|
|
|
|
|
|
|
9114
|
4
|
50
|
|
|
|
14
|
return 0+($n >= 2) if $n < 4; |
|
9115
|
4
|
50
|
33
|
|
|
29
|
return 0 if ($n % 2) == 0 || _is_perfect_square($n); |
|
9116
|
|
|
|
|
|
|
|
|
9117
|
4
|
|
|
|
|
26
|
my ($P, $Q, $D) = _lucas_selfridge_params($n); |
|
9118
|
4
|
50
|
|
|
|
17
|
return 0 if $D == 0; # We found a divisor in the sequence |
|
9119
|
4
|
50
|
|
|
|
16
|
die "Lucas parameter error: $D, $P, $Q\n" if ($D != $P*$P - 4*$Q); |
|
9120
|
|
|
|
|
|
|
|
|
9121
|
4
|
|
|
|
|
6
|
my $m = $n+1; |
|
9122
|
4
|
|
|
|
|
9
|
my($s, $k) = (0, $m); |
|
9123
|
4
|
|
66
|
|
|
18
|
while ( $k > 0 && !($k % 2) ) { |
|
9124
|
11
|
|
|
|
|
9
|
$s++; |
|
9125
|
11
|
|
|
|
|
30
|
$k >>= 1; |
|
9126
|
|
|
|
|
|
|
} |
|
9127
|
4
|
|
|
|
|
17
|
my($U, $V) = lucasuvmod($P, $Q, $k, $n); |
|
9128
|
4
|
100
|
|
|
|
40
|
return 1 if $U == 0; |
|
9129
|
|
|
|
|
|
|
|
|
9130
|
2
|
|
|
|
|
12
|
my $Qk = Mpowmod($Q,$k,$n); |
|
9131
|
2
|
|
|
|
|
101
|
foreach my $r (0 .. $s-1) { |
|
9132
|
7
|
100
|
|
|
|
445
|
return 1 if $V == 0; |
|
9133
|
5
|
50
|
|
|
|
17
|
if ($r < ($s-1)) { |
|
9134
|
5
|
|
|
|
|
17
|
$V = Mmulsubmod($V, $V, Maddmod($Qk,$Qk,$n), $n); |
|
9135
|
5
|
|
|
|
|
18
|
$Qk = Mmulmod($Qk, $Qk, $n); |
|
9136
|
|
|
|
|
|
|
} |
|
9137
|
|
|
|
|
|
|
} |
|
9138
|
0
|
|
|
|
|
0
|
return 0; |
|
9139
|
|
|
|
|
|
|
} |
|
9140
|
|
|
|
|
|
|
|
|
9141
|
|
|
|
|
|
|
sub is_extra_strong_lucas_pseudoprime { |
|
9142
|
112
|
|
|
112
|
0
|
410
|
my($n) = @_; |
|
9143
|
|
|
|
|
|
|
|
|
9144
|
112
|
50
|
|
|
|
510
|
return 0+($n >= 2) if $n < 4; |
|
9145
|
112
|
50
|
33
|
|
|
23909
|
return 0 if ($n % 2) == 0 || _is_perfect_square($n); |
|
9146
|
|
|
|
|
|
|
|
|
9147
|
112
|
|
|
|
|
10223
|
my ($P, $Q, $D) = _lucas_extrastrong_params($n); |
|
9148
|
112
|
50
|
|
|
|
476
|
return 0 if $D == 0; # We found a divisor in the sequence |
|
9149
|
112
|
50
|
|
|
|
519
|
die "Lucas parameter error: $D, $P, $Q\n" if ($D != $P*$P - 4*$Q); |
|
9150
|
|
|
|
|
|
|
|
|
9151
|
|
|
|
|
|
|
# This would be a great place to use a factor remove function |
|
9152
|
112
|
|
|
|
|
837
|
my($s, $k) = (0, Madd1int($n)); |
|
9153
|
112
|
|
66
|
|
|
26788
|
while (Mis_even($k) && $k != 0) { |
|
9154
|
1338
|
|
|
|
|
733770
|
$s++; |
|
9155
|
1338
|
|
|
|
|
8564
|
$k = Mrshiftint($k); |
|
9156
|
|
|
|
|
|
|
} |
|
9157
|
|
|
|
|
|
|
|
|
9158
|
112
|
|
|
|
|
30034
|
my($U, $V) = lucasuvmod($P, $Q, $k, $n); |
|
9159
|
112
|
50
|
66
|
|
|
1083
|
return 1 if $U == 0 && ($V == 2 || $V == Msubint($n,2)); |
|
|
|
|
100
|
|
|
|
|
|
9160
|
52
|
|
|
|
|
9755
|
foreach my $r (0 .. $s-2) { |
|
9161
|
1217
|
100
|
|
|
|
284998
|
return 1 if $V == 0; |
|
9162
|
1169
|
|
|
|
|
267822
|
$V = Mmulsubmod($V, $V, 2, $n); |
|
9163
|
|
|
|
|
|
|
} |
|
9164
|
4
|
|
|
|
|
47
|
return 0; |
|
9165
|
|
|
|
|
|
|
} |
|
9166
|
|
|
|
|
|
|
|
|
9167
|
|
|
|
|
|
|
sub is_almost_extra_strong_lucas_pseudoprime { |
|
9168
|
50
|
|
|
50
|
0
|
194
|
my($n, $incr) = @_; |
|
9169
|
50
|
100
|
|
|
|
239
|
if (defined $incr) { |
|
9170
|
9
|
|
|
|
|
25
|
validate_integer($incr); |
|
9171
|
9
|
50
|
33
|
|
|
93
|
croak "Invalid lucas parameter increment: $incr" if $incr<1 || $incr>256; |
|
9172
|
|
|
|
|
|
|
} else { |
|
9173
|
41
|
|
|
|
|
110
|
$incr = 1; |
|
9174
|
|
|
|
|
|
|
} |
|
9175
|
|
|
|
|
|
|
|
|
9176
|
50
|
50
|
|
|
|
199
|
return 0+($n >= 2) if $n < 4; |
|
9177
|
50
|
50
|
33
|
|
|
479
|
return 0 if ($n % 2) == 0 || _is_perfect_square($n); |
|
9178
|
|
|
|
|
|
|
|
|
9179
|
50
|
|
|
|
|
312
|
my ($P, $Q, $D) = _lucas_extrastrong_params($n, $incr); |
|
9180
|
50
|
50
|
|
|
|
226
|
return 0 if $D == 0; # We found a divisor in the sequence |
|
9181
|
50
|
50
|
|
|
|
205
|
die "Lucas parameter error: $D, $P, $Q\n" if ($D != $P*$P - 4*$Q); |
|
9182
|
|
|
|
|
|
|
|
|
9183
|
50
|
|
|
|
|
294
|
my($s, $k) = (0, Madd1int($n)); |
|
9184
|
50
|
|
66
|
|
|
435
|
while (Mis_even($k) && $k != 0) { |
|
9185
|
119
|
|
|
|
|
197
|
$s++; |
|
9186
|
119
|
|
|
|
|
464
|
$k = Mrshiftint($k); |
|
9187
|
|
|
|
|
|
|
} |
|
9188
|
50
|
|
|
|
|
655
|
my @kbits = Mtodigits($k, 2); |
|
9189
|
50
|
|
|
|
|
130
|
shift @kbits; # Remove leading 1 |
|
9190
|
50
|
|
|
|
|
181
|
my($V,$W) = ($P,$P*$P-2); |
|
9191
|
50
|
|
|
|
|
151
|
foreach my $bit (@kbits) { |
|
9192
|
2144
|
100
|
|
|
|
3854
|
if ($bit) { |
|
9193
|
1197
|
|
|
|
|
2802
|
$V = Mmulsubmod($V, $W, $P, $n); |
|
9194
|
1197
|
|
|
|
|
3000
|
$W = Mmulsubmod($W, $W, 2, $n); |
|
9195
|
|
|
|
|
|
|
} else { |
|
9196
|
947
|
|
|
|
|
2078
|
$W = Mmulsubmod($W, $V, $P, $n); |
|
9197
|
947
|
|
|
|
|
2108
|
$V = Mmulsubmod($V, $V, 2, $n); |
|
9198
|
|
|
|
|
|
|
} |
|
9199
|
|
|
|
|
|
|
} |
|
9200
|
50
|
100
|
100
|
|
|
746
|
return 1 if $V == 2 || Msubint($n,$V) == 2; |
|
9201
|
17
|
|
|
|
|
74
|
foreach my $r (0 .. $s-2) { |
|
9202
|
60
|
100
|
|
|
|
281
|
return 1 if $V == 0; |
|
9203
|
46
|
|
|
|
|
145
|
$V = Mmulsubmod($V, $V, 2, $n); |
|
9204
|
|
|
|
|
|
|
} |
|
9205
|
3
|
|
|
|
|
42
|
return 0; |
|
9206
|
|
|
|
|
|
|
} |
|
9207
|
|
|
|
|
|
|
|
|
9208
|
|
|
|
|
|
|
sub is_frobenius_khashin_pseudoprime { |
|
9209
|
1
|
|
|
1
|
0
|
4
|
my($n) = @_; |
|
9210
|
1
|
50
|
|
|
|
3
|
return 0+($n >= 2) if $n < 4; |
|
9211
|
1
|
50
|
|
|
|
3
|
return 0 unless $n % 2; |
|
9212
|
1
|
50
|
|
|
|
6
|
return 0 if _is_perfect_square($n); |
|
9213
|
|
|
|
|
|
|
|
|
9214
|
1
|
|
|
|
|
10
|
$n = tobigint($n); |
|
9215
|
|
|
|
|
|
|
|
|
9216
|
1
|
|
|
|
|
3
|
my($k,$c) = (2,1); |
|
9217
|
1
|
50
|
|
|
|
8
|
if ($n % 4 == 3) { $c = $n-1; } |
|
|
1
|
0
|
|
|
|
497
|
|
|
9218
|
0
|
|
|
|
|
0
|
elsif ($n % 8 == 5) { $c = 2; } |
|
9219
|
|
|
|
|
|
|
else { |
|
9220
|
0
|
|
|
|
|
0
|
do { |
|
9221
|
0
|
|
|
|
|
0
|
$c += 2; |
|
9222
|
0
|
|
|
|
|
0
|
$k = Mkronecker($c, $n); |
|
9223
|
|
|
|
|
|
|
} while $k == 1; |
|
9224
|
|
|
|
|
|
|
} |
|
9225
|
1
|
50
|
33
|
|
|
255
|
return 0 if $k == 0 || ($k == 2 && !($n % 3)); |
|
|
|
|
33
|
|
|
|
|
|
9226
|
|
|
|
|
|
|
|
|
9227
|
1
|
50
|
|
|
|
308
|
my $ea = ($k == 2) ? 2 : 1; |
|
9228
|
1
|
|
|
|
|
6
|
my($ra,$rb,$a,$b,$d) = ($ea,1,$ea,1,$n-1); |
|
9229
|
1
|
|
|
|
|
317
|
while ($d != 0) { |
|
9230
|
29
|
100
|
|
|
|
46912
|
if ($d % 2 == 1) { |
|
9231
|
18
|
|
|
|
|
7064
|
($ra, $rb) = ( (($ra*$a)%$n + ((($rb*$b)%$n)*$c)%$n) % $n, |
|
9232
|
|
|
|
|
|
|
(($rb*$a)%$n + ($ra*$b)%$n) % $n ); |
|
9233
|
|
|
|
|
|
|
} |
|
9234
|
29
|
|
|
|
|
31102
|
$d >>= 1; |
|
9235
|
29
|
100
|
|
|
|
8210
|
if ($d != 0) { |
|
9236
|
28
|
|
|
|
|
4940
|
($a, $b) = ( (($a*$a)%$n + ((($b*$b)%$n)*$c)%$n) % $n, |
|
9237
|
|
|
|
|
|
|
(($b*$a)%$n + ($a*$b)%$n) % $n ); |
|
9238
|
|
|
|
|
|
|
} |
|
9239
|
|
|
|
|
|
|
} |
|
9240
|
1
|
50
|
33
|
|
|
444
|
return ($ra == $ea && $rb == $n-1) ? 1 : 0; |
|
9241
|
|
|
|
|
|
|
} |
|
9242
|
|
|
|
|
|
|
|
|
9243
|
|
|
|
|
|
|
sub is_frobenius_underwood_pseudoprime { |
|
9244
|
1
|
|
|
1
|
0
|
3
|
my($n) = @_; |
|
9245
|
1
|
50
|
|
|
|
4
|
return 0+($n >= 2) if $n < 4; |
|
9246
|
1
|
50
|
|
|
|
4
|
return 0 unless $n % 2; |
|
9247
|
|
|
|
|
|
|
|
|
9248
|
1
|
|
|
|
|
3
|
my($a, $temp1, $temp2); |
|
9249
|
1
|
50
|
|
|
|
5
|
if ($n % 4 == 3) { |
|
9250
|
1
|
|
|
|
|
4
|
$a = 0; |
|
9251
|
|
|
|
|
|
|
} else { |
|
9252
|
0
|
|
|
|
|
0
|
for ($a = 1; $a < 1000000; $a++) { |
|
9253
|
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
|
|
|
|
|
|
9254
|
0
|
|
|
|
|
0
|
my $j = Mkronecker($a*$a - 4, $n); |
|
9255
|
0
|
0
|
|
|
|
0
|
last if $j == -1; |
|
9256
|
0
|
0
|
0
|
|
|
0
|
return 0 if $j == 0 || ($a == 20 && _is_perfect_square($n)); |
|
|
|
|
0
|
|
|
|
|
|
9257
|
|
|
|
|
|
|
} |
|
9258
|
|
|
|
|
|
|
} |
|
9259
|
1
|
|
|
|
|
8
|
$temp1 = Mgcd(($a+4)*(2*$a+5), $n); |
|
9260
|
1
|
50
|
33
|
|
|
7
|
return 0 if $temp1 != 1 && $temp1 != $n; |
|
9261
|
|
|
|
|
|
|
|
|
9262
|
1
|
|
|
|
|
9
|
$n = tobigint($n); |
|
9263
|
1
|
|
|
|
|
5
|
my($s, $t, $ap2) = map { tobigint($_) } (1, 2, $a+2); |
|
|
3
|
|
|
|
|
6
|
|
|
9264
|
1
|
|
|
|
|
7
|
my $np1string = todigitstring($n+1,2); |
|
9265
|
1
|
|
|
|
|
5
|
my $np1len = length($np1string); |
|
9266
|
|
|
|
|
|
|
|
|
9267
|
1
|
|
|
|
|
5
|
foreach my $bit (1 .. $np1len-1) { |
|
9268
|
28
|
|
|
|
|
63
|
$temp2 = $t+$t; |
|
9269
|
28
|
50
|
|
|
|
3056
|
$temp2 += ($s * $a) if $a != 0; |
|
9270
|
28
|
|
|
|
|
58
|
$temp1 = $temp2 * $s; |
|
9271
|
28
|
|
|
|
|
3098
|
$temp2 = $t - $s; |
|
9272
|
28
|
|
|
|
|
3292
|
$s += $t; |
|
9273
|
28
|
|
|
|
|
2363
|
$t = ($s * $temp2) % $n; |
|
9274
|
28
|
|
|
|
|
7100
|
$s = $temp1 % $n; |
|
9275
|
28
|
100
|
|
|
|
3426
|
if ( substr( $np1string, $bit, 1 ) ) { |
|
9276
|
17
|
50
|
|
|
|
63
|
if ($a == 0) { $temp1 = $s + $s; } |
|
|
17
|
|
|
|
|
42
|
|
|
9277
|
0
|
|
|
|
|
0
|
else { $temp1 = $s * $ap2; } |
|
9278
|
17
|
|
|
|
|
2101
|
$temp1 += $t; |
|
9279
|
17
|
|
|
|
|
1384
|
$t = $t + $t - $s; |
|
9280
|
17
|
|
|
|
|
4187
|
$s = $temp1; |
|
9281
|
|
|
|
|
|
|
} |
|
9282
|
|
|
|
|
|
|
} |
|
9283
|
1
|
|
|
|
|
5
|
$temp1 = (2*$a+5) % $n; |
|
9284
|
1
|
50
|
33
|
|
|
165
|
return ($s == 0 && $t == $temp1) ? 1 : 0; |
|
9285
|
|
|
|
|
|
|
} |
|
9286
|
|
|
|
|
|
|
|
|
9287
|
|
|
|
|
|
|
sub _perrin_signature { |
|
9288
|
2
|
|
|
2
|
|
19
|
my($n) = @_; |
|
9289
|
2
|
|
|
|
|
7
|
my @S = (1,$n-1,3, 3,0,2); |
|
9290
|
2
|
50
|
|
|
|
8
|
return @S if $n <= 1; |
|
9291
|
|
|
|
|
|
|
|
|
9292
|
2
|
|
|
|
|
12
|
my @nbin = Mtodigits($n,2); |
|
9293
|
2
|
|
|
|
|
6
|
shift @nbin; |
|
9294
|
|
|
|
|
|
|
|
|
9295
|
2
|
|
|
|
|
8
|
while (@nbin) { |
|
9296
|
54
|
|
|
|
|
102
|
my @SUB = map { Maddmod($n-$S[5-$_], $n-$S[5-$_],$n) } 0..5; |
|
|
324
|
|
|
|
|
600
|
|
|
9297
|
54
|
|
|
|
|
104
|
my @T = map { Mmuladdmod($S[$_], $S[$_], $SUB[$_], $n); } 0..5; |
|
|
324
|
|
|
|
|
696
|
|
|
9298
|
|
|
|
|
|
|
|
|
9299
|
54
|
|
|
|
|
155
|
my $T01 = Msubmod($T[2], $T[1], $n); |
|
9300
|
54
|
|
|
|
|
129
|
my $T34 = Msubmod($T[5], $T[4], $n); |
|
9301
|
54
|
|
|
|
|
131
|
my $T45 = Maddmod($T34, $T[3], $n); |
|
9302
|
54
|
100
|
|
|
|
141
|
if (shift @nbin) { |
|
9303
|
29
|
|
|
|
|
122
|
@S = ($T[0], $T01, $T[1], $T[4], $T45, $T[5]); |
|
9304
|
|
|
|
|
|
|
} else { |
|
9305
|
25
|
|
|
|
|
60
|
@S = ($T01, $T[1], Maddmod($T01,$T[0],$n), $T34, $T[4], $T45); |
|
9306
|
|
|
|
|
|
|
} |
|
9307
|
|
|
|
|
|
|
} |
|
9308
|
2
|
|
|
|
|
9
|
@S; |
|
9309
|
|
|
|
|
|
|
} |
|
9310
|
|
|
|
|
|
|
|
|
9311
|
|
|
|
|
|
|
sub is_perrin_pseudoprime { |
|
9312
|
2
|
|
|
2
|
0
|
713
|
my($n, $restrict) = @_; |
|
9313
|
2
|
|
|
|
|
15
|
validate_integer($n); |
|
9314
|
2
|
100
|
|
|
|
11
|
if (defined $restrict) { validate_integer_nonneg($restrict); } |
|
|
1
|
|
|
|
|
10
|
|
|
9315
|
1
|
|
|
|
|
2
|
else { $restrict = 0; } |
|
9316
|
2
|
50
|
|
|
|
8
|
return 0+($n >= 2) if $n < 4; |
|
9317
|
2
|
50
|
66
|
|
|
12
|
return 0 if $restrict > 2 && ($n % 2) == 0; |
|
9318
|
|
|
|
|
|
|
|
|
9319
|
2
|
|
|
|
|
8
|
my @S = _perrin_signature($n); |
|
9320
|
2
|
50
|
|
|
|
9
|
return 0 unless $S[4] == 0; |
|
9321
|
2
|
100
|
|
|
|
20
|
return 1 if $restrict == 0; |
|
9322
|
1
|
50
|
|
|
|
10
|
return 0 unless $S[1] == Msub1int($n); |
|
9323
|
1
|
50
|
|
|
|
5
|
return 1 if $restrict == 1; |
|
9324
|
1
|
|
|
|
|
6
|
my $j = Mkronecker(-23,$n); |
|
9325
|
1
|
50
|
|
|
|
6
|
if ($j == -1) { |
|
9326
|
0
|
|
|
|
|
0
|
my $B = $S[2]; |
|
9327
|
0
|
|
|
|
|
0
|
my $B2 = Mmulmod($B,$B,$n); |
|
9328
|
0
|
|
|
|
|
0
|
my $A = Msubmod(Mmuladdmod(3, $B, 1, $n), $B2, $n); |
|
9329
|
0
|
|
|
|
|
0
|
my $C = Mmulsubmod(3,$B2,2,$n); |
|
9330
|
0
|
0
|
0
|
|
|
0
|
return 1 if $S[0] == $A && $S[2] == $B && $S[3] == $B && $S[5] == $C && $B != 3 && Mmulsubmod($B2,$B,$B,$n) == 1; |
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
9331
|
|
|
|
|
|
|
} else { |
|
9332
|
1
|
0
|
33
|
|
|
7
|
return 0 if $j == 0 && $n != 23 && $restrict > 2; |
|
|
|
|
33
|
|
|
|
|
|
9333
|
1
|
50
|
33
|
|
|
21
|
return 1 if $S[0] == 1 && $S[2] == 3 && $S[3] == 3 && $S[5] == 2; |
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
9334
|
0
|
0
|
0
|
|
|
0
|
return 1 if $S[0] == 0 && $S[5] == $n-1 && $S[2] != $S[3] && Maddmod($S[2],$S[3],$n) == $n-3 && Mmulmod(Msubmod($S[2],$S[3],$n),Msubmod($S[2],$S[3],$n),$n) == $n-(23%$n); |
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
9335
|
|
|
|
|
|
|
} |
|
9336
|
0
|
|
|
|
|
0
|
0; |
|
9337
|
|
|
|
|
|
|
} |
|
9338
|
|
|
|
|
|
|
|
|
9339
|
|
|
|
|
|
|
# Aebi and Cairns (2008) |
|
9340
|
|
|
|
|
|
|
sub _catgamma { |
|
9341
|
9
|
|
|
9
|
|
16
|
my($n,$mod) = @_; |
|
9342
|
|
|
|
|
|
|
|
|
9343
|
|
|
|
|
|
|
# Theorem 6, allowing us to possibly reduce n |
|
9344
|
9
|
100
|
|
|
|
14
|
if ($mod < $n) { |
|
9345
|
3
|
|
|
|
|
8
|
my $NP = Mdivint($n,$mod); |
|
9346
|
3
|
50
|
|
|
|
8
|
if ($NP & 1) { # odd |
|
9347
|
0
|
0
|
|
|
|
0
|
return $mod*$NP == $n ? _catgamma($NP,$mod) : 0; |
|
9348
|
|
|
|
|
|
|
} else { |
|
9349
|
3
|
|
|
|
|
16
|
return Mmulmod(_catgamma($NP+1,$mod),_catgamma($n-$mod*$NP,$mod),$mod); |
|
9350
|
|
|
|
|
|
|
} |
|
9351
|
|
|
|
|
|
|
} |
|
9352
|
|
|
|
|
|
|
# Section 5 rephrases Theorem 2 into the middle binomial. |
|
9353
|
6
|
|
|
|
|
16
|
my $N = Msub1int($n); |
|
9354
|
6
|
|
|
|
|
30
|
my $m = Mrshiftint($N); |
|
9355
|
6
|
|
|
|
|
16
|
my $r = Math::Prime::Util::binomialmod($N, $m, $mod); |
|
9356
|
6
|
100
|
|
|
|
65
|
return ($m & 1) ? $mod-$r : $r; |
|
9357
|
|
|
|
|
|
|
} |
|
9358
|
|
|
|
|
|
|
sub _catvtest { |
|
9359
|
4
|
|
|
4
|
|
6
|
my($n,$p) = @_; |
|
9360
|
4
|
50
|
|
|
|
13
|
while ($n = int($n/$p)) { return 1 if $n % 2; } |
|
|
11
|
|
|
|
|
30
|
|
|
9361
|
4
|
|
|
|
|
11
|
0; |
|
9362
|
|
|
|
|
|
|
} |
|
9363
|
|
|
|
|
|
|
sub is_catalan_pseudoprime { |
|
9364
|
3
|
|
|
3
|
0
|
6
|
my($n) = @_; |
|
9365
|
3
|
50
|
|
|
|
7
|
return 0+($n >= 2) if $n < 4; |
|
9366
|
3
|
50
|
|
|
|
7
|
return 0 unless $n & 1; |
|
9367
|
|
|
|
|
|
|
|
|
9368
|
|
|
|
|
|
|
{ |
|
9369
|
3
|
|
|
|
|
4
|
my @f = Mtrial_factor($n, 10000); |
|
|
3
|
|
|
|
|
14
|
|
|
9370
|
3
|
50
|
66
|
|
|
18
|
if (@f == 2 && is_prime($f[1]) && $f[0] != $f[1]) { |
|
|
|
|
66
|
|
|
|
|
|
9371
|
1
|
|
|
|
|
3
|
my($p,$q) = ($f[0],$f[1]); # two primes, q > p |
|
9372
|
1
|
50
|
|
|
|
4
|
return 0 if 2*$p+1 >= $q; # by Theorem 6(a) |
|
9373
|
|
|
|
|
|
|
# Proposition 3 (semiprimes) |
|
9374
|
1
|
50
|
33
|
|
|
3
|
return 0 unless _catgamma($q,$p) == 1 && _catgamma($p,$q) == 1; |
|
9375
|
|
|
|
|
|
|
} |
|
9376
|
2
|
50
|
|
|
|
9
|
if (is_prime($f[-1])) { # fully factored |
|
9377
|
2
|
|
|
|
|
12
|
for my $F (vecuniq(@f)) { |
|
9378
|
4
|
50
|
|
|
|
14
|
return 0 if _catvtest($n-1,$F); |
|
9379
|
|
|
|
|
|
|
} |
|
9380
|
|
|
|
|
|
|
} |
|
9381
|
|
|
|
|
|
|
} |
|
9382
|
2
|
50
|
|
|
|
8
|
return _catgamma($n,$n) == 1 ? 1 : 0; |
|
9383
|
|
|
|
|
|
|
} |
|
9384
|
|
|
|
|
|
|
|
|
9385
|
|
|
|
|
|
|
sub is_frobenius_pseudoprime { |
|
9386
|
1
|
|
|
1
|
0
|
3
|
my($n, $P, $Q) = @_; |
|
9387
|
1
|
50
|
33
|
|
|
4
|
($P,$Q) = (0,0) unless defined $P && defined $Q; |
|
9388
|
1
|
50
|
|
|
|
3
|
return 0+($n >= 2) if $n < 4; |
|
9389
|
|
|
|
|
|
|
|
|
9390
|
1
|
|
|
|
|
7
|
$n = tobigint($n); |
|
9391
|
1
|
50
|
|
|
|
8
|
return 0 if Mis_even($n); |
|
9392
|
|
|
|
|
|
|
|
|
9393
|
1
|
|
|
|
|
4
|
my($k, $Vcomp, $D, $Du) = (0, 4); |
|
9394
|
1
|
50
|
33
|
|
|
8
|
if ($P == 0 && $Q == 0) { |
|
9395
|
1
|
|
|
|
|
3
|
($P,$Q) = (-1,2); |
|
9396
|
1
|
|
|
|
|
3
|
while ($k != -1) { |
|
9397
|
1
|
|
|
|
|
3
|
$P += 2; |
|
9398
|
1
|
50
|
|
|
|
4
|
$P = 5 if $P == 3; # Skip 3 |
|
9399
|
1
|
|
|
|
|
3
|
$D = $P*$P-4*$Q; |
|
9400
|
1
|
50
|
|
|
|
5
|
$Du = ($D >= 0) ? $D : -$D; |
|
9401
|
1
|
50
|
33
|
|
|
20
|
last if $P >= $n || $Du >= $n; # TODO: remove? |
|
9402
|
1
|
|
|
|
|
200
|
$k = Mkronecker($D, $n); |
|
9403
|
1
|
50
|
|
|
|
6
|
return 0 if $k == 0; |
|
9404
|
1
|
50
|
33
|
|
|
8
|
return 0 if $P == 10001 && _is_perfect_square($n); |
|
9405
|
|
|
|
|
|
|
} |
|
9406
|
|
|
|
|
|
|
} else { |
|
9407
|
0
|
|
|
|
|
0
|
$D = $P*$P-4*$Q; |
|
9408
|
0
|
0
|
|
|
|
0
|
$Du = ($D >= 0) ? $D : -$D; |
|
9409
|
0
|
0
|
|
|
|
0
|
croak "Frobenius invalid P,Q: ($P,$Q)" if _is_perfect_square($Du); |
|
9410
|
|
|
|
|
|
|
} |
|
9411
|
1
|
0
|
33
|
|
|
5
|
return (Mis_prime($n) ? 1 : 0) if $n <= $Du || $n <= abs($Q) || $n <= abs($P); |
|
|
|
50
|
33
|
|
|
|
|
|
9412
|
1
|
50
|
|
|
|
404
|
return 0 if Mgcd(abs($P*$Q*$D), $n) > 1; |
|
9413
|
|
|
|
|
|
|
|
|
9414
|
1
|
50
|
|
|
|
4
|
if ($k == 0) { |
|
9415
|
0
|
|
|
|
|
0
|
$k = Mkronecker($D, $n); |
|
9416
|
0
|
0
|
|
|
|
0
|
return 0 if $k == 0; |
|
9417
|
0
|
|
|
|
|
0
|
my $Q2 = (2*abs($Q)) % $n; |
|
9418
|
0
|
0
|
|
|
|
0
|
$Vcomp = ($k == 1) ? 2 : ($Q >= 0) ? $Q2 : $n-$Q2; |
|
|
|
0
|
|
|
|
|
|
|
9419
|
|
|
|
|
|
|
} |
|
9420
|
|
|
|
|
|
|
|
|
9421
|
1
|
|
|
|
|
5
|
my($U, $V) = lucasuvmod($P, $Q, $n-$k, $n); |
|
9422
|
1
|
50
|
33
|
|
|
16
|
return 1 if $U == 0 && $V == $Vcomp; |
|
9423
|
1
|
|
|
|
|
18
|
0; |
|
9424
|
|
|
|
|
|
|
} |
|
9425
|
|
|
|
|
|
|
|
|
9426
|
|
|
|
|
|
|
# Since people have graciously donated millions of CPU years to doing these |
|
9427
|
|
|
|
|
|
|
# tests, it would be rude of us not to use the results. This means we don't |
|
9428
|
|
|
|
|
|
|
# actually use the pretest and Lucas-Lehmer test coded below for any reasonable |
|
9429
|
|
|
|
|
|
|
# size number. |
|
9430
|
|
|
|
|
|
|
# See: http://www.mersenne.org/report_milestones/ |
|
9431
|
|
|
|
|
|
|
my %_mersenne_primes; |
|
9432
|
|
|
|
|
|
|
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,77232917,82589933,136279841}; |
|
9433
|
|
|
|
|
|
|
|
|
9434
|
|
|
|
|
|
|
sub is_mersenne_prime { |
|
9435
|
3
|
|
|
3
|
0
|
27
|
my($p) = @_; |
|
9436
|
|
|
|
|
|
|
|
|
9437
|
|
|
|
|
|
|
# Use the known Mersenne primes |
|
9438
|
3
|
100
|
|
|
|
57
|
return 1 if exists $_mersenne_primes{$p}; |
|
9439
|
1
|
50
|
|
|
|
9
|
return 0 if $p < 79711549; # GIMPS has tested and verified all below |
|
9440
|
|
|
|
|
|
|
# Past this we do a generic Mersenne prime test |
|
9441
|
|
|
|
|
|
|
|
|
9442
|
0
|
0
|
|
|
|
0
|
return 1 if $p == 2; |
|
9443
|
0
|
0
|
|
|
|
0
|
return 0 unless is_prob_prime($p); |
|
9444
|
0
|
0
|
0
|
|
|
0
|
return 0 if $p > 3 && $p % 4 == 3 && $p < ((~0)>>1) && is_prob_prime($p*2+1); |
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
9445
|
0
|
|
|
|
|
0
|
my $mp = Msub1int(Mlshiftint(1,$p)); |
|
9446
|
|
|
|
|
|
|
|
|
9447
|
|
|
|
|
|
|
# Definitely faster than using Math::BigInt that doesn't have GMP. |
|
9448
|
|
|
|
|
|
|
return (0 == (Math::Prime::Util::GMP::lucasuvmod(4, 1, $mp+1, $mp))[0]) |
|
9449
|
0
|
0
|
|
|
|
0
|
if $Math::Prime::Util::_GMPfunc{"lucasuvmod"}; |
|
9450
|
|
|
|
|
|
|
|
|
9451
|
0
|
|
|
|
|
0
|
my $V = 4; |
|
9452
|
0
|
|
|
|
|
0
|
for my $k (3 .. $p) { |
|
9453
|
0
|
|
|
|
|
0
|
$V = Mmulsubmod($V, $V, 2, $mp); |
|
9454
|
|
|
|
|
|
|
} |
|
9455
|
0
|
|
|
|
|
0
|
return $V == 0; |
|
9456
|
|
|
|
|
|
|
} |
|
9457
|
|
|
|
|
|
|
|
|
9458
|
|
|
|
|
|
|
|
|
9459
|
|
|
|
|
|
|
sub _poly_new { |
|
9460
|
0
|
|
|
0
|
|
0
|
my($refn, @poly) = @_; |
|
9461
|
0
|
0
|
|
|
|
0
|
push @poly, 0 unless scalar @poly; |
|
9462
|
0
|
0
|
|
|
|
0
|
@poly = map { tobigint("$_") } @poly if $refn; |
|
|
0
|
|
|
|
|
0
|
|
|
9463
|
0
|
|
|
|
|
0
|
return \@poly; |
|
9464
|
|
|
|
|
|
|
} |
|
9465
|
|
|
|
|
|
|
|
|
9466
|
|
|
|
|
|
|
#sub _poly_print { |
|
9467
|
|
|
|
|
|
|
# my($poly) = @_; |
|
9468
|
|
|
|
|
|
|
# carp "poly has null top degree" if $#$poly > 0 && !$poly->[-1]; |
|
9469
|
|
|
|
|
|
|
# foreach my $d (reverse 1 .. $#$poly) { |
|
9470
|
|
|
|
|
|
|
# my $coef = $poly->[$d]; |
|
9471
|
|
|
|
|
|
|
# print "", ($coef != 1) ? $coef : "", ($d > 1) ? "x^$d" : "x", " + " |
|
9472
|
|
|
|
|
|
|
# if $coef; |
|
9473
|
|
|
|
|
|
|
# } |
|
9474
|
|
|
|
|
|
|
# my $p0 = $poly->[0] || 0; |
|
9475
|
|
|
|
|
|
|
# print "$p0\n"; |
|
9476
|
|
|
|
|
|
|
#} |
|
9477
|
|
|
|
|
|
|
|
|
9478
|
|
|
|
|
|
|
sub _poly_mod_mul { |
|
9479
|
0
|
|
|
0
|
|
0
|
my($px, $py, $r, $n) = @_; |
|
9480
|
|
|
|
|
|
|
|
|
9481
|
0
|
|
|
|
|
0
|
my $px_degree = $#$px; |
|
9482
|
0
|
|
|
|
|
0
|
my $py_degree = $#$py; |
|
9483
|
0
|
0
|
|
|
|
0
|
my @res = ref($n) ? map { tobigint(0) } 0..$r-1 : map { 0 } 0..$r-1; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
9484
|
|
|
|
|
|
|
|
|
9485
|
|
|
|
|
|
|
# convolve(px, py) mod (X^r-1,n) |
|
9486
|
0
|
|
|
|
|
0
|
my @indices_y = grep { $py->[$_] } (0 .. $py_degree); |
|
|
0
|
|
|
|
|
0
|
|
|
9487
|
0
|
|
|
|
|
0
|
foreach my $ix (0 .. $px_degree) { |
|
9488
|
0
|
|
|
|
|
0
|
my $px_at_ix = $px->[$ix]; |
|
9489
|
0
|
0
|
|
|
|
0
|
next unless $px_at_ix; |
|
9490
|
0
|
|
|
|
|
0
|
foreach my $iy (@indices_y) { |
|
9491
|
0
|
|
|
|
|
0
|
my $rindex = ($ix + $iy) % $r; # reduce mod X^r-1 |
|
9492
|
0
|
|
|
|
|
0
|
$res[$rindex] = ($res[$rindex] + $px_at_ix * $py->[$iy]) % $n; |
|
9493
|
|
|
|
|
|
|
} |
|
9494
|
|
|
|
|
|
|
} |
|
9495
|
|
|
|
|
|
|
# In case we had upper terms go to zero after modulo, reduce the degree. |
|
9496
|
0
|
|
|
|
|
0
|
pop @res while !$res[-1]; |
|
9497
|
0
|
|
|
|
|
0
|
return \@res; |
|
9498
|
|
|
|
|
|
|
} |
|
9499
|
|
|
|
|
|
|
|
|
9500
|
|
|
|
|
|
|
sub _poly_mod_pow { |
|
9501
|
0
|
|
|
0
|
|
0
|
my($pn, $power, $r, $mod) = @_; |
|
9502
|
0
|
|
|
|
|
0
|
my $res = _poly_new(ref($mod), 1); |
|
9503
|
0
|
|
|
|
|
0
|
my $p = $power; |
|
9504
|
|
|
|
|
|
|
|
|
9505
|
0
|
|
|
|
|
0
|
while ($p) { |
|
9506
|
0
|
0
|
|
|
|
0
|
$res = _poly_mod_mul($res, $pn, $r, $mod) if ($p % 2) != 0; |
|
9507
|
0
|
|
|
|
|
0
|
$p >>= 1; |
|
9508
|
0
|
0
|
|
|
|
0
|
$pn = _poly_mod_mul($pn, $pn, $r, $mod) if $p; |
|
9509
|
|
|
|
|
|
|
} |
|
9510
|
0
|
|
|
|
|
0
|
return $res; |
|
9511
|
|
|
|
|
|
|
} |
|
9512
|
|
|
|
|
|
|
|
|
9513
|
|
|
|
|
|
|
sub _test_anr { |
|
9514
|
0
|
|
|
0
|
|
0
|
my($a, $n, $r) = @_; |
|
9515
|
0
|
|
|
|
|
0
|
my $pp = _poly_mod_pow(_poly_new(ref($n), $a, 1), $n, $r, $n); |
|
9516
|
0
|
|
|
|
|
0
|
my $nr = $n % $r; |
|
9517
|
0
|
|
0
|
|
|
0
|
$pp->[$nr] = (($pp->[$nr] || 0) - 1) % $n; # subtract X^(n%r) |
|
9518
|
0
|
|
0
|
|
|
0
|
$pp->[ 0] = (($pp->[ 0] || 0) - $a) % $n; # subtract a |
|
9519
|
0
|
0
|
|
|
|
0
|
return 0 if scalar grep { $_ } @$pp; |
|
|
0
|
|
|
|
|
0
|
|
|
9520
|
0
|
|
|
|
|
0
|
1; |
|
9521
|
|
|
|
|
|
|
} |
|
9522
|
|
|
|
|
|
|
|
|
9523
|
|
|
|
|
|
|
sub _log_gamma { |
|
9524
|
624
|
|
|
624
|
|
1107
|
my($x) = @_; |
|
9525
|
624
|
|
|
|
|
1302
|
my @lanczos = (0.99999999999980993, 676.5203681218851, -1259.1392167224028, |
|
9526
|
|
|
|
|
|
|
771.32342877765313, -176.61502916214059, 12.507343278686905, |
|
9527
|
|
|
|
|
|
|
-0.13857109526572012, 9.9843695780195716e-6, 1.5056327351493116e-7); |
|
9528
|
624
|
|
|
|
|
1153
|
my($base,$sum) = ($x+7.5, 0); |
|
9529
|
624
|
|
|
|
|
3797
|
$sum += $lanczos[$_] / ($x + $_) for (8,7,6,5,4,3,2,1); |
|
9530
|
624
|
|
|
|
|
996
|
$sum += $lanczos[0]; |
|
9531
|
624
|
|
|
|
|
2329
|
return 0.91893853320467274178 + log($sum/$x) + (($x+0.5)*log($base)-$base); |
|
9532
|
|
|
|
|
|
|
} |
|
9533
|
|
|
|
|
|
|
sub _log_binomial { |
|
9534
|
208
|
|
|
208
|
|
383
|
my($n,$k) = @_; |
|
9535
|
208
|
50
|
|
|
|
498
|
return 0 if $n < $k; |
|
9536
|
208
|
|
|
|
|
466
|
return _log_gamma($n+1) - _log_gamma($k+1) - _log_gamma($n-$k+1); |
|
9537
|
|
|
|
|
|
|
} |
|
9538
|
|
|
|
|
|
|
sub _log_bern41_binomial { |
|
9539
|
52
|
|
|
52
|
|
120
|
my($r,$d,$i,$j,$s) = @_; |
|
9540
|
52
|
|
|
|
|
160
|
return _log_binomial( 2*$s, $i) |
|
9541
|
|
|
|
|
|
|
+ _log_binomial( $d, $i) |
|
9542
|
|
|
|
|
|
|
+ _log_binomial( 2*$s-$i, $j) |
|
9543
|
|
|
|
|
|
|
+ _log_binomial( $r-2-$d, $j); |
|
9544
|
|
|
|
|
|
|
} |
|
9545
|
|
|
|
|
|
|
sub _bern41_acceptable { |
|
9546
|
52
|
|
|
52
|
|
130
|
my($n,$r,$s) = @_; |
|
9547
|
52
|
|
|
|
|
192
|
my $scmp = int(sqrt(($r-1)/3.0) + 0.99999) * log($n); |
|
9548
|
52
|
|
|
|
|
111
|
my $d = int(0.5 * ($r-1)); |
|
9549
|
52
|
|
|
|
|
97
|
my $i = int(0.475 * ($r-1)); |
|
9550
|
52
|
|
|
|
|
106
|
my $j = $i; |
|
9551
|
52
|
50
|
|
|
|
134
|
$d = $r-2 if $d > $r-2; |
|
9552
|
52
|
50
|
|
|
|
135
|
$i = $d if $i > $d; |
|
9553
|
52
|
50
|
|
|
|
143
|
$j = $r-2-$d if $j > ($r-2-$d); |
|
9554
|
52
|
|
|
|
|
143
|
return _log_bern41_binomial($r,$d,$i,$j,$s) >= $scmp; |
|
9555
|
|
|
|
|
|
|
} |
|
9556
|
|
|
|
|
|
|
|
|
9557
|
|
|
|
|
|
|
sub is_aks_prime { |
|
9558
|
10
|
|
|
10
|
0
|
31
|
my($n) = @_; |
|
9559
|
10
|
|
|
|
|
37
|
validate_integer($n); |
|
9560
|
10
|
100
|
100
|
|
|
84
|
return 0 if $n < 2 || Mis_power($n); |
|
9561
|
7
|
100
|
|
|
|
40
|
return 1 if $n == 2; |
|
9562
|
|
|
|
|
|
|
|
|
9563
|
6
|
100
|
|
|
|
25
|
if ($n > 11) { |
|
9564
|
5
|
100
|
|
|
|
40
|
return 0 if Mis_divisible($n,2,3,5,7,11); |
|
9565
|
|
|
|
|
|
|
} |
|
9566
|
|
|
|
|
|
|
|
|
9567
|
5
|
|
|
|
|
12
|
my($starta, $s); |
|
9568
|
5
|
|
|
|
|
45
|
my $_verbose = getconfig()->{'verbose'}; |
|
9569
|
|
|
|
|
|
|
|
|
9570
|
5
|
|
|
|
|
46
|
my $log2n = log($n)/log(2) + 0.0001; # Error on large side. |
|
9571
|
5
|
50
|
|
|
|
25
|
my $r0 = ($log2n > 32 ? 0.010 : 0.003) * $log2n * $log2n; |
|
9572
|
5
|
50
|
|
|
|
20
|
my $rmult = $log2n > 32 ? 6 : 30; |
|
9573
|
|
|
|
|
|
|
|
|
9574
|
5
|
50
|
|
|
|
45
|
my $r = Mnext_prime($r0 < 2 ? 2 : Mtoint($r0)); |
|
9575
|
5
|
|
100
|
|
|
72
|
while ( !Math::Prime::Util::is_primitive_root($n,$r) |
|
9576
|
|
|
|
|
|
|
|| !_bern41_acceptable($n,$r,$rmult * ($r-1))) { |
|
9577
|
9
|
|
|
|
|
32
|
$r = next_prime($r); |
|
9578
|
|
|
|
|
|
|
} |
|
9579
|
|
|
|
|
|
|
|
|
9580
|
|
|
|
|
|
|
{ |
|
9581
|
5
|
|
|
|
|
11
|
my $bi = 1; |
|
|
5
|
|
|
|
|
22
|
|
|
9582
|
5
|
|
|
|
|
24
|
my $bj = $rmult * ($r-1); |
|
9583
|
5
|
|
|
|
|
16
|
while ($bi < $bj) { |
|
9584
|
38
|
|
|
|
|
95
|
$s = $bi + (($bj-$bi) >> 1); |
|
9585
|
38
|
100
|
|
|
|
79
|
if (!_bern41_acceptable($n, $r, $s)) { $bi = $s+1; } |
|
|
11
|
|
|
|
|
35
|
|
|
9586
|
27
|
|
|
|
|
113
|
else { $bj = $s; } |
|
9587
|
|
|
|
|
|
|
} |
|
9588
|
5
|
|
|
|
|
33
|
$s = $bj; |
|
9589
|
5
|
50
|
|
|
|
14
|
croak "AKS: internal error bad s" unless _bern41_acceptable($n, $r, $s); |
|
9590
|
|
|
|
|
|
|
# S will range from 2 to s+1 |
|
9591
|
5
|
|
|
|
|
15
|
$starta = 2; |
|
9592
|
5
|
|
|
|
|
11
|
$s = $s+1; |
|
9593
|
|
|
|
|
|
|
} |
|
9594
|
5
|
|
|
|
|
26
|
my $slim = $s * ($s-1); |
|
9595
|
5
|
50
|
|
|
|
28
|
print "# aks trial to $slim\n" if $_verbose >= 2; |
|
9596
|
|
|
|
|
|
|
{ |
|
9597
|
5
|
|
|
|
|
11
|
my @f = Mtrial_factor($n, $slim); |
|
|
5
|
|
|
|
|
20
|
|
|
9598
|
5
|
100
|
|
|
|
41
|
return 0 if @f >= 2; |
|
9599
|
|
|
|
|
|
|
} |
|
9600
|
3
|
50
|
|
|
|
17
|
return 1 if Mmulint($slim,$slim) >= $n; |
|
9601
|
|
|
|
|
|
|
# Check b^(n-1) = 1 mod n for b in [2..s] |
|
9602
|
0
|
|
|
|
|
0
|
for my $a (2 .. $s) { |
|
9603
|
0
|
0
|
|
|
|
0
|
return 0 if Mpowmod($a, $n-1, $n) != 1; |
|
9604
|
|
|
|
|
|
|
} |
|
9605
|
|
|
|
|
|
|
|
|
9606
|
0
|
0
|
|
|
|
0
|
if ($n < (MPU_HALFWORD-1) ) { |
|
9607
|
0
|
0
|
|
|
|
0
|
$n = _bigint_to_int($n) if ref($n); |
|
9608
|
|
|
|
|
|
|
} else { |
|
9609
|
0
|
|
|
|
|
0
|
$n = tobigint($n); |
|
9610
|
|
|
|
|
|
|
} |
|
9611
|
|
|
|
|
|
|
|
|
9612
|
0
|
0
|
|
|
|
0
|
print "# aks r = $r s = $s\n" if $_verbose; |
|
9613
|
0
|
0
|
|
|
|
0
|
local $| = 1 if $_verbose > 1; |
|
9614
|
0
|
|
|
|
|
0
|
for (my $a = $starta; $a <= $s; $a++) { |
|
9615
|
0
|
0
|
|
|
|
0
|
return 0 unless _test_anr($a, $n, $r); |
|
9616
|
0
|
0
|
|
|
|
0
|
print "." if $_verbose > 1; |
|
9617
|
|
|
|
|
|
|
} |
|
9618
|
0
|
0
|
|
|
|
0
|
print "\n" if $_verbose > 1; |
|
9619
|
|
|
|
|
|
|
|
|
9620
|
0
|
|
|
|
|
0
|
return 1; |
|
9621
|
|
|
|
|
|
|
} |
|
9622
|
|
|
|
|
|
|
|
|
9623
|
|
|
|
|
|
|
|
|
9624
|
|
|
|
|
|
|
################################################################################ |
|
9625
|
|
|
|
|
|
|
|
|
9626
|
|
|
|
|
|
|
sub factor_exp { |
|
9627
|
3644
|
|
|
3644
|
0
|
38626
|
my($n) = @_; |
|
9628
|
3644
|
|
|
|
|
8621
|
validate_integer_nonneg($n); |
|
9629
|
|
|
|
|
|
|
|
|
9630
|
3644
|
|
|
|
|
8392
|
my %exponents; |
|
9631
|
3644
|
|
|
|
|
7827
|
my @factors = grep { !$exponents{$_}++ } Mfactor($n); |
|
|
12087
|
|
|
|
|
37929
|
|
|
9632
|
3644
|
100
|
|
|
|
20805
|
return scalar @factors unless wantarray; |
|
9633
|
552
|
|
|
|
|
888
|
return (map { [$_, $exponents{$_}] } @factors); |
|
|
1430
|
|
|
|
|
4558
|
|
|
9634
|
|
|
|
|
|
|
} |
|
9635
|
|
|
|
|
|
|
|
|
9636
|
|
|
|
|
|
|
sub _basic_factor { |
|
9637
|
|
|
|
|
|
|
# MODIFIES INPUT SCALAR |
|
9638
|
30
|
0
|
|
30
|
|
164
|
return ($_[0] == 1) ? () : ($_[0]) if $_[0] < 4; |
|
|
|
50
|
|
|
|
|
|
|
9639
|
|
|
|
|
|
|
|
|
9640
|
30
|
|
|
|
|
3809
|
my @factors; |
|
9641
|
30
|
100
|
|
|
|
151
|
if (!ref($_[0])) { |
|
9642
|
14
|
|
|
|
|
58
|
while ( !($_[0] % 2) ) { push @factors, 2; $_[0] = int($_[0] / 2); } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
9643
|
14
|
|
|
|
|
52
|
while ( !($_[0] % 3) ) { push @factors, 3; $_[0] = int($_[0] / 3); } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
9644
|
14
|
|
|
|
|
76
|
while ( !($_[0] % 5) ) { push @factors, 5; $_[0] = int($_[0] / 5); } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
9645
|
|
|
|
|
|
|
} else { |
|
9646
|
16
|
50
|
|
|
|
122
|
if (Mgcd($_[0], 30) != 1) { |
|
9647
|
0
|
|
|
|
|
0
|
while ($_[0] % 2 == 0) { push @factors, 2; $_[0] >>= 1; } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
9648
|
0
|
|
|
|
|
0
|
while ($_[0] % 3 == 0) { push @factors, 3; $_[0] = Mdivint($_[0],3); } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
9649
|
0
|
|
|
|
|
0
|
while ($_[0] % 5 == 0) { push @factors, 5; $_[0] = Mdivint($_[0],5); } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
9650
|
|
|
|
|
|
|
} |
|
9651
|
|
|
|
|
|
|
} |
|
9652
|
|
|
|
|
|
|
|
|
9653
|
30
|
50
|
33
|
|
|
225
|
if ($_[0] > 1 && _is_prime7($_[0])) { |
|
9654
|
0
|
|
|
|
|
0
|
push @factors, $_[0]; |
|
9655
|
0
|
|
|
|
|
0
|
$_[0] = 1; |
|
9656
|
|
|
|
|
|
|
} |
|
9657
|
30
|
|
|
|
|
154
|
@factors; |
|
9658
|
|
|
|
|
|
|
} |
|
9659
|
|
|
|
|
|
|
|
|
9660
|
|
|
|
|
|
|
# Assume $f divides $n. Remove all occurances, add them to @$flist. Return $n. |
|
9661
|
|
|
|
|
|
|
sub _remove_factor { |
|
9662
|
417
|
|
|
417
|
|
1239
|
my($n, $f, $flist) = @_; |
|
9663
|
|
|
|
|
|
|
|
|
9664
|
417
|
|
|
|
|
717
|
while (1) { |
|
9665
|
1077
|
|
|
|
|
275703
|
push @$flist, $f; |
|
9666
|
1077
|
|
|
|
|
5077
|
$n = Mdivint($n,$f); |
|
9667
|
1077
|
100
|
|
|
|
10607
|
last unless Mis_divisible($n,$f); |
|
9668
|
|
|
|
|
|
|
} |
|
9669
|
|
|
|
|
|
|
|
|
9670
|
|
|
|
|
|
|
# Better for many repeated factors |
|
9671
|
|
|
|
|
|
|
#if ($n % ($f*$f)) { |
|
9672
|
|
|
|
|
|
|
# push @$flist, $f; |
|
9673
|
|
|
|
|
|
|
# $n = Mdivint($n,$f); |
|
9674
|
|
|
|
|
|
|
#} else { |
|
9675
|
|
|
|
|
|
|
# my($k,$fk,$fk1) = (2,$f*$f,Mmulint($f*$f,$f)); |
|
9676
|
|
|
|
|
|
|
# while (!($n % $fk1)) { $k++; ($fk,$fk1)=($fk1,Mmulint($fk1,$f)); } |
|
9677
|
|
|
|
|
|
|
# $n = Mdivint($n,$fk); |
|
9678
|
|
|
|
|
|
|
# push @$flist, map { $f } 1..$k; |
|
9679
|
|
|
|
|
|
|
#} |
|
9680
|
|
|
|
|
|
|
|
|
9681
|
417
|
|
|
|
|
1088
|
$n = addint($n,0) if OLD_PERL_VERSION; |
|
9682
|
417
|
|
|
|
|
1330
|
$n; |
|
9683
|
|
|
|
|
|
|
} |
|
9684
|
|
|
|
|
|
|
sub trial_factor { |
|
9685
|
4407
|
|
|
4407
|
0
|
10301
|
my($n, $limit) = @_; |
|
9686
|
4407
|
|
|
|
|
10203
|
validate_integer_nonneg($n); |
|
9687
|
4407
|
50
|
|
|
|
16880
|
validate_integer_nonneg($limit) if defined $limit; |
|
9688
|
|
|
|
|
|
|
|
|
9689
|
4407
|
50
|
|
|
|
8114
|
return ($n==1) ? () : ($n) if $n < 4; |
|
|
|
100
|
|
|
|
|
|
|
9690
|
4406
|
50
|
33
|
|
|
34643
|
return ($n) if defined $limit && $limit < 2; |
|
9691
|
|
|
|
|
|
|
|
|
9692
|
4406
|
50
|
33
|
|
|
10823
|
if ($Math::Prime::Util::_GMPfunc{"trial_factor"} && $Math::Prime::Util::GMP::VERSION >= 0.22) { |
|
9693
|
|
|
|
|
|
|
# Not the same API -- other than 2/3/5, returns a single factor |
|
9694
|
0
|
|
|
|
|
0
|
my @F = (); |
|
9695
|
0
|
|
|
|
|
0
|
while (1) { |
|
9696
|
0
|
0
|
|
|
|
0
|
my @f = defined $limit ? Math::Prime::Util::GMP::trial_factor($n,$limit) |
|
9697
|
|
|
|
|
|
|
: Math::Prime::Util::GMP::trial_factor($n); |
|
9698
|
|
|
|
|
|
|
# Pull off the factors of 2,3,5 that are done fully. |
|
9699
|
0
|
|
0
|
|
|
0
|
push @F,shift(@f) while @f && $f[0] <= 5; |
|
9700
|
0
|
0
|
|
|
|
0
|
push @F,$f[0] if @f == 1; |
|
9701
|
0
|
0
|
|
|
|
0
|
last if @f <= 1; |
|
9702
|
|
|
|
|
|
|
# Store the small factor we found, then keep factoring the remainder. |
|
9703
|
0
|
|
|
|
|
0
|
$n = pop(@f); |
|
9704
|
0
|
|
|
|
|
0
|
push @F,@f; |
|
9705
|
|
|
|
|
|
|
} |
|
9706
|
0
|
0
|
|
|
|
0
|
return ref($_[0]) ? maybetobigintall(@F) : @F; |
|
9707
|
|
|
|
|
|
|
} |
|
9708
|
|
|
|
|
|
|
|
|
9709
|
4406
|
|
|
|
|
7054
|
my @factors; |
|
9710
|
|
|
|
|
|
|
# Don't use _basic_factor here -- they want a trial forced. |
|
9711
|
|
|
|
|
|
|
|
|
9712
|
|
|
|
|
|
|
# For 32-bit n, we can simplify things a lot. |
|
9713
|
4406
|
100
|
|
|
|
9679
|
if ($n <= 4294967295) { |
|
9714
|
4308
|
|
|
|
|
8888
|
my $sqrtn = int(sqrt($n)); |
|
9715
|
4308
|
100
|
66
|
|
|
15227
|
$limit = $sqrtn if !defined $limit || $limit > $sqrtn; |
|
9716
|
|
|
|
|
|
|
|
|
9717
|
4308
|
100
|
66
|
|
|
13941
|
if ($limit >= 2 && ($n % 2 == 0)) { |
|
9718
|
2095
|
|
|
|
|
3207
|
do { push @factors, 2; $n >>= 1; } while ($n % 2) == 0; |
|
|
4120
|
|
|
|
|
6874
|
|
|
|
4120
|
|
|
|
|
8945
|
|
|
9719
|
2095
|
|
|
|
|
3597
|
$sqrtn = int(sqrt($n)); |
|
9720
|
2095
|
100
|
|
|
|
4640
|
$limit = $sqrtn if $sqrtn < $limit; |
|
9721
|
|
|
|
|
|
|
} |
|
9722
|
4308
|
|
|
|
|
9947
|
for my $p (3,5,7,11,13,17,19,23,29,31,37,41,43,47,53) { |
|
9723
|
27028
|
100
|
100
|
|
|
76020
|
last if $n == 1 || $p > $limit; |
|
9724
|
23058
|
100
|
|
|
|
44311
|
if ($n % $p == 0) { |
|
9725
|
3445
|
|
|
|
|
6390
|
do { push @factors, $p; $n = int($n/$p); } while ($n % $p) == 0; |
|
|
4464
|
|
|
|
|
7666
|
|
|
|
4464
|
|
|
|
|
10194
|
|
|
9726
|
3445
|
|
|
|
|
5314
|
$sqrtn = int(sqrt($n)); |
|
9727
|
3445
|
100
|
|
|
|
8071
|
$limit = $sqrtn if $sqrtn < $limit; |
|
9728
|
|
|
|
|
|
|
} |
|
9729
|
|
|
|
|
|
|
} |
|
9730
|
4308
|
100
|
|
|
|
9127
|
return @factors if $n == 1; |
|
9731
|
3956
|
100
|
|
|
|
15890
|
return (@factors,$n) if $limit < 59; |
|
9732
|
|
|
|
|
|
|
|
|
9733
|
251
|
50
|
|
|
|
760
|
_expand_prime_cache($limit+72) if $limit > $_primes_small[-1];; |
|
9734
|
|
|
|
|
|
|
|
|
9735
|
251
|
|
|
|
|
743
|
for my $i (17 .. $#_primes_small) { |
|
9736
|
14000
|
|
|
|
|
20801
|
my $p = $_primes_small[$i]; |
|
9737
|
14000
|
100
|
|
|
|
26867
|
last if $p > $limit; |
|
9738
|
13753
|
100
|
|
|
|
28008
|
if (($n % $p) == 0) { |
|
9739
|
61
|
|
|
|
|
137
|
do { push @factors, $p; $n = int($n/$p); } while ($n % $p) == 0; |
|
|
65
|
|
|
|
|
148
|
|
|
|
65
|
|
|
|
|
227
|
|
|
9740
|
61
|
100
|
|
|
|
191
|
last if $n == 1; |
|
9741
|
57
|
|
|
|
|
123
|
$sqrtn = int(sqrt($n)); |
|
9742
|
57
|
50
|
|
|
|
171
|
$limit = $sqrtn if $sqrtn < $limit; |
|
9743
|
|
|
|
|
|
|
} |
|
9744
|
|
|
|
|
|
|
} |
|
9745
|
251
|
100
|
|
|
|
782
|
push @factors, $n if $n > 1; |
|
9746
|
251
|
|
|
|
|
946
|
return @factors; |
|
9747
|
|
|
|
|
|
|
} |
|
9748
|
|
|
|
|
|
|
|
|
9749
|
|
|
|
|
|
|
# STEP 1 Pull out factors of 2 |
|
9750
|
98
|
100
|
|
|
|
21517
|
if (!ref($n)) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
9751
|
5
|
|
|
|
|
39
|
while ($n % 2 == 0) { |
|
9752
|
2
|
|
|
|
|
5
|
push @factors, 2; |
|
9753
|
2
|
|
|
|
|
8
|
$n >>= 1; |
|
9754
|
|
|
|
|
|
|
} |
|
9755
|
|
|
|
|
|
|
} elsif (ref($n) eq 'Math::BigInt') { |
|
9756
|
93
|
|
|
|
|
255
|
my $k = 0; |
|
9757
|
93
|
100
|
|
|
|
432
|
if ($n->is_even) { |
|
9758
|
45
|
|
|
|
|
1086
|
my $s = substr($n->as_bin(),2); |
|
9759
|
45
|
|
|
|
|
27272
|
$k = length($s) - rindex($s,'1') - 1; |
|
9760
|
|
|
|
|
|
|
} |
|
9761
|
93
|
100
|
|
|
|
1291
|
if ($k > 0) { push @factors, (2) x $k; $n = Mrshiftint($n,$k); } |
|
|
45
|
|
|
|
|
192
|
|
|
|
45
|
|
|
|
|
376
|
|
|
9762
|
|
|
|
|
|
|
} elsif ($n % 2 == 0) { |
|
9763
|
0
|
|
|
|
|
0
|
my $k = Mvaluation($n,2); |
|
9764
|
0
|
0
|
|
|
|
0
|
if ($k > 0) { push @factors, (2) x $k; $n = Mrshiftint($n,$k); } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
9765
|
|
|
|
|
|
|
} |
|
9766
|
|
|
|
|
|
|
|
|
9767
|
|
|
|
|
|
|
# STEP 2 Defined and accurate $limit, add more small primes |
|
9768
|
98
|
50
|
33
|
|
|
10061
|
$limit = Msqrtint($n) if !defined $limit || $limit*$limit > $n; |
|
9769
|
|
|
|
|
|
|
|
|
9770
|
|
|
|
|
|
|
# Add more primes if we might use them. Maybe wait until needed? |
|
9771
|
98
|
100
|
100
|
|
|
13264
|
_expand_prime_cache(100_003) |
|
9772
|
|
|
|
|
|
|
if $_primes_small[-1] < 100_000 && $limit > $_primes_small[-1]; |
|
9773
|
|
|
|
|
|
|
|
|
9774
|
98
|
|
|
|
|
317
|
my $I = 2; # small prime index, start at p=3 |
|
9775
|
|
|
|
|
|
|
|
|
9776
|
|
|
|
|
|
|
# STEP 3: Math::BigInt using small primes list until native or no more |
|
9777
|
98
|
100
|
|
|
|
416
|
if (ref($n) eq 'Math::BigInt') { |
|
9778
|
|
|
|
|
|
|
# n is a odd positive Math::BigInt with at least 32 bits. |
|
9779
|
|
|
|
|
|
|
# Batch primes and use gcd to check. If using Math::BigInt, 2-5x faster. |
|
9780
|
88
|
|
100
|
|
|
856
|
while ($I+3 <= $#_primes_small && $_primes_small[$I+3] <= $limit && $I <= 1951956) { |
|
|
|
|
66
|
|
|
|
|
|
9781
|
4697
|
|
|
|
|
125454
|
my($f1,$f2,$f3,$f4) = @_primes_small[$I .. $I+3]; |
|
9782
|
4697
|
100
|
|
|
|
23224
|
my $g = $n->bgcd($f1<=5581 ? $f1*$f2*$f3*$f4 : Mmulint($f1*$f4,$f2*$f3)); |
|
9783
|
4697
|
|
|
|
|
8104319
|
$I += 4; |
|
9784
|
4697
|
100
|
|
|
|
15250
|
next if $g->is_one; |
|
9785
|
208
|
|
|
|
|
4561
|
my $G = _bigint_to_int($g); # Native int (or larger) |
|
9786
|
208
|
50
|
|
|
|
8915
|
$G = $g if $G >= INTMAX; # Must use original if multiples found. |
|
9787
|
208
|
100
|
|
|
|
1086
|
$n = _remove_factor($n, $f1, \@factors) unless $G % $f1; |
|
9788
|
208
|
100
|
|
|
|
1266
|
$n = _remove_factor($n, $f2, \@factors) unless $G % $f2; |
|
9789
|
208
|
100
|
|
|
|
1141
|
$n = _remove_factor($n, $f3, \@factors) unless $G % $f3; |
|
9790
|
208
|
100
|
|
|
|
991
|
$n = _remove_factor($n, $f4, \@factors) unless $G % $f4; |
|
9791
|
208
|
100
|
|
|
|
913
|
if ($limit*$limit >= $n) { |
|
9792
|
7
|
|
|
|
|
59
|
my $sqrtn = Msqrtint($n); |
|
9793
|
7
|
50
|
|
|
|
25
|
$limit = $sqrtn if $limit > $sqrtn; |
|
9794
|
|
|
|
|
|
|
} |
|
9795
|
208
|
100
|
|
|
|
24044
|
last if !ref($n); |
|
9796
|
|
|
|
|
|
|
} |
|
9797
|
|
|
|
|
|
|
# n is either a bigint and > INTMAX, or a native type <= INTMAX; |
|
9798
|
88
|
100
|
|
|
|
832
|
return @factors if $n == 1; |
|
9799
|
81
|
50
|
|
|
|
5254
|
my $f = $I > $#_primes_small ? $_primes_small[-1]+2 : $_primes_small[$I]; |
|
9800
|
81
|
100
|
|
|
|
468
|
return (@factors,$n) if $f > $limit; |
|
9801
|
|
|
|
|
|
|
} |
|
9802
|
|
|
|
|
|
|
|
|
9803
|
|
|
|
|
|
|
# STEP 4: any bigint, small primes list until native or no more |
|
9804
|
72
|
100
|
|
|
|
347
|
if (ref($n)) { |
|
9805
|
2
|
|
|
|
|
8
|
while ($I <= $#_primes_small) { |
|
9806
|
8
|
|
|
|
|
2069
|
my $f = $_primes_small[$I]; |
|
9807
|
8
|
100
|
|
|
|
21
|
last if $f > $limit; |
|
9808
|
6
|
|
|
|
|
10
|
$I++; |
|
9809
|
6
|
50
|
|
|
|
18
|
next if $n % $f; |
|
9810
|
0
|
|
|
|
|
0
|
$n = _remove_factor($n, $f, \@factors); |
|
9811
|
0
|
0
|
|
|
|
0
|
if ($limit*$limit >= $n) { |
|
9812
|
0
|
|
|
|
|
0
|
my $sqrtn = Msqrtint($n); |
|
9813
|
0
|
0
|
|
|
|
0
|
$limit = $sqrtn if $limit > $sqrtn; |
|
9814
|
|
|
|
|
|
|
} |
|
9815
|
0
|
0
|
|
|
|
0
|
last if !ref($n); |
|
9816
|
|
|
|
|
|
|
} |
|
9817
|
2
|
50
|
|
|
|
7
|
return @factors if $n == 1; |
|
9818
|
2
|
50
|
|
|
|
379
|
my $f = $I > $#_primes_small ? $_primes_small[-1]+2 : $_primes_small[$I]; |
|
9819
|
2
|
50
|
|
|
|
19
|
return (@factors,$n) if $f > $limit; |
|
9820
|
|
|
|
|
|
|
} |
|
9821
|
|
|
|
|
|
|
|
|
9822
|
|
|
|
|
|
|
# STEP 5: Still a bigint. Wheel (mod 2310) starting from last small prime. |
|
9823
|
70
|
50
|
|
|
|
265
|
if (ref($n)) { |
|
9824
|
0
|
|
|
|
|
0
|
my $f = $_primes_small[-1]; |
|
9825
|
0
|
|
|
|
|
0
|
my($s,$w) = ($_primes_small[-1], 2*3*5*7*11); |
|
9826
|
0
|
|
|
0
|
|
0
|
my @wheel = Mvecslide(sub{$b-$a}, grep { Mgcd($_,$w)==1 } $s+0..$s+$w); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
9827
|
0
|
|
|
|
|
0
|
SEARCH: while ($f <= $limit) { |
|
9828
|
0
|
|
|
|
|
0
|
for my $inc (@wheel) { |
|
9829
|
0
|
|
|
|
|
0
|
$f += $inc; |
|
9830
|
0
|
0
|
0
|
|
|
0
|
if ($f <= $limit && !($n % $f)) { |
|
9831
|
0
|
|
|
|
|
0
|
$n = _remove_factor($n, $f, \@factors); |
|
9832
|
0
|
0
|
|
|
|
0
|
last SEARCH if $n == 1; |
|
9833
|
0
|
0
|
|
|
|
0
|
if ($limit*$limit >= $n) { |
|
9834
|
0
|
|
|
|
|
0
|
my $sqrtn = Msqrtint($n); |
|
9835
|
0
|
0
|
|
|
|
0
|
$limit = $sqrtn if $limit > $sqrtn; |
|
9836
|
|
|
|
|
|
|
} |
|
9837
|
|
|
|
|
|
|
} |
|
9838
|
|
|
|
|
|
|
} |
|
9839
|
|
|
|
|
|
|
} |
|
9840
|
0
|
0
|
|
|
|
0
|
push @factors, $n if $n > 1; |
|
9841
|
0
|
|
|
|
|
0
|
return @factors; |
|
9842
|
|
|
|
|
|
|
} |
|
9843
|
|
|
|
|
|
|
|
|
9844
|
|
|
|
|
|
|
# STEP 6: native small primes list |
|
9845
|
70
|
|
|
|
|
318
|
for my $i ($I .. $#_primes_small) { |
|
9846
|
32616
|
|
|
|
|
47253
|
my $p = $_primes_small[$i]; |
|
9847
|
32616
|
100
|
|
|
|
62379
|
last if $p > $limit; |
|
9848
|
32548
|
100
|
|
|
|
64352
|
if (($n % $p) == 0) { |
|
9849
|
186
|
|
|
|
|
294
|
do { push @factors, $p; $n = int($n/$p); } while ($n % $p) == 0; |
|
|
196
|
|
|
|
|
404
|
|
|
|
196
|
|
|
|
|
643
|
|
|
9850
|
186
|
100
|
|
|
|
496
|
last if $n == 1; |
|
9851
|
184
|
|
|
|
|
403
|
my $newlim = int( sqrt($n) + 0.001); |
|
9852
|
184
|
100
|
|
|
|
580
|
$limit = $newlim if $newlim < $limit; |
|
9853
|
|
|
|
|
|
|
} |
|
9854
|
|
|
|
|
|
|
} |
|
9855
|
70
|
100
|
|
|
|
353
|
return @factors if $n == 1; |
|
9856
|
|
|
|
|
|
|
|
|
9857
|
|
|
|
|
|
|
# STEP 7: native wheel (mod 30) |
|
9858
|
68
|
50
|
|
|
|
284
|
if ($_primes_small[-1] < $limit) { |
|
9859
|
0
|
0
|
|
|
|
0
|
my $inc = (($_primes_small[-1] % 6) == 1) ? 4 : 2; |
|
9860
|
0
|
|
|
|
|
0
|
my $p = $_primes_small[-1] + $inc; |
|
9861
|
0
|
|
|
|
|
0
|
while ($p <= $limit) { |
|
9862
|
0
|
0
|
|
|
|
0
|
if (($n % $p) == 0) { |
|
9863
|
0
|
|
|
|
|
0
|
do { push @factors, $p; $n = int($n/$p); } while ($n % $p) == 0; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
9864
|
0
|
0
|
|
|
|
0
|
last if $n == 1; |
|
9865
|
0
|
|
|
|
|
0
|
my $newlim = int( sqrt($n) + 0.001); |
|
9866
|
0
|
0
|
|
|
|
0
|
$limit = $newlim if $newlim < $limit; |
|
9867
|
|
|
|
|
|
|
} |
|
9868
|
0
|
|
|
|
|
0
|
$p += ($inc ^= 6); |
|
9869
|
|
|
|
|
|
|
} |
|
9870
|
|
|
|
|
|
|
} |
|
9871
|
68
|
50
|
|
|
|
318
|
push @factors, $n if $n > 1; |
|
9872
|
68
|
|
|
|
|
607
|
@factors; |
|
9873
|
|
|
|
|
|
|
} |
|
9874
|
|
|
|
|
|
|
|
|
9875
|
|
|
|
|
|
|
my $_holf_r; |
|
9876
|
|
|
|
|
|
|
my @_fsublist = ( |
|
9877
|
|
|
|
|
|
|
[ "power", sub { _power_factor (shift) } ], |
|
9878
|
|
|
|
|
|
|
|
|
9879
|
|
|
|
|
|
|
[ "pbrent 8k", sub { pbrent_factor (shift, 8*1024, 1, 1) } ], |
|
9880
|
|
|
|
|
|
|
[ "p-1 16k", sub { pminus1_factor(shift, 16_384, 16_384, 1); } ], |
|
9881
|
|
|
|
|
|
|
[ "ECM 500", sub { ecm_factor (shift, 500, 10_000, 10) } ], |
|
9882
|
|
|
|
|
|
|
[ "ECM 4k", sub { ecm_factor (shift, 4_000, 20_000, 20) } ], |
|
9883
|
|
|
|
|
|
|
|
|
9884
|
|
|
|
|
|
|
[ "pbrent 512k",sub { pbrent_factor (shift, 512*1024, 7, 1) } ], |
|
9885
|
|
|
|
|
|
|
[ "p-1 4M", sub { pminus1_factor(shift, 4_000_000, undef, 1); } ], |
|
9886
|
|
|
|
|
|
|
[ "ECM 10k", sub { ecm_factor (shift, 10_000, 50_000, 10) } ], |
|
9887
|
|
|
|
|
|
|
[ "pbrent 512k",sub { pbrent_factor (shift, 512*1024, 11, 1) } ], |
|
9888
|
|
|
|
|
|
|
[ "HOLF 256k", sub { holf_factor (shift, 256*1024, $_holf_r); $_holf_r += 256*1024; } ], |
|
9889
|
|
|
|
|
|
|
[ "p-1 20M", sub { pminus1_factor(shift,20_000_000); } ], |
|
9890
|
|
|
|
|
|
|
[ "ECM 100k", sub { ecm_factor (shift, 100_000, 800_000, 10) } ], |
|
9891
|
|
|
|
|
|
|
[ "HOLF 512k", sub { holf_factor (shift, 512*1024, $_holf_r); $_holf_r += 512*1024; } ], |
|
9892
|
|
|
|
|
|
|
[ "pbrent 2M", sub { pbrent_factor (shift, 2048*1024, 13, 1) } ], |
|
9893
|
|
|
|
|
|
|
[ "HOLF 2M", sub { holf_factor (shift, 2048*1024, $_holf_r); $_holf_r += 2048*1024; } ], |
|
9894
|
|
|
|
|
|
|
[ "ECM 1M", sub { ecm_factor (shift, 1_000_000, 1_000_000, 10) } ], |
|
9895
|
|
|
|
|
|
|
[ "p-1 100M", sub { pminus1_factor(shift, 100_000_000, 500_000_000); } ], |
|
9896
|
|
|
|
|
|
|
); |
|
9897
|
|
|
|
|
|
|
|
|
9898
|
|
|
|
|
|
|
sub factor { |
|
9899
|
4494
|
|
|
4494
|
0
|
12663
|
my($n) = @_; |
|
9900
|
4494
|
|
|
|
|
11546
|
validate_integer_nonneg($n); |
|
9901
|
|
|
|
|
|
|
|
|
9902
|
4494
|
|
|
|
|
11211
|
my @factors; |
|
9903
|
4494
|
100
|
|
|
|
9495
|
if ($n < 4) { |
|
9904
|
118
|
100
|
|
|
|
373
|
@factors = ($n == 1) ? () : ($n); |
|
9905
|
118
|
|
|
|
|
297
|
return @factors; |
|
9906
|
|
|
|
|
|
|
} |
|
9907
|
|
|
|
|
|
|
|
|
9908
|
4376
|
50
|
|
|
|
28652
|
if ($Math::Prime::Util::_GMPfunc{"factor"}) { |
|
9909
|
0
|
|
|
|
|
0
|
my @factors = Math::Prime::Util::GMP::factor($n); |
|
9910
|
0
|
0
|
|
|
|
0
|
return ref($_[0]) ? maybetobigintall(@factors) : @factors; |
|
9911
|
|
|
|
|
|
|
} |
|
9912
|
|
|
|
|
|
|
|
|
9913
|
4376
|
100
|
|
|
|
9767
|
$n = Maddint($n,0) if ref($n); # Ensure we have a copy |
|
9914
|
4376
|
|
|
|
|
26162
|
my $lim = 4999; # How much trial factoring to do |
|
9915
|
|
|
|
|
|
|
|
|
9916
|
|
|
|
|
|
|
# For native integers, we could save a little time by doing hardcoded trials |
|
9917
|
|
|
|
|
|
|
# by 2-29 here. Skipping it. |
|
9918
|
|
|
|
|
|
|
|
|
9919
|
4376
|
|
|
|
|
11460
|
push @factors, Mtrial_factor($n, $lim); |
|
9920
|
4376
|
100
|
|
|
|
16211
|
return @factors if $factors[-1] < $lim*$lim; |
|
9921
|
63
|
|
|
|
|
3762
|
$n = pop(@factors); |
|
9922
|
|
|
|
|
|
|
|
|
9923
|
63
|
|
|
|
|
435
|
my @nstack = ($n); |
|
9924
|
63
|
|
|
|
|
222
|
while (@nstack) { |
|
9925
|
97
|
|
|
|
|
210
|
$n = pop @nstack; |
|
9926
|
|
|
|
|
|
|
# Don't use bignum on $n if it has gotten small enough. |
|
9927
|
97
|
50
|
66
|
|
|
537
|
$n = _bigint_to_int($n) if ref($n) && $n <= INTMAX; |
|
9928
|
|
|
|
|
|
|
#print "Looking at $n with stack ", join(",",@nstack), "\n"; |
|
9929
|
97
|
|
100
|
|
|
5888
|
while ( ($n >= ($lim*$lim)) && !_is_prime7($n) ) { |
|
9930
|
34
|
|
|
|
|
96
|
my @ftry; |
|
9931
|
34
|
|
|
|
|
89
|
$_holf_r = 1; |
|
9932
|
34
|
|
|
|
|
116
|
foreach my $sub (@_fsublist) { |
|
9933
|
102
|
100
|
|
|
|
398
|
last if scalar @ftry >= 2; |
|
9934
|
68
|
50
|
|
|
|
393
|
print " starting $sub->[0]\n" if getconfig()->{'verbose'} > 1; |
|
9935
|
68
|
|
|
|
|
481
|
@ftry = $sub->[1]->($n); |
|
9936
|
|
|
|
|
|
|
} |
|
9937
|
34
|
50
|
|
|
|
174
|
if (scalar @ftry > 1) { |
|
9938
|
|
|
|
|
|
|
#print " split into ", join(",",@ftry), "\n"; |
|
9939
|
34
|
|
|
|
|
86
|
$n = shift @ftry; |
|
9940
|
34
|
50
|
33
|
|
|
199
|
$n = _bigint_to_int($n) if ref($n) && $n <= INTMAX; |
|
9941
|
34
|
|
|
|
|
211
|
push @nstack, @ftry; |
|
9942
|
|
|
|
|
|
|
} else { |
|
9943
|
|
|
|
|
|
|
#warn "trial factor $n\n"; |
|
9944
|
0
|
|
|
|
|
0
|
push @factors, Mtrial_factor($n); |
|
9945
|
|
|
|
|
|
|
#print " trial into ", join(",",@factors), "\n"; |
|
9946
|
0
|
|
|
|
|
0
|
$n = 1; |
|
9947
|
0
|
|
|
|
|
0
|
last; |
|
9948
|
|
|
|
|
|
|
} |
|
9949
|
|
|
|
|
|
|
} |
|
9950
|
97
|
50
|
|
|
|
1404
|
push @factors, $n if $n != 1; |
|
9951
|
|
|
|
|
|
|
} |
|
9952
|
63
|
|
|
|
|
2288
|
Mvecsort(@factors); |
|
9953
|
|
|
|
|
|
|
} |
|
9954
|
|
|
|
|
|
|
|
|
9955
|
|
|
|
|
|
|
sub _found_factor { |
|
9956
|
61
|
|
|
61
|
|
357
|
my($f, $n, $what, @factors) = @_; |
|
9957
|
61
|
50
|
33
|
|
|
492
|
if ($f == 1 || $f == $n) { |
|
9958
|
0
|
|
|
|
|
0
|
push @factors, $n; |
|
9959
|
|
|
|
|
|
|
} else { |
|
9960
|
61
|
|
|
|
|
6794
|
my $f2 = Mdivint($n,$f); |
|
9961
|
61
|
50
|
|
|
|
1475
|
croak "internal error in $what" unless Mmulint($f,$f2) == $n; |
|
9962
|
61
|
100
|
|
|
|
9574
|
($f,$f2) = ($f2,$f) if $f > $f2; |
|
9963
|
61
|
|
|
|
|
984
|
push @factors, $f, $f2; |
|
9964
|
|
|
|
|
|
|
# MPU::GMP prints this type of message if verbose, so do the same. |
|
9965
|
61
|
50
|
|
|
|
370
|
print "$what found factor $f\n" if getconfig()->{'verbose'} > 0; |
|
9966
|
|
|
|
|
|
|
} |
|
9967
|
61
|
|
|
|
|
1420
|
@factors; |
|
9968
|
|
|
|
|
|
|
} |
|
9969
|
|
|
|
|
|
|
|
|
9970
|
|
|
|
|
|
|
################################################################################ |
|
9971
|
|
|
|
|
|
|
|
|
9972
|
|
|
|
|
|
|
# TODO: |
|
9973
|
0
|
|
|
0
|
0
|
0
|
sub squfof_factor { Mtrial_factor(@_) } |
|
9974
|
0
|
|
|
0
|
0
|
0
|
sub lehman_factor { Mtrial_factor(@_) } |
|
9975
|
0
|
|
|
0
|
0
|
0
|
sub pplus1_factor { pminus1_factor(@_) } |
|
9976
|
|
|
|
|
|
|
|
|
9977
|
|
|
|
|
|
|
sub _power_factor { |
|
9978
|
34
|
|
|
34
|
|
89
|
my $r; |
|
9979
|
34
|
|
|
|
|
395
|
my $k = Mis_power($_[0],0,\$r); |
|
9980
|
34
|
50
|
|
|
|
270
|
return ($_[0]) unless $k > 1; |
|
9981
|
0
|
0
|
|
|
|
0
|
print "power found factor $r\n" if getconfig()->{'verbose'} > 0; |
|
9982
|
0
|
|
|
|
|
0
|
map { $r } 1..$k; |
|
|
0
|
|
|
|
|
0
|
|
|
9983
|
|
|
|
|
|
|
} |
|
9984
|
|
|
|
|
|
|
|
|
9985
|
|
|
|
|
|
|
sub prho_factor { |
|
9986
|
5
|
|
|
5
|
0
|
5300
|
my($n, $rounds, $pa, $skipbasic) = @_; |
|
9987
|
5
|
|
|
|
|
28
|
validate_integer_nonneg($n); |
|
9988
|
5
|
50
|
|
|
|
20
|
if (defined $rounds) { validate_integer_nonneg($rounds); } |
|
|
0
|
|
|
|
|
0
|
|
|
9989
|
5
|
|
|
|
|
13
|
else { $rounds = 4*1024*1024; } |
|
9990
|
5
|
50
|
|
|
|
15
|
if (defined $pa) { validate_integer_nonneg($pa); } |
|
|
0
|
|
|
|
|
0
|
|
|
9991
|
5
|
|
|
|
|
11
|
else { $pa = 3; } |
|
9992
|
|
|
|
|
|
|
|
|
9993
|
5
|
|
|
|
|
26
|
my @factors; |
|
9994
|
5
|
50
|
|
|
|
18
|
if (!$skipbasic) { |
|
9995
|
5
|
|
|
|
|
24
|
@factors = _basic_factor($n); |
|
9996
|
5
|
50
|
|
|
|
21
|
return @factors if $n < 4; |
|
9997
|
|
|
|
|
|
|
} |
|
9998
|
|
|
|
|
|
|
|
|
9999
|
5
|
|
|
|
|
233
|
my($U,$V) = (7,7); |
|
10000
|
|
|
|
|
|
|
|
|
10001
|
5
|
100
|
100
|
|
|
29
|
if (ref($n) || $n >= MPU_HALFWORD) { |
|
10002
|
|
|
|
|
|
|
|
|
10003
|
3
|
|
|
|
|
9
|
my $inner = 32; |
|
10004
|
3
|
|
|
|
|
16
|
$rounds = int( ($rounds + $inner-1) / $inner ); |
|
10005
|
3
|
|
|
|
|
31
|
while ($rounds-- > 0) { |
|
10006
|
3
|
|
|
|
|
11
|
my($m, $oldU, $oldV, $f) = (1, $U, $V); |
|
10007
|
3
|
|
|
|
|
21
|
for my $i (1 .. $inner) { |
|
10008
|
96
|
|
|
|
|
8980
|
$U = Mmuladdmod($U, $U, $pa, $n); |
|
10009
|
96
|
|
|
|
|
7597
|
$V = Mmuladdmod($V, $V, $pa, $n); |
|
10010
|
96
|
|
|
|
|
9580
|
$V = Mmuladdmod($V, $V, $pa, $n); |
|
10011
|
96
|
100
|
|
|
|
7771
|
$f = ($U > $V) ? Msubint($U,$V) : Msubint($V,$U); |
|
10012
|
96
|
|
|
|
|
7731
|
$m = Mmulmod($m,$f,$n); |
|
10013
|
|
|
|
|
|
|
} |
|
10014
|
3
|
|
|
|
|
246
|
$f = Mgcd($m,$n); |
|
10015
|
3
|
50
|
|
|
|
17
|
next if $f == 1; |
|
10016
|
3
|
100
|
|
|
|
26
|
if ($f == $n) { |
|
10017
|
1
|
|
|
|
|
3
|
($U, $V) = ($oldU, $oldV); |
|
10018
|
1
|
|
|
|
|
5
|
for my $i (1 .. $inner) { |
|
10019
|
3
|
|
|
|
|
13
|
$U = Mmuladdmod($U, $U, $pa, $n); |
|
10020
|
3
|
|
|
|
|
14
|
$V = Mmuladdmod($V, $V, $pa, $n); |
|
10021
|
3
|
|
|
|
|
11
|
$V = Mmuladdmod($V, $V, $pa, $n); |
|
10022
|
3
|
50
|
|
|
|
17
|
$f = ($U > $V) ? Msubint($U,$V) : Msubint($V,$U); |
|
10023
|
3
|
|
|
|
|
10
|
$f = Mgcd($f, $n); |
|
10024
|
3
|
100
|
|
|
|
12
|
last if $f != 1; |
|
10025
|
|
|
|
|
|
|
} |
|
10026
|
1
|
50
|
33
|
|
|
11
|
last if $f == 1 || $f == $n; |
|
10027
|
|
|
|
|
|
|
} |
|
10028
|
3
|
|
|
|
|
237
|
return _found_factor($f, $n, "prho-bigint", @factors); |
|
10029
|
|
|
|
|
|
|
} |
|
10030
|
|
|
|
|
|
|
|
|
10031
|
|
|
|
|
|
|
} else { |
|
10032
|
|
|
|
|
|
|
|
|
10033
|
2
|
|
|
|
|
6
|
my $inner = 32; |
|
10034
|
2
|
|
|
|
|
9
|
$rounds = int( ($rounds + $inner-1) / $inner ); |
|
10035
|
2
|
|
|
|
|
13
|
while ($rounds-- > 0) { |
|
10036
|
2
|
|
|
|
|
17
|
my($m, $oldU, $oldV, $f) = (1, $U, $V); |
|
10037
|
2
|
|
|
|
|
9
|
for my $i (1 .. $inner) { |
|
10038
|
64
|
|
|
|
|
147
|
$U = ($U * $U + $pa) % $n; |
|
10039
|
64
|
|
|
|
|
105
|
$V = ($V * $V + $pa) % $n; |
|
10040
|
64
|
|
|
|
|
97
|
$V = ($V * $V + $pa) % $n; |
|
10041
|
64
|
100
|
|
|
|
121
|
$f = ($U > $V) ? $U-$V : $V-$U; |
|
10042
|
64
|
|
|
|
|
101
|
$m = ($m * $f) % $n; |
|
10043
|
|
|
|
|
|
|
} |
|
10044
|
2
|
|
|
|
|
12
|
$f = _gcd_ui( $m, $n ); |
|
10045
|
2
|
50
|
|
|
|
10
|
next if $f == 1; |
|
10046
|
2
|
100
|
|
|
|
8
|
if ($f == $n) { |
|
10047
|
1
|
|
|
|
|
4
|
($U, $V) = ($oldU, $oldV); |
|
10048
|
1
|
|
|
|
|
4
|
for my $i (1 .. $inner) { |
|
10049
|
2
|
|
|
|
|
20
|
$U = ($U * $U + $pa) % $n; |
|
10050
|
2
|
|
|
|
|
5
|
$V = ($V * $V + $pa) % $n; |
|
10051
|
2
|
|
|
|
|
4
|
$V = ($V * $V + $pa) % $n; |
|
10052
|
2
|
100
|
|
|
|
18
|
$f = ($U > $V) ? $U-$V : $V-$U; |
|
10053
|
2
|
|
|
|
|
6
|
$f = _gcd_ui( $f, $n); |
|
10054
|
2
|
100
|
|
|
|
9
|
last if $f != 1; |
|
10055
|
|
|
|
|
|
|
} |
|
10056
|
1
|
50
|
33
|
|
|
10
|
last if $f == 1 || $f == $n; |
|
10057
|
|
|
|
|
|
|
} |
|
10058
|
2
|
|
|
|
|
8
|
return _found_factor($f, $n, "prho-32", @factors); |
|
10059
|
|
|
|
|
|
|
} |
|
10060
|
|
|
|
|
|
|
|
|
10061
|
|
|
|
|
|
|
} |
|
10062
|
0
|
|
|
|
|
0
|
push @factors, $n; |
|
10063
|
0
|
|
|
|
|
0
|
@factors; |
|
10064
|
|
|
|
|
|
|
} |
|
10065
|
|
|
|
|
|
|
|
|
10066
|
|
|
|
|
|
|
sub pbrent_factor { |
|
10067
|
40
|
|
|
40
|
0
|
4193
|
my($n, $rounds, $pa, $skipbasic) = @_; |
|
10068
|
40
|
|
|
|
|
235
|
validate_integer_nonneg($n); |
|
10069
|
40
|
100
|
|
|
|
857
|
if (defined $rounds) { validate_integer_nonneg($rounds); } |
|
|
35
|
|
|
|
|
134
|
|
|
10070
|
5
|
|
|
|
|
14
|
else { $rounds = 4*1024*1024; } |
|
10071
|
40
|
100
|
|
|
|
109
|
if (defined $pa) { validate_integer_nonneg($pa); } |
|
|
35
|
|
|
|
|
100
|
|
|
10072
|
5
|
|
|
|
|
9
|
else { $pa = 3; } |
|
10073
|
|
|
|
|
|
|
|
|
10074
|
40
|
|
|
|
|
85
|
my @factors; |
|
10075
|
40
|
100
|
|
|
|
133
|
if (!$skipbasic) { |
|
10076
|
6
|
|
|
|
|
28
|
@factors = _basic_factor($n); |
|
10077
|
6
|
50
|
|
|
|
24
|
return @factors if $n < 4; |
|
10078
|
|
|
|
|
|
|
} |
|
10079
|
|
|
|
|
|
|
|
|
10080
|
40
|
|
|
|
|
324
|
my($Xi,$Xm) = (2,2); |
|
10081
|
|
|
|
|
|
|
|
|
10082
|
40
|
100
|
100
|
|
|
210
|
if (ref($n) || $n >= MPU_HALFWORD) { |
|
10083
|
|
|
|
|
|
|
|
|
10084
|
|
|
|
|
|
|
# Same code as the GMP version, but runs *much* slower. Even with |
|
10085
|
|
|
|
|
|
|
# Math::BigInt::GMP it's >200x slower. With the default Calc backend |
|
10086
|
|
|
|
|
|
|
# it's thousands of times slower. |
|
10087
|
37
|
|
|
|
|
134
|
my($inner,$r,$saveXi,$f) = (32,1); |
|
10088
|
|
|
|
|
|
|
|
|
10089
|
37
|
|
|
|
|
149
|
while ($rounds > 0) { |
|
10090
|
317
|
50
|
|
|
|
1135
|
my $rleft = ($r > $rounds) ? $rounds : $r; |
|
10091
|
317
|
|
|
|
|
746
|
while ($rleft > 0) { |
|
10092
|
896
|
100
|
|
|
|
2271
|
my $dorounds = ($rleft > $inner) ? $inner : $rleft; |
|
10093
|
896
|
|
|
|
|
1698
|
my $m = 1; |
|
10094
|
896
|
|
|
|
|
3262
|
$saveXi = Maddint($Xi,0); |
|
10095
|
896
|
|
|
|
|
36614
|
foreach my $i (1 .. $dorounds) { |
|
10096
|
23947
|
|
|
|
|
1317051
|
$Xi = Mmuladdmod($Xi, $Xi, $pa, $n); |
|
10097
|
23947
|
|
|
|
|
1321889
|
if (OLD_PERL_VERSION) { $m=mulmod($m,subint($Xi,$Xm),$n); next; } |
|
10098
|
23947
|
100
|
|
|
|
84041
|
$m = Mmulmod($m, $Xi > $Xm ? $Xi-$Xm : $Xm-$Xi,$n); |
|
10099
|
|
|
|
|
|
|
} |
|
10100
|
896
|
|
|
|
|
51933
|
$rleft -= $dorounds; |
|
10101
|
896
|
|
|
|
|
1610
|
$rounds -= $dorounds; |
|
10102
|
896
|
|
|
|
|
4437
|
$f = Mgcd($m,$n); |
|
10103
|
896
|
100
|
|
|
|
4452
|
last unless $f == 1; |
|
10104
|
|
|
|
|
|
|
} |
|
10105
|
317
|
100
|
|
|
|
905
|
if ($f == 1) { |
|
10106
|
280
|
|
|
|
|
570
|
$r *= 2; |
|
10107
|
280
|
|
|
|
|
1229
|
$Xm = Maddint($Xi,0); |
|
10108
|
280
|
|
|
|
|
20370
|
next; |
|
10109
|
|
|
|
|
|
|
} |
|
10110
|
37
|
100
|
|
|
|
159
|
if ($f == $n) { # back up to determine the factor |
|
10111
|
1
|
|
|
|
|
7
|
$Xi = Maddint($saveXi,0); |
|
10112
|
1
|
|
66
|
|
|
32
|
do { |
|
10113
|
7
|
|
|
|
|
31
|
$Xi = Mmuladdmod($Xi, $Xi, $pa, $n); |
|
10114
|
7
|
100
|
|
|
|
44
|
$f = Mgcd($Xi > $Xm ? $Xi-$Xm : $Xm-$Xi, $n); |
|
10115
|
|
|
|
|
|
|
} while ($f == 1 && $r-- != 0); |
|
10116
|
1
|
50
|
33
|
|
|
13
|
last if $f == 1 || $f == $n; |
|
10117
|
|
|
|
|
|
|
} |
|
10118
|
37
|
|
|
|
|
4092
|
return _found_factor($f, $n, "pbrent", @factors); |
|
10119
|
|
|
|
|
|
|
} |
|
10120
|
|
|
|
|
|
|
|
|
10121
|
|
|
|
|
|
|
} else { |
|
10122
|
|
|
|
|
|
|
|
|
10123
|
|
|
|
|
|
|
# Doing the gcd batching as above works pretty well here, but it's a lot |
|
10124
|
|
|
|
|
|
|
# of code for not much gain for general users. |
|
10125
|
3
|
|
|
|
|
27
|
for my $i (1 .. $rounds) { |
|
10126
|
416
|
|
|
|
|
740
|
$Xi = ($Xi * $Xi) % $n; |
|
10127
|
416
|
50
|
|
|
|
699
|
$Xi += $pa; $Xi -= $n if $Xi >= $n; |
|
|
416
|
|
|
|
|
858
|
|
|
10128
|
416
|
100
|
|
|
|
1031
|
my $f = _gcd_ui( ($Xi>$Xm) ? $Xi-$Xm : $Xm-$Xi, $n); |
|
10129
|
416
|
100
|
66
|
|
|
1109
|
return _found_factor($f, $n, "pbrent-32",@factors) if $f != 1 && $f != $n; |
|
10130
|
413
|
100
|
|
|
|
1061
|
$Xm = $Xi if ($i & ($i-1)) == 0; # i is a power of 2 |
|
10131
|
|
|
|
|
|
|
} |
|
10132
|
|
|
|
|
|
|
|
|
10133
|
|
|
|
|
|
|
} |
|
10134
|
0
|
|
|
|
|
0
|
push @factors, $n; |
|
10135
|
0
|
|
|
|
|
0
|
@factors; |
|
10136
|
|
|
|
|
|
|
} |
|
10137
|
|
|
|
|
|
|
|
|
10138
|
|
|
|
|
|
|
sub pminus1_factor { |
|
10139
|
8
|
|
|
8
|
0
|
4701
|
my($n, $B1, $B2, $skipbasic) = @_; |
|
10140
|
8
|
|
|
|
|
76
|
validate_integer_nonneg($n); |
|
10141
|
8
|
100
|
|
|
|
49
|
validate_integer_nonneg($B1) if defined $B1; |
|
10142
|
8
|
100
|
|
|
|
37
|
validate_integer_nonneg($B2) if defined $B2; |
|
10143
|
|
|
|
|
|
|
|
|
10144
|
8
|
|
|
|
|
30
|
my @factors; |
|
10145
|
8
|
50
|
|
|
|
47
|
if (!$skipbasic) { |
|
10146
|
8
|
|
|
|
|
48
|
@factors = _basic_factor($n); |
|
10147
|
8
|
50
|
|
|
|
57
|
return @factors if $n < 4; |
|
10148
|
|
|
|
|
|
|
} |
|
10149
|
|
|
|
|
|
|
|
|
10150
|
8
|
|
|
|
|
1518
|
$n = tobigint($n) if OLD_PERL_VERSION && !ref($n) && $n > INTMAX; |
|
10151
|
|
|
|
|
|
|
|
|
10152
|
8
|
100
|
|
|
|
53
|
if (!ref($n)) { |
|
10153
|
|
|
|
|
|
|
# Stage 1 only |
|
10154
|
1
|
|
|
|
|
7
|
my $sqrtn = Msqrtint($n); |
|
10155
|
1
|
50
|
33
|
|
|
34
|
$B1 = $sqrtn if !defined $B1 || $B1 > $sqrtn; |
|
10156
|
1
|
|
|
|
|
5
|
my $sqrtb1 = int(sqrt($B1)); |
|
10157
|
1
|
|
|
|
|
5
|
my($pc_beg, $pc_end) = (2, 6_000-1); |
|
10158
|
1
|
|
|
|
|
4
|
my $pa = 2; |
|
10159
|
|
|
|
|
|
|
|
|
10160
|
1
|
|
|
|
|
15
|
while (1) { |
|
10161
|
1
|
50
|
|
|
|
14
|
$pc_end = $B1 if $pc_end > $B1; |
|
10162
|
1
|
|
|
|
|
2
|
foreach my $q (@{Mprimes($pc_beg, $pc_end)}) { |
|
|
1
|
|
|
|
|
24
|
|
|
10163
|
2
|
|
|
|
|
6
|
my $k = $q; |
|
10164
|
2
|
50
|
|
|
|
19
|
if ($q <= $sqrtb1) { |
|
10165
|
2
|
|
|
|
|
10
|
my $kmin = int($B1 / $q); |
|
10166
|
2
|
|
|
|
|
9
|
while ($k <= $kmin) { $k *= $q; } |
|
|
4
|
|
|
|
|
10
|
|
|
10167
|
|
|
|
|
|
|
} |
|
10168
|
2
|
|
|
|
|
12
|
$pa = Mpowmod($pa, $k, $n); |
|
10169
|
2
|
50
|
|
|
|
115
|
if ($pa == 0) { push @factors, $n; return @factors; } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
10170
|
2
|
|
|
|
|
29
|
my $f = Mgcd($pa-1, $n); |
|
10171
|
2
|
100
|
|
|
|
29
|
return _found_factor($f, $n, "pminus1-64", @factors) if $f != 1; |
|
10172
|
|
|
|
|
|
|
} |
|
10173
|
0
|
0
|
|
|
|
0
|
last if $pc_end >= $B1; |
|
10174
|
0
|
|
|
|
|
0
|
($pc_beg, $pc_end) = ($pc_end+1, $pc_end+18000); |
|
10175
|
|
|
|
|
|
|
} |
|
10176
|
0
|
|
|
|
|
0
|
push @factors, $n; |
|
10177
|
0
|
|
|
|
|
0
|
return @factors; |
|
10178
|
|
|
|
|
|
|
} |
|
10179
|
|
|
|
|
|
|
|
|
10180
|
7
|
100
|
|
|
|
33
|
if (!defined $B1) { |
|
10181
|
2
|
|
|
|
|
22
|
for my $mul (1, 100, 1000, 10_000, 100_000, 1_000_000) { |
|
10182
|
2
|
|
|
|
|
6
|
$B1 = 1000 * $mul; |
|
10183
|
2
|
|
|
|
|
5
|
$B2 = 1*$B1; |
|
10184
|
|
|
|
|
|
|
#warn "Trying p-1 with $B1 / $B2\n"; |
|
10185
|
2
|
|
|
|
|
24
|
my @nf = pminus1_factor($n, $B1, $B2); |
|
10186
|
2
|
50
|
|
|
|
31
|
if (scalar @nf > 1) { |
|
10187
|
2
|
|
|
|
|
7
|
push @factors, @nf; |
|
10188
|
2
|
|
|
|
|
35
|
return @factors; |
|
10189
|
|
|
|
|
|
|
} |
|
10190
|
|
|
|
|
|
|
} |
|
10191
|
0
|
|
|
|
|
0
|
push @factors, $n; |
|
10192
|
0
|
|
|
|
|
0
|
return @factors; |
|
10193
|
|
|
|
|
|
|
} |
|
10194
|
5
|
50
|
|
|
|
23
|
$B2 = 1*$B1 unless defined $B2; |
|
10195
|
|
|
|
|
|
|
|
|
10196
|
5
|
50
|
33
|
|
|
71
|
$n = tobigint($n) if !ref($n) || (defined $_BIGINT && $_BIGINT ne ref($n)); |
|
|
|
|
33
|
|
|
|
|
|
10197
|
|
|
|
|
|
|
# bigints: n, pa, t, savea, [stage2] b, bm |
|
10198
|
|
|
|
|
|
|
|
|
10199
|
5
|
|
|
|
|
19
|
my ($j, $q, $saveq) = (32, 2, 2); |
|
10200
|
5
|
|
|
|
|
41
|
my $pa = tobigint(2); |
|
10201
|
5
|
|
|
|
|
16
|
my $t = tobigint(1); |
|
10202
|
5
|
|
|
|
|
30
|
my $savea = $pa+0; |
|
10203
|
5
|
|
|
|
|
1631
|
my $f = 1; |
|
10204
|
5
|
|
|
|
|
18
|
my($pc_beg, $pc_end) = (2, 2+100_000); |
|
10205
|
|
|
|
|
|
|
|
|
10206
|
5
|
|
|
|
|
10
|
while (1) { |
|
10207
|
5
|
50
|
|
|
|
37
|
$pc_end = $B1 if $pc_end > $B1; |
|
10208
|
5
|
|
|
|
|
13
|
my @bprimes = @{ Mprimes($pc_beg, $pc_end) }; |
|
|
5
|
|
|
|
|
36
|
|
|
10209
|
5
|
|
|
|
|
86
|
foreach my $q (@bprimes) { |
|
10210
|
3220
|
|
|
|
|
38646
|
my($k, $kmin) = ($q, int($B1 / $q)); |
|
10211
|
3220
|
|
|
|
|
10028
|
while ($k <= $kmin) { $k *= $q; } |
|
|
156
|
|
|
|
|
311
|
|
|
10212
|
3220
|
|
|
|
|
10092
|
$t *= $k; # accumulate powers for a |
|
10213
|
3220
|
100
|
|
|
|
1093200
|
if ( ($j++ % 64) == 0) { |
|
10214
|
51
|
50
|
33
|
|
|
276
|
next if $pc_beg > 2 && ($j-1) % 256; |
|
10215
|
51
|
|
|
|
|
347
|
$pa = _bi_powmod($pa, $t, $n); |
|
10216
|
51
|
|
|
|
|
710
|
$t = tobigint(1); |
|
10217
|
51
|
50
|
|
|
|
629
|
if ($pa == 0) { push @factors, $n; return @factors; } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
10218
|
51
|
|
|
|
|
15118
|
$f = Mgcd($pa-1, $n); |
|
10219
|
51
|
100
|
|
|
|
379
|
last if $f == $n; |
|
10220
|
50
|
100
|
|
|
|
11486
|
return _found_factor($f, $n, "pminus1-bigint $B1", @factors) unless $f == 1; |
|
10221
|
49
|
|
|
|
|
190
|
$saveq = $q; |
|
10222
|
49
|
|
|
|
|
270
|
$savea = $pa+0; |
|
10223
|
|
|
|
|
|
|
} |
|
10224
|
|
|
|
|
|
|
} |
|
10225
|
4
|
|
|
|
|
85
|
$q = $bprimes[-1]; |
|
10226
|
4
|
50
|
66
|
|
|
282
|
last if $f != 1 || $pc_end >= $B1; |
|
10227
|
0
|
|
|
|
|
0
|
($pc_beg, $pc_end) = (Madd1int($pc_end), Maddint($pc_end,500_000)); |
|
10228
|
|
|
|
|
|
|
} |
|
10229
|
4
|
|
|
|
|
461
|
$pa = _bi_powmod($pa, $t, $n); |
|
10230
|
4
|
50
|
|
|
|
37
|
if ($pa == 0) { push @factors, $n; return @factors; } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
10231
|
4
|
|
|
|
|
1047
|
$f = Mgcd($pa-1, $n); |
|
10232
|
4
|
100
|
|
|
|
29
|
if ($f == $n) { |
|
10233
|
1
|
|
|
|
|
47
|
$q = $saveq; |
|
10234
|
1
|
|
|
|
|
7
|
$pa = $savea+0; |
|
10235
|
1
|
|
|
|
|
386
|
while ($q <= $B1) { |
|
10236
|
4
|
|
|
|
|
24
|
my ($k, $kmin) = ($q, int($B1 / $q)); |
|
10237
|
4
|
|
|
|
|
16
|
while ($k <= $kmin) { $k *= $q; } |
|
|
18
|
|
|
|
|
33
|
|
|
10238
|
4
|
|
|
|
|
27
|
$pa = _bi_powmod($pa, $k, $n); |
|
10239
|
4
|
|
|
|
|
41
|
$f = Mgcd($pa-1, $n); |
|
10240
|
4
|
50
|
|
|
|
28
|
if ($f == $n) { push @factors, $n; return @factors; } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
10241
|
4
|
100
|
|
|
|
780
|
last if $f != 1; |
|
10242
|
3
|
|
|
|
|
44
|
$q = Mnext_prime($q); |
|
10243
|
|
|
|
|
|
|
} |
|
10244
|
|
|
|
|
|
|
} |
|
10245
|
|
|
|
|
|
|
# STAGE 2 |
|
10246
|
4
|
100
|
66
|
|
|
650
|
if ($f == 1 && $B2 > $B1) { |
|
10247
|
3
|
|
|
|
|
16
|
my $bm = $pa + 0; |
|
10248
|
3
|
|
|
|
|
932
|
my $b = tobigint(1); |
|
10249
|
3
|
|
|
|
|
20
|
my @precomp_bm; |
|
10250
|
3
|
|
|
|
|
16
|
$precomp_bm[0] = ($bm * $bm) % $n; |
|
10251
|
3
|
|
|
|
|
2074
|
$precomp_bm[$_] = ($precomp_bm[$_-1] * $bm * $bm) % $n for 1..19; |
|
10252
|
3
|
|
|
|
|
49787
|
$pa = _bi_powmod($pa, $q, $n); |
|
10253
|
|
|
|
|
|
|
|
|
10254
|
3
|
|
|
|
|
19
|
my $j = 1; |
|
10255
|
3
|
|
|
|
|
9
|
$pc_beg = $q+1; |
|
10256
|
3
|
|
|
|
|
23
|
$pc_end = Maddint($pc_beg, 100_000); |
|
10257
|
3
|
|
|
|
|
16
|
while (1) { |
|
10258
|
3
|
50
|
|
|
|
17
|
$pc_end = $B2 if $pc_end > $B2; |
|
10259
|
3
|
|
|
|
|
10
|
my @bprimes = @{ Mprimes($pc_beg, $pc_end) }; |
|
|
3
|
|
|
|
|
63
|
|
|
10260
|
3
|
|
|
|
|
63
|
foreach my $i (0 .. $#bprimes) { |
|
10261
|
1024
|
|
|
|
|
3095
|
my $diff = $bprimes[$i] - $q; |
|
10262
|
1024
|
|
|
|
|
2030
|
$q = $bprimes[$i]; |
|
10263
|
1024
|
|
|
|
|
2076
|
my $qdiff = ($diff >> 1) - 1; |
|
10264
|
1024
|
100
|
|
|
|
2907
|
$precomp_bm[$qdiff] = _bi_powmod($bm, $diff, $n) |
|
10265
|
|
|
|
|
|
|
unless defined $precomp_bm[$qdiff]; |
|
10266
|
1024
|
|
|
|
|
3610
|
$pa = ($pa * $precomp_bm[$qdiff]) % $n; |
|
10267
|
1024
|
50
|
|
|
|
641206
|
if ($pa == 0) { push @factors, $n; return @factors; } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
10268
|
1024
|
|
|
|
|
256877
|
$b *= ($pa-1); |
|
10269
|
1024
|
100
|
|
|
|
2716385
|
if (($j++ % 128) == 0) { |
|
10270
|
8
|
|
|
|
|
72
|
$b %= $n; |
|
10271
|
8
|
|
|
|
|
71625
|
$f = Mgcd($b, $n); |
|
10272
|
8
|
100
|
|
|
|
50
|
last if $f != 1; |
|
10273
|
|
|
|
|
|
|
} |
|
10274
|
|
|
|
|
|
|
} |
|
10275
|
3
|
50
|
33
|
|
|
91
|
last if $f != 1 || $pc_end >= $B2; |
|
10276
|
0
|
|
|
|
|
0
|
($pc_beg, $pc_end) = (Madd1int($pc_end), Maddint($pc_end,500_000)); |
|
10277
|
|
|
|
|
|
|
} |
|
10278
|
3
|
|
|
|
|
13
|
$f = Mgcd($b, $n); |
|
10279
|
|
|
|
|
|
|
} |
|
10280
|
4
|
|
|
|
|
97
|
return _found_factor($f, $n, "pminus1-bigint $B1/$B2", @factors); |
|
10281
|
|
|
|
|
|
|
} |
|
10282
|
|
|
|
|
|
|
|
|
10283
|
|
|
|
|
|
|
sub cheb_factor { |
|
10284
|
1
|
|
|
1
|
0
|
958
|
my($n, $B1, $initx, $skipbasic) = @_; |
|
10285
|
1
|
|
|
|
|
6
|
validate_integer_nonneg($n); |
|
10286
|
1
|
50
|
|
|
|
4
|
validate_integer_nonneg($B1) if defined $B1; |
|
10287
|
1
|
50
|
|
|
|
21
|
validate_integer_nonneg($initx) if defined $initx; |
|
10288
|
|
|
|
|
|
|
|
|
10289
|
1
|
|
|
|
|
4
|
my @factors; |
|
10290
|
1
|
50
|
|
|
|
5
|
if (!$skipbasic) { |
|
10291
|
1
|
|
|
|
|
5
|
@factors = _basic_factor($n); |
|
10292
|
1
|
50
|
|
|
|
5
|
return @factors if $n < 4; |
|
10293
|
|
|
|
|
|
|
} |
|
10294
|
|
|
|
|
|
|
|
|
10295
|
1
|
50
|
33
|
|
|
7
|
my $x = (defined $initx && $initx > 0) ? $initx : 72; # Arbitrary |
|
10296
|
1
|
50
|
33
|
|
|
23
|
my $B = (defined $B1 && $B1 > 0) ? $B1 : Mmulint(Mpowint(Mlogint($n,2),2),8); |
|
10297
|
1
|
50
|
|
|
|
21
|
$B = Msqrtint($n) if $B > Msqrtint($n); |
|
10298
|
1
|
|
|
|
|
5
|
my $sqrtB = Msqrtint($B); |
|
10299
|
1
|
|
|
|
|
8
|
my $inv = Minvmod(2,$n); |
|
10300
|
1
|
|
|
|
|
4
|
my $f = 1; |
|
10301
|
|
|
|
|
|
|
|
|
10302
|
1
|
|
|
|
|
3
|
my @bprimes = @{ Mprimes(2, $B) }; |
|
|
1
|
|
|
|
|
7
|
|
|
10303
|
1
|
|
|
|
|
21
|
foreach my $p (@bprimes) { |
|
10304
|
2
|
|
|
|
|
16
|
my $xx = Maddmod($x,$x,$n); |
|
10305
|
2
|
50
|
|
|
|
10
|
if ($p <= $sqrtB) { |
|
10306
|
2
|
|
|
|
|
21
|
my $plgp = Mpowint($p, Mlogint($B, $p)); |
|
10307
|
2
|
|
|
|
|
41
|
$x = Mmulmod(Math::Prime::Util::lucasvmod($xx, 1, $plgp, $n), $inv, $n); |
|
10308
|
|
|
|
|
|
|
} else { |
|
10309
|
0
|
|
|
|
|
0
|
$x = Mmulmod(Math::Prime::Util::lucasvmod($xx, 1, $p, $n), $inv, $n); |
|
10310
|
|
|
|
|
|
|
} |
|
10311
|
2
|
|
|
|
|
15
|
$f = Mgcd($x-1, $n); |
|
10312
|
2
|
100
|
|
|
|
11
|
last if $f != 1; |
|
10313
|
|
|
|
|
|
|
} |
|
10314
|
1
|
|
|
|
|
8
|
return _found_factor($f, $n, "cheb", @factors); |
|
10315
|
|
|
|
|
|
|
} |
|
10316
|
|
|
|
|
|
|
|
|
10317
|
|
|
|
|
|
|
sub holf_factor { |
|
10318
|
3
|
|
|
3
|
0
|
1120
|
my($n, $rounds, $startrounds) = @_; |
|
10319
|
3
|
|
|
|
|
29
|
validate_integer_nonneg($n); |
|
10320
|
3
|
50
|
|
|
|
31
|
if (defined $rounds) { validate_integer_nonneg($rounds); } |
|
|
0
|
|
|
|
|
0
|
|
|
10321
|
3
|
|
|
|
|
9
|
else { $rounds = 64*1024*1024; } |
|
10322
|
3
|
50
|
33
|
|
|
22
|
$startrounds = 1 if (!defined $startrounds) || ($startrounds < 1); |
|
10323
|
|
|
|
|
|
|
|
|
10324
|
3
|
|
|
|
|
19
|
my @factors = _basic_factor($n); |
|
10325
|
3
|
50
|
|
|
|
21
|
return @factors if $n < 4; |
|
10326
|
|
|
|
|
|
|
|
|
10327
|
3
|
100
|
|
|
|
1673
|
if (ref($n)) { |
|
10328
|
2
|
|
|
|
|
11
|
for my $i ($startrounds .. $rounds) { |
|
10329
|
2
|
|
|
|
|
16
|
my $ni = Mmulint($n,$i); |
|
10330
|
2
|
|
|
|
|
600
|
my $s = Msqrtint($ni); |
|
10331
|
2
|
50
|
|
|
|
28
|
if (Mmulint($s,$s) == $ni) { |
|
10332
|
|
|
|
|
|
|
# s^2 = n*i, so m = s^2 mod n = 0. Hence f = GCD(n, s) = GCD(n, n*i) |
|
10333
|
0
|
|
|
|
|
0
|
my $f = Mgcd($ni, $n); |
|
10334
|
0
|
|
|
|
|
0
|
return _found_factor($f, $n, "HOLF", @factors); |
|
10335
|
|
|
|
|
|
|
} |
|
10336
|
2
|
|
|
|
|
701
|
$s = Madd1int($s); |
|
10337
|
2
|
|
|
|
|
11
|
my $m = Msubint(Mmulint($s,$s),$ni); |
|
10338
|
2
|
50
|
|
|
|
144
|
if (Mis_power($m, 2, \my $f)) { |
|
10339
|
2
|
50
|
|
|
|
21
|
$f = Mgcd($n, $s > $f ? $s-$f : $f-$s); |
|
10340
|
2
|
|
|
|
|
17
|
return _found_factor($f, $n, "HOLF ($i rounds)", @factors); |
|
10341
|
|
|
|
|
|
|
} |
|
10342
|
|
|
|
|
|
|
} |
|
10343
|
|
|
|
|
|
|
} else { |
|
10344
|
1
|
|
|
|
|
8
|
for my $i ($startrounds .. $rounds) { |
|
10345
|
3
|
|
|
|
|
10
|
my $s = int(sqrt($n * $i)); |
|
10346
|
3
|
50
|
|
|
|
13
|
$s++ if ($s * $s) != ($n * $i); |
|
10347
|
3
|
50
|
|
|
|
10
|
my $m = ($s < MPU_HALFWORD) ? ($s*$s) % $n : _mulmod($s, $s, $n); |
|
10348
|
|
|
|
|
|
|
# Check for perfect square |
|
10349
|
3
|
|
|
|
|
22
|
my $mc = $m & 31; |
|
10350
|
3
|
50
|
33
|
|
|
50
|
next unless $mc==0||$mc==1||$mc==4||$mc==9||$mc==16||$mc==17||$mc==25; |
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
10351
|
1
|
|
|
|
|
4
|
my $f = int(sqrt($m)); |
|
10352
|
1
|
50
|
|
|
|
5
|
next unless $f*$f == $m; |
|
10353
|
1
|
|
|
|
|
32
|
$f = _gcd_ui($s - $f, $n); |
|
10354
|
1
|
|
|
|
|
9
|
return _found_factor($f, $n, "HOLF ($i rounds)", @factors); |
|
10355
|
|
|
|
|
|
|
} |
|
10356
|
|
|
|
|
|
|
} |
|
10357
|
0
|
|
|
|
|
0
|
push @factors, $n; |
|
10358
|
0
|
|
|
|
|
0
|
@factors; |
|
10359
|
|
|
|
|
|
|
} |
|
10360
|
|
|
|
|
|
|
|
|
10361
|
|
|
|
|
|
|
sub fermat_factor { |
|
10362
|
2
|
|
|
2
|
0
|
3529
|
my($n, $rounds) = @_; |
|
10363
|
2
|
|
|
|
|
21
|
validate_integer_nonneg($n); |
|
10364
|
2
|
50
|
|
|
|
9
|
if (defined $rounds) { validate_integer_nonneg($rounds); } |
|
|
0
|
|
|
|
|
0
|
|
|
10365
|
2
|
|
|
|
|
17
|
else { $rounds = 64*1024*1024; } |
|
10366
|
|
|
|
|
|
|
|
|
10367
|
2
|
|
|
|
|
20
|
my @factors = _basic_factor($n); |
|
10368
|
2
|
50
|
|
|
|
25
|
return @factors if $n < 4; |
|
10369
|
|
|
|
|
|
|
|
|
10370
|
2
|
100
|
|
|
|
243
|
if (ref($n)) { |
|
10371
|
1
|
|
|
|
|
25
|
my $pa = Msqrtint($n); |
|
10372
|
1
|
50
|
|
|
|
10
|
return _found_factor($pa, $n, "Fermat", @factors) if Mmulint($pa,$pa) == $n; |
|
10373
|
1
|
|
|
|
|
341
|
$pa = Madd1int($pa); |
|
10374
|
1
|
|
|
|
|
5
|
my $b2 = Msubint(Mmulint($pa,$pa),$n); |
|
10375
|
1
|
|
|
|
|
56
|
my $lasta = Maddint($pa,$rounds); |
|
10376
|
1
|
|
|
|
|
7
|
while ($pa <= $lasta) { |
|
10377
|
1
|
50
|
|
|
|
26
|
if (Mis_power($b2, 2, \my $s)) { |
|
10378
|
1
|
|
|
|
|
19
|
my $i = Msubint($pa,($lasta-$rounds))+1; |
|
10379
|
1
|
|
|
|
|
4
|
return _found_factor(Msubint($pa,$s), $n, "Fermat ($i rounds)", @factors); |
|
10380
|
|
|
|
|
|
|
} |
|
10381
|
0
|
|
|
|
|
0
|
$pa = Madd1int($pa); |
|
10382
|
0
|
|
|
|
|
0
|
$b2 = Msubint(Mmulint($pa,$pa),$n); |
|
10383
|
|
|
|
|
|
|
} |
|
10384
|
|
|
|
|
|
|
} else { |
|
10385
|
1
|
|
|
|
|
5
|
my $pa = int(sqrt($n)); |
|
10386
|
1
|
50
|
|
|
|
6
|
return _found_factor($pa, $n, "Fermat", @factors) if $pa*$pa == $n; |
|
10387
|
1
|
|
|
|
|
2
|
$pa++; |
|
10388
|
1
|
|
|
|
|
4
|
my $b2 = $pa*$pa - $n; |
|
10389
|
1
|
|
|
|
|
5
|
my $lasta = $pa + $rounds; |
|
10390
|
1
|
|
|
|
|
7
|
while ($pa <= $lasta) { |
|
10391
|
2
|
|
|
|
|
7
|
my $mc = $b2 & 31; |
|
10392
|
2
|
100
|
33
|
|
|
72
|
if ($mc==0||$mc==1||$mc==4||$mc==9||$mc==16||$mc==17||$mc==25) { |
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
10393
|
1
|
|
|
|
|
5
|
my $s = int(sqrt($b2)); |
|
10394
|
1
|
50
|
|
|
|
7
|
if ($s*$s == $b2) { |
|
10395
|
1
|
|
|
|
|
7
|
my $i = $pa-($lasta-$rounds)+1; |
|
10396
|
1
|
|
|
|
|
21
|
return _found_factor($pa - $s, $n, "Fermat ($i rounds)", @factors); |
|
10397
|
|
|
|
|
|
|
} |
|
10398
|
|
|
|
|
|
|
} |
|
10399
|
1
|
|
|
|
|
3
|
$pa++; |
|
10400
|
1
|
|
|
|
|
5
|
$b2 = $pa*$pa-$n; |
|
10401
|
|
|
|
|
|
|
} |
|
10402
|
|
|
|
|
|
|
} |
|
10403
|
0
|
|
|
|
|
0
|
push @factors, $n; |
|
10404
|
0
|
|
|
|
|
0
|
@factors; |
|
10405
|
|
|
|
|
|
|
} |
|
10406
|
|
|
|
|
|
|
|
|
10407
|
|
|
|
|
|
|
|
|
10408
|
|
|
|
|
|
|
sub ecm_factor { |
|
10409
|
5
|
|
|
5
|
0
|
4505
|
my($n, $B1, $B2, $ncurves) = @_; |
|
10410
|
5
|
|
|
|
|
72
|
validate_integer_nonneg($n); |
|
10411
|
|
|
|
|
|
|
|
|
10412
|
5
|
|
|
|
|
32
|
my @factors = _basic_factor($n); |
|
10413
|
5
|
50
|
|
|
|
49
|
return @factors if $n < 4; |
|
10414
|
|
|
|
|
|
|
|
|
10415
|
5
|
50
|
|
|
|
1027
|
if ($Math::Prime::Util::_GMPfunc{"ecm_factor"}) { |
|
10416
|
0
|
0
|
|
|
|
0
|
$B1 = 0 if !defined $B1; |
|
10417
|
0
|
0
|
|
|
|
0
|
$ncurves = 0 if !defined $ncurves; |
|
10418
|
0
|
|
|
|
|
0
|
my @ef = Math::Prime::Util::GMP::ecm_factor($n, $B1, $ncurves); |
|
10419
|
0
|
0
|
|
|
|
0
|
if (@ef > 1) { |
|
10420
|
0
|
|
|
|
|
0
|
my $ecmfac = reftyped($n, $ef[-1]); |
|
10421
|
0
|
|
|
|
|
0
|
return _found_factor($ecmfac, $n, "ECM (GMP) B1=$B1 curves $ncurves", @factors); |
|
10422
|
|
|
|
|
|
|
} |
|
10423
|
0
|
|
|
|
|
0
|
push @factors, $n; |
|
10424
|
0
|
|
|
|
|
0
|
return @factors; |
|
10425
|
|
|
|
|
|
|
} |
|
10426
|
|
|
|
|
|
|
|
|
10427
|
5
|
|
|
|
|
24
|
$n = tobigint($n) if OLD_PERL_VERSION && !ref($n) && $n > INTMAX; |
|
10428
|
|
|
|
|
|
|
|
|
10429
|
5
|
100
|
|
|
|
29
|
$ncurves = 10 unless defined $ncurves; |
|
10430
|
|
|
|
|
|
|
|
|
10431
|
5
|
100
|
|
|
|
23
|
if (!defined $B1) { |
|
10432
|
1
|
|
|
|
|
6
|
for my $mul (1, 10, 100, 1000, 10_000, 100_000, 1_000_000) { |
|
10433
|
1
|
|
|
|
|
5
|
$B1 = 100 * $mul; |
|
10434
|
1
|
|
|
|
|
5
|
$B2 = 10*$B1; |
|
10435
|
|
|
|
|
|
|
#warn "Trying ecm with $B1 / $B2\n"; |
|
10436
|
1
|
|
|
|
|
48
|
my @nf = ecm_factor($n, $B1, $B2, $ncurves); |
|
10437
|
1
|
50
|
|
|
|
8
|
if (scalar @nf > 1) { |
|
10438
|
1
|
|
|
|
|
5
|
push @factors, @nf; |
|
10439
|
1
|
|
|
|
|
14
|
return @factors; |
|
10440
|
|
|
|
|
|
|
} |
|
10441
|
|
|
|
|
|
|
} |
|
10442
|
0
|
|
|
|
|
0
|
push @factors, $n; |
|
10443
|
0
|
|
|
|
|
0
|
return @factors; |
|
10444
|
|
|
|
|
|
|
} |
|
10445
|
|
|
|
|
|
|
|
|
10446
|
4
|
50
|
|
|
|
17
|
$B2 = 10*$B1 unless defined $B2; |
|
10447
|
4
|
|
|
|
|
18
|
my $sqrt_b1 = int(sqrt($B1)+1); |
|
10448
|
|
|
|
|
|
|
|
|
10449
|
|
|
|
|
|
|
# Affine code. About 3x slower than the projective, and no stage 2. |
|
10450
|
|
|
|
|
|
|
# |
|
10451
|
|
|
|
|
|
|
#if (!defined $Math::Prime::Util::ECAffinePoint::VERSION) { |
|
10452
|
|
|
|
|
|
|
# eval { require Math::Prime::Util::ECAffinePoint; 1; } |
|
10453
|
|
|
|
|
|
|
# or do { croak "Cannot load Math::Prime::Util::ECAffinePoint"; }; |
|
10454
|
|
|
|
|
|
|
#} |
|
10455
|
|
|
|
|
|
|
#my @bprimes = @{ primes(2, $B1) }; |
|
10456
|
|
|
|
|
|
|
#my $irandf = Math::Prime::Util::_get_rand_func(); |
|
10457
|
|
|
|
|
|
|
#foreach my $curve (1 .. $ncurves) { |
|
10458
|
|
|
|
|
|
|
# my $a = $irandf->($n-1); |
|
10459
|
|
|
|
|
|
|
# my $b = 1; |
|
10460
|
|
|
|
|
|
|
# my $ECP = Math::Prime::Util::ECAffinePoint->new($a, $b, $n, 0, 1); |
|
10461
|
|
|
|
|
|
|
# foreach my $q (@bprimes) { |
|
10462
|
|
|
|
|
|
|
# my $k = $q; |
|
10463
|
|
|
|
|
|
|
# if ($k < $sqrt_b1) { |
|
10464
|
|
|
|
|
|
|
# my $kmin = int($B1 / $q); |
|
10465
|
|
|
|
|
|
|
# while ($k <= $kmin) { $k *= $q; } |
|
10466
|
|
|
|
|
|
|
# } |
|
10467
|
|
|
|
|
|
|
# $ECP->mul($k); |
|
10468
|
|
|
|
|
|
|
# my $f = $ECP->f; |
|
10469
|
|
|
|
|
|
|
# if ($f != 1) { |
|
10470
|
|
|
|
|
|
|
# last if $f == $n; |
|
10471
|
|
|
|
|
|
|
# warn "ECM found factors with B1 = $B1 in curve $curve\n"; |
|
10472
|
|
|
|
|
|
|
# return _found_factor($f, $n, "ECM B1=$B1 curve $curve", @factors); |
|
10473
|
|
|
|
|
|
|
# } |
|
10474
|
|
|
|
|
|
|
# last if $ECP->is_infinity; |
|
10475
|
|
|
|
|
|
|
# } |
|
10476
|
|
|
|
|
|
|
#} |
|
10477
|
|
|
|
|
|
|
|
|
10478
|
4
|
|
|
|
|
1910
|
require Math::Prime::Util::ECProjectivePoint; |
|
10479
|
4
|
|
|
|
|
1111
|
require Math::Prime::Util::RandomPrimes; |
|
10480
|
|
|
|
|
|
|
|
|
10481
|
|
|
|
|
|
|
# With multiple curves, it's better to get all the primes at once. |
|
10482
|
|
|
|
|
|
|
# The downside is this can kill memory with a very large B1. |
|
10483
|
4
|
|
|
|
|
21
|
my @bprimes = @{ Mprimes(3, $B1) }; |
|
|
4
|
|
|
|
|
37
|
|
|
10484
|
4
|
|
|
|
|
22
|
foreach my $q (@bprimes) { |
|
10485
|
11
|
100
|
|
|
|
41
|
last if $q > $sqrt_b1; |
|
10486
|
7
|
|
|
|
|
25
|
my($k,$kmin) = ($q, int($B1/$q)); |
|
10487
|
7
|
|
|
|
|
32
|
while ($k <= $kmin) { $k *= $q; } |
|
|
6
|
|
|
|
|
12
|
|
|
10488
|
7
|
|
|
|
|
11
|
$q = $k; |
|
10489
|
|
|
|
|
|
|
} |
|
10490
|
4
|
50
|
|
|
|
26
|
my @b2primes = ($B2 > $B1) ? @{Mprimes($B1+1, $B2)} : (); |
|
|
4
|
|
|
|
|
24
|
|
|
10491
|
|
|
|
|
|
|
|
|
10492
|
4
|
|
|
|
|
171
|
foreach my $curve (1 .. $ncurves) { |
|
10493
|
4
|
|
|
|
|
60
|
my $sigma = tobigint(Murandomm($n-6)) + 6; |
|
10494
|
|
|
|
|
|
|
|
|
10495
|
4
|
|
|
|
|
1578
|
my ($u, $v) = ( ($sigma*$sigma - 5) % $n, (4 * $sigma) % $n ); |
|
10496
|
4
|
|
|
|
|
6476
|
my ($x, $z) = ( ($u*$u*$u) % $n, ($v*$v*$v) % $n ); |
|
10497
|
4
|
|
|
|
|
6672
|
my $cb = (4 * $x * $v) % $n; |
|
10498
|
4
|
|
|
|
|
3795
|
my $ca = ( (($v-$u)**3) * (3*$u + $v) ) % $n; |
|
10499
|
|
|
|
|
|
|
|
|
10500
|
4
|
|
|
|
|
9454
|
my $f = Mgcd( $cb, $n ); |
|
10501
|
4
|
50
|
|
|
|
34
|
$f = Mgcd( $z, $n ) if $f == 1; |
|
10502
|
4
|
50
|
|
|
|
41
|
next if $f == $n; |
|
10503
|
4
|
50
|
|
|
|
673
|
return _found_factor($f,$n, "ECM B1=$B1 curve $curve", @factors) if $f != 1; |
|
10504
|
4
|
|
|
|
|
42
|
$u = Minvmod($cb,$n); |
|
10505
|
4
|
|
|
|
|
30
|
$ca = (($ca*$u) - 2) % $n; |
|
10506
|
|
|
|
|
|
|
|
|
10507
|
4
|
|
|
|
|
4305
|
my $ECP = Math::Prime::Util::ECProjectivePoint->new($ca, $n, $x, $z); |
|
10508
|
4
|
|
|
|
|
16
|
my $fm = $n-$n+1; |
|
10509
|
4
|
|
|
|
|
1724
|
my $i = 15; |
|
10510
|
|
|
|
|
|
|
|
|
10511
|
4
|
|
|
|
|
25
|
for (my $q = 2; $q < $B1; $q *= 2) { $ECP->double(); } |
|
|
13
|
|
|
|
|
71
|
|
|
10512
|
4
|
|
|
|
|
19
|
foreach my $k (@bprimes) { |
|
10513
|
25
|
|
|
|
|
161
|
$ECP->mul($k); |
|
10514
|
25
|
|
|
|
|
225
|
$fm = ($fm * $ECP->x() ) % $n; |
|
10515
|
25
|
100
|
|
|
|
12710
|
if ($i++ % 32 == 0) { |
|
10516
|
1
|
|
|
|
|
12
|
$f = Mgcd($fm, $n); |
|
10517
|
1
|
50
|
|
|
|
9
|
last if $f != 1; |
|
10518
|
|
|
|
|
|
|
} |
|
10519
|
|
|
|
|
|
|
} |
|
10520
|
4
|
|
|
|
|
36
|
$f = Mgcd($fm, $n); |
|
10521
|
4
|
50
|
|
|
|
25
|
next if $f == $n; |
|
10522
|
|
|
|
|
|
|
|
|
10523
|
4
|
100
|
66
|
|
|
762
|
if ($f == 1 && $B2 > $B1) { # BEGIN STAGE 2 |
|
10524
|
3
|
100
|
|
|
|
44
|
my $D = Msqrtint($B2 >> 1); $D++ if $D % 2; |
|
|
3
|
|
|
|
|
16
|
|
|
10525
|
3
|
|
|
|
|
13
|
my $one = $n - $n + 1; |
|
10526
|
3
|
|
|
|
|
1217
|
my $g = $one; |
|
10527
|
|
|
|
|
|
|
|
|
10528
|
3
|
|
|
|
|
43
|
my $S2P = $ECP->copy->normalize; |
|
10529
|
3
|
|
|
|
|
21
|
$f = $S2P->f; |
|
10530
|
3
|
50
|
|
|
|
16
|
if ($f != 1) { |
|
10531
|
0
|
0
|
|
|
|
0
|
next if $f == $n; |
|
10532
|
|
|
|
|
|
|
#warn "ECM S2 normalize f=$f\n" if $f != 1; |
|
10533
|
0
|
|
|
|
|
0
|
return _found_factor($f, $n, "ECM S2 B1=$B1 curve $curve"); |
|
10534
|
|
|
|
|
|
|
} |
|
10535
|
3
|
|
|
|
|
1167
|
my $S2x = $S2P->x; |
|
10536
|
3
|
|
|
|
|
23
|
my $S2d = $S2P->d; |
|
10537
|
3
|
|
|
|
|
29
|
my @nqx = ($n-$n, $S2x); |
|
10538
|
|
|
|
|
|
|
|
|
10539
|
3
|
|
|
|
|
437
|
foreach my $i (2 .. 2*$D) { |
|
10540
|
156
|
|
|
|
|
108913
|
my($x2, $z2); |
|
10541
|
156
|
100
|
|
|
|
653
|
if ($i % 2) { |
|
10542
|
77
|
|
|
|
|
682
|
($x2, $z2) = Math::Prime::Util::ECProjectivePoint::_addx($nqx[($i-1)/2], $nqx[($i+1)/2], $S2x, $n); |
|
10543
|
|
|
|
|
|
|
} else { |
|
10544
|
79
|
|
|
|
|
618
|
($x2, $z2) = Math::Prime::Util::ECProjectivePoint::_double($nqx[$i/2], $one, $n, $S2d); |
|
10545
|
|
|
|
|
|
|
} |
|
10546
|
156
|
|
|
|
|
89528
|
$nqx[$i] = $x2; |
|
10547
|
|
|
|
|
|
|
#($f, $u, undef) = _extended_gcd($z2, $n); |
|
10548
|
156
|
|
|
|
|
1012
|
$f = Mgcd( $z2, $n ); |
|
10549
|
156
|
100
|
|
|
|
838
|
last if $f != 1; |
|
10550
|
155
|
|
|
|
|
785
|
$u = Minvmod($z2,$n); |
|
10551
|
155
|
|
|
|
|
933
|
$nqx[$i] = ($x2 * $u) % $n; |
|
10552
|
|
|
|
|
|
|
} |
|
10553
|
3
|
100
|
|
|
|
896
|
if ($f != 1) { |
|
10554
|
1
|
50
|
|
|
|
6
|
next if $f == $n; |
|
10555
|
|
|
|
|
|
|
#warn "ECM S2 1: B1 $B1 B2 $B2 curve $curve f=$f\n"; |
|
10556
|
1
|
|
|
|
|
8
|
return _found_factor($f, $n, "ECM S2 B1=$B1 curve $curve", @factors); |
|
10557
|
|
|
|
|
|
|
} |
|
10558
|
|
|
|
|
|
|
|
|
10559
|
2
|
|
|
|
|
8
|
$x = $nqx[2*$D-1]; |
|
10560
|
2
|
|
|
|
|
10
|
my $m = 1; |
|
10561
|
2
|
|
|
|
|
17
|
while ($m < ($B2+$D)) { |
|
10562
|
37
|
100
|
|
|
|
135
|
if ($m != 1) { |
|
10563
|
35
|
|
|
|
|
67
|
my $oldx = $S2x; |
|
10564
|
35
|
|
|
|
|
266
|
my ($x1, $z1) = Math::Prime::Util::ECProjectivePoint::_addx($nqx[2*$D], $S2x, $x, $n); |
|
10565
|
35
|
|
|
|
|
38072
|
$f = Mgcd( $z1, $n ); |
|
10566
|
35
|
50
|
|
|
|
183
|
last if $f != 1; |
|
10567
|
35
|
|
|
|
|
130
|
$u = $z1->copy->bmodinv($n); |
|
10568
|
35
|
|
|
|
|
185840
|
$S2x = ($x1 * $u) % $n; |
|
10569
|
35
|
|
|
|
|
20347
|
$x = $oldx; |
|
10570
|
35
|
50
|
|
|
|
288
|
last if $f != 1; |
|
10571
|
|
|
|
|
|
|
} |
|
10572
|
37
|
50
|
|
|
|
211
|
if ($m+$D > $B1) { |
|
10573
|
37
|
100
|
|
|
|
235
|
my @p = grep { $_ >= $m-$D && $_ <= $m+$D } @b2primes; |
|
|
8652
|
|
|
|
|
21438
|
|
|
10574
|
37
|
|
|
|
|
101
|
foreach my $i (@p) { |
|
10575
|
194
|
100
|
|
|
|
119997
|
last if $i >= $m; |
|
10576
|
157
|
|
|
|
|
713
|
$g = ($g * ($S2x - $nqx[$m+$D-$i])) % $n; |
|
10577
|
|
|
|
|
|
|
} |
|
10578
|
37
|
|
|
|
|
95
|
foreach my $i (@p) { |
|
10579
|
335
|
100
|
|
|
|
57090
|
next unless $i > $m; |
|
10580
|
166
|
100
|
100
|
|
|
766
|
next if $i > ($m+$m) || is_prime($m+$m-$i); |
|
10581
|
101
|
|
|
|
|
475
|
$g = ($g * ($S2x - $nqx[$i-$m])) % $n; |
|
10582
|
|
|
|
|
|
|
} |
|
10583
|
37
|
|
|
|
|
19156
|
$f = Mgcd($g, $n); |
|
10584
|
|
|
|
|
|
|
#warn "ECM S2 3: found $f in stage 2\n" if $f != 1; |
|
10585
|
37
|
100
|
|
|
|
336
|
last if $f != 1; |
|
10586
|
|
|
|
|
|
|
} |
|
10587
|
35
|
|
|
|
|
193
|
$m += 2*$D; |
|
10588
|
|
|
|
|
|
|
} |
|
10589
|
|
|
|
|
|
|
} # END STAGE 2 |
|
10590
|
|
|
|
|
|
|
|
|
10591
|
3
|
50
|
|
|
|
35
|
next if $f == $n; |
|
10592
|
3
|
50
|
|
|
|
676
|
if ($f != 1) { |
|
10593
|
|
|
|
|
|
|
#warn "ECM found factors with B1 = $B1 in curve $curve\n"; |
|
10594
|
3
|
|
|
|
|
1113
|
return _found_factor($f, $n, "ECM B1=$B1 curve $curve", @factors); |
|
10595
|
|
|
|
|
|
|
} |
|
10596
|
|
|
|
|
|
|
# end of curve loop |
|
10597
|
|
|
|
|
|
|
} |
|
10598
|
0
|
|
|
|
|
0
|
push @factors, $n; |
|
10599
|
0
|
|
|
|
|
0
|
@factors; |
|
10600
|
|
|
|
|
|
|
} |
|
10601
|
|
|
|
|
|
|
|
|
10602
|
|
|
|
|
|
|
sub divisors { |
|
10603
|
40
|
|
|
40
|
0
|
4988
|
my($n,$k) = @_; |
|
10604
|
40
|
|
|
|
|
220
|
validate_integer_nonneg($n); |
|
10605
|
40
|
100
|
|
|
|
520
|
if (defined $k) { |
|
10606
|
1
|
|
|
|
|
5
|
validate_integer_nonneg($k); |
|
10607
|
1
|
50
|
|
|
|
3
|
$k = $n if $k > $n; |
|
10608
|
|
|
|
|
|
|
} else { |
|
10609
|
39
|
|
|
|
|
94
|
$k = $n; |
|
10610
|
|
|
|
|
|
|
} |
|
10611
|
|
|
|
|
|
|
|
|
10612
|
40
|
50
|
|
|
|
362
|
if (!wantarray) { |
|
10613
|
|
|
|
|
|
|
# In scalar context, returns sigma_0(n). Very fast. |
|
10614
|
0
|
0
|
|
|
|
0
|
return Mdivisor_sum($n,0) if $k >= $n; |
|
10615
|
0
|
|
|
|
|
0
|
my @div = divisors($n,$k); |
|
10616
|
0
|
|
|
|
|
0
|
return scalar(@div); |
|
10617
|
|
|
|
|
|
|
} |
|
10618
|
|
|
|
|
|
|
|
|
10619
|
40
|
50
|
33
|
|
|
271
|
return () if $n == 0 || $k == 0; |
|
10620
|
40
|
100
|
66
|
|
|
3774
|
return (1) if $n == 1 || $k == 1; |
|
10621
|
|
|
|
|
|
|
|
|
10622
|
36
|
|
|
|
|
2987
|
my @d; |
|
10623
|
36
|
50
|
|
|
|
157
|
if ($Math::Prime::Util::_GMPfunc{"divisors"}) { |
|
10624
|
|
|
|
|
|
|
# This trips an erroneous compile time error without the eval. |
|
10625
|
0
|
0
|
0
|
|
|
0
|
if ($k < $n && $Math::Prime::Util::GMP::VERSION >= 0.53) { |
|
10626
|
0
|
|
|
|
|
0
|
eval "\@d = Math::Prime::Util::GMP::divisors(\"$n\",\"$k\"); "; ## no critic qw(ProhibitStringyEval) |
|
10627
|
|
|
|
|
|
|
} else { |
|
10628
|
0
|
|
|
|
|
0
|
eval "\@d = Math::Prime::Util::GMP::divisors(\"$n\"); "; ## no critic qw(ProhibitStringyEval) |
|
10629
|
0
|
0
|
|
|
|
0
|
@d = grep { $_ <= $k } @d if $k < $n; |
|
|
0
|
|
|
|
|
0
|
|
|
10630
|
|
|
|
|
|
|
} |
|
10631
|
0
|
|
|
|
|
0
|
return maybetobigintall(@d); |
|
10632
|
|
|
|
|
|
|
} |
|
10633
|
|
|
|
|
|
|
|
|
10634
|
36
|
|
|
|
|
195
|
my @pe = Mfactor_exp($n); |
|
10635
|
36
|
100
|
100
|
|
|
350
|
return (1,$n) if @pe == 1 && $pe[0]->[1] == 1 && $n <= $k; |
|
|
|
|
66
|
|
|
|
|
|
10636
|
|
|
|
|
|
|
|
|
10637
|
31
|
|
|
|
|
97
|
@d = (1); |
|
10638
|
31
|
|
|
|
|
83
|
for my $pe (@pe) { |
|
10639
|
91
|
|
|
|
|
291
|
my($p,$e) = @$pe; |
|
10640
|
91
|
100
|
|
|
|
290
|
last if $p > $k; |
|
10641
|
90
|
|
|
|
|
2900
|
my @t; |
|
10642
|
90
|
|
|
|
|
189
|
push @d, @t = map { Mmulint($_,$p) } @d; # multiply through |
|
|
404
|
|
|
|
|
9063
|
|
|
10643
|
90
|
|
|
|
|
1679
|
push @d, @t = map { Mmulint($_,$p) } @t for 2 .. $e; # repeat |
|
|
19
|
|
|
|
|
49
|
|
|
10644
|
|
|
|
|
|
|
} |
|
10645
|
|
|
|
|
|
|
|
|
10646
|
31
|
100
|
|
|
|
123
|
@d = grep { $_ <= $k } @d if $k < $n; |
|
|
96
|
|
|
|
|
268
|
|
|
10647
|
31
|
|
|
|
|
527
|
Mvecsort(@d); |
|
10648
|
|
|
|
|
|
|
} |
|
10649
|
|
|
|
|
|
|
|
|
10650
|
|
|
|
|
|
|
|
|
10651
|
|
|
|
|
|
|
################################################################################ |
|
10652
|
|
|
|
|
|
|
|
|
10653
|
|
|
|
|
|
|
|
|
10654
|
|
|
|
|
|
|
sub _chebyshev_theta { |
|
10655
|
2
|
|
|
2
|
|
9
|
my($n,$low) = @_; |
|
10656
|
2
|
|
|
|
|
7
|
my($sum,$high) = (0.0, 0); |
|
10657
|
2
|
|
|
|
|
9
|
while ($low <= $n) { |
|
10658
|
2
|
|
|
|
|
6
|
$high = $low + 1e6; |
|
10659
|
2
|
50
|
|
|
|
20
|
$high = $n if $high > $n; |
|
10660
|
2
|
|
|
|
|
5
|
$sum += log($_) for @{Mprimes($low,$high)}; |
|
|
2
|
|
|
|
|
16
|
|
|
10661
|
2
|
|
|
|
|
54
|
$low = $high+1; |
|
10662
|
|
|
|
|
|
|
} |
|
10663
|
2
|
|
|
|
|
19
|
$sum; |
|
10664
|
|
|
|
|
|
|
} |
|
10665
|
|
|
|
|
|
|
sub chebyshev_theta { |
|
10666
|
1
|
|
|
1
|
0
|
4
|
my($n) = @_; |
|
10667
|
1
|
|
|
|
|
6
|
validate_integer_nonneg($n); |
|
10668
|
1
|
|
|
|
|
6
|
_chebyshev_theta($n,2); |
|
10669
|
|
|
|
|
|
|
} |
|
10670
|
|
|
|
|
|
|
|
|
10671
|
|
|
|
|
|
|
sub chebyshev_psi { |
|
10672
|
1
|
|
|
1
|
0
|
5
|
my($n) = @_; |
|
10673
|
1
|
|
|
|
|
9
|
validate_integer_nonneg($n); |
|
10674
|
1
|
50
|
|
|
|
6
|
return 0 if $n <= 1; |
|
10675
|
1
|
|
|
|
|
10
|
my ($sum, $logn, $sqrtn) = (0.0, log($n), Msqrtint($n)); |
|
10676
|
|
|
|
|
|
|
|
|
10677
|
|
|
|
|
|
|
# Sum the log of prime powers first |
|
10678
|
1
|
|
|
|
|
4
|
for my $p (@{Mprimes($sqrtn)}) { |
|
|
1
|
|
|
|
|
7
|
|
|
10679
|
22
|
|
|
|
|
47
|
my $logp = log($p); |
|
10680
|
22
|
|
|
|
|
49
|
$sum += $logp * int($logn/$logp+1e-15); |
|
10681
|
|
|
|
|
|
|
} |
|
10682
|
|
|
|
|
|
|
# The rest all have exponent 1: add them in using the segmenting theta code |
|
10683
|
1
|
|
|
|
|
9
|
$sum += _chebyshev_theta($n, $sqrtn+1); |
|
10684
|
|
|
|
|
|
|
|
|
10685
|
1
|
|
|
|
|
41
|
$sum; |
|
10686
|
|
|
|
|
|
|
} |
|
10687
|
|
|
|
|
|
|
|
|
10688
|
|
|
|
|
|
|
sub hclassno { |
|
10689
|
14
|
|
|
14
|
0
|
37
|
my($n) = @_; |
|
10690
|
14
|
|
|
|
|
76
|
validate_integer($n); |
|
10691
|
|
|
|
|
|
|
|
|
10692
|
14
|
50
|
|
|
|
36
|
return -1 if $n == 0; |
|
10693
|
14
|
50
|
33
|
|
|
123
|
return 0 if $n < 0 || ($n % 4) == 1 || ($n % 4) == 2; |
|
|
|
|
33
|
|
|
|
|
|
10694
|
14
|
100
|
|
|
|
74
|
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; |
|
10695
|
|
|
|
|
|
|
|
|
10696
|
6
|
|
|
|
|
29
|
my ($h, $square, $b, $b2) = (0, 0, $n & 1, ($n+1) >> 2); |
|
10697
|
|
|
|
|
|
|
|
|
10698
|
6
|
50
|
|
|
|
16
|
if ($b == 0) { |
|
10699
|
6
|
|
|
|
|
34
|
my $lim = Msqrtint($b2); |
|
10700
|
6
|
100
|
|
|
|
22
|
if (_is_perfect_square($b2)) { |
|
10701
|
2
|
|
|
|
|
6
|
$square = 1; |
|
10702
|
2
|
|
|
|
|
36
|
$lim--; |
|
10703
|
|
|
|
|
|
|
} |
|
10704
|
|
|
|
|
|
|
#$h += scalar(grep { $_ <= $lim } divisors($b2)); |
|
10705
|
6
|
100
|
|
|
|
23
|
for my $i (1 .. $lim) { $h++ unless $b2 % $i; } |
|
|
32
|
|
|
|
|
105
|
|
|
10706
|
6
|
|
|
|
|
28
|
($b,$b2) = (2, ($n+4) >> 2); |
|
10707
|
|
|
|
|
|
|
} |
|
10708
|
6
|
|
|
|
|
29
|
while ($b2 * 3 < $n) { |
|
10709
|
18
|
100
|
|
|
|
38
|
$h++ unless $b2 % $b; |
|
10710
|
18
|
|
|
|
|
44
|
my $lim = Msqrtint($b2); |
|
10711
|
18
|
100
|
|
|
|
50
|
if (_is_perfect_square($b2)) { |
|
10712
|
3
|
|
|
|
|
6
|
$h++; |
|
10713
|
3
|
|
|
|
|
9
|
$lim--; |
|
10714
|
|
|
|
|
|
|
} |
|
10715
|
|
|
|
|
|
|
#$h += 2 * scalar(grep { $_ > $b && $_ <= $lim } divisors($b2)); |
|
10716
|
18
|
100
|
|
|
|
48
|
for my $i ($b+1 .. $lim) { $h += 2 unless $b2 % $i; } |
|
|
37
|
|
|
|
|
103
|
|
|
10717
|
18
|
|
|
|
|
28
|
$b += 2; |
|
10718
|
18
|
|
|
|
|
66
|
$b2 = ($n+$b*$b) >> 2; |
|
10719
|
|
|
|
|
|
|
} |
|
10720
|
6
|
100
|
|
|
|
40
|
return (($b2*3 == $n) ? 2*(3*$h+1) : $square ? 3*(2*$h+1) : 6*$h) << 1; |
|
|
|
50
|
|
|
|
|
|
|
10721
|
|
|
|
|
|
|
} |
|
10722
|
|
|
|
|
|
|
|
|
10723
|
|
|
|
|
|
|
# Ramanujan Tau using Cohen's method with Hurwitz class numbers. |
|
10724
|
|
|
|
|
|
|
# Also see Lygeros (2010). |
|
10725
|
|
|
|
|
|
|
# The two hclassno calls could be collapsed with some work |
|
10726
|
|
|
|
|
|
|
sub _tauprime { |
|
10727
|
11
|
|
|
11
|
|
27
|
my($p) = @_; |
|
10728
|
11
|
100
|
|
|
|
29
|
return -24 if $p == 2; |
|
10729
|
|
|
|
|
|
|
|
|
10730
|
9
|
|
|
|
|
24
|
my $sum = 0; |
|
10731
|
9
|
|
|
|
|
95
|
my($p9,$pp7) = (Mmulint(9,$p), Mvecprod(7,$p,$p)); |
|
10732
|
9
|
|
|
|
|
50
|
for my $t (1 .. Msqrtint($p)) { |
|
10733
|
44
|
|
|
|
|
115
|
my $t2 = Mpowint($t,2); |
|
10734
|
44
|
|
|
|
|
104
|
my $v = Msubint($p,$t2); |
|
10735
|
44
|
|
|
|
|
102
|
my $T1 = Mpowint($t2,3); |
|
10736
|
44
|
|
|
|
|
185
|
my $T2 = Maddint( Msubint(Mvecprod(4,$t2,$t2), Mmulint($p9,$t2)), $pp7); |
|
10737
|
44
|
|
|
|
|
94
|
my $T3; |
|
10738
|
44
|
|
|
|
|
83
|
my $v4 = $v % 4; |
|
10739
|
44
|
100
|
|
|
|
121
|
if ($v4 == 0) { |
|
|
|
100
|
|
|
|
|
|
|
10740
|
18
|
|
|
|
|
102
|
$T3 = Maddint(Mmulint(2,Mhclassno($v)), Mhclassno(Mmulint(4,$v)) ); |
|
10741
|
|
|
|
|
|
|
} elsif ($v4 == 3) { |
|
10742
|
3
|
100
|
|
|
|
38
|
$T3 = Mmulint( $v%8 == 3 ? 6 : 4, Mhclassno($v) ); |
|
10743
|
|
|
|
|
|
|
} else { |
|
10744
|
23
|
|
|
|
|
86
|
$T3 = Mhclassno(Mmulint(4,$v)); |
|
10745
|
|
|
|
|
|
|
} |
|
10746
|
|
|
|
|
|
|
|
|
10747
|
44
|
|
|
|
|
188
|
$sum = Maddint($sum, Mvecprod($T1, $T2, $T3)); |
|
10748
|
|
|
|
|
|
|
} |
|
10749
|
9
|
|
|
|
|
99
|
Mvecsum( Mmulint( 28, Mpowint($p,6)), |
|
10750
|
|
|
|
|
|
|
Mmulint(-28, Mpowint($p,5)), |
|
10751
|
|
|
|
|
|
|
Mmulint(-90, Mpowint($p,4)), |
|
10752
|
|
|
|
|
|
|
Mmulint(-35, Mpowint($p,3)), |
|
10753
|
|
|
|
|
|
|
-1, |
|
10754
|
|
|
|
|
|
|
Mmulint(-32,Mdivint($sum,3)) ); |
|
10755
|
|
|
|
|
|
|
} |
|
10756
|
|
|
|
|
|
|
|
|
10757
|
|
|
|
|
|
|
# Recursive method for handling prime powers |
|
10758
|
|
|
|
|
|
|
sub _taupower { |
|
10759
|
13
|
|
|
13
|
|
35
|
my($p, $e, $tp) = @_; |
|
10760
|
13
|
50
|
|
|
|
36
|
return 1 if $e <= 0; |
|
10761
|
13
|
100
|
|
|
|
65
|
$tp = _tauprime($p) unless defined $tp; |
|
10762
|
|
|
|
|
|
|
|
|
10763
|
13
|
100
|
|
|
|
352
|
return $tp if $e == 1; |
|
10764
|
|
|
|
|
|
|
|
|
10765
|
4
|
|
|
|
|
14
|
my $p11 = Mpowint($p,11); |
|
10766
|
4
|
100
|
|
|
|
26
|
return Msubint(Mpowint($tp,2), $p11) if $e == 2; |
|
10767
|
2
|
50
|
|
|
|
42
|
return Msubint(Mpowint($tp,3), Mvecprod(2,$tp,$p11)) if $e == 3; |
|
10768
|
2
|
100
|
|
|
|
12
|
return Mvecsum(Mpowint($tp,4), Mvecprod(-3,Mpowint($tp,2),$p11), Mpowint($p11,2)) if $e == 4; |
|
10769
|
|
|
|
|
|
|
|
|
10770
|
|
|
|
|
|
|
# Recurse -3 |
|
10771
|
1
|
|
|
|
|
6
|
my $F3 = Msubint(Mpowint($tp,3),Mvecprod(2,$tp,$p11)); |
|
10772
|
1
|
|
|
|
|
6
|
my $F4 = Msubint(Mmulint($p11,$p11),Mvecprod($tp,$tp,$p11)); |
|
10773
|
1
|
|
|
|
|
7
|
Maddint( Mmulint($F3,_taupower($p,$e-3,$tp)), |
|
10774
|
|
|
|
|
|
|
Mmulint($F4,_taupower($p,$e-4,$tp)) ); |
|
10775
|
|
|
|
|
|
|
} |
|
10776
|
|
|
|
|
|
|
|
|
10777
|
|
|
|
|
|
|
sub ramanujan_tau { |
|
10778
|
7
|
|
|
7
|
0
|
5254
|
my($n) = @_; |
|
10779
|
7
|
|
|
|
|
48
|
validate_integer_nonneg($n); |
|
10780
|
7
|
50
|
|
|
|
23
|
return 0 if $n <= 0; |
|
10781
|
|
|
|
|
|
|
|
|
10782
|
|
|
|
|
|
|
# Use GMP if we have no XS or if size is small |
|
10783
|
7
|
50
|
33
|
|
|
33
|
if ($n < 100000 || !getconfig()->{'xs'}) { |
|
10784
|
7
|
50
|
|
|
|
44
|
if ($Math::Prime::Util::_GMPfunc{"ramanujan_tau"}) { |
|
10785
|
0
|
|
|
|
|
0
|
return reftyped($_[0], Math::Prime::Util::GMP::ramanujan_tau($n)); |
|
10786
|
|
|
|
|
|
|
} |
|
10787
|
|
|
|
|
|
|
} |
|
10788
|
7
|
|
|
|
|
75
|
Mvecprod(map { _taupower($_->[0],$_->[1]) } Mfactor_exp($n)); |
|
|
11
|
|
|
|
|
69
|
|
|
10789
|
|
|
|
|
|
|
} |
|
10790
|
|
|
|
|
|
|
|
|
10791
|
|
|
|
|
|
|
sub _Euler { |
|
10792
|
82
|
|
|
82
|
|
205
|
my($dig) = @_; |
|
10793
|
|
|
|
|
|
|
return Math::Prime::Util::GMP::Euler($dig) |
|
10794
|
82
|
0
|
33
|
|
|
272
|
if $dig > 70 && $Math::Prime::Util::_GMPfunc{"Euler"}; |
|
10795
|
82
|
|
|
|
|
915
|
'0.57721566490153286060651209008240243104215933593992359880576723488486772677766467'; |
|
10796
|
|
|
|
|
|
|
} |
|
10797
|
|
|
|
|
|
|
sub _Li2 { |
|
10798
|
1
|
|
|
1
|
|
6
|
my($dig) = @_; |
|
10799
|
|
|
|
|
|
|
return Math::Prime::Util::GMP::li(2,$dig) |
|
10800
|
1
|
0
|
33
|
|
|
6
|
if $dig > 70 && $Math::Prime::Util::_GMPfunc{"li"}; |
|
10801
|
1
|
|
|
|
|
12
|
'1.04516378011749278484458888919461313652261557815120157583290914407501320521'; |
|
10802
|
|
|
|
|
|
|
} |
|
10803
|
|
|
|
|
|
|
|
|
10804
|
|
|
|
|
|
|
sub ExponentialIntegral { |
|
10805
|
57
|
|
|
57
|
0
|
116
|
my($x) = @_; |
|
10806
|
57
|
50
|
|
|
|
170
|
return - MPU_INFINITY if $x == 0; |
|
10807
|
57
|
50
|
|
|
|
134
|
return 0 if $x == - MPU_INFINITY; |
|
10808
|
57
|
50
|
|
|
|
152
|
return MPU_INFINITY if $x == MPU_INFINITY; |
|
10809
|
|
|
|
|
|
|
|
|
10810
|
|
|
|
|
|
|
# We are going to ignore bignum, as it's: |
|
10811
|
|
|
|
|
|
|
# 1) unclear what we should do different |
|
10812
|
|
|
|
|
|
|
# 2) hard to tell if it's active in scope |
|
10813
|
|
|
|
|
|
|
# We do have to care in regards to giving correct results. But we're not |
|
10814
|
|
|
|
|
|
|
# going to actively promote things based on it. |
|
10815
|
|
|
|
|
|
|
|
|
10816
|
57
|
50
|
|
|
|
140
|
if ($Math::Prime::Util::_GMPfunc{"ei"}) { |
|
10817
|
0
|
0
|
|
|
|
0
|
my $r = _try_real_gmp_func(\&Math::Prime::Util::GMP::ei, $x<100?0.49:0.53, $x); |
|
10818
|
0
|
0
|
|
|
|
0
|
return $r if defined $r; |
|
10819
|
|
|
|
|
|
|
} |
|
10820
|
57
|
0
|
33
|
|
|
163
|
$x=_bigint_to_int($x) if ref($x)eq'Math::BigInt' && $x<=INTMAX && $x>=INTMIN; |
|
|
|
|
33
|
|
|
|
|
|
10821
|
57
|
50
|
33
|
|
|
151
|
$x=_upgrade_to_float($x) if ref($x) && ref($x) ne 'Math::BigFloat'; |
|
10822
|
|
|
|
|
|
|
|
|
10823
|
57
|
|
|
|
|
117
|
my $tol = 1e-16; |
|
10824
|
57
|
|
|
|
|
113
|
my $sum = 0.0; |
|
10825
|
57
|
|
|
|
|
94
|
my($y, $t); |
|
10826
|
57
|
|
|
|
|
94
|
my $c = 0.0; |
|
10827
|
57
|
|
|
|
|
88
|
my $val; # The result from one of the four methods |
|
10828
|
|
|
|
|
|
|
|
|
10829
|
57
|
100
|
|
|
|
268
|
if ($x < -1) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
10830
|
|
|
|
|
|
|
# Continued fraction |
|
10831
|
1
|
|
|
|
|
3
|
my $lc = 0; |
|
10832
|
1
|
|
|
|
|
4
|
my $ld = 1 / (1 - $x); |
|
10833
|
1
|
|
|
|
|
6
|
$val = $ld * (-exp($x)); |
|
10834
|
1
|
|
|
|
|
4
|
for my $n (1 .. 100000) { |
|
10835
|
15
|
|
|
|
|
33
|
$lc = 1 / (2*$n + 1 - $x - $n*$n*$lc); |
|
10836
|
15
|
|
|
|
|
31
|
$ld = 1 / (2*$n + 1 - $x - $n*$n*$ld); |
|
10837
|
15
|
|
|
|
|
25
|
my $old = $val; |
|
10838
|
15
|
|
|
|
|
25
|
$val *= $ld/$lc; |
|
10839
|
15
|
100
|
|
|
|
40
|
last if abs($val - $old) <= ($tol * abs($val)); |
|
10840
|
|
|
|
|
|
|
} |
|
10841
|
|
|
|
|
|
|
} elsif ($x < 0) { |
|
10842
|
|
|
|
|
|
|
# Rational Chebyshev approximation |
|
10843
|
5
|
|
|
|
|
18
|
my @C6p = ( -148151.02102575750838086, |
|
10844
|
|
|
|
|
|
|
150260.59476436982420737, |
|
10845
|
|
|
|
|
|
|
89904.972007457256553251, |
|
10846
|
|
|
|
|
|
|
15924.175980637303639884, |
|
10847
|
|
|
|
|
|
|
2150.0672908092918123209, |
|
10848
|
|
|
|
|
|
|
116.69552669734461083368, |
|
10849
|
|
|
|
|
|
|
5.0196785185439843791020); |
|
10850
|
5
|
|
|
|
|
16
|
my @C6q = ( 256664.93484897117319268, |
|
10851
|
|
|
|
|
|
|
184340.70063353677359298, |
|
10852
|
|
|
|
|
|
|
52440.529172056355429883, |
|
10853
|
|
|
|
|
|
|
8125.8035174768735759866, |
|
10854
|
|
|
|
|
|
|
750.43163907103936624165, |
|
10855
|
|
|
|
|
|
|
40.205465640027706061433, |
|
10856
|
|
|
|
|
|
|
1.0000000000000000000000); |
|
10857
|
5
|
|
|
|
|
15
|
my $sumn = $C6p[0]-$x*($C6p[1]-$x*($C6p[2]-$x*($C6p[3]-$x*($C6p[4]-$x*($C6p[5]-$x*$C6p[6]))))); |
|
10858
|
5
|
|
|
|
|
11
|
my $sumd = $C6q[0]-$x*($C6q[1]-$x*($C6q[2]-$x*($C6q[3]-$x*($C6q[4]-$x*($C6q[5]-$x*$C6q[6]))))); |
|
10859
|
5
|
|
|
|
|
26
|
$val = log(-$x) - ($sumn / $sumd); |
|
10860
|
|
|
|
|
|
|
} elsif ($x < -log($tol)) { |
|
10861
|
|
|
|
|
|
|
# Convergent series |
|
10862
|
48
|
|
|
|
|
82
|
my $fact_n = 1; |
|
10863
|
48
|
|
|
|
|
125
|
$y = _Euler(18)-$c; $t = $sum+$y; $c = ($t-$sum)-$y; $sum = $t; |
|
|
48
|
|
|
|
|
114
|
|
|
|
48
|
|
|
|
|
112
|
|
|
|
48
|
|
|
|
|
73
|
|
|
10864
|
48
|
|
|
|
|
94
|
$y = log($x)-$c; $t = $sum+$y; $c = ($t-$sum)-$y; $sum = $t; |
|
|
48
|
|
|
|
|
93
|
|
|
|
48
|
|
|
|
|
78
|
|
|
|
48
|
|
|
|
|
76
|
|
|
10865
|
48
|
|
|
|
|
143
|
for my $n (1 .. 200) { |
|
10866
|
4298
|
|
|
|
|
6956
|
$fact_n *= $x/$n; |
|
10867
|
4298
|
|
|
|
|
7056
|
my $term = $fact_n / $n; |
|
10868
|
4298
|
|
|
|
|
6723
|
$y = $term-$c; $t = $sum+$y; $c = ($t-$sum)-$y; $sum = $t; |
|
|
4298
|
|
|
|
|
6560
|
|
|
|
4298
|
|
|
|
|
6634
|
|
|
|
4298
|
|
|
|
|
6317
|
|
|
10869
|
4298
|
100
|
|
|
|
9281
|
last if $term < $tol; |
|
10870
|
|
|
|
|
|
|
} |
|
10871
|
48
|
|
|
|
|
117
|
$val = $sum; |
|
10872
|
|
|
|
|
|
|
} else { |
|
10873
|
|
|
|
|
|
|
# Asymptotic divergent series |
|
10874
|
3
|
|
|
|
|
13
|
my $invx = 1.0 / $x; |
|
10875
|
3
|
|
|
|
|
8
|
my $term = $invx; |
|
10876
|
3
|
|
|
|
|
6
|
$sum = 1.0 + $term; |
|
10877
|
3
|
|
|
|
|
30
|
for my $n (2 .. 200) { |
|
10878
|
81
|
|
|
|
|
124
|
my $last_term = $term; |
|
10879
|
81
|
|
|
|
|
144
|
$term *= $n * $invx; |
|
10880
|
81
|
100
|
|
|
|
161
|
last if $term < $tol; |
|
10881
|
78
|
50
|
|
|
|
145
|
if ($term < $last_term) { |
|
10882
|
78
|
|
|
|
|
114
|
$y = $term-$c; $t = $sum+$y; $c = ($t-$sum)-$y; $sum = $t; |
|
|
78
|
|
|
|
|
138
|
|
|
|
78
|
|
|
|
|
117
|
|
|
|
78
|
|
|
|
|
152
|
|
|
10883
|
|
|
|
|
|
|
} else { |
|
10884
|
0
|
|
|
|
|
0
|
$y = (-$last_term/3)-$c; $t = $sum+$y; $c = ($t-$sum)-$y; $sum = $t; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
10885
|
0
|
|
|
|
|
0
|
last; |
|
10886
|
|
|
|
|
|
|
} |
|
10887
|
|
|
|
|
|
|
} |
|
10888
|
3
|
|
|
|
|
12
|
$val = exp($x) * $invx * $sum; |
|
10889
|
|
|
|
|
|
|
} |
|
10890
|
57
|
|
|
|
|
493
|
$val; |
|
10891
|
|
|
|
|
|
|
} |
|
10892
|
|
|
|
|
|
|
|
|
10893
|
|
|
|
|
|
|
sub LogarithmicIntegral { |
|
10894
|
56
|
|
|
56
|
0
|
150
|
my($x) = @_; |
|
10895
|
56
|
50
|
|
|
|
250
|
return 0 if $x == 0; |
|
10896
|
56
|
50
|
|
|
|
11483
|
return - MPU_INFINITY if $x == 1; |
|
10897
|
56
|
50
|
|
|
|
10454
|
return MPU_INFINITY if $x == MPU_INFINITY; |
|
10898
|
56
|
50
|
|
|
|
8520
|
croak "Invalid input to LogarithmicIntegral: x must be > 0" if $x <= 0; |
|
10899
|
|
|
|
|
|
|
|
|
10900
|
56
|
50
|
|
|
|
10753
|
if ($Math::Prime::Util::_GMPfunc{"li"}) { |
|
10901
|
0
|
|
|
|
|
0
|
my $r = _try_real_gmp_func(\&Math::Prime::Util::GMP::li, 0.49, $x); |
|
10902
|
0
|
0
|
|
|
|
0
|
return $r if defined $r; |
|
10903
|
|
|
|
|
|
|
} |
|
10904
|
|
|
|
|
|
|
|
|
10905
|
56
|
100
|
|
|
|
212
|
if ($x == 2) { |
|
10906
|
1
|
50
|
|
|
|
42
|
my $li2const = (ref($x) eq 'Math::BigFloat') ? Math::BigFloat->new(_Li2(_find_big_acc($x))) : 0.0+_Li2(30); |
|
10907
|
1
|
|
|
|
|
19
|
return $li2const; |
|
10908
|
|
|
|
|
|
|
} |
|
10909
|
|
|
|
|
|
|
|
|
10910
|
55
|
0
|
33
|
|
|
11429
|
$x=_bigint_to_int($x) if ref($x)eq'Math::BigInt' && $x<=INTMAX && $x>=INTMIN; |
|
|
|
|
33
|
|
|
|
|
|
10911
|
55
|
50
|
66
|
|
|
265
|
$x=_upgrade_to_float($x) if ref($x) && ref($x) ne 'Math::BigFloat'; |
|
10912
|
|
|
|
|
|
|
|
|
10913
|
|
|
|
|
|
|
# Make sure we preserve whatever accuracy setting the input was using. |
|
10914
|
55
|
100
|
66
|
|
|
533
|
$x->accuracy($_[0]->accuracy) if ref($x) && ref($_[0]) =~ /^Math::Big/ && $_[0]->accuracy; |
|
|
|
|
100
|
|
|
|
|
|
10915
|
|
|
|
|
|
|
|
|
10916
|
|
|
|
|
|
|
# Do divergent series here for big inputs. Common for big pc approximations. |
|
10917
|
|
|
|
|
|
|
# Why is this here? |
|
10918
|
|
|
|
|
|
|
# 1) exp(log(x)) results in a lot of lost precision |
|
10919
|
|
|
|
|
|
|
# 2) exp(x) with lots of precision turns out to be really slow, and in |
|
10920
|
|
|
|
|
|
|
# this case it was unnecessary. |
|
10921
|
55
|
|
|
|
|
1545
|
my $tol = 1e-16; |
|
10922
|
55
|
|
|
|
|
95
|
my $xdigits = 0; |
|
10923
|
55
|
|
|
|
|
161
|
my $finalacc = 0; |
|
10924
|
55
|
100
|
|
|
|
223
|
if (ref($x) =~ /^Math::Big/) { |
|
10925
|
24
|
|
|
|
|
116
|
$xdigits = _find_big_acc($x); |
|
10926
|
24
|
|
|
|
|
118
|
my $xlen = length($x->copy->bfloor->bstr()); |
|
10927
|
24
|
100
|
|
|
|
5913
|
$xdigits = $xlen if $xdigits < $xlen; |
|
10928
|
24
|
|
|
|
|
56
|
$finalacc = $xdigits; |
|
10929
|
24
|
|
|
|
|
108
|
$xdigits += length(int(log(0.0+"$x"))) + 1; |
|
10930
|
24
|
|
|
|
|
1536
|
$tol = Math::BigFloat->new(10)->bpow(-$xdigits); |
|
10931
|
24
|
|
|
|
|
55038
|
$x->accuracy($xdigits); |
|
10932
|
|
|
|
|
|
|
} |
|
10933
|
55
|
100
|
|
|
|
2937
|
my $logx = $xdigits ? $x->copy->blog(undef,$xdigits) : log($x); |
|
10934
|
|
|
|
|
|
|
|
|
10935
|
|
|
|
|
|
|
# TODO: See if we can tune this |
|
10936
|
55
|
|
|
|
|
3600284
|
if (0 && $x >= 1) { |
|
10937
|
|
|
|
|
|
|
_upgrade_to_float(); |
|
10938
|
|
|
|
|
|
|
my $sum = Math::BigFloat->new(0); |
|
10939
|
|
|
|
|
|
|
my $inner_sum = Math::BigFloat->new(0); |
|
10940
|
|
|
|
|
|
|
my $p = Math::BigFloat->new(-1); |
|
10941
|
|
|
|
|
|
|
my $factorial = 1; |
|
10942
|
|
|
|
|
|
|
my $power2 = 1; |
|
10943
|
|
|
|
|
|
|
my $q; |
|
10944
|
|
|
|
|
|
|
my $k = 0; |
|
10945
|
|
|
|
|
|
|
my $neglogx = -$logx; |
|
10946
|
|
|
|
|
|
|
for my $n (1 .. 1000) { |
|
10947
|
|
|
|
|
|
|
$factorial = mulint($factorial, $n); |
|
10948
|
|
|
|
|
|
|
$q = mulint($factorial, $power2); |
|
10949
|
|
|
|
|
|
|
$power2 = mulint(2, $power2); |
|
10950
|
|
|
|
|
|
|
while ($k <= ($n-1)>>1) { |
|
10951
|
|
|
|
|
|
|
$inner_sum += Math::BigFloat->bone / (2*$k+1); |
|
10952
|
|
|
|
|
|
|
$k++; |
|
10953
|
|
|
|
|
|
|
} |
|
10954
|
|
|
|
|
|
|
$p->bmul($neglogx); |
|
10955
|
|
|
|
|
|
|
my $term = $p->copy->bdiv("$q", $xdigits)->bmul($inner_sum); |
|
10956
|
|
|
|
|
|
|
$term->bround($xdigits) if $xdigits; |
|
10957
|
|
|
|
|
|
|
$sum->badd($term); |
|
10958
|
|
|
|
|
|
|
last if $term->copy->babs < $tol; |
|
10959
|
|
|
|
|
|
|
} |
|
10960
|
|
|
|
|
|
|
$sum *= sqrt($x); |
|
10961
|
|
|
|
|
|
|
return 0.0+_Euler(18) + log($logx) + $sum unless ref($x)=~/^Math::Big/; |
|
10962
|
|
|
|
|
|
|
my $val = Math::BigFloat->new(_Euler(40))->badd("".log($logx))->badd("$sum"); |
|
10963
|
|
|
|
|
|
|
$val->accuracy($finalacc) if $xdigits; |
|
10964
|
|
|
|
|
|
|
return $val; |
|
10965
|
|
|
|
|
|
|
} |
|
10966
|
|
|
|
|
|
|
|
|
10967
|
55
|
100
|
|
|
|
250
|
if ($x > 1e16) { |
|
10968
|
21
|
100
|
|
|
|
12822
|
my $invx = ref($logx) ? Math::BigFloat->bone / $logx : 1.0/$logx; |
|
10969
|
|
|
|
|
|
|
# n = 0 => 0!/(logx)^0 = 1/1 = 1 |
|
10970
|
|
|
|
|
|
|
# n = 1 => 1!/(logx)^1 = 1/logx |
|
10971
|
21
|
|
|
|
|
29431
|
my $term = $invx; |
|
10972
|
21
|
|
|
|
|
174
|
my $sum = 1.0 + $term; |
|
10973
|
21
|
|
|
|
|
19814
|
for my $n (2 .. 1000) { |
|
10974
|
1030
|
|
|
|
|
85178
|
my $last_term = $term; |
|
10975
|
1030
|
|
|
|
|
4054
|
$term *= $n * $invx; |
|
10976
|
1030
|
100
|
|
|
|
1665491
|
last if $term < $tol; |
|
10977
|
1029
|
100
|
|
|
|
298696
|
if ($term < $last_term) { |
|
10978
|
1009
|
|
|
|
|
283598
|
$sum += $term; |
|
10979
|
|
|
|
|
|
|
} else { |
|
10980
|
20
|
|
|
|
|
6973
|
$sum -= ($last_term/3); |
|
10981
|
20
|
|
|
|
|
45965
|
last; |
|
10982
|
|
|
|
|
|
|
} |
|
10983
|
1009
|
100
|
|
|
|
885113
|
$term->bround($xdigits) if $xdigits; |
|
10984
|
|
|
|
|
|
|
} |
|
10985
|
21
|
|
|
|
|
102
|
$invx *= $sum; |
|
10986
|
21
|
|
|
|
|
19851
|
$invx *= $x; |
|
10987
|
21
|
100
|
66
|
|
|
13066
|
$invx->accuracy($finalacc) if ref($invx) && $xdigits; |
|
10988
|
21
|
|
|
|
|
9059
|
return $invx; |
|
10989
|
|
|
|
|
|
|
} |
|
10990
|
|
|
|
|
|
|
# Convergent series. |
|
10991
|
34
|
50
|
|
|
|
2857
|
if ($x >= 1) { |
|
10992
|
34
|
|
|
|
|
2188
|
my $fact_n = 1.0; |
|
10993
|
34
|
|
|
|
|
58
|
my $nfac = 1.0; |
|
10994
|
34
|
|
|
|
|
65
|
my $sum = 0.0; |
|
10995
|
34
|
|
|
|
|
119
|
for my $n (1 .. 200) { |
|
10996
|
2004
|
|
|
|
|
45963
|
$fact_n *= $logx/$n; |
|
10997
|
2004
|
|
|
|
|
1023412
|
my $term = $fact_n / $n; |
|
10998
|
2004
|
|
|
|
|
614134
|
$sum += $term; |
|
10999
|
2004
|
100
|
|
|
|
414604
|
last if $term < $tol; |
|
11000
|
1970
|
100
|
|
|
|
164846
|
$term->bround($xdigits) if $xdigits; |
|
11001
|
|
|
|
|
|
|
} |
|
11002
|
|
|
|
|
|
|
|
|
11003
|
34
|
100
|
|
|
|
1494
|
return 0.0+_Euler(18) + log($logx) + $sum unless ref($x) =~ /^Math::Big/; |
|
11004
|
|
|
|
|
|
|
|
|
11005
|
4
|
|
|
|
|
29
|
my $val = Math::BigFloat->new(_Euler(40))->badd("".log($logx))->badd("$sum"); |
|
11006
|
4
|
50
|
|
|
|
538525
|
$val->accuracy($finalacc) if $xdigits; |
|
11007
|
4
|
|
|
|
|
1994
|
return $val; |
|
11008
|
|
|
|
|
|
|
} |
|
11009
|
|
|
|
|
|
|
|
|
11010
|
0
|
|
|
|
|
0
|
ExponentialIntegral($logx); |
|
11011
|
|
|
|
|
|
|
} |
|
11012
|
|
|
|
|
|
|
|
|
11013
|
|
|
|
|
|
|
# Riemann Zeta function for native integers. |
|
11014
|
|
|
|
|
|
|
my @_Riemann_Zeta_Table = ( |
|
11015
|
|
|
|
|
|
|
0.6449340668482264364724151666460251892, # zeta(2) - 1 |
|
11016
|
|
|
|
|
|
|
0.2020569031595942853997381615114499908, |
|
11017
|
|
|
|
|
|
|
0.0823232337111381915160036965411679028, |
|
11018
|
|
|
|
|
|
|
0.0369277551433699263313654864570341681, |
|
11019
|
|
|
|
|
|
|
0.0173430619844491397145179297909205279, |
|
11020
|
|
|
|
|
|
|
0.0083492773819228268397975498497967596, |
|
11021
|
|
|
|
|
|
|
0.0040773561979443393786852385086524653, |
|
11022
|
|
|
|
|
|
|
0.0020083928260822144178527692324120605, |
|
11023
|
|
|
|
|
|
|
0.0009945751278180853371459589003190170, |
|
11024
|
|
|
|
|
|
|
0.0004941886041194645587022825264699365, |
|
11025
|
|
|
|
|
|
|
0.0002460865533080482986379980477396710, |
|
11026
|
|
|
|
|
|
|
0.0001227133475784891467518365263573957, |
|
11027
|
|
|
|
|
|
|
0.0000612481350587048292585451051353337, |
|
11028
|
|
|
|
|
|
|
0.0000305882363070204935517285106450626, |
|
11029
|
|
|
|
|
|
|
0.0000152822594086518717325714876367220, |
|
11030
|
|
|
|
|
|
|
0.0000076371976378997622736002935630292, |
|
11031
|
|
|
|
|
|
|
0.0000038172932649998398564616446219397, |
|
11032
|
|
|
|
|
|
|
0.0000019082127165539389256569577951013, |
|
11033
|
|
|
|
|
|
|
0.0000009539620338727961131520386834493, |
|
11034
|
|
|
|
|
|
|
0.0000004769329867878064631167196043730, |
|
11035
|
|
|
|
|
|
|
0.0000002384505027277329900036481867530, |
|
11036
|
|
|
|
|
|
|
0.0000001192199259653110730677887188823, |
|
11037
|
|
|
|
|
|
|
0.0000000596081890512594796124402079358, |
|
11038
|
|
|
|
|
|
|
0.0000000298035035146522801860637050694, |
|
11039
|
|
|
|
|
|
|
0.0000000149015548283650412346585066307, |
|
11040
|
|
|
|
|
|
|
0.0000000074507117898354294919810041706, |
|
11041
|
|
|
|
|
|
|
0.0000000037253340247884570548192040184, |
|
11042
|
|
|
|
|
|
|
0.0000000018626597235130490064039099454, |
|
11043
|
|
|
|
|
|
|
0.0000000009313274324196681828717647350, |
|
11044
|
|
|
|
|
|
|
0.0000000004656629065033784072989233251, |
|
11045
|
|
|
|
|
|
|
0.0000000002328311833676505492001455976, |
|
11046
|
|
|
|
|
|
|
0.0000000001164155017270051977592973835, |
|
11047
|
|
|
|
|
|
|
0.0000000000582077208790270088924368599, |
|
11048
|
|
|
|
|
|
|
0.0000000000291038504449709968692942523, |
|
11049
|
|
|
|
|
|
|
0.0000000000145519218910419842359296322, |
|
11050
|
|
|
|
|
|
|
0.0000000000072759598350574810145208690, |
|
11051
|
|
|
|
|
|
|
0.0000000000036379795473786511902372363, |
|
11052
|
|
|
|
|
|
|
0.0000000000018189896503070659475848321, |
|
11053
|
|
|
|
|
|
|
0.0000000000009094947840263889282533118, |
|
11054
|
|
|
|
|
|
|
); |
|
11055
|
|
|
|
|
|
|
|
|
11056
|
|
|
|
|
|
|
|
|
11057
|
|
|
|
|
|
|
sub RiemannZeta { |
|
11058
|
627
|
|
|
627
|
0
|
949
|
my($x) = @_; |
|
11059
|
|
|
|
|
|
|
|
|
11060
|
|
|
|
|
|
|
# Try our GMP code if possible. |
|
11061
|
627
|
50
|
|
|
|
1123
|
if ($Math::Prime::Util::_GMPfunc{"zeta"}) { |
|
11062
|
0
|
|
|
|
|
0
|
my($wantbf,$xdigits) = _bfdigits($x); |
|
11063
|
|
|
|
|
|
|
# If we knew the *exact* number of zero digits, we could let GMP zeta |
|
11064
|
|
|
|
|
|
|
# handle the correct rounding. But we don't, so we have to go over. |
|
11065
|
0
|
|
|
|
|
0
|
my $zero_dig = "".int($x / 3) - 1; |
|
11066
|
0
|
|
|
|
|
0
|
my $strval = Math::Prime::Util::GMP::zeta($x, $xdigits + 8 + $zero_dig); |
|
11067
|
0
|
0
|
|
|
|
0
|
if ($strval =~ s/^(1\.0*)/./) { |
|
11068
|
0
|
0
|
|
|
|
0
|
$strval .= "e-".(length($1)-2) if length($1) > 2; |
|
11069
|
|
|
|
|
|
|
} else { |
|
11070
|
0
|
|
|
|
|
0
|
$strval =~ s/^(-?\d+)/$1-1/e; |
|
|
0
|
|
|
|
|
0
|
|
|
11071
|
|
|
|
|
|
|
} |
|
11072
|
|
|
|
|
|
|
|
|
11073
|
0
|
0
|
|
|
|
0
|
return ($wantbf) ? Math::BigFloat->new($strval,$wantbf) : 0.0 + $strval; |
|
11074
|
|
|
|
|
|
|
} |
|
11075
|
|
|
|
|
|
|
|
|
11076
|
|
|
|
|
|
|
# If we need a bigfloat result, then call our PP routine. |
|
11077
|
627
|
100
|
|
|
|
1185
|
if (ref($x) =~ /^Math::Big/) { |
|
11078
|
4
|
|
|
|
|
1354
|
require Math::Prime::Util::ZetaBigFloat; |
|
11079
|
4
|
|
|
|
|
33
|
return Math::Prime::Util::ZetaBigFloat::RiemannZeta($x); |
|
11080
|
|
|
|
|
|
|
} |
|
11081
|
|
|
|
|
|
|
|
|
11082
|
|
|
|
|
|
|
# Native float results |
|
11083
|
623
|
100
|
100
|
|
|
1860
|
return 0.0 + $_Riemann_Zeta_Table[int($x)-2] |
|
11084
|
|
|
|
|
|
|
if $x == int($x) && defined $_Riemann_Zeta_Table[int($x)-2]; |
|
11085
|
596
|
|
|
|
|
750
|
my $tol = 1.11e-16; |
|
11086
|
|
|
|
|
|
|
|
|
11087
|
|
|
|
|
|
|
# Series based on (2n)! / B_2n. |
|
11088
|
|
|
|
|
|
|
# This is a simplification of the Cephes zeta function. |
|
11089
|
596
|
|
|
|
|
1162
|
my @A = ( |
|
11090
|
|
|
|
|
|
|
12.0, |
|
11091
|
|
|
|
|
|
|
-720.0, |
|
11092
|
|
|
|
|
|
|
30240.0, |
|
11093
|
|
|
|
|
|
|
-1209600.0, |
|
11094
|
|
|
|
|
|
|
47900160.0, |
|
11095
|
|
|
|
|
|
|
-1892437580.3183791606367583212735166426, |
|
11096
|
|
|
|
|
|
|
74724249600.0, |
|
11097
|
|
|
|
|
|
|
-2950130727918.1642244954382084600497650, |
|
11098
|
|
|
|
|
|
|
116467828143500.67248729113000661089202, |
|
11099
|
|
|
|
|
|
|
-4597978722407472.6105457273596737891657, |
|
11100
|
|
|
|
|
|
|
181521054019435467.73425331153534235290, |
|
11101
|
|
|
|
|
|
|
-7166165256175667011.3346447367083352776, |
|
11102
|
|
|
|
|
|
|
282908877253042996618.18640556532523927, |
|
11103
|
|
|
|
|
|
|
); |
|
11104
|
596
|
|
|
|
|
825
|
my $s = 0.0; |
|
11105
|
596
|
|
|
|
|
753
|
my $rb = 0.0; |
|
11106
|
596
|
|
|
|
|
922
|
foreach my $i (2 .. 10) { |
|
11107
|
2124
|
|
|
|
|
3174
|
$rb = $i ** -$x; |
|
11108
|
2124
|
|
|
|
|
2687
|
$s += $rb; |
|
11109
|
2124
|
100
|
|
|
|
4691
|
return $s if abs($rb/$s) < $tol; |
|
11110
|
|
|
|
|
|
|
} |
|
11111
|
4
|
|
|
|
|
9
|
my $w = 10.0; |
|
11112
|
4
|
|
|
|
|
13
|
$s = $s + $rb*$w/($x-1.0) - 0.5*$rb; |
|
11113
|
4
|
|
|
|
|
9
|
my $ra = 1.0; |
|
11114
|
4
|
|
|
|
|
9
|
foreach my $i (0 .. 12) { |
|
11115
|
29
|
|
|
|
|
41
|
my $k = 2*$i; |
|
11116
|
29
|
|
|
|
|
79
|
$ra *= $x + $k; |
|
11117
|
29
|
|
|
|
|
49
|
$rb /= $w; |
|
11118
|
29
|
|
|
|
|
57
|
my $t = $ra*$rb/$A[$i]; |
|
11119
|
29
|
|
|
|
|
41
|
$s += $t; |
|
11120
|
29
|
|
|
|
|
47
|
$t = abs($t/$s); |
|
11121
|
29
|
100
|
|
|
|
61
|
last if $t < $tol; |
|
11122
|
25
|
|
|
|
|
42
|
$ra *= $x + $k + 1.0; |
|
11123
|
25
|
|
|
|
|
46
|
$rb /= $w; |
|
11124
|
|
|
|
|
|
|
} |
|
11125
|
4
|
|
|
|
|
72
|
return $s; |
|
11126
|
|
|
|
|
|
|
} |
|
11127
|
|
|
|
|
|
|
|
|
11128
|
|
|
|
|
|
|
# Riemann R function |
|
11129
|
|
|
|
|
|
|
sub RiemannR { |
|
11130
|
29
|
|
|
29
|
0
|
65
|
my($x) = @_; |
|
11131
|
|
|
|
|
|
|
|
|
11132
|
29
|
50
|
|
|
|
71
|
croak "Invalid input to RiemannR: x must be > 0" if $x <= 0; |
|
11133
|
|
|
|
|
|
|
|
|
11134
|
29
|
50
|
|
|
|
110
|
if ($Math::Prime::Util::_GMPfunc{"riemannr"}) { |
|
11135
|
0
|
|
|
|
|
0
|
my $r = _try_real_gmp_func(\&Math::Prime::Util::GMP::riemannr, 0.41, $x); |
|
11136
|
0
|
0
|
|
|
|
0
|
return $r if defined $r; |
|
11137
|
|
|
|
|
|
|
} |
|
11138
|
29
|
0
|
33
|
|
|
97
|
$x=_bigint_to_int($x) if ref($x)eq'Math::BigInt' && $x<=INTMAX && $x>=INTMIN; |
|
|
|
|
33
|
|
|
|
|
|
11139
|
29
|
50
|
33
|
|
|
85
|
$x=_upgrade_to_float($x) if ref($x) && ref($x) ne 'Math::BigFloat'; |
|
11140
|
|
|
|
|
|
|
|
|
11141
|
|
|
|
|
|
|
|
|
11142
|
|
|
|
|
|
|
# TODO: look into this as a generic solution |
|
11143
|
29
|
|
|
|
|
42
|
if (0 && $Math::Prime::Util::_GMPfunc{"zeta"}) { |
|
11144
|
|
|
|
|
|
|
my($wantbf,$xdigits) = _bfdigits($x); |
|
11145
|
|
|
|
|
|
|
$x = _upgrade_to_float($x); |
|
11146
|
|
|
|
|
|
|
|
|
11147
|
|
|
|
|
|
|
my $extra_acc = 4; |
|
11148
|
|
|
|
|
|
|
$xdigits += $extra_acc; |
|
11149
|
|
|
|
|
|
|
$x->accuracy($xdigits); |
|
11150
|
|
|
|
|
|
|
|
|
11151
|
|
|
|
|
|
|
my $logx = log($x); |
|
11152
|
|
|
|
|
|
|
my $part_term = $x->copy->bone; |
|
11153
|
|
|
|
|
|
|
my $sum = $x->copy->bone; |
|
11154
|
|
|
|
|
|
|
my $tol = $x->copy->bone->brsft($xdigits-1, 10); |
|
11155
|
|
|
|
|
|
|
my $bigk = $x->copy->bone; |
|
11156
|
|
|
|
|
|
|
my $term; |
|
11157
|
|
|
|
|
|
|
for my $k (1 .. 10000) { |
|
11158
|
|
|
|
|
|
|
$part_term *= $logx / $bigk; |
|
11159
|
|
|
|
|
|
|
my $zarg = $bigk->copy->binc; |
|
11160
|
|
|
|
|
|
|
my $zeta = (RiemannZeta($zarg) * $bigk) + $bigk; |
|
11161
|
|
|
|
|
|
|
#my $strval = Math::Prime::Util::GMP::zeta($k+1, $xdigits + int(($k+1) / 3)); |
|
11162
|
|
|
|
|
|
|
#my $zeta = Math::BigFloat->new($strval)->bdec->bmul($bigk)->badd($bigk); |
|
11163
|
|
|
|
|
|
|
$term = $part_term / $zeta; |
|
11164
|
|
|
|
|
|
|
$sum += $term; |
|
11165
|
|
|
|
|
|
|
last if $term < ($tol * $sum); |
|
11166
|
|
|
|
|
|
|
$bigk->binc; |
|
11167
|
|
|
|
|
|
|
} |
|
11168
|
|
|
|
|
|
|
$sum->bround($xdigits-$extra_acc); |
|
11169
|
|
|
|
|
|
|
my $strval = "$sum"; |
|
11170
|
|
|
|
|
|
|
return ($wantbf) ? Math::BigFloat->new($strval,$wantbf) : 0.0 + $strval; |
|
11171
|
|
|
|
|
|
|
} |
|
11172
|
|
|
|
|
|
|
|
|
11173
|
29
|
50
|
|
|
|
69
|
if (ref($x) =~ /^Math::Big/) { |
|
11174
|
0
|
|
|
|
|
0
|
require Math::Prime::Util::ZetaBigFloat; |
|
11175
|
0
|
|
|
|
|
0
|
return Math::Prime::Util::ZetaBigFloat::RiemannR($x); |
|
11176
|
|
|
|
|
|
|
} |
|
11177
|
|
|
|
|
|
|
|
|
11178
|
29
|
|
|
|
|
51
|
my $sum = 0.0; |
|
11179
|
29
|
|
|
|
|
45
|
my $tol = 1e-18; |
|
11180
|
29
|
|
|
|
|
60
|
my($c, $y, $t) = (0.0); |
|
11181
|
29
|
100
|
|
|
|
128
|
if ($x > 10**17) { |
|
11182
|
1
|
|
|
|
|
11
|
my @mob = Mmoebius(0,300); |
|
11183
|
1
|
|
|
|
|
8
|
for my $k (1 .. 300) { |
|
11184
|
19
|
100
|
|
|
|
50
|
next if $mob[$k] == 0; |
|
11185
|
13
|
|
|
|
|
78
|
my $term = $mob[$k] / $k * MLi($x**(1.0/$k)); |
|
11186
|
13
|
|
|
|
|
32
|
$y = $term-$c; $t = $sum+$y; $c = ($t-$sum)-$y; $sum = $t; |
|
|
13
|
|
|
|
|
24
|
|
|
|
13
|
|
|
|
|
24
|
|
|
|
13
|
|
|
|
|
23
|
|
|
11187
|
13
|
100
|
|
|
|
73
|
last if abs($term) < ($tol * abs($sum)); |
|
11188
|
|
|
|
|
|
|
} |
|
11189
|
|
|
|
|
|
|
} else { |
|
11190
|
28
|
|
|
|
|
52
|
$y = 1.0-$c; $t = $sum+$y; $c = ($t-$sum)-$y; $sum = $t; |
|
|
28
|
|
|
|
|
68
|
|
|
|
28
|
|
|
|
|
55
|
|
|
|
28
|
|
|
|
|
46
|
|
|
11191
|
28
|
|
|
|
|
69
|
my $flogx = log($x); |
|
11192
|
28
|
|
|
|
|
55
|
my $part_term = 1.0; |
|
11193
|
28
|
|
|
|
|
96
|
for my $k (1 .. 10000) { |
|
11194
|
1614
|
100
|
|
|
|
2943
|
my $zeta = ($k <= $#_Riemann_Zeta_Table) |
|
11195
|
|
|
|
|
|
|
? $_Riemann_Zeta_Table[$k+1-2] # Small k from table |
|
11196
|
|
|
|
|
|
|
: RiemannZeta($k+1); # Large k from function |
|
11197
|
1614
|
|
|
|
|
2369
|
$part_term *= $flogx / $k; |
|
11198
|
1614
|
|
|
|
|
2492
|
my $term = $part_term / ($k + $k * $zeta); |
|
11199
|
1614
|
|
|
|
|
2049
|
$y = $term-$c; $t = $sum+$y; $c = ($t-$sum)-$y; $sum = $t; |
|
|
1614
|
|
|
|
|
2027
|
|
|
|
1614
|
|
|
|
|
2055
|
|
|
|
1614
|
|
|
|
|
2073
|
|
|
11200
|
1614
|
100
|
|
|
|
3034
|
last if $term < ($tol * $sum); |
|
11201
|
|
|
|
|
|
|
} |
|
11202
|
|
|
|
|
|
|
} |
|
11203
|
29
|
|
|
|
|
196
|
return $sum; |
|
11204
|
|
|
|
|
|
|
} |
|
11205
|
|
|
|
|
|
|
|
|
11206
|
|
|
|
|
|
|
sub LambertW { |
|
11207
|
1
|
|
|
1
|
0
|
4
|
my($x) = @_; |
|
11208
|
1
|
50
|
|
|
|
7
|
croak "Invalid input to LambertW: x must be >= -1/e" if $x < -0.36787944118; |
|
11209
|
|
|
|
|
|
|
|
|
11210
|
1
|
50
|
|
|
|
5
|
if ($Math::Prime::Util::_GMPfunc{"lambertw"}) { |
|
11211
|
0
|
|
|
|
|
0
|
my $r = _try_real_gmp_func(\&Math::Prime::Util::GMP::lambertw, 0.42, $x); |
|
11212
|
0
|
0
|
|
|
|
0
|
return $r if defined $r; |
|
11213
|
|
|
|
|
|
|
} |
|
11214
|
1
|
0
|
33
|
|
|
7
|
$x=_bigint_to_int($x) if ref($x)eq'Math::BigInt' && $x<=INTMAX && $x>=INTMIN; |
|
|
|
|
33
|
|
|
|
|
|
11215
|
1
|
50
|
33
|
|
|
7
|
$x=_upgrade_to_float($x) if ref($x) && ref($x) ne 'Math::BigFloat'; |
|
11216
|
|
|
|
|
|
|
|
|
11217
|
1
|
50
|
|
|
|
5
|
my $xacc = ref($x) ? _find_big_acc($x) : 0; |
|
11218
|
1
|
|
|
|
|
3
|
my $w; |
|
11219
|
|
|
|
|
|
|
|
|
11220
|
|
|
|
|
|
|
# Approximation |
|
11221
|
1
|
50
|
|
|
|
7
|
if ($x < -0.06) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
11222
|
0
|
|
|
|
|
0
|
my $ti = $x * 2 * exp($x-$x+1) + 2; |
|
11223
|
0
|
0
|
|
|
|
0
|
return -1 if $ti <= 0; |
|
11224
|
0
|
|
|
|
|
0
|
my $t = sqrt($ti); |
|
11225
|
0
|
|
|
|
|
0
|
$w = (-1 + 1/6*$t + (257/720)*$t*$t + (13/720)*$t*$t*$t) / (1 + (5/6)*$t + (103/720)*$t*$t); |
|
11226
|
|
|
|
|
|
|
} elsif ($x < 1.363) { |
|
11227
|
0
|
|
|
|
|
0
|
my $l1 = log($x + 1); |
|
11228
|
0
|
|
|
|
|
0
|
$w = $l1 * (1 - log(1+$l1) / (2+$l1)); |
|
11229
|
|
|
|
|
|
|
} elsif ($x < 3.7) { |
|
11230
|
0
|
|
|
|
|
0
|
my $l1 = log($x); |
|
11231
|
0
|
|
|
|
|
0
|
my $l2 = log($l1); |
|
11232
|
0
|
|
|
|
|
0
|
$w = $l1 - $l2 - log(1 - $l2/$l1)/2.0; |
|
11233
|
|
|
|
|
|
|
} else { |
|
11234
|
1
|
|
|
|
|
4
|
my $l1 = log($x); |
|
11235
|
1
|
|
|
|
|
3
|
my $l2 = log($l1); |
|
11236
|
1
|
|
|
|
|
4
|
my $d1 = 2 * $l1 * $l1; |
|
11237
|
1
|
|
|
|
|
3
|
my $d2 = 3 * $l1 * $d1; |
|
11238
|
1
|
|
|
|
|
3
|
my $d3 = 2 * $l1 * $d2; |
|
11239
|
1
|
|
|
|
|
5
|
my $d4 = 5 * $l1 * $d3; |
|
11240
|
1
|
|
|
|
|
12
|
$w = $l1 - $l2 + $l2/$l1 + $l2*($l2-2)/$d1 |
|
11241
|
|
|
|
|
|
|
+ $l2*(6+$l2*(-9+2*$l2))/$d2 |
|
11242
|
|
|
|
|
|
|
+ $l2*(-12+$l2*(36+$l2*(-22+3*$l2)))/$d3 |
|
11243
|
|
|
|
|
|
|
+ $l2*(60+$l2*(-300+$l2*(350+$l2*(-125+12*$l2))))/$d4; |
|
11244
|
|
|
|
|
|
|
} |
|
11245
|
|
|
|
|
|
|
|
|
11246
|
|
|
|
|
|
|
# Now iterate to get the answer |
|
11247
|
|
|
|
|
|
|
# |
|
11248
|
|
|
|
|
|
|
# Newton: |
|
11249
|
|
|
|
|
|
|
# $w = $w*(log($x) - log($w) + 1) / ($w+1); |
|
11250
|
|
|
|
|
|
|
# Halley: |
|
11251
|
|
|
|
|
|
|
# my $e = exp($w); |
|
11252
|
|
|
|
|
|
|
# my $f = $w * $e - $x; |
|
11253
|
|
|
|
|
|
|
# $w -= $f / ($w*$e+$e - ($w+2)*$f/(2*$w+2)); |
|
11254
|
|
|
|
|
|
|
# |
|
11255
|
|
|
|
|
|
|
# Also see https://arxiv.org/pdf/2008.06122 |
|
11256
|
|
|
|
|
|
|
# https://people.eecs.berkeley.edu/~wkahan/Math273/LmbrtsW.pdf |
|
11257
|
|
|
|
|
|
|
|
|
11258
|
|
|
|
|
|
|
# Fritsch converges quadratically, so tolerance could be 4x smaller. Use 2x. |
|
11259
|
1
|
|
|
|
|
2
|
my $tol = 1.054e-8; # sqrt(double eps) |
|
11260
|
1
|
50
|
|
|
|
7
|
if ($xacc) { |
|
11261
|
0
|
|
|
|
|
0
|
$tol = 10**(-int(1+$xacc/2)); |
|
11262
|
0
|
|
|
|
|
0
|
$w->accuracy($xacc+15); |
|
11263
|
|
|
|
|
|
|
} |
|
11264
|
1
|
|
|
|
|
4
|
for (1 .. 200) { |
|
11265
|
2
|
50
|
|
|
|
9
|
last if $w == 0; |
|
11266
|
2
|
|
|
|
|
5
|
my $w1 = $w + 1; |
|
11267
|
2
|
|
|
|
|
5
|
my $zn = log($x/$w) - $w; |
|
11268
|
2
|
|
|
|
|
6
|
my $qn = $w1 * 2 * ($w1+(2*$zn/3)); |
|
11269
|
2
|
|
|
|
|
6
|
my $en = ($zn/$w1) * ($qn-$zn)/($qn-$zn*2); |
|
11270
|
2
|
|
|
|
|
5
|
my $wen = $w * $en; |
|
11271
|
2
|
|
|
|
|
4
|
$w += $wen; |
|
11272
|
2
|
100
|
|
|
|
8
|
last if abs($wen) < $tol; |
|
11273
|
|
|
|
|
|
|
} |
|
11274
|
1
|
50
|
|
|
|
4
|
$w->accuracy($xacc) if $xacc; |
|
11275
|
1
|
|
|
|
|
10
|
return $w; |
|
11276
|
|
|
|
|
|
|
} |
|
11277
|
|
|
|
|
|
|
|
|
11278
|
|
|
|
|
|
|
my $_Pi = "3.141592653589793238462643383279503"; |
|
11279
|
|
|
|
|
|
|
sub Pi { |
|
11280
|
986
|
|
|
986
|
0
|
1459537
|
my($digits) = @_; |
|
11281
|
986
|
50
|
|
|
|
4700
|
return 0.0+$_Pi unless $digits; |
|
11282
|
986
|
50
|
|
|
|
4896
|
return 0.0+sprintf("%.*lf", $digits-1, $_Pi) if $digits < 15; |
|
11283
|
986
|
100
|
|
|
|
5110
|
return _upgrade_to_float($_Pi, $digits) if $digits < 30; |
|
11284
|
|
|
|
|
|
|
|
|
11285
|
|
|
|
|
|
|
# Performance ranking: |
|
11286
|
|
|
|
|
|
|
# MPU::GMP Uses AGM or Ramanujan/Chudnosky with binary splitting |
|
11287
|
|
|
|
|
|
|
# MPFR Uses AGM, from 1x to 1/4x the above |
|
11288
|
|
|
|
|
|
|
# Perl AGM w/GMP also AGM, nice growth rate, but slower than above |
|
11289
|
|
|
|
|
|
|
# C pidigits much worse than above, but faster than the others |
|
11290
|
|
|
|
|
|
|
# Perl AGM without Math::BigInt::GMP, it's sluggish |
|
11291
|
|
|
|
|
|
|
# Math::BigFloat new versions use AGM, old ones are *very* slow |
|
11292
|
|
|
|
|
|
|
# |
|
11293
|
|
|
|
|
|
|
# With a few thousand digits, any of the top 4 are fine. |
|
11294
|
|
|
|
|
|
|
# At 10k digits, the first two are pulling away. |
|
11295
|
|
|
|
|
|
|
# At 50k digits, the first three are 5-20x faster than C pidigits, and |
|
11296
|
|
|
|
|
|
|
# pray you're not having to the Perl BigFloat methods without GMP. |
|
11297
|
|
|
|
|
|
|
# At 100k digits, the first two are 15x faster than the third, C pidigits |
|
11298
|
|
|
|
|
|
|
# is 200x slower, and the rest thousands of times slower. |
|
11299
|
|
|
|
|
|
|
# At 1M digits, the first is under 1 second, MPFR under 2 seconds, |
|
11300
|
|
|
|
|
|
|
# Perl AGM (Math::BigInt::GMP) over a minute, C pidigits 1.5 hours. |
|
11301
|
|
|
|
|
|
|
# |
|
11302
|
|
|
|
|
|
|
# Interestingly, Math::BigInt::Pari, while greatly faster than Calc, is |
|
11303
|
|
|
|
|
|
|
# *much* slower than GMP for these operations (both AGM and Machin). While |
|
11304
|
|
|
|
|
|
|
# Perl AGM with the Math::BigInt::GMP backend will pull away from C pidigits, |
|
11305
|
|
|
|
|
|
|
# using it with the other backends doesn't do so. |
|
11306
|
|
|
|
|
|
|
# |
|
11307
|
|
|
|
|
|
|
# The GMP program at https://gmplib.org/download/misc/gmp-chudnovsky.c |
|
11308
|
|
|
|
|
|
|
# will run ~4x faster than MPFR and ~1.5x faster than MPU::GMP. |
|
11309
|
|
|
|
|
|
|
|
|
11310
|
972
|
|
|
|
|
6858
|
my $have_bigint_gmp = Math::BigInt->config()->{lib} =~ /GMP/; |
|
11311
|
972
|
|
|
|
|
204604
|
my $have_xdigits = getconfig()->{'xs'}; |
|
11312
|
972
|
|
|
|
|
4118
|
my $_verbose = getconfig()->{'verbose'}; |
|
11313
|
|
|
|
|
|
|
|
|
11314
|
972
|
50
|
|
|
|
5230
|
if ($Math::Prime::Util::_GMPfunc{"Pi"}) { |
|
11315
|
0
|
0
|
|
|
|
0
|
print " using MPUGMP for Pi($digits)\n" if $_verbose; |
|
11316
|
0
|
|
|
|
|
0
|
return _upgrade_to_float( Math::Prime::Util::GMP::Pi($digits) ); |
|
11317
|
|
|
|
|
|
|
} |
|
11318
|
|
|
|
|
|
|
|
|
11319
|
|
|
|
|
|
|
# We could consider looking for Math::MPFR or Math::Pari |
|
11320
|
|
|
|
|
|
|
|
|
11321
|
|
|
|
|
|
|
# This has a *much* better growth rate than the later solutions. |
|
11322
|
972
|
100
|
33
|
|
|
6249
|
if ( !$have_xdigits || ($have_bigint_gmp && $digits > 100) ) { |
|
|
|
|
66
|
|
|
|
|
|
11323
|
1
|
50
|
|
|
|
4
|
print " using Perl AGM for Pi($digits)\n" if $_verbose; |
|
11324
|
|
|
|
|
|
|
# Brent-Salamin (aka AGM or Gauss-Legendre) |
|
11325
|
1
|
|
|
|
|
4
|
$digits += 8; |
|
11326
|
1
|
|
|
|
|
5
|
my $HALF = _upgrade_to_float(0.5); |
|
11327
|
1
|
|
|
|
|
577
|
my ($an, $bn, $tn, $pn) = ($HALF->copy->bone, $HALF->copy->bsqrt($digits), |
|
11328
|
|
|
|
|
|
|
$HALF->copy->bmul($HALF), $HALF->copy->bone); |
|
11329
|
1
|
|
|
|
|
12013
|
while ($pn < $digits) { |
|
11330
|
7
|
|
|
|
|
8388
|
my $prev_an = $an->copy; |
|
11331
|
7
|
|
|
|
|
346
|
$an->badd($bn)->bmul($HALF, $digits); |
|
11332
|
7
|
|
|
|
|
9825
|
$bn->bmul($prev_an)->bsqrt($digits); |
|
11333
|
7
|
|
|
|
|
79080
|
$prev_an->bsub($an); |
|
11334
|
7
|
|
|
|
|
6970
|
$tn->bsub($pn * $prev_an * $prev_an); |
|
11335
|
7
|
|
|
|
|
22953
|
$pn->badd($pn); |
|
11336
|
|
|
|
|
|
|
} |
|
11337
|
1
|
|
|
|
|
1286
|
$an->badd($bn); |
|
11338
|
1
|
|
|
|
|
753
|
$an->bmul($an,$digits)->bdiv(4*$tn, $digits-8); |
|
11339
|
1
|
|
|
|
|
4039
|
return $an; |
|
11340
|
|
|
|
|
|
|
} |
|
11341
|
|
|
|
|
|
|
|
|
11342
|
|
|
|
|
|
|
# Spigot method in C. Low overhead but not good growth rate. |
|
11343
|
971
|
50
|
|
|
|
3071
|
if ($have_xdigits) { |
|
11344
|
971
|
50
|
|
|
|
2571
|
print " using XS spigot for Pi($digits)\n" if $_verbose; |
|
11345
|
971
|
|
|
|
|
3774270
|
return _upgrade_to_float(Math::Prime::Util::_pidigits($digits)); |
|
11346
|
|
|
|
|
|
|
} |
|
11347
|
|
|
|
|
|
|
|
|
11348
|
|
|
|
|
|
|
# We're going to have to use the Math::BigFloat code. |
|
11349
|
|
|
|
|
|
|
# 1) it rounds incorrectly (e.g. 761, 1372, 1509,...). |
|
11350
|
|
|
|
|
|
|
# Fix by adding some digits and rounding. |
|
11351
|
|
|
|
|
|
|
# 2) AGM is *much* faster once past ~2000 digits |
|
11352
|
|
|
|
|
|
|
# 3) It is very slow without the GMP backend. The Pari backend helps |
|
11353
|
|
|
|
|
|
|
# but it still pretty bad. With Calc it's glacial for large inputs. |
|
11354
|
|
|
|
|
|
|
|
|
11355
|
|
|
|
|
|
|
# Math::BigFloat AGM spigot AGM |
|
11356
|
|
|
|
|
|
|
# Size GMP Pari Calc GMP Pari Calc C C+GMP |
|
11357
|
|
|
|
|
|
|
# 500 0.04 0.60 0.30 0.08 0.10 0.47 0.09 0.06 |
|
11358
|
|
|
|
|
|
|
# 1000 0.04 0.11 1.82 0.09 0.14 1.82 0.09 0.06 |
|
11359
|
|
|
|
|
|
|
# 2000 0.07 0.37 13.5 0.09 0.34 9.16 0.10 0.06 |
|
11360
|
|
|
|
|
|
|
# 4000 0.14 2.17 107.8 0.12 1.14 39.7 0.20 0.06 |
|
11361
|
|
|
|
|
|
|
# 8000 0.52 15.7 0.22 4.63 186.2 0.56 0.08 |
|
11362
|
|
|
|
|
|
|
# 16000 2.73 121.8 0.52 19.2 2.00 0.08 |
|
11363
|
|
|
|
|
|
|
# 32000 15.4 1.42 7.78 0.12 |
|
11364
|
|
|
|
|
|
|
# ^ ^ ^ |
|
11365
|
|
|
|
|
|
|
# | use this THIRD ---+ | |
|
11366
|
|
|
|
|
|
|
# use this SECOND ---+ | |
|
11367
|
|
|
|
|
|
|
# use this FIRST ---+ |
|
11368
|
|
|
|
|
|
|
# approx |
|
11369
|
|
|
|
|
|
|
# growth 5.6x 7.6x 8.0x 2.7x 4.1x 4.7x 3.9x 2.0x |
|
11370
|
|
|
|
|
|
|
|
|
11371
|
0
|
0
|
|
|
|
0
|
print " using BigFloat for Pi($digits)\n" if $_verbose; |
|
11372
|
0
|
|
|
|
|
0
|
_upgrade_to_float(0); |
|
11373
|
0
|
|
|
|
|
0
|
return Math::BigFloat::bpi($digits+10)->round($digits); |
|
11374
|
|
|
|
|
|
|
} |
|
11375
|
|
|
|
|
|
|
|
|
11376
|
|
|
|
|
|
|
################################################################################ |
|
11377
|
|
|
|
|
|
|
|
|
11378
|
|
|
|
|
|
|
sub forprimes { |
|
11379
|
878
|
|
|
878
|
0
|
91043
|
my($sub, $beg, $end) = @_; |
|
11380
|
878
|
100
|
|
|
|
1922
|
if (defined $end) { validate_integer_nonneg($beg); } |
|
|
863
|
|
|
|
|
1890
|
|
|
11381
|
15
|
|
|
|
|
48
|
else { ($beg,$end) = (2, $beg); } |
|
11382
|
878
|
|
|
|
|
2426
|
validate_integer_nonneg($end); |
|
11383
|
878
|
50
|
|
|
|
1947
|
$beg = 2 if $beg < 2; |
|
11384
|
|
|
|
|
|
|
|
|
11385
|
878
|
|
|
|
|
3018
|
my $oldforexit = Math::Prime::Util::_start_for_loop(); |
|
11386
|
|
|
|
|
|
|
{ |
|
11387
|
878
|
|
|
|
|
1625
|
my $pp; |
|
|
878
|
|
|
|
|
1237
|
|
|
11388
|
878
|
|
|
|
|
2302
|
local *_ = \$pp; |
|
11389
|
878
|
|
|
|
|
2634
|
for (my $p = Mnext_prime($beg-1); $p <= $end; $p = Mnext_prime($p)) { |
|
11390
|
3181
|
|
|
|
|
6039
|
$pp = $p; |
|
11391
|
3181
|
|
|
|
|
7351
|
$sub->(); |
|
11392
|
3181
|
100
|
|
|
|
8700
|
last if Math::Prime::Util::_get_forexit(); |
|
11393
|
|
|
|
|
|
|
} |
|
11394
|
|
|
|
|
|
|
} |
|
11395
|
878
|
|
|
|
|
2567
|
Math::Prime::Util::_end_for_loop($oldforexit); |
|
11396
|
|
|
|
|
|
|
} |
|
11397
|
|
|
|
|
|
|
|
|
11398
|
|
|
|
|
|
|
|
|
11399
|
|
|
|
|
|
|
sub _forcomp_sub { |
|
11400
|
4
|
|
|
4
|
|
18
|
my($what, $sub, $beg, $end) = @_; |
|
11401
|
4
|
50
|
|
|
|
17
|
if (defined $end) { validate_integer_nonneg($beg); } |
|
|
4
|
|
|
|
|
32
|
|
|
11402
|
0
|
|
|
|
|
0
|
else { ($beg,$end) = (0, $beg); } |
|
11403
|
4
|
|
|
|
|
23
|
validate_integer_nonneg($end); |
|
11404
|
|
|
|
|
|
|
|
|
11405
|
4
|
|
|
|
|
9
|
my $cinc = 1; |
|
11406
|
4
|
100
|
|
|
|
28
|
if ($what eq 'oddcomposites') { |
|
11407
|
2
|
50
|
|
|
|
12
|
$beg = 9 if $beg < 9; |
|
11408
|
2
|
50
|
|
|
|
119
|
$beg++ unless $beg % 2 == 1; |
|
11409
|
2
|
|
|
|
|
397
|
$cinc = 2; |
|
11410
|
|
|
|
|
|
|
} else { |
|
11411
|
2
|
50
|
|
|
|
10
|
$beg = 4 if $beg < 4; |
|
11412
|
|
|
|
|
|
|
} |
|
11413
|
4
|
50
|
33
|
|
|
264
|
$end = tobigint(~0) if $end == ~0 && !ref($end); |
|
11414
|
4
|
|
|
|
|
434
|
my $oldforexit = Math::Prime::Util::_start_for_loop(); |
|
11415
|
|
|
|
|
|
|
{ |
|
11416
|
4
|
|
|
|
|
11
|
my $pp; |
|
|
4
|
|
|
|
|
8
|
|
|
11417
|
4
|
|
|
|
|
12
|
local *_ = \$pp; |
|
11418
|
4
|
|
|
|
|
28
|
for (my $p = Mnext_prime($beg-1); $beg <= $end; $p = Mnext_prime($p)) { |
|
11419
|
14
|
|
100
|
|
|
294
|
for ( ; $beg < $p && $beg <= $end ; $beg += $cinc ) { |
|
11420
|
14
|
|
|
|
|
941
|
$pp = $beg; |
|
11421
|
14
|
|
|
|
|
66
|
$sub->(); |
|
11422
|
14
|
50
|
|
|
|
304
|
last if Math::Prime::Util::_get_forexit(); |
|
11423
|
|
|
|
|
|
|
} |
|
11424
|
14
|
|
|
|
|
1473
|
$beg += $cinc; |
|
11425
|
14
|
50
|
|
|
|
1176
|
last if Math::Prime::Util::_get_forexit(); |
|
11426
|
|
|
|
|
|
|
} |
|
11427
|
|
|
|
|
|
|
} |
|
11428
|
4
|
|
|
|
|
135
|
Math::Prime::Util::_end_for_loop($oldforexit); |
|
11429
|
|
|
|
|
|
|
} |
|
11430
|
|
|
|
|
|
|
sub forcomposites { |
|
11431
|
2
|
|
|
2
|
0
|
1427
|
_forcomp_sub('composites', @_); |
|
11432
|
|
|
|
|
|
|
} |
|
11433
|
|
|
|
|
|
|
sub foroddcomposites { |
|
11434
|
2
|
|
|
2
|
0
|
902
|
_forcomp_sub('oddcomposites', @_); |
|
11435
|
|
|
|
|
|
|
} |
|
11436
|
|
|
|
|
|
|
sub forsemiprimes { |
|
11437
|
3
|
|
|
3
|
0
|
1409
|
foralmostprimes($_[0], 2, $_[1], $_[2]); |
|
11438
|
|
|
|
|
|
|
} |
|
11439
|
|
|
|
|
|
|
|
|
11440
|
|
|
|
|
|
|
sub _forfac_sub { |
|
11441
|
15
|
|
|
15
|
|
58
|
my($sf, $sub, $beg, $end) = @_; |
|
11442
|
15
|
100
|
|
|
|
45
|
if (defined $end) { validate_integer_nonneg($beg); } |
|
|
7
|
|
|
|
|
62
|
|
|
11443
|
8
|
|
|
|
|
18
|
else { ($beg,$end) = (1, $beg); } |
|
11444
|
15
|
|
|
|
|
175
|
validate_integer_nonneg($end); |
|
11445
|
15
|
50
|
|
|
|
164
|
$beg = 1 if $beg < 1; |
|
11446
|
|
|
|
|
|
|
|
|
11447
|
15
|
|
|
|
|
1309
|
my $oldforexit = Math::Prime::Util::_start_for_loop(); |
|
11448
|
|
|
|
|
|
|
{ |
|
11449
|
15
|
|
|
|
|
33
|
my $pp; |
|
|
15
|
|
|
|
|
28
|
|
|
11450
|
15
|
|
|
|
|
41
|
local *_ = \$pp; |
|
11451
|
15
|
|
|
|
|
47
|
while ($beg <= $end) { |
|
11452
|
174
|
100
|
100
|
|
|
3098
|
if (!$sf || Mis_square_free($beg)) { |
|
11453
|
123
|
|
|
|
|
183
|
$pp = $beg; |
|
11454
|
123
|
100
|
|
|
|
275
|
if ($sf == 2) { |
|
11455
|
14
|
|
|
|
|
31
|
$sub->(); |
|
11456
|
|
|
|
|
|
|
} else { |
|
11457
|
109
|
|
|
|
|
314
|
my @f = Mfactor($beg); |
|
11458
|
109
|
|
|
|
|
320
|
$sub->(@f); |
|
11459
|
|
|
|
|
|
|
} |
|
11460
|
123
|
50
|
|
|
|
1204
|
last if Math::Prime::Util::_get_forexit(); |
|
11461
|
|
|
|
|
|
|
} |
|
11462
|
174
|
|
|
|
|
4121
|
$beg++; |
|
11463
|
|
|
|
|
|
|
} |
|
11464
|
|
|
|
|
|
|
} |
|
11465
|
15
|
|
|
|
|
1509
|
Math::Prime::Util::_end_for_loop($oldforexit); |
|
11466
|
|
|
|
|
|
|
} |
|
11467
|
|
|
|
|
|
|
sub forfactored { |
|
11468
|
4
|
|
|
4
|
0
|
1604
|
_forfac_sub(0, @_); |
|
11469
|
|
|
|
|
|
|
} |
|
11470
|
|
|
|
|
|
|
sub forsquarefree { |
|
11471
|
9
|
|
|
9
|
0
|
1395
|
_forfac_sub(1, @_); |
|
11472
|
|
|
|
|
|
|
} |
|
11473
|
|
|
|
|
|
|
sub forsquarefreeint { |
|
11474
|
2
|
|
|
2
|
0
|
2057
|
_forfac_sub(2, @_); |
|
11475
|
|
|
|
|
|
|
} |
|
11476
|
|
|
|
|
|
|
|
|
11477
|
|
|
|
|
|
|
sub fordivisors { |
|
11478
|
17
|
|
|
17
|
0
|
1563
|
my($sub, $n) = @_; |
|
11479
|
17
|
|
|
|
|
65
|
validate_integer_nonneg($n); |
|
11480
|
17
|
|
|
|
|
69
|
my @divisors = Mdivisors($n); |
|
11481
|
17
|
|
|
|
|
116
|
my $oldforexit = Math::Prime::Util::_start_for_loop(); |
|
11482
|
|
|
|
|
|
|
{ |
|
11483
|
17
|
|
|
|
|
30
|
my $pp; |
|
|
17
|
|
|
|
|
29
|
|
|
11484
|
17
|
|
|
|
|
48
|
local *_ = \$pp; |
|
11485
|
17
|
|
|
|
|
44
|
foreach my $d (@divisors) { |
|
11486
|
80
|
|
|
|
|
124
|
$pp = $d; |
|
11487
|
80
|
|
|
|
|
193
|
$sub->(); |
|
11488
|
80
|
50
|
|
|
|
367
|
last if Math::Prime::Util::_get_forexit(); |
|
11489
|
|
|
|
|
|
|
} |
|
11490
|
|
|
|
|
|
|
} |
|
11491
|
17
|
|
|
|
|
76
|
Math::Prime::Util::_end_for_loop($oldforexit); |
|
11492
|
|
|
|
|
|
|
} |
|
11493
|
|
|
|
|
|
|
|
|
11494
|
|
|
|
|
|
|
sub forpart { |
|
11495
|
1
|
|
|
1
|
0
|
5
|
my($sub, $n, $rhash) = @_; |
|
11496
|
1
|
|
|
|
|
5
|
_forcompositions(1, $sub, $n, $rhash); |
|
11497
|
|
|
|
|
|
|
} |
|
11498
|
|
|
|
|
|
|
sub forcomp { |
|
11499
|
1
|
|
|
1
|
0
|
16
|
my($sub, $n, $rhash) = @_; |
|
11500
|
1
|
|
|
|
|
6
|
_forcompositions(0, $sub, $n, $rhash); |
|
11501
|
|
|
|
|
|
|
} |
|
11502
|
|
|
|
|
|
|
sub _forcompositions { |
|
11503
|
2
|
|
|
2
|
|
8
|
my($ispart, $sub, $n, $rhash) = @_; |
|
11504
|
2
|
|
|
|
|
19
|
validate_integer_nonneg($n); |
|
11505
|
2
|
|
|
|
|
17
|
my($mina, $maxa, $minn, $maxn, $primeq) = (1,$n,1,$n,-1); |
|
11506
|
2
|
100
|
|
|
|
17
|
if (defined $rhash) { |
|
11507
|
1
|
50
|
|
|
|
7
|
croak "forpart second argument must be a hash reference" |
|
11508
|
|
|
|
|
|
|
unless ref($rhash) eq 'HASH'; |
|
11509
|
1
|
50
|
|
|
|
6
|
if (defined $rhash->{amin}) { |
|
11510
|
1
|
|
|
|
|
3
|
$mina = $rhash->{amin}; |
|
11511
|
1
|
|
|
|
|
5
|
validate_integer_nonneg($mina); |
|
11512
|
|
|
|
|
|
|
} |
|
11513
|
1
|
50
|
|
|
|
6
|
if (defined $rhash->{amax}) { |
|
11514
|
0
|
|
|
|
|
0
|
$maxa = $rhash->{amax}; |
|
11515
|
0
|
|
|
|
|
0
|
validate_integer_nonneg($maxa); |
|
11516
|
|
|
|
|
|
|
} |
|
11517
|
1
|
50
|
|
|
|
5
|
$minn = $maxn = $rhash->{n} if defined $rhash->{n}; |
|
11518
|
1
|
50
|
|
|
|
32
|
$minn = $rhash->{nmin} if defined $rhash->{nmin}; |
|
11519
|
1
|
50
|
|
|
|
5
|
$maxn = $rhash->{nmax} if defined $rhash->{nmax}; |
|
11520
|
1
|
|
|
|
|
6
|
validate_integer_nonneg($minn); |
|
11521
|
1
|
|
|
|
|
5
|
validate_integer_nonneg($maxn); |
|
11522
|
1
|
50
|
|
|
|
5
|
if (defined $rhash->{prime}) { |
|
11523
|
0
|
|
|
|
|
0
|
$primeq = $rhash->{prime}; |
|
11524
|
0
|
|
|
|
|
0
|
validate_integer_nonneg($primeq); |
|
11525
|
|
|
|
|
|
|
} |
|
11526
|
1
|
50
|
|
|
|
4
|
$mina = 1 if $mina < 1; |
|
11527
|
1
|
50
|
|
|
|
5
|
$maxa = $n if $maxa > $n; |
|
11528
|
1
|
50
|
|
|
|
6
|
$minn = 1 if $minn < 1; |
|
11529
|
1
|
50
|
|
|
|
4
|
$maxn = $n if $maxn > $n; |
|
11530
|
1
|
50
|
33
|
|
|
18
|
$primeq = 2 if $primeq != -1 && $primeq != 0; |
|
11531
|
|
|
|
|
|
|
} |
|
11532
|
|
|
|
|
|
|
|
|
11533
|
2
|
50
|
33
|
|
|
10
|
$sub->() if $n == 0 && $minn <= 1; |
|
11534
|
2
|
50
|
33
|
|
|
40
|
return if $n < $minn || $minn > $maxn || $mina > $maxa || $maxn <= 0 || $maxa <= 0; |
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
11535
|
|
|
|
|
|
|
|
|
11536
|
2
|
|
|
|
|
10
|
my $oldforexit = Math::Prime::Util::_start_for_loop(); |
|
11537
|
2
|
|
|
|
|
5
|
my ($x, $y, $r, $k); |
|
11538
|
2
|
|
|
|
|
12
|
my @a = (0) x ($n); |
|
11539
|
2
|
|
|
|
|
3
|
$k = 1; |
|
11540
|
2
|
|
|
|
|
15
|
$a[0] = $mina - 1; |
|
11541
|
2
|
|
|
|
|
6
|
$a[1] = $n - $mina + 1; |
|
11542
|
2
|
|
|
|
|
34
|
while ($k != 0) { |
|
11543
|
37
|
|
|
|
|
129
|
$x = $a[$k-1]+1; |
|
11544
|
37
|
|
|
|
|
76
|
$y = $a[$k]-1; |
|
11545
|
37
|
|
|
|
|
69
|
$k--; |
|
11546
|
37
|
100
|
|
|
|
82
|
$r = $ispart ? $x : 1; |
|
11547
|
37
|
|
|
|
|
99
|
while ($r <= $y) { |
|
11548
|
35
|
|
|
|
|
68
|
$a[$k] = $x; |
|
11549
|
35
|
|
|
|
|
87
|
$x = $r; |
|
11550
|
35
|
|
|
|
|
63
|
$y -= $x; |
|
11551
|
35
|
|
|
|
|
110
|
$k++; |
|
11552
|
|
|
|
|
|
|
} |
|
11553
|
37
|
|
|
|
|
79
|
$a[$k] = $x + $y; |
|
11554
|
|
|
|
|
|
|
# Restrict size |
|
11555
|
37
|
|
|
|
|
92
|
while ($k+1 > $maxn) { |
|
11556
|
0
|
|
|
|
|
0
|
$a[$k-1] += $a[$k]; |
|
11557
|
0
|
|
|
|
|
0
|
$k--; |
|
11558
|
|
|
|
|
|
|
} |
|
11559
|
37
|
100
|
|
|
|
99
|
next if $k+1 < $minn; |
|
11560
|
|
|
|
|
|
|
# Restrict values |
|
11561
|
31
|
100
|
66
|
|
|
116
|
if ($mina > 1 || $maxa < $n) { |
|
11562
|
26
|
50
|
|
|
|
58
|
last if $a[0] > $maxa; |
|
11563
|
26
|
50
|
|
|
|
54
|
if ($ispart) { |
|
11564
|
0
|
0
|
|
|
|
0
|
next if $a[$k] > $maxa; |
|
11565
|
|
|
|
|
|
|
} else { |
|
11566
|
26
|
100
|
|
64
|
|
149
|
next if Mvecany(sub{ $_ < $mina || $_ > $maxa }, @a[0..$k]); |
|
|
64
|
100
|
|
|
|
373
|
|
|
11567
|
|
|
|
|
|
|
} |
|
11568
|
|
|
|
|
|
|
} |
|
11569
|
8
|
50
|
33
|
0
|
|
27
|
next if $primeq == 0 && Mvecany(sub{ Mis_prime($_) }, @a[0..$k]); |
|
|
0
|
|
|
|
|
0
|
|
|
11570
|
8
|
50
|
33
|
0
|
|
24
|
next if $primeq == 2 && Mvecany(sub{ !Mis_prime($_) }, @a[0..$k]); |
|
|
0
|
|
|
|
|
0
|
|
|
11571
|
8
|
50
|
|
|
|
31
|
last if Math::Prime::Util::_get_forexit(); |
|
11572
|
8
|
|
|
|
|
28
|
$sub->(@a[0 .. $k]); |
|
11573
|
|
|
|
|
|
|
} |
|
11574
|
2
|
|
|
|
|
12
|
Math::Prime::Util::_end_for_loop($oldforexit); |
|
11575
|
|
|
|
|
|
|
} |
|
11576
|
|
|
|
|
|
|
sub forcomb { |
|
11577
|
1
|
|
|
1
|
0
|
15
|
my($sub, $n, $k) = @_; |
|
11578
|
1
|
|
|
|
|
6
|
validate_integer_nonneg($n); |
|
11579
|
|
|
|
|
|
|
|
|
11580
|
1
|
|
|
|
|
3
|
my($begk, $endk); |
|
11581
|
1
|
50
|
|
|
|
9
|
if (defined $k) { |
|
11582
|
1
|
|
|
|
|
4
|
validate_integer_nonneg($k); |
|
11583
|
1
|
50
|
|
|
|
5
|
return if $k > $n; |
|
11584
|
1
|
|
|
|
|
4
|
$begk = $endk = $k; |
|
11585
|
|
|
|
|
|
|
} else { |
|
11586
|
0
|
|
|
|
|
0
|
$begk = 0; |
|
11587
|
0
|
|
|
|
|
0
|
$endk = $n; |
|
11588
|
|
|
|
|
|
|
} |
|
11589
|
|
|
|
|
|
|
|
|
11590
|
1
|
|
|
|
|
5
|
my $oldforexit = Math::Prime::Util::_start_for_loop(); |
|
11591
|
1
|
|
|
|
|
5
|
for my $k ($begk .. $endk) { |
|
11592
|
1
|
50
|
|
|
|
5
|
if ($k == 0) { |
|
11593
|
0
|
|
|
|
|
0
|
$sub->(); |
|
11594
|
|
|
|
|
|
|
} else { |
|
11595
|
1
|
|
|
|
|
7
|
my @c = 0 .. $k-1; |
|
11596
|
1
|
|
|
|
|
2
|
while (1) { |
|
11597
|
3
|
|
|
|
|
13
|
$sub->(@c); |
|
11598
|
3
|
50
|
|
|
|
20
|
last if Math::Prime::Util::_get_forexit(); |
|
11599
|
3
|
100
|
|
|
|
12
|
next if $c[-1]++ < $n-1; |
|
11600
|
2
|
|
|
|
|
5
|
my $i = $k-2; |
|
11601
|
2
|
|
100
|
|
|
18
|
$i-- while $i >= 0 && $c[$i] >= $n-($k-$i); |
|
11602
|
2
|
100
|
|
|
|
9
|
last if $i < 0; |
|
11603
|
1
|
|
|
|
|
21
|
$c[$i]++; |
|
11604
|
1
|
|
|
|
|
4
|
while (++$i < $k) { $c[$i] = $c[$i-1] + 1; } |
|
|
1
|
|
|
|
|
18
|
|
|
11605
|
|
|
|
|
|
|
} |
|
11606
|
|
|
|
|
|
|
} |
|
11607
|
1
|
50
|
|
|
|
36
|
last if Math::Prime::Util::_get_forexit(); |
|
11608
|
|
|
|
|
|
|
} |
|
11609
|
1
|
|
|
|
|
4
|
Math::Prime::Util::_end_for_loop($oldforexit); |
|
11610
|
|
|
|
|
|
|
} |
|
11611
|
|
|
|
|
|
|
sub _forperm { |
|
11612
|
2
|
|
|
2
|
|
8
|
my($sub, $n, $all_perm) = @_; |
|
11613
|
2
|
50
|
|
|
|
11
|
if ($n <= 1) { |
|
11614
|
0
|
|
|
|
|
0
|
my $oldforexit = Math::Prime::Util::_start_for_loop(); |
|
11615
|
0
|
0
|
|
|
|
0
|
if ($n == 0) { $sub->(); } else { $sub->(0); } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
11616
|
0
|
|
|
|
|
0
|
Math::Prime::Util::_end_for_loop($oldforexit); |
|
11617
|
0
|
|
|
|
|
0
|
return; |
|
11618
|
|
|
|
|
|
|
} |
|
11619
|
2
|
|
|
|
|
12
|
my $k = $n; |
|
11620
|
2
|
|
|
|
|
10
|
my @c = reverse 0 .. $k-1; |
|
11621
|
2
|
|
|
|
|
6
|
my $inc = 0; |
|
11622
|
2
|
|
|
|
|
5
|
my $send = 1; |
|
11623
|
2
|
|
|
|
|
44
|
my $oldforexit = Math::Prime::Util::_start_for_loop(); |
|
11624
|
2
|
|
|
|
|
19
|
while (1) { |
|
11625
|
30
|
100
|
|
|
|
70
|
if (!$all_perm) { # Derangements via simple filtering. |
|
11626
|
24
|
|
|
|
|
37
|
$send = 1; |
|
11627
|
24
|
|
|
|
|
46
|
for my $p (0 .. $#c) { |
|
11628
|
67
|
100
|
|
|
|
164
|
if ($c[$p] == $k-$p-1) { |
|
11629
|
15
|
|
|
|
|
21
|
$send = 0; |
|
11630
|
15
|
|
|
|
|
30
|
last; |
|
11631
|
|
|
|
|
|
|
} |
|
11632
|
|
|
|
|
|
|
} |
|
11633
|
|
|
|
|
|
|
} |
|
11634
|
30
|
100
|
|
|
|
83
|
if ($send) { |
|
11635
|
15
|
|
|
|
|
49
|
$sub->(reverse @c); |
|
11636
|
15
|
50
|
|
|
|
78
|
last if Math::Prime::Util::_get_forexit(); |
|
11637
|
|
|
|
|
|
|
} |
|
11638
|
30
|
100
|
|
|
|
66
|
if (++$inc & 1) { |
|
11639
|
15
|
|
|
|
|
37
|
@c[0,1] = @c[1,0]; |
|
11640
|
15
|
|
|
|
|
28
|
next; |
|
11641
|
|
|
|
|
|
|
} |
|
11642
|
15
|
|
|
|
|
29
|
my $j = 2; |
|
11643
|
15
|
|
100
|
|
|
71
|
$j++ while $j < $k && $c[$j] > $c[$j-1]; |
|
11644
|
15
|
100
|
|
|
|
36
|
last if $j >= $k; |
|
11645
|
13
|
|
|
|
|
25
|
my $m = 0; |
|
11646
|
13
|
|
|
|
|
67
|
$m++ while $c[$j] > $c[$m]; |
|
11647
|
13
|
|
|
|
|
32
|
@c[$j,$m] = @c[$m,$j]; |
|
11648
|
13
|
|
|
|
|
47
|
@c[0..$j-1] = reverse @c[0..$j-1]; |
|
11649
|
|
|
|
|
|
|
} |
|
11650
|
2
|
|
|
|
|
19
|
Math::Prime::Util::_end_for_loop($oldforexit); |
|
11651
|
|
|
|
|
|
|
} |
|
11652
|
|
|
|
|
|
|
sub forperm { |
|
11653
|
1
|
|
|
1
|
0
|
6
|
my($sub, $n, $k) = @_; |
|
11654
|
1
|
|
|
|
|
7
|
validate_integer_nonneg($n); |
|
11655
|
1
|
50
|
|
|
|
5
|
croak "Too many arguments for forperm" if defined $k; |
|
11656
|
1
|
|
|
|
|
32
|
_forperm($sub, $n, 1); |
|
11657
|
|
|
|
|
|
|
} |
|
11658
|
|
|
|
|
|
|
sub forderange { |
|
11659
|
1
|
|
|
1
|
0
|
3
|
my($sub, $n, $k) = @_; |
|
11660
|
1
|
|
|
|
|
5
|
validate_integer_nonneg($n); |
|
11661
|
1
|
50
|
|
|
|
4
|
croak "Too many arguments for forderange" if defined $k; |
|
11662
|
1
|
50
|
|
|
|
4
|
return if $n == 1; |
|
11663
|
1
|
|
|
|
|
4
|
_forperm($sub, $n, 0); |
|
11664
|
|
|
|
|
|
|
} |
|
11665
|
|
|
|
|
|
|
|
|
11666
|
|
|
|
|
|
|
sub _multiset_permutations { |
|
11667
|
78
|
|
|
78
|
|
154
|
my($sub, $prefix, $ar, $sum) = @_; |
|
11668
|
|
|
|
|
|
|
|
|
11669
|
78
|
100
|
|
|
|
166
|
return if $sum == 0; |
|
11670
|
|
|
|
|
|
|
|
|
11671
|
|
|
|
|
|
|
# Remove any values with 0 occurances |
|
11672
|
77
|
|
|
|
|
140
|
my @n = grep { $_->[1] > 0 } @$ar; |
|
|
238
|
|
|
|
|
536
|
|
|
11673
|
|
|
|
|
|
|
|
|
11674
|
77
|
50
|
|
|
|
186
|
if ($sum == 1) { # A single value |
|
|
|
100
|
|
|
|
|
|
|
11675
|
0
|
|
|
|
|
0
|
$sub->(@$prefix, $n[0]->[0]); |
|
11676
|
|
|
|
|
|
|
} elsif ($sum == 2) { # Optimize the leaf case |
|
11677
|
51
|
|
|
|
|
110
|
my($n0,$n1) = map { $_->[0] } @n; |
|
|
97
|
|
|
|
|
220
|
|
|
11678
|
51
|
100
|
|
|
|
111
|
if (@n == 1) { |
|
11679
|
5
|
|
|
|
|
15
|
$sub->(@$prefix, $n0, $n0); |
|
11680
|
|
|
|
|
|
|
} else { |
|
11681
|
46
|
|
|
|
|
136
|
$sub->(@$prefix, $n0, $n1); |
|
11682
|
46
|
100
|
|
|
|
325
|
$sub->(@$prefix, $n1, $n0) unless Math::Prime::Util::_get_forexit(); |
|
11683
|
|
|
|
|
|
|
} |
|
11684
|
|
|
|
|
|
|
} elsif (0 && $sum == scalar(@n)) { # All entries have 1 occurance |
|
11685
|
|
|
|
|
|
|
# TODO: Figure out a way to use this safely. We need to capture any |
|
11686
|
|
|
|
|
|
|
# lastfor that was seen in the forperm. |
|
11687
|
|
|
|
|
|
|
my @i = map { $_->[0] } @n; |
|
11688
|
0
|
|
|
0
|
|
0
|
Math::Prime::Util::forperm(sub { $sub->(@$prefix, @i[@_]) }, 1+$#i); |
|
11689
|
|
|
|
|
|
|
} else { # Recurse over each leading value |
|
11690
|
26
|
|
|
|
|
54
|
for my $v (@n) { |
|
11691
|
73
|
|
|
|
|
124
|
$v->[1]--; |
|
11692
|
73
|
|
|
|
|
136
|
push @$prefix, $v->[0]; |
|
11693
|
77
|
|
|
77
|
|
4983435
|
no warnings 'recursion'; |
|
|
77
|
|
|
|
|
305
|
|
|
|
77
|
|
|
|
|
138116
|
|
|
11694
|
73
|
|
|
|
|
212
|
_multiset_permutations($sub, $prefix, \@n, $sum-1); |
|
11695
|
73
|
|
|
|
|
296
|
pop @$prefix; |
|
11696
|
73
|
|
|
|
|
147
|
$v->[1]++; |
|
11697
|
73
|
100
|
|
|
|
216
|
last if Math::Prime::Util::_get_forexit(); |
|
11698
|
|
|
|
|
|
|
} |
|
11699
|
|
|
|
|
|
|
} |
|
11700
|
|
|
|
|
|
|
} |
|
11701
|
|
|
|
|
|
|
|
|
11702
|
|
|
|
|
|
|
sub numtoperm { |
|
11703
|
1
|
|
|
1
|
0
|
12
|
my($n,$k) = @_; |
|
11704
|
1
|
|
|
|
|
7
|
validate_integer_nonneg($n); |
|
11705
|
1
|
|
|
|
|
5
|
validate_integer($k); |
|
11706
|
1
|
50
|
|
|
|
5
|
return () if $n == 0; |
|
11707
|
1
|
50
|
|
|
|
4
|
return (0) if $n == 1; |
|
11708
|
1
|
|
|
|
|
8
|
my $f = Mfactorial($n-1); |
|
11709
|
1
|
50
|
33
|
|
|
11
|
$k %= Mmulint($f,$n) if $k < 0 || int($k/$f) >= $n; |
|
11710
|
1
|
|
|
|
|
4
|
my @S = map { $_ } 0 .. $n-1; |
|
|
11
|
|
|
|
|
21
|
|
|
11711
|
1
|
|
|
|
|
16
|
my @V; |
|
11712
|
1
|
|
|
|
|
7
|
while ($n-- > 0) { |
|
11713
|
11
|
|
|
|
|
21
|
my $i = int($k/$f); |
|
11714
|
11
|
|
|
|
|
52
|
push @V, splice(@S,$i,1); |
|
11715
|
11
|
100
|
|
|
|
24
|
last if $n == 0; |
|
11716
|
10
|
|
|
|
|
15
|
$k -= $i*$f; |
|
11717
|
10
|
|
|
|
|
24
|
$f /= $n; |
|
11718
|
|
|
|
|
|
|
} |
|
11719
|
1
|
|
|
|
|
14
|
@V; |
|
11720
|
|
|
|
|
|
|
} |
|
11721
|
|
|
|
|
|
|
|
|
11722
|
|
|
|
|
|
|
sub permtonum { |
|
11723
|
3
|
|
|
3
|
0
|
27652
|
my($A) = @_; |
|
11724
|
3
|
50
|
|
|
|
49
|
croak "permtonum argument must be an array reference" |
|
11725
|
|
|
|
|
|
|
unless ref($A) eq 'ARRAY'; |
|
11726
|
3
|
|
|
|
|
9
|
my $n = scalar(@$A); |
|
11727
|
3
|
100
|
|
|
|
20
|
return 0 if $n == 0; |
|
11728
|
|
|
|
|
|
|
{ |
|
11729
|
2
|
|
|
|
|
5
|
my %S; |
|
|
2
|
|
|
|
|
6
|
|
|
11730
|
2
|
|
|
|
|
25
|
for my $v (@$A) { |
|
11731
|
|
|
|
|
|
|
croak "permtonum invalid permutation array" |
|
11732
|
37
|
50
|
33
|
|
|
308
|
if !defined $v || $v < 0 || $v >= $n || $S{$v}++; |
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
11733
|
|
|
|
|
|
|
} |
|
11734
|
|
|
|
|
|
|
} |
|
11735
|
2
|
|
|
|
|
13
|
my $f = factorial($n-1); |
|
11736
|
2
|
|
|
|
|
18
|
my $rank = 0; |
|
11737
|
2
|
|
|
|
|
11
|
for my $i (0 .. $n-2) { |
|
11738
|
35
|
|
|
|
|
15701
|
my $k = 0; |
|
11739
|
35
|
|
|
|
|
127
|
for my $j ($i+1 .. $n-1) { |
|
11740
|
380
|
100
|
|
|
|
1063
|
$k++ if $A->[$j] < $A->[$i]; |
|
11741
|
|
|
|
|
|
|
} |
|
11742
|
35
|
|
|
|
|
266
|
$rank = Maddint($rank, Mmulint($k,$f)); |
|
11743
|
35
|
|
|
|
|
7067
|
$f /= $n-$i-1; |
|
11744
|
|
|
|
|
|
|
} |
|
11745
|
2
|
|
|
|
|
426
|
$rank; |
|
11746
|
|
|
|
|
|
|
} |
|
11747
|
|
|
|
|
|
|
|
|
11748
|
|
|
|
|
|
|
sub randperm { |
|
11749
|
4
|
|
|
4
|
0
|
695
|
my($n,$k) = @_; |
|
11750
|
4
|
|
|
|
|
17
|
validate_integer_nonneg($n); |
|
11751
|
4
|
50
|
|
|
|
13
|
if (defined $k) { |
|
11752
|
4
|
|
|
|
|
22
|
validate_integer_nonneg($k); |
|
11753
|
|
|
|
|
|
|
} |
|
11754
|
4
|
50
|
33
|
|
|
21
|
$k = $n if !defined($k) || $k > $n; |
|
11755
|
4
|
50
|
|
|
|
11
|
return () if $k == 0; |
|
11756
|
|
|
|
|
|
|
|
|
11757
|
4
|
|
|
|
|
17
|
my @S; |
|
11758
|
4
|
100
|
|
|
|
39
|
if ("$k"/"$n" <= 0.30) { |
|
11759
|
2
|
|
|
|
|
7
|
my %seen; |
|
11760
|
|
|
|
|
|
|
my $v; |
|
11761
|
2
|
|
|
|
|
7
|
for my $i (1 .. $k) { |
|
11762
|
8
|
|
|
|
|
12
|
do { $v = Murandomm($n); } while $seen{$v}++; |
|
|
8
|
|
|
|
|
21
|
|
|
11763
|
8
|
|
|
|
|
24
|
push @S,$v; |
|
11764
|
|
|
|
|
|
|
} |
|
11765
|
|
|
|
|
|
|
} else { |
|
11766
|
2
|
|
|
|
|
10
|
@S = (0..$n-1); |
|
11767
|
2
|
|
|
|
|
8
|
for my $i (0 .. $n-2) { |
|
11768
|
14
|
100
|
|
|
|
57
|
last if $i >= $k; |
|
11769
|
12
|
|
|
|
|
27
|
my $j = Murandomm($n-$i); |
|
11770
|
12
|
|
|
|
|
42
|
@S[$i,$i+$j] = @S[$i+$j,$i]; |
|
11771
|
|
|
|
|
|
|
} |
|
11772
|
2
|
|
|
|
|
11
|
$#S = $k-1; |
|
11773
|
|
|
|
|
|
|
} |
|
11774
|
4
|
|
|
|
|
41
|
return @S; |
|
11775
|
|
|
|
|
|
|
} |
|
11776
|
|
|
|
|
|
|
|
|
11777
|
|
|
|
|
|
|
sub shuffle { |
|
11778
|
1
|
|
|
1
|
0
|
23
|
my @S=@_; |
|
11779
|
|
|
|
|
|
|
# Note: almost all the time is spent in urandomm. |
|
11780
|
1
|
|
|
|
|
8
|
for (my $i = $#S; $i >= 1; $i--) { |
|
11781
|
127
|
|
|
|
|
177
|
my $j = Murandomm($i+1); |
|
11782
|
127
|
|
|
|
|
219
|
@S[$i,$j] = @S[$j,$i]; |
|
11783
|
|
|
|
|
|
|
} |
|
11784
|
1
|
|
|
|
|
13
|
@S; |
|
11785
|
|
|
|
|
|
|
} |
|
11786
|
|
|
|
|
|
|
|
|
11787
|
|
|
|
|
|
|
sub vecsample { |
|
11788
|
1
|
|
|
1
|
0
|
4
|
my $k = shift; |
|
11789
|
1
|
50
|
33
|
|
|
10
|
return () if $k == 0 || @_ == 0; |
|
11790
|
1
|
|
|
|
|
3
|
my $R = $_[0]; |
|
11791
|
1
|
|
33
|
|
|
13
|
my $isarr = (@_ > 1 || !ref($R) || ref($R) ne 'ARRAY'); |
|
11792
|
1
|
50
|
|
|
|
4
|
my $len = $isarr ? scalar(@_) : scalar(@$R); |
|
11793
|
|
|
|
|
|
|
|
|
11794
|
1
|
50
|
|
|
|
3
|
$k = $len if $k > $len; |
|
11795
|
1
|
|
|
|
|
5
|
my @I = ($len-1, 0 .. $len-2); |
|
11796
|
1
|
|
|
|
|
14
|
my $j; |
|
11797
|
1
|
|
|
|
|
2
|
my @O = map { $j = Murandomm(scalar(@I)); # random index from remaining |
|
|
4
|
|
|
|
|
8
|
|
|
11798
|
4
|
|
|
|
|
6
|
@I[0,$j] = @I[$j,0]; # move to front |
|
11799
|
4
|
|
|
|
|
7
|
shift @I; # take it off |
|
11800
|
|
|
|
|
|
|
} 1 .. $k; |
|
11801
|
1
|
50
|
|
|
|
9
|
return $isarr ? @_[@O] : @$R[@O]; |
|
11802
|
|
|
|
|
|
|
} |
|
11803
|
|
|
|
|
|
|
|
|
11804
|
|
|
|
|
|
|
############################################################################### |
|
11805
|
|
|
|
|
|
|
|
|
11806
|
|
|
|
|
|
|
sub vecsort { |
|
11807
|
62
|
|
|
62
|
0
|
16665
|
my(@s) = @_; |
|
11808
|
|
|
|
|
|
|
# If we have a single array reference, unpack it. |
|
11809
|
62
|
100
|
100
|
|
|
396
|
@s = @{$s[0]} if scalar(@s) == 1 && (ref($s[0]) || '') eq 'ARRAY'; |
|
|
3
|
|
100
|
|
|
12
|
|
|
11810
|
|
|
|
|
|
|
|
|
11811
|
|
|
|
|
|
|
# Validate and convert everything into a native int or bigint |
|
11812
|
62
|
|
|
|
|
366
|
validate_integer($_) for @s; |
|
11813
|
|
|
|
|
|
|
|
|
11814
|
|
|
|
|
|
|
# See https://github.com/perl/perl5/issues/12803 for various discussion. |
|
11815
|
|
|
|
|
|
|
# Optimize to skip the sorting. |
|
11816
|
62
|
100
|
|
|
|
2267
|
return scalar(@s) unless wantarray; |
|
11817
|
|
|
|
|
|
|
|
|
11818
|
|
|
|
|
|
|
# Before Perl 5.26, numerical sort used doubles (sigh). |
|
11819
|
61
|
50
|
|
|
|
209
|
if ($] < 5.026) { |
|
11820
|
0
|
|
|
|
|
0
|
@s = sort { 0+($a<=>$b) } @s; # Prevent sort from using built-in compare |
|
|
0
|
|
|
|
|
0
|
|
|
11821
|
|
|
|
|
|
|
} else { |
|
11822
|
61
|
|
|
|
|
458
|
@s = sort { $a<=>$b } @s; |
|
|
1232
|
|
|
|
|
12302
|
|
|
11823
|
|
|
|
|
|
|
} |
|
11824
|
61
|
|
|
|
|
2206
|
return @s; |
|
11825
|
|
|
|
|
|
|
} |
|
11826
|
|
|
|
|
|
|
|
|
11827
|
|
|
|
|
|
|
# In-place sort. |
|
11828
|
|
|
|
|
|
|
sub vecsorti { |
|
11829
|
53
|
|
|
53
|
0
|
603
|
my($r) = @_; |
|
11830
|
53
|
50
|
50
|
|
|
297
|
croak 'Not an array reference' unless (ref($r) || '') eq 'ARRAY'; |
|
11831
|
53
|
|
|
|
|
345
|
validate_integer($_) for @$r; |
|
11832
|
53
|
50
|
|
|
|
1412
|
if ($] < 5.026) { @$r = sort { 0+($a<=>$b) } @$r; } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
11833
|
53
|
|
|
|
|
306
|
else { @$r = sort { $a<=>$b } @$r; } |
|
|
444
|
|
|
|
|
10971
|
|
|
11834
|
53
|
|
|
|
|
1695
|
return $r; |
|
11835
|
|
|
|
|
|
|
} |
|
11836
|
|
|
|
|
|
|
|
|
11837
|
|
|
|
|
|
|
sub setbinop (&$;$) { ## no critic qw(ProhibitSubroutinePrototypes) |
|
11838
|
6
|
|
|
6
|
0
|
6346
|
my($sub, $ra, $rb) = @_; |
|
11839
|
6
|
50
|
50
|
|
|
40
|
croak 'Not a subroutine reference' unless (ref($sub) || '') eq 'CODE'; |
|
11840
|
6
|
50
|
50
|
|
|
29
|
croak 'Not an array reference' unless (ref($ra) || '') eq 'ARRAY'; |
|
11841
|
6
|
50
|
|
|
|
24
|
if (defined $rb) { |
|
11842
|
6
|
50
|
50
|
|
|
41
|
croak 'Not an array reference' unless (ref($rb) || '') eq 'ARRAY'; |
|
11843
|
|
|
|
|
|
|
} else { |
|
11844
|
0
|
|
|
|
|
0
|
$rb = $ra; |
|
11845
|
|
|
|
|
|
|
} |
|
11846
|
|
|
|
|
|
|
|
|
11847
|
6
|
|
|
|
|
21
|
my $caller = caller(); |
|
11848
|
77
|
|
|
77
|
|
793
|
no strict 'refs'; ## no critic(strict) |
|
|
77
|
|
|
|
|
208
|
|
|
|
77
|
|
|
|
|
736200
|
|
|
11849
|
6
|
|
|
|
|
29
|
local(*{$caller.'::a'}) = \my $a; |
|
|
6
|
|
|
|
|
33
|
|
|
11850
|
6
|
|
|
|
|
16
|
local(*{$caller.'::b'}) = \my $b; |
|
|
6
|
|
|
|
|
20
|
|
|
11851
|
|
|
|
|
|
|
|
|
11852
|
|
|
|
|
|
|
# Typically faster and less memory to push them all instead of hashing here. |
|
11853
|
6
|
|
|
|
|
19
|
my @set; |
|
11854
|
6
|
|
|
|
|
19
|
for my $ia (@$ra) { |
|
11855
|
16
|
|
|
|
|
331
|
for my $ib (@$rb) { |
|
11856
|
|
|
|
|
|
|
# Set both here in case they modified $a in their function. |
|
11857
|
43
|
|
|
|
|
383
|
$a = $ia; |
|
11858
|
43
|
|
|
|
|
78
|
$b = $ib; |
|
11859
|
43
|
|
|
|
|
87
|
push @set, $sub->(); |
|
11860
|
|
|
|
|
|
|
} |
|
11861
|
|
|
|
|
|
|
} |
|
11862
|
6
|
|
|
|
|
1415
|
Mtoset(@set); |
|
11863
|
|
|
|
|
|
|
} |
|
11864
|
|
|
|
|
|
|
|
|
11865
|
|
|
|
|
|
|
sub sumset { |
|
11866
|
12
|
|
|
12
|
0
|
17565
|
my($ra,$rb) = @_; |
|
11867
|
12
|
50
|
50
|
|
|
71
|
croak 'Not an array reference' unless (ref($ra) || '') eq 'ARRAY'; |
|
11868
|
12
|
100
|
|
|
|
46
|
if (defined $rb) { |
|
11869
|
11
|
50
|
50
|
|
|
46
|
croak 'Not an array reference' unless (ref($rb) || '') eq 'ARRAY'; |
|
11870
|
|
|
|
|
|
|
} else { |
|
11871
|
1
|
|
|
|
|
8
|
$rb = $ra; |
|
11872
|
|
|
|
|
|
|
} |
|
11873
|
12
|
50
|
33
|
|
|
81
|
return [] if scalar(@$ra) == 0 || scalar(@$rb) == 0; |
|
11874
|
|
|
|
|
|
|
|
|
11875
|
12
|
|
|
|
|
69
|
validate_integer($_) for @$ra; |
|
11876
|
12
|
100
|
|
|
|
47
|
if ($ra != $rb) { validate_integer($_) for @$rb; } |
|
|
11
|
|
|
|
|
62
|
|
|
11877
|
|
|
|
|
|
|
|
|
11878
|
12
|
|
|
|
|
33
|
my @set; |
|
11879
|
12
|
|
|
|
|
30
|
for my $x (@$ra) { |
|
11880
|
29
|
|
|
|
|
673
|
for my $y (@$rb) { |
|
11881
|
74
|
|
|
|
|
1048
|
push @set, Maddint($x,$y); |
|
11882
|
|
|
|
|
|
|
} |
|
11883
|
|
|
|
|
|
|
} |
|
11884
|
12
|
|
|
|
|
1854
|
Mtoset(@set); |
|
11885
|
|
|
|
|
|
|
} |
|
11886
|
|
|
|
|
|
|
|
|
11887
|
|
|
|
|
|
|
sub vecuniq { |
|
11888
|
3
|
|
|
3
|
0
|
10
|
my %seen = (); |
|
11889
|
3
|
|
|
|
|
7
|
my $k; |
|
11890
|
|
|
|
|
|
|
# Validation means about 1.4x slower. |
|
11891
|
|
|
|
|
|
|
#my @T = @_; return grep { validate_integer($_) && not $seen{$k = $_}++; } @T; |
|
11892
|
|
|
|
|
|
|
# We have decided to skip validation and not support undefined values. |
|
11893
|
3
|
|
|
|
|
12
|
return grep { not $seen{$k = $_}++; } @_; |
|
|
14
|
|
|
|
|
74
|
|
|
11894
|
|
|
|
|
|
|
} |
|
11895
|
|
|
|
|
|
|
|
|
11896
|
|
|
|
|
|
|
sub vecfreq { |
|
11897
|
5
|
|
|
5
|
0
|
18202
|
my %count = (); |
|
11898
|
5
|
|
|
|
|
15
|
my $countundef = 0; |
|
11899
|
5
|
|
|
|
|
11
|
my $k; |
|
11900
|
5
|
|
|
|
|
17
|
for (@_) { |
|
11901
|
32
|
100
|
|
|
|
84
|
if (defined $_) { $count{$k = $_}++; } else { $countundef++; } |
|
|
30
|
|
|
|
|
85
|
|
|
|
2
|
|
|
|
|
3
|
|
|
11902
|
|
|
|
|
|
|
} |
|
11903
|
5
|
100
|
|
|
|
54
|
return wantarray ? %count : scalar(keys %count) if !$countundef; |
|
|
|
100
|
|
|
|
|
|
|
11904
|
1
|
50
|
|
|
|
5
|
return 1 + scalar(keys %count) if !wantarray; |
|
11905
|
1
|
|
|
|
|
3
|
undef $k; |
|
11906
|
1
|
|
|
|
|
8
|
return (%count, (\$k => $countundef)); |
|
11907
|
|
|
|
|
|
|
} |
|
11908
|
|
|
|
|
|
|
|
|
11909
|
|
|
|
|
|
|
sub vecsingleton { |
|
11910
|
5
|
|
|
5
|
0
|
53940
|
my %count = (); |
|
11911
|
5
|
|
|
|
|
33
|
my ($countundef,$k) = (0); |
|
11912
|
|
|
|
|
|
|
# Filter later duplicates during the count stage for a ~10% speedup. |
|
11913
|
|
|
|
|
|
|
# Idea from List::MoreUtil. |
|
11914
|
23
|
100
|
|
|
|
116
|
return grep { (defined $_ ? $count{$k=$_} : $countundef) == 1 } |
|
11915
|
5
|
100
|
|
|
|
17
|
grep { ! (defined $_ ? $count{$k = $_}++ : $countundef++) } |
|
|
36
|
|
|
|
|
126
|
|
|
11916
|
|
|
|
|
|
|
@_; |
|
11917
|
|
|
|
|
|
|
} |
|
11918
|
|
|
|
|
|
|
|
|
11919
|
|
|
|
|
|
|
# SET/VEC generic. |
|
11920
|
|
|
|
|
|
|
|
|
11921
|
|
|
|
|
|
|
# Assume two (sorted,uniqed,validated) sets as input, merge $T into $S. |
|
11922
|
|
|
|
|
|
|
sub _merge_sets_inplace { |
|
11923
|
1
|
|
|
1
|
|
4
|
my($S,$T) = @_; |
|
11924
|
|
|
|
|
|
|
|
|
11925
|
|
|
|
|
|
|
# 1 Push set over to make room at the front. |
|
11926
|
1
|
|
|
|
|
34
|
unshift @$S, (0) x scalar(@$T); |
|
11927
|
|
|
|
|
|
|
# 2 walk the two arrays merging values |
|
11928
|
1
|
|
|
|
|
4
|
my($it,$nt) = (0, scalar(@$T)); |
|
11929
|
1
|
|
|
|
|
3
|
my($is,$ns) = ($nt, scalar(@$S)); |
|
11930
|
1
|
|
|
|
|
3
|
my $i = 0; |
|
11931
|
1
|
|
66
|
|
|
17
|
while ($it < $nt && $is < $ns) { |
|
11932
|
95
|
|
|
|
|
120
|
my($SV,$TV) = ($S->[$is], $T->[$it]); |
|
11933
|
95
|
100
|
|
|
|
95
|
if ($SV == $TV) { $S->[$i++] = $SV; $is++; $it++; } |
|
|
93
|
50
|
|
|
|
87
|
|
|
|
93
|
|
|
|
|
83
|
|
|
|
93
|
|
|
|
|
156
|
|
|
11934
|
0
|
|
|
|
|
0
|
elsif ($SV < $TV) { $S->[$i++] = $SV; $is++; } |
|
|
0
|
|
|
|
|
0
|
|
|
11935
|
2
|
|
|
|
|
4
|
else { $S->[$i++] = $TV; $it++; } |
|
|
2
|
|
|
|
|
4
|
|
|
11936
|
|
|
|
|
|
|
} |
|
11937
|
|
|
|
|
|
|
# 3 splice the remainder onto the end of the set |
|
11938
|
1
|
50
|
|
|
|
6
|
if ($is < $ns) { # slide the last part over |
|
|
|
50
|
|
|
|
|
|
|
11939
|
0
|
|
|
|
|
0
|
splice(@$S, $i, $is-$i); |
|
11940
|
|
|
|
|
|
|
} elsif ($it < $nt) { # replace everything at the end with the new values |
|
11941
|
1
|
|
|
|
|
25
|
splice(@$S, $i, @$S-$i, @{$T}[$it..$nt-1]); |
|
|
1
|
|
|
|
|
33
|
|
|
11942
|
|
|
|
|
|
|
} else { |
|
11943
|
0
|
|
|
|
|
0
|
$#$S = $i-1; |
|
11944
|
|
|
|
|
|
|
} |
|
11945
|
1
|
|
|
|
|
9
|
$S; |
|
11946
|
|
|
|
|
|
|
} |
|
11947
|
|
|
|
|
|
|
sub setunion { |
|
11948
|
5
|
|
|
5
|
0
|
11335
|
my($ra,$rb) = @_; |
|
11949
|
5
|
50
|
50
|
|
|
42
|
croak 'Not an array reference' unless (ref($ra) || '') eq 'ARRAY' |
|
|
|
|
50
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
11950
|
|
|
|
|
|
|
&& (ref($rb) || '') eq 'ARRAY'; |
|
11951
|
|
|
|
|
|
|
# return toset(@$ra,@$rb); |
|
11952
|
5
|
|
|
|
|
9
|
my(%seen,$k); |
|
11953
|
5
|
|
|
|
|
12
|
Mtoset(grep { not $seen{$k = $_}++ } @$ra,@$rb); |
|
|
28
|
|
|
|
|
273
|
|
|
11954
|
|
|
|
|
|
|
} |
|
11955
|
|
|
|
|
|
|
sub setintersect { |
|
11956
|
9
|
|
|
9
|
0
|
16915
|
my($ra,$rb) = @_; |
|
11957
|
9
|
50
|
50
|
|
|
90
|
croak 'Not an array reference' unless (ref($ra) || '') eq 'ARRAY' |
|
|
|
|
50
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
11958
|
|
|
|
|
|
|
&& (ref($rb) || '') eq 'ARRAY'; |
|
11959
|
9
|
100
|
|
|
|
33
|
($ra,$rb) = ($rb,$ra) if scalar(@$ra) > scalar(@$rb); # Performance |
|
11960
|
9
|
50
|
|
|
|
28
|
return [] if scalar(@$ra) == 0; |
|
11961
|
9
|
|
|
|
|
17
|
my %ina; |
|
11962
|
9
|
|
|
|
|
39
|
undef @ina{@$ra}; |
|
11963
|
9
|
|
|
|
|
129
|
Mtoset(grep { exists $ina{$_} } @$rb); |
|
|
26
|
|
|
|
|
255
|
|
|
11964
|
|
|
|
|
|
|
} |
|
11965
|
|
|
|
|
|
|
sub setminus { |
|
11966
|
6
|
|
|
6
|
0
|
16027
|
my($ra,$rb) = @_; |
|
11967
|
6
|
50
|
50
|
|
|
96
|
croak 'Not an array reference' unless (ref($ra) || '') eq 'ARRAY' |
|
|
|
|
50
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
11968
|
|
|
|
|
|
|
&& (ref($rb) || '') eq 'ARRAY'; |
|
11969
|
6
|
50
|
|
|
|
22
|
return $ra if scalar(@$rb) == 0; |
|
11970
|
6
|
|
|
|
|
15
|
my %inb; |
|
11971
|
6
|
|
|
|
|
27
|
undef @inb{@$rb}; |
|
11972
|
6
|
|
|
|
|
118
|
Mtoset(grep { !exists $inb{$_} } @$ra); |
|
|
19
|
|
|
|
|
191
|
|
|
11973
|
|
|
|
|
|
|
} |
|
11974
|
|
|
|
|
|
|
sub setdelta { |
|
11975
|
5
|
|
|
5
|
0
|
17124
|
my($ra,$rb) = @_; |
|
11976
|
5
|
50
|
50
|
|
|
57
|
croak 'Not an array reference' unless (ref($ra) || '') eq 'ARRAY' |
|
|
|
|
50
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
11977
|
|
|
|
|
|
|
&& (ref($rb) || '') eq 'ARRAY'; |
|
11978
|
5
|
50
|
|
|
|
20
|
return $ra if scalar(@$rb) == 0; |
|
11979
|
5
|
50
|
|
|
|
13
|
return $rb if scalar(@$ra) == 0; |
|
11980
|
5
|
|
|
|
|
13
|
my(%ina, %inb); |
|
11981
|
5
|
|
|
|
|
113
|
undef @ina{@$ra}; |
|
11982
|
5
|
|
|
|
|
123
|
undef @inb{@$rb}; |
|
11983
|
5
|
|
|
|
|
123
|
my @s = grep { !exists $inb{$_} } @$ra; |
|
|
15
|
|
|
|
|
92
|
|
|
11984
|
5
|
|
|
|
|
55
|
push @s, grep { !exists $ina{$_} } @$rb; |
|
|
13
|
|
|
|
|
88
|
|
|
11985
|
5
|
|
|
|
|
157
|
Mtoset(@s); |
|
11986
|
|
|
|
|
|
|
} |
|
11987
|
|
|
|
|
|
|
|
|
11988
|
|
|
|
|
|
|
# Can do setminus([$min..$max],\@L) albeit 2x slower |
|
11989
|
|
|
|
|
|
|
sub _setcomplement { |
|
11990
|
0
|
|
|
0
|
|
0
|
my($ra, $min, $max) = @_; |
|
11991
|
0
|
0
|
0
|
|
|
0
|
croak 'Not an array reference' unless (ref($ra) || '') eq 'ARRAY'; |
|
11992
|
0
|
|
|
|
|
0
|
validate_integer($min); |
|
11993
|
0
|
|
|
|
|
0
|
validate_integer($max); |
|
11994
|
0
|
|
|
|
|
0
|
my %ina; |
|
11995
|
0
|
|
|
|
|
0
|
$ina{$_} = undef for @$ra; |
|
11996
|
0
|
|
|
|
|
0
|
my @s; |
|
11997
|
0
|
0
|
0
|
|
|
0
|
if ((ref($min) && !ref($max)) || (!ref($min) && ref($max))) { |
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
11998
|
0
|
|
|
|
|
0
|
while ($min <= $max) { |
|
11999
|
0
|
0
|
|
|
|
0
|
push @s, $min unless exists $ina{$min}; |
|
12000
|
0
|
|
|
|
|
0
|
$min = Madd1int($min); |
|
12001
|
|
|
|
|
|
|
} |
|
12002
|
|
|
|
|
|
|
} else { |
|
12003
|
0
|
|
|
|
|
0
|
while ($min <= $max) { |
|
12004
|
0
|
0
|
|
|
|
0
|
push @s, $min unless exists $ina{$min}; |
|
12005
|
0
|
|
|
|
|
0
|
$min++; |
|
12006
|
|
|
|
|
|
|
} |
|
12007
|
|
|
|
|
|
|
} |
|
12008
|
0
|
|
|
|
|
0
|
@s; |
|
12009
|
|
|
|
|
|
|
} |
|
12010
|
|
|
|
|
|
|
|
|
12011
|
|
|
|
|
|
|
sub toset { |
|
12012
|
442
|
|
|
442
|
0
|
25991
|
my(@list) = @_; |
|
12013
|
442
|
|
|
|
|
1511
|
validate_integer($_) for @list; |
|
12014
|
442
|
100
|
|
|
|
3000
|
return \@list if scalar(@list) <= 1; |
|
12015
|
38
|
|
|
|
|
86
|
my($k,%seen); |
|
12016
|
38
|
|
|
|
|
100
|
@list = grep { not $seen{$k = $_}++; } @list; |
|
|
192
|
|
|
|
|
1480
|
|
|
12017
|
38
|
|
|
|
|
1150
|
Mvecsorti(\@list); |
|
12018
|
|
|
|
|
|
|
} |
|
12019
|
|
|
|
|
|
|
|
|
12020
|
|
|
|
|
|
|
# Is the second set a subset of the first set? |
|
12021
|
|
|
|
|
|
|
sub setcontains { |
|
12022
|
18
|
|
|
18
|
0
|
16846
|
my $set = shift @_; |
|
12023
|
18
|
|
|
|
|
46
|
my $iset; |
|
12024
|
18
|
100
|
100
|
|
|
144
|
if (@_ == 1 && ref($_[0]) eq 'ARRAY') { |
|
12025
|
7
|
|
|
|
|
14
|
$iset = $_[0]; |
|
12026
|
|
|
|
|
|
|
} else { |
|
12027
|
11
|
|
|
|
|
76
|
$iset = Mtoset(@_); |
|
12028
|
|
|
|
|
|
|
} |
|
12029
|
18
|
50
|
|
|
|
120
|
return 1 if @$iset == 0; |
|
12030
|
18
|
100
|
33
|
|
|
187
|
return 0 if @$set == 0 || @$iset > @$set || $iset->[-1] > $set->[-1] || $iset->[0] < $set->[0]; |
|
|
|
|
66
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
12031
|
|
|
|
|
|
|
|
|
12032
|
12
|
100
|
33
|
|
|
1150
|
if (@$set <= 150 || (@$set <= 250 && @$iset > 2)) { # Linear search |
|
|
|
|
66
|
|
|
|
|
|
12033
|
11
|
|
|
|
|
20
|
my $i = 0; |
|
12034
|
11
|
|
|
|
|
35
|
for my $sv (@$set) { |
|
12035
|
95
|
100
|
|
|
|
591
|
if ($sv >= $iset->[$i]) { |
|
12036
|
13
|
100
|
|
|
|
348
|
return 0 if $sv > $iset->[$i]; |
|
12037
|
10
|
100
|
|
|
|
328
|
return 1 if $i == $#$iset; |
|
12038
|
2
|
|
|
|
|
4
|
$i++; |
|
12039
|
|
|
|
|
|
|
} |
|
12040
|
|
|
|
|
|
|
} |
|
12041
|
0
|
|
|
|
|
0
|
return 0; |
|
12042
|
|
|
|
|
|
|
} |
|
12043
|
|
|
|
|
|
|
|
|
12044
|
1
|
|
|
|
|
3
|
my $newlo = 0; |
|
12045
|
|
|
|
|
|
|
# The next value is probably in this range. Can save a lot of steps. |
|
12046
|
1
|
|
|
|
|
9
|
my $range = Mcdivint(scalar(@$set),(scalar(@$iset)+1) >> 1); |
|
12047
|
1
|
|
|
|
|
35
|
for my $v (@$iset) { |
|
12048
|
4
|
|
|
|
|
11
|
my($lo,$hi) = ($newlo,$#$set); |
|
12049
|
4
|
100
|
66
|
|
|
22
|
$hi = $lo + $range if $hi-$lo > $range && $set->[$lo+$range] >= $v; |
|
12050
|
4
|
|
|
|
|
12
|
while ($lo < $hi) { |
|
12051
|
32
|
|
|
|
|
77
|
my $mid = $lo + (($hi-$lo) >> 1); |
|
12052
|
32
|
100
|
|
|
|
60
|
if ($set->[$mid] < $v) { $lo = $mid+1; } |
|
|
8
|
|
|
|
|
17
|
|
|
12053
|
24
|
|
|
|
|
50
|
else { $hi = $mid; } |
|
12054
|
|
|
|
|
|
|
} |
|
12055
|
4
|
50
|
|
|
|
12
|
return 0 if $set->[$hi] != $v; |
|
12056
|
4
|
|
|
|
|
12
|
$newlo = $hi+1; |
|
12057
|
|
|
|
|
|
|
} |
|
12058
|
1
|
|
|
|
|
33
|
1; |
|
12059
|
|
|
|
|
|
|
} |
|
12060
|
|
|
|
|
|
|
|
|
12061
|
|
|
|
|
|
|
sub setcontainsany { |
|
12062
|
2
|
|
|
2
|
0
|
10
|
my($set,@in) = @_; |
|
12063
|
2
|
|
|
|
|
16
|
my $iset; |
|
12064
|
2
|
50
|
33
|
|
|
19
|
if (@in == 1 && ref($in[0]) eq 'ARRAY') { |
|
12065
|
2
|
|
|
|
|
6
|
$iset = $in[0]; |
|
12066
|
|
|
|
|
|
|
} else { |
|
12067
|
0
|
|
|
|
|
0
|
$iset = \@in; |
|
12068
|
|
|
|
|
|
|
} |
|
12069
|
|
|
|
|
|
|
# For better performance, make iset the larger |
|
12070
|
2
|
50
|
|
|
|
10
|
($set,$iset) = ($iset,$set) if scalar(@$set) > scalar(@$iset); |
|
12071
|
2
|
50
|
|
|
|
8
|
return 0 if @$set == 0; |
|
12072
|
|
|
|
|
|
|
|
|
12073
|
2
|
|
|
|
|
4
|
my %ina; |
|
12074
|
2
|
|
|
|
|
12
|
undef @ina{@$set}; |
|
12075
|
2
|
100
|
|
|
|
6
|
for (@$iset) { return 1 if exists $ina{$_} } |
|
|
12
|
|
|
|
|
38
|
|
|
12076
|
1
|
|
|
|
|
9
|
return 0; |
|
12077
|
|
|
|
|
|
|
} |
|
12078
|
|
|
|
|
|
|
|
|
12079
|
|
|
|
|
|
|
|
|
12080
|
|
|
|
|
|
|
sub _setinsert1 { # UNUSED |
|
12081
|
0
|
|
|
0
|
|
0
|
my($rset, $v) = @_; |
|
12082
|
0
|
|
|
|
|
0
|
validate_integer($v); |
|
12083
|
|
|
|
|
|
|
|
|
12084
|
0
|
0
|
0
|
|
|
0
|
if (scalar(@$rset) == 0 || $v > $rset->[-1]) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
12085
|
0
|
|
|
|
|
0
|
push @$rset, $v; |
|
12086
|
|
|
|
|
|
|
} elsif ($v < $rset->[0]) { |
|
12087
|
0
|
|
|
|
|
0
|
unshift @$rset, $v; |
|
12088
|
|
|
|
|
|
|
} elsif (scalar(@$rset) > 1) { |
|
12089
|
0
|
|
|
|
|
0
|
my($lo,$hi) = (0,$#$rset); |
|
12090
|
0
|
|
|
|
|
0
|
while ($lo < $hi) { |
|
12091
|
0
|
|
|
|
|
0
|
my $mid = $lo + (($hi-$lo) >> 1); |
|
12092
|
0
|
0
|
|
|
|
0
|
if ($rset->[$mid] < $v) { $lo = $mid+1; } |
|
|
0
|
|
|
|
|
0
|
|
|
12093
|
0
|
|
|
|
|
0
|
else { $hi = $mid; } |
|
12094
|
|
|
|
|
|
|
} |
|
12095
|
0
|
0
|
|
|
|
0
|
return 0 if $rset->[$hi] == $v; |
|
12096
|
0
|
0
|
0
|
|
|
0
|
croak "internal too high" if $hi > 0 && $rset->[$hi-1] >= $v; |
|
12097
|
0
|
0
|
|
|
|
0
|
croak "internal too low" if $rset->[$hi] <= $v; |
|
12098
|
0
|
|
|
|
|
0
|
splice @$rset, $hi, 0, $v; |
|
12099
|
|
|
|
|
|
|
} else { |
|
12100
|
0
|
|
|
|
|
0
|
return 0; # Single element already in list. |
|
12101
|
|
|
|
|
|
|
} |
|
12102
|
0
|
|
|
|
|
0
|
1; |
|
12103
|
|
|
|
|
|
|
} |
|
12104
|
|
|
|
|
|
|
|
|
12105
|
|
|
|
|
|
|
sub setinsert { |
|
12106
|
390
|
|
|
390
|
0
|
3364
|
my($set, @in) = @_; |
|
12107
|
390
|
|
|
|
|
550
|
my $iset; |
|
12108
|
390
|
100
|
66
|
|
|
1669
|
if (@in == 1 && ref($in[0]) eq 'ARRAY') { |
|
12109
|
2
|
|
|
|
|
28
|
$iset = $in[0]; |
|
12110
|
|
|
|
|
|
|
} else { |
|
12111
|
388
|
|
|
|
|
1087
|
$iset = Mtoset(@in); |
|
12112
|
|
|
|
|
|
|
} |
|
12113
|
390
|
50
|
|
|
|
976
|
return 0 if @$iset == 0; |
|
12114
|
390
|
|
|
|
|
689
|
my $setsize = scalar(@$set); |
|
12115
|
390
|
100
|
100
|
|
|
1785
|
if ($setsize == 0 || $iset->[0] > $set->[-1]) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
12116
|
119
|
|
|
|
|
296
|
push @$set, @$iset; |
|
12117
|
|
|
|
|
|
|
} elsif ($iset->[-1] < $set->[0]) { |
|
12118
|
53
|
|
|
|
|
156
|
unshift @$set, @$iset; |
|
12119
|
|
|
|
|
|
|
} elsif (@$iset > 400) { |
|
12120
|
|
|
|
|
|
|
# $set is required to be in proper form as input. |
|
12121
|
|
|
|
|
|
|
# @newset was run through toset() earlier, so it is in proper form. |
|
12122
|
|
|
|
|
|
|
# Times from the 20x50k insert operation in xt/test-sets. |
|
12123
|
|
|
|
|
|
|
|
|
12124
|
|
|
|
|
|
|
# 17.09 In theory efficient, but too much redundant work |
|
12125
|
|
|
|
|
|
|
#@$set = @{Msetunion($set,$iset)}; |
|
12126
|
|
|
|
|
|
|
|
|
12127
|
|
|
|
|
|
|
# 12.48 Better but still ignores all input structure |
|
12128
|
|
|
|
|
|
|
#@$set = @{Mtoset([@$set,@$iset])}; |
|
12129
|
|
|
|
|
|
|
|
|
12130
|
|
|
|
|
|
|
# 6.04 toset inlined and with all unnecessary work removed |
|
12131
|
|
|
|
|
|
|
#my($k,%seen); |
|
12132
|
|
|
|
|
|
|
#@$set = grep { not $seen{$k=$_}++ } @$set,@$iset; |
|
12133
|
|
|
|
|
|
|
#if ($] < 5.026) { @$set = sort { 0+($a<=>$b) } @$set; } |
|
12134
|
|
|
|
|
|
|
#else { @$set = sort { $a<=>$b } @$set; } |
|
12135
|
|
|
|
|
|
|
|
|
12136
|
|
|
|
|
|
|
# 5.64 as above but assume $set has no duplicates |
|
12137
|
|
|
|
|
|
|
#my($k,%seen); |
|
12138
|
|
|
|
|
|
|
#undef @seen{@$set}; |
|
12139
|
|
|
|
|
|
|
#push @$set, grep { !exists $seen{$k=$_} } @$iset; |
|
12140
|
|
|
|
|
|
|
#if ($] < 5.026) { @$set = sort { 0+($a<=>$b) } @$set; } |
|
12141
|
|
|
|
|
|
|
#else { @$set = sort { $a<=>$b } @$set; } |
|
12142
|
|
|
|
|
|
|
|
|
12143
|
|
|
|
|
|
|
# 4.12 Merge two proper-form sets |
|
12144
|
1
|
|
|
|
|
33
|
_merge_sets_inplace($set, $iset); |
|
12145
|
|
|
|
|
|
|
|
|
12146
|
|
|
|
|
|
|
} else { |
|
12147
|
|
|
|
|
|
|
# 1. values in front and back. |
|
12148
|
217
|
|
|
|
|
430
|
my($nbeg,$nend) = (0,0); |
|
12149
|
217
|
|
|
|
|
393
|
my(@sbeg,@send); |
|
12150
|
217
|
|
66
|
|
|
997
|
$nend++ while $nend < scalar(@$iset) && $iset->[-1 - $nend] > $set->[-1]; |
|
12151
|
217
|
100
|
|
|
|
449
|
@send = splice(@$iset,-$nend) if $nend > 0; |
|
12152
|
217
|
|
33
|
|
|
903
|
$nbeg++ while $nbeg < scalar(@$iset) && $iset->[$nbeg] < $set->[0]; |
|
12153
|
217
|
50
|
|
|
|
503
|
@sbeg = splice(@$iset,0,$nbeg) if $nbeg > 0; |
|
12154
|
|
|
|
|
|
|
# 2. values in the middle. |
|
12155
|
217
|
|
|
|
|
382
|
my $start = 0; |
|
12156
|
217
|
|
|
|
|
1039
|
my $range = Mcdivint(scalar(@$set),(scalar(@$iset)+2) >> 1); |
|
12157
|
217
|
|
|
|
|
556
|
for my $v (@$iset) { |
|
12158
|
219
|
|
|
|
|
519
|
my($lo,$hi) = ($start,$#$set); |
|
12159
|
219
|
100
|
66
|
|
|
619
|
$hi = $lo + $range if $hi-$lo > $range && $set->[$lo+$range] >= $v; |
|
12160
|
219
|
|
|
|
|
498
|
while ($lo < $hi) { |
|
12161
|
353
|
|
|
|
|
689
|
my $mid = $lo + (($hi-$lo) >> 1); |
|
12162
|
353
|
100
|
|
|
|
774
|
if ($set->[$mid] < $v) { $lo = $mid+1; } |
|
|
155
|
|
|
|
|
370
|
|
|
12163
|
198
|
|
|
|
|
451
|
else { $hi = $mid; } |
|
12164
|
|
|
|
|
|
|
} |
|
12165
|
219
|
100
|
|
|
|
592
|
splice @$set, $hi, 0, $v if $set->[$hi] != $v; |
|
12166
|
219
|
|
|
|
|
470
|
$start = $hi+1; |
|
12167
|
|
|
|
|
|
|
} |
|
12168
|
|
|
|
|
|
|
# 3. bulk insert the front and back values we saved earlier |
|
12169
|
217
|
50
|
|
|
|
441
|
unshift @$set, @sbeg if @sbeg; |
|
12170
|
217
|
100
|
|
|
|
546
|
push @$set, @send if @send; |
|
12171
|
|
|
|
|
|
|
} |
|
12172
|
390
|
|
|
|
|
1967
|
return scalar(@$set) - $setsize; |
|
12173
|
|
|
|
|
|
|
} |
|
12174
|
|
|
|
|
|
|
|
|
12175
|
|
|
|
|
|
|
sub _setremove1 { |
|
12176
|
2
|
|
|
2
|
|
6
|
my($rset, $v) = @_; |
|
12177
|
|
|
|
|
|
|
#validate_integer($v); |
|
12178
|
|
|
|
|
|
|
|
|
12179
|
2
|
50
|
33
|
|
|
15
|
return 0 if scalar(@$rset) == 0 || $v > $rset->[-1] || $v < $rset->[0]; |
|
|
|
|
33
|
|
|
|
|
|
12180
|
|
|
|
|
|
|
|
|
12181
|
2
|
|
|
|
|
8
|
my($lo,$hi) = (0,$#$rset); |
|
12182
|
2
|
|
|
|
|
6
|
while ($lo < $hi) { |
|
12183
|
6
|
|
|
|
|
13
|
my $mid = $lo + (($hi-$lo) >> 1); |
|
12184
|
6
|
100
|
|
|
|
13
|
if ($rset->[$mid] < $v) { $lo = $mid+1; } |
|
|
2
|
|
|
|
|
6
|
|
|
12185
|
4
|
|
|
|
|
9
|
else { $hi = $mid; } |
|
12186
|
|
|
|
|
|
|
} |
|
12187
|
2
|
100
|
|
|
|
9
|
return 0 if $rset->[$hi] != $v; |
|
12188
|
1
|
|
|
|
|
5
|
splice @$rset, $hi, 1; |
|
12189
|
1
|
|
|
|
|
5
|
1; |
|
12190
|
|
|
|
|
|
|
} |
|
12191
|
|
|
|
|
|
|
|
|
12192
|
|
|
|
|
|
|
sub setremove { |
|
12193
|
3
|
|
|
3
|
0
|
3142
|
my $set = shift; |
|
12194
|
3
|
|
|
|
|
8
|
my $iset; |
|
12195
|
3
|
100
|
66
|
|
|
53
|
if (@_ == 1 && ref($_[0]) eq 'ARRAY') { |
|
12196
|
1
|
|
|
|
|
5
|
$iset = $_[0]; |
|
12197
|
|
|
|
|
|
|
} else { |
|
12198
|
2
|
|
|
|
|
10
|
$iset = Mtoset(@_); |
|
12199
|
|
|
|
|
|
|
} |
|
12200
|
3
|
|
|
|
|
10
|
my $setsize = scalar(@$set); |
|
12201
|
3
|
50
|
33
|
|
|
18
|
return 0 if $setsize == 0 || @$iset == 0; |
|
12202
|
|
|
|
|
|
|
|
|
12203
|
3
|
|
|
|
|
10
|
my($SMIN,$SMAX) = ($set->[0],$set->[-1]); |
|
12204
|
3
|
|
33
|
|
|
20
|
pop @$iset while @$iset && $iset->[-1] > $SMAX; |
|
12205
|
3
|
|
33
|
|
|
20
|
shift @$iset while @$iset && $iset->[0] < $SMIN; |
|
12206
|
|
|
|
|
|
|
|
|
12207
|
|
|
|
|
|
|
# Try to decide the most performant of the two methods. |
|
12208
|
3
|
0
|
|
|
|
17
|
my $fitmin = $setsize < 170 ? 1 + ($setsize>=35) + int($setsize/30) |
|
|
|
50
|
|
|
|
|
|
|
12209
|
|
|
|
|
|
|
: $setsize < 75000 ? int(2.7*sqrt($setsize)-28) |
|
12210
|
|
|
|
|
|
|
: 700; |
|
12211
|
3
|
100
|
|
|
|
23
|
if (@$iset <= $fitmin) { |
|
12212
|
2
|
|
|
|
|
12
|
_setremove1($set,$_) for @$iset; |
|
12213
|
|
|
|
|
|
|
} else { |
|
12214
|
1
|
|
|
|
|
3
|
my(%remove, $k); |
|
12215
|
1
|
|
|
|
|
9
|
$remove{$k=$_}=undef for @$iset; |
|
12216
|
1
|
|
|
|
|
4
|
my $remsize = scalar(keys(%remove)); |
|
12217
|
1
|
50
|
|
|
|
4
|
return 0 if $remsize == 0; |
|
12218
|
1
|
|
|
|
|
4
|
@$set = grep { !exists $remove{$k=$_} } @$set; |
|
|
7
|
|
|
|
|
19
|
|
|
12219
|
|
|
|
|
|
|
} |
|
12220
|
3
|
|
|
|
|
14
|
return $setsize - scalar(@$set); |
|
12221
|
|
|
|
|
|
|
} |
|
12222
|
|
|
|
|
|
|
|
|
12223
|
|
|
|
|
|
|
sub _setinvert1 { |
|
12224
|
4
|
|
|
4
|
|
10
|
my($rset, $v) = @_; |
|
12225
|
|
|
|
|
|
|
# No validate here. |
|
12226
|
|
|
|
|
|
|
|
|
12227
|
4
|
50
|
33
|
|
|
30
|
if (scalar(@$rset) == 0 || $v > $rset->[-1]) { |
|
|
|
50
|
|
|
|
|
|
|
12228
|
0
|
|
|
|
|
0
|
push @$rset, $v; |
|
12229
|
|
|
|
|
|
|
} elsif ($v < $rset->[0]) { |
|
12230
|
0
|
|
|
|
|
0
|
unshift @$rset, $v; |
|
12231
|
|
|
|
|
|
|
} else { |
|
12232
|
4
|
|
|
|
|
19
|
my($lo,$hi) = (0,$#$rset); |
|
12233
|
4
|
|
|
|
|
14
|
while ($lo < $hi) { |
|
12234
|
12
|
|
|
|
|
60
|
my $mid = $lo + (($hi-$lo) >> 1); |
|
12235
|
12
|
100
|
|
|
|
25
|
if ($rset->[$mid] < $v) { $lo = $mid+1; } |
|
|
5
|
|
|
|
|
13
|
|
|
12236
|
7
|
|
|
|
|
18
|
else { $hi = $mid; } |
|
12237
|
|
|
|
|
|
|
} |
|
12238
|
4
|
100
|
|
|
|
13
|
if ($rset->[$hi] == $v) { |
|
12239
|
2
|
|
|
|
|
5
|
splice @$rset, $hi, 1; |
|
12240
|
2
|
|
|
|
|
8
|
return -1; |
|
12241
|
|
|
|
|
|
|
} |
|
12242
|
2
|
|
|
|
|
10
|
splice @$rset, $hi, 0, $v; |
|
12243
|
|
|
|
|
|
|
} |
|
12244
|
2
|
|
|
|
|
6
|
1; |
|
12245
|
|
|
|
|
|
|
} |
|
12246
|
|
|
|
|
|
|
|
|
12247
|
|
|
|
|
|
|
sub setinvert { |
|
12248
|
3
|
|
|
3
|
0
|
3150
|
my($set, @in) = @_; |
|
12249
|
3
|
50
|
|
|
|
14
|
return 0 if @in == 0; |
|
12250
|
3
|
|
|
|
|
10
|
my $iset; |
|
12251
|
3
|
100
|
66
|
|
|
21
|
if (@in == 1 && ref($in[0]) eq 'ARRAY') { |
|
12252
|
1
|
|
|
|
|
4
|
$iset = $in[0]; |
|
12253
|
|
|
|
|
|
|
} else { |
|
12254
|
2
|
|
|
|
|
8
|
$iset = Mtoset(@in); |
|
12255
|
|
|
|
|
|
|
} |
|
12256
|
3
|
|
|
|
|
11
|
my $setsize = scalar(@$set); |
|
12257
|
3
|
50
|
|
|
|
22
|
if ($setsize == 0) { |
|
12258
|
0
|
|
|
|
|
0
|
@$set = @$iset; |
|
12259
|
0
|
|
|
|
|
0
|
return scalar(@$set); |
|
12260
|
|
|
|
|
|
|
} |
|
12261
|
|
|
|
|
|
|
# Like setinsert and setremove, we assume the input set is in set form. |
|
12262
|
|
|
|
|
|
|
|
|
12263
|
3
|
50
|
|
|
|
11
|
if (@$iset <= 100) { |
|
12264
|
3
|
|
|
|
|
22
|
_setinvert1($set,$_) for @$iset; |
|
12265
|
|
|
|
|
|
|
} else { |
|
12266
|
0
|
|
|
|
|
0
|
my @S; |
|
12267
|
0
|
|
|
|
|
0
|
for my $sv (@$set) { |
|
12268
|
0
|
|
0
|
|
|
0
|
push @S, shift @$iset while @$iset && $iset->[0] < $sv; |
|
12269
|
0
|
0
|
0
|
|
|
0
|
if (@$iset && $iset->[0] == $sv) { |
|
12270
|
0
|
|
|
|
|
0
|
shift @$iset; |
|
12271
|
|
|
|
|
|
|
} else { |
|
12272
|
0
|
|
|
|
|
0
|
push @S, $sv; |
|
12273
|
|
|
|
|
|
|
} |
|
12274
|
|
|
|
|
|
|
} |
|
12275
|
0
|
|
|
|
|
0
|
push @S, @$iset; |
|
12276
|
0
|
|
|
|
|
0
|
@$set = @S; |
|
12277
|
|
|
|
|
|
|
} |
|
12278
|
3
|
|
|
|
|
14
|
return scalar(@$set) - $setsize; |
|
12279
|
|
|
|
|
|
|
} |
|
12280
|
|
|
|
|
|
|
|
|
12281
|
|
|
|
|
|
|
# For these set_is_ functions, the inputs can be unordered but no duplicates. |
|
12282
|
|
|
|
|
|
|
|
|
12283
|
|
|
|
|
|
|
sub set_is_disjoint { |
|
12284
|
4
|
|
|
4
|
0
|
17245
|
my($s,$t) = @_; |
|
12285
|
4
|
50
|
50
|
|
|
48
|
croak 'Not an array reference' unless (ref($s) || '') eq 'ARRAY' |
|
|
|
|
50
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
12286
|
|
|
|
|
|
|
&& (ref($t) || '') eq 'ARRAY'; |
|
12287
|
4
|
100
|
|
|
|
22
|
($s,$t) = ($t,$s) if scalar(@$s) > scalar(@$t); |
|
12288
|
4
|
50
|
33
|
|
|
25
|
return 1 if @$s == 0 || @$t == 0; |
|
12289
|
4
|
|
|
|
|
9
|
my($k,%ins); |
|
12290
|
4
|
|
|
|
|
26
|
$ins{$k=$_}=undef for @$s; |
|
12291
|
4
|
100
|
|
|
|
11
|
for my $v (@$t) { return 0 if exists $ins{$k=$v} } |
|
|
8
|
|
|
|
|
50
|
|
|
12292
|
2
|
|
|
|
|
17
|
1; |
|
12293
|
|
|
|
|
|
|
} |
|
12294
|
|
|
|
|
|
|
sub set_is_equal { |
|
12295
|
3
|
|
|
3
|
0
|
13449
|
my($s,$t) = @_; |
|
12296
|
3
|
50
|
50
|
|
|
42
|
croak 'Not an array reference' unless (ref($s) || '') eq 'ARRAY' |
|
|
|
|
50
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
12297
|
|
|
|
|
|
|
&& (ref($t) || '') eq 'ARRAY'; |
|
12298
|
3
|
50
|
|
|
|
12
|
return 0 unless @$s == @$t; |
|
12299
|
3
|
|
|
|
|
10
|
my %ins; |
|
12300
|
3
|
|
|
|
|
21
|
$ins{$_} = 0 for @$s; |
|
12301
|
3
|
|
|
|
|
9
|
for my $v (@$t) { |
|
12302
|
8
|
100
|
|
|
|
34
|
return 0 unless exists $ins{$v}; |
|
12303
|
6
|
|
|
|
|
12
|
$ins{$v}++; |
|
12304
|
|
|
|
|
|
|
} |
|
12305
|
1
|
50
|
|
|
|
4
|
for (values %ins) { return 0 unless $_ } |
|
|
4
|
|
|
|
|
10
|
|
|
12306
|
1
|
|
|
|
|
6
|
1; |
|
12307
|
|
|
|
|
|
|
} |
|
12308
|
|
|
|
|
|
|
sub set_is_subset { |
|
12309
|
16
|
|
|
16
|
0
|
38600
|
my($s,$t) = @_; |
|
12310
|
16
|
50
|
50
|
|
|
159
|
croak 'Not an array reference' unless (ref($s) || '') eq 'ARRAY' |
|
|
|
|
50
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
12311
|
|
|
|
|
|
|
&& (ref($t) || '') eq 'ARRAY'; |
|
12312
|
16
|
50
|
|
|
|
55
|
return 1 if @$t == 0; |
|
12313
|
16
|
50
|
|
|
|
50
|
return 0 if @$s < @$t; |
|
12314
|
16
|
|
|
|
|
60
|
my %ins; |
|
12315
|
16
|
|
|
|
|
84
|
undef @ins{@$s}; |
|
12316
|
16
|
100
|
|
|
|
65
|
for my $v (@$t) { return 0 unless exists $ins{$v} } |
|
|
30
|
|
|
|
|
210
|
|
|
12317
|
10
|
|
|
|
|
72
|
1; |
|
12318
|
|
|
|
|
|
|
} |
|
12319
|
|
|
|
|
|
|
sub set_is_proper_subset { |
|
12320
|
6
|
|
|
6
|
0
|
19145
|
my($s,$t) = @_; |
|
12321
|
6
|
50
|
50
|
|
|
73
|
croak 'Not an array reference' unless (ref($s) || '') eq 'ARRAY' |
|
|
|
|
50
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
12322
|
|
|
|
|
|
|
&& (ref($t) || '') eq 'ARRAY'; |
|
12323
|
6
|
100
|
|
|
|
52
|
return 0 if @$s <= @$t; |
|
12324
|
4
|
|
|
|
|
17
|
set_is_subset($s,$t); |
|
12325
|
|
|
|
|
|
|
} |
|
12326
|
|
|
|
|
|
|
sub set_is_superset { |
|
12327
|
5
|
|
|
5
|
0
|
22194
|
set_is_subset($_[1],$_[0]); |
|
12328
|
|
|
|
|
|
|
} |
|
12329
|
|
|
|
|
|
|
sub set_is_proper_superset { |
|
12330
|
3
|
|
|
3
|
0
|
14284
|
set_is_proper_subset($_[1],$_[0]); |
|
12331
|
|
|
|
|
|
|
} |
|
12332
|
|
|
|
|
|
|
sub set_is_proper_intersection { |
|
12333
|
4
|
|
|
4
|
0
|
10813
|
my($s,$t) = @_; |
|
12334
|
4
|
50
|
50
|
|
|
42
|
croak 'Not an array reference' unless (ref($s) || '') eq 'ARRAY' |
|
|
|
|
50
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
12335
|
|
|
|
|
|
|
&& (ref($t) || '') eq 'ARRAY'; |
|
12336
|
4
|
50
|
|
|
|
18
|
my $minsize = (scalar(@$s) < scalar(@$t)) ? scalar(@$s) : scalar(@$t); |
|
12337
|
4
|
|
|
|
|
8
|
my $intersize = scalar(@{Msetintersect($s,$t)}); |
|
|
4
|
|
|
|
|
119
|
|
|
12338
|
4
|
100
|
100
|
|
|
58
|
return ($intersize > 0 && $intersize < $minsize) ? 1 : 0; |
|
12339
|
|
|
|
|
|
|
} |
|
12340
|
|
|
|
|
|
|
|
|
12341
|
|
|
|
|
|
|
sub is_sidon_set { |
|
12342
|
4
|
|
|
4
|
0
|
5898
|
my($ra) = @_; |
|
12343
|
4
|
50
|
50
|
|
|
26
|
croak 'Not an array reference' unless (ref($ra) || '') eq 'ARRAY'; |
|
12344
|
|
|
|
|
|
|
|
|
12345
|
4
|
|
|
|
|
10
|
my %sums; |
|
12346
|
4
|
|
|
|
|
7
|
my @S = @{Mtoset(@$ra)}; # Validated, sorted, deduped. |
|
|
4
|
|
|
|
|
22
|
|
|
12347
|
4
|
|
|
|
|
18
|
while (@S) { |
|
12348
|
16
|
|
|
|
|
129
|
my $x = pop @S; |
|
12349
|
16
|
50
|
|
|
|
39
|
return 0 if $x < 0; |
|
12350
|
16
|
|
|
|
|
36
|
for my $y ($x, @S) { |
|
12351
|
49
|
|
|
|
|
787
|
my $s = Maddint($x, $y); |
|
12352
|
49
|
100
|
|
|
|
1894
|
return 0 if exists $sums{$s}; |
|
12353
|
48
|
|
|
|
|
515
|
$sums{$s} = undef; |
|
12354
|
|
|
|
|
|
|
} |
|
12355
|
|
|
|
|
|
|
} |
|
12356
|
3
|
|
|
|
|
102
|
1; |
|
12357
|
|
|
|
|
|
|
} |
|
12358
|
|
|
|
|
|
|
|
|
12359
|
|
|
|
|
|
|
sub is_sumfree_set { |
|
12360
|
4
|
|
|
4
|
0
|
6255
|
my($ra) = @_; |
|
12361
|
4
|
50
|
50
|
|
|
27
|
croak 'Not an array reference' unless (ref($ra) || '') eq 'ARRAY'; |
|
12362
|
|
|
|
|
|
|
|
|
12363
|
4
|
|
|
|
|
10
|
my %ina; |
|
12364
|
4
|
|
|
|
|
10
|
my @S = @{Mtoset(@$ra)}; # Validated, sorted, deduped. |
|
|
4
|
|
|
|
|
24
|
|
|
12365
|
4
|
|
|
|
|
29
|
$ina{$_}=undef for @S; |
|
12366
|
4
|
|
|
|
|
14
|
while (@S) { |
|
12367
|
12
|
|
|
|
|
26
|
my $x = pop @S; |
|
12368
|
12
|
|
|
|
|
28
|
for my $y ($x, @S) { |
|
12369
|
25
|
100
|
|
|
|
590
|
return 0 if exists $ina{Maddint($x,$y)}; |
|
12370
|
|
|
|
|
|
|
} |
|
12371
|
|
|
|
|
|
|
} |
|
12372
|
3
|
|
|
|
|
653
|
1; |
|
12373
|
|
|
|
|
|
|
} |
|
12374
|
|
|
|
|
|
|
|
|
12375
|
|
|
|
|
|
|
|
|
12376
|
|
|
|
|
|
|
############################################################################### |
|
12377
|
|
|
|
|
|
|
|
|
12378
|
|
|
|
|
|
|
sub foralmostprimes { |
|
12379
|
4
|
|
|
4
|
0
|
1440
|
my($sub, $k, $lo, $hi) = @_; |
|
12380
|
4
|
|
|
|
|
32
|
validate_integer_nonneg($k); |
|
12381
|
4
|
50
|
|
|
|
17
|
return if $k == 0; |
|
12382
|
4
|
50
|
|
|
|
29
|
if (defined $hi) { validate_integer_nonneg($lo); } |
|
|
4
|
|
|
|
|
30
|
|
|
12383
|
0
|
|
|
|
|
0
|
else { ($lo,$hi) = (1, $lo); } |
|
12384
|
4
|
|
|
|
|
28
|
validate_integer_nonneg($hi); |
|
12385
|
|
|
|
|
|
|
|
|
12386
|
4
|
|
|
|
|
38
|
$lo = Mvecmax($lo, Mpowint(2, $k)); |
|
12387
|
4
|
50
|
|
|
|
18
|
return if $lo > $hi; |
|
12388
|
|
|
|
|
|
|
|
|
12389
|
|
|
|
|
|
|
#return Math::Prime::Util::forprimes($sub,$lo,$hi) if $k == 1; |
|
12390
|
|
|
|
|
|
|
|
|
12391
|
4
|
|
|
|
|
246
|
my $estcount = almost_prime_count_approx($k,$hi) - almost_prime_count_approx($k,$lo); |
|
12392
|
4
|
|
|
|
|
19
|
my $nsegs = "$estcount" / 1e6; |
|
12393
|
4
|
|
|
|
|
26
|
my $len = Madd1int(Msubint($hi,$lo)); |
|
12394
|
4
|
50
|
|
|
|
143
|
my $segsize = ($nsegs <= 1.1) ? $len : int("$len"/$nsegs); |
|
12395
|
4
|
50
|
|
|
|
18
|
if ($segsize < 5*1e6) { $segsize = 5e6; } |
|
|
4
|
|
|
|
|
11
|
|
|
12396
|
|
|
|
|
|
|
# warn " estcount $estcount nsegs $nsegs segsize $segsize\n"; |
|
12397
|
|
|
|
|
|
|
|
|
12398
|
4
|
|
|
|
|
47
|
my $oldforexit = Math::Prime::Util::_start_for_loop(); |
|
12399
|
4
|
|
|
|
|
19
|
while ($lo <= $hi) { |
|
12400
|
4
|
|
|
|
|
199
|
my $seghi = Mvecmin($hi, Maddint($lo,$segsize)-1); |
|
12401
|
4
|
|
|
|
|
58
|
my $ap = Math::Prime::Util::almost_primes($k, $lo, $seghi); |
|
12402
|
|
|
|
|
|
|
#my $ap = []; _genkap($lo, $seghi, $k, 1, 2, sub { push @$ap,$_[0]; }); |
|
12403
|
|
|
|
|
|
|
# warn " from $lo to $seghi found ",scalar(@$ap), " $k-almost-primes\n"; |
|
12404
|
|
|
|
|
|
|
{ |
|
12405
|
4
|
|
|
|
|
29
|
my $pp; |
|
|
4
|
|
|
|
|
10
|
|
|
12406
|
4
|
|
|
|
|
23
|
local *_ = \$pp; |
|
12407
|
4
|
|
|
|
|
13
|
for my $kap (@$ap) { |
|
12408
|
22
|
|
|
|
|
57
|
$pp = $kap; |
|
12409
|
22
|
|
|
|
|
97
|
$sub->(); |
|
12410
|
22
|
50
|
|
|
|
229
|
last if Math::Prime::Util::_get_forexit(); |
|
12411
|
|
|
|
|
|
|
} |
|
12412
|
|
|
|
|
|
|
} |
|
12413
|
4
|
|
|
|
|
30
|
$lo = Madd1int($seghi); |
|
12414
|
4
|
50
|
|
|
|
813
|
last if Math::Prime::Util::_get_forexit(); |
|
12415
|
|
|
|
|
|
|
} |
|
12416
|
4
|
|
|
|
|
185
|
Math::Prime::Util::_end_for_loop($oldforexit); |
|
12417
|
|
|
|
|
|
|
} |
|
12418
|
|
|
|
|
|
|
|
|
12419
|
|
|
|
|
|
|
|
|
12420
|
|
|
|
|
|
|
|
|
12421
|
|
|
|
|
|
|
############################################################################### |
|
12422
|
|
|
|
|
|
|
# Random numbers |
|
12423
|
|
|
|
|
|
|
############################################################################### |
|
12424
|
|
|
|
|
|
|
|
|
12425
|
|
|
|
|
|
|
# PPFE: irand irand64 drand random_bytes csrand srand _is_csprng_well_seeded |
|
12426
|
|
|
|
|
|
|
sub urandomb { |
|
12427
|
27
|
|
|
27
|
0
|
108
|
my($n) = @_; |
|
12428
|
27
|
50
|
|
|
|
133
|
return 0 if $n <= 0; |
|
12429
|
27
|
50
|
|
|
|
114
|
return ( Math::Prime::Util::irand() >> (32-$n) ) if $n <= 32; |
|
12430
|
27
|
50
|
|
|
|
87
|
return ( Math::Prime::Util::irand64() >> (64-$n) ) if MPU_MAXBITS >= 64 && $n <= 64; |
|
12431
|
27
|
|
|
|
|
365
|
my $bytes = Math::Prime::Util::random_bytes(($n+7)>>3); |
|
12432
|
27
|
|
|
|
|
283
|
return _frombinary( substr(unpack("B*",$bytes),0,$n) ); |
|
12433
|
|
|
|
|
|
|
} |
|
12434
|
|
|
|
|
|
|
sub urandomm { |
|
12435
|
179
|
|
|
179
|
0
|
1862
|
my($n) = @_; |
|
12436
|
|
|
|
|
|
|
# validate_integer_nonneg($n); |
|
12437
|
|
|
|
|
|
|
return reftyped($_[0], Math::Prime::Util::GMP::urandomm($n)) |
|
12438
|
179
|
50
|
|
|
|
395
|
if $Math::Prime::Util::_GMPfunc{"urandomm"}; |
|
12439
|
179
|
100
|
|
|
|
342
|
return 0 if $n <= 1; |
|
12440
|
178
|
|
|
|
|
6431
|
my $r; |
|
12441
|
178
|
100
|
|
|
|
325
|
if ($n <= 4294967295) { |
|
|
|
50
|
|
|
|
|
|
|
12442
|
152
|
|
|
|
|
201
|
my $rmin = (4294967295 - ($n-1)) % $n; |
|
12443
|
152
|
|
|
|
|
158
|
do { $r = Math::Prime::Util::irand(); } while $r < $rmin; |
|
|
152
|
|
|
|
|
277
|
|
|
12444
|
|
|
|
|
|
|
} elsif (!ref($n)) { |
|
12445
|
0
|
|
|
|
|
0
|
my $rmin = (~0 - ($n-1)) % $n; |
|
12446
|
0
|
|
|
|
|
0
|
do { $r = Math::Prime::Util::irand64(); } while $r < $rmin; |
|
|
0
|
|
|
|
|
0
|
|
|
12447
|
|
|
|
|
|
|
} else { |
|
12448
|
|
|
|
|
|
|
# TODO: verify and try to optimize this |
|
12449
|
26
|
|
|
|
|
6384
|
my $bytes = 1 + length(todigitstring($n,16)); |
|
12450
|
26
|
|
|
|
|
2058
|
my $rmax = Msub1int(Mpowint(2,$bytes*8)); |
|
12451
|
26
|
|
|
|
|
6638
|
my $overflow = $rmax - ($rmax % $n); |
|
12452
|
26
|
|
|
|
|
15559
|
do { $r = Murandomb($bytes*8); } while $r >= $overflow; |
|
|
26
|
|
|
|
|
2093
|
|
|
12453
|
|
|
|
|
|
|
} |
|
12454
|
178
|
|
|
|
|
29656
|
return $r % $n; |
|
12455
|
|
|
|
|
|
|
} |
|
12456
|
|
|
|
|
|
|
|
|
12457
|
|
|
|
|
|
|
sub random_prime { |
|
12458
|
2
|
|
|
2
|
0
|
23677
|
my($low, $high) = @_; |
|
12459
|
2
|
50
|
|
|
|
11
|
if (scalar(@_) == 1) { ($low,$high) = (2,$low); } |
|
|
0
|
|
|
|
|
0
|
|
|
12460
|
2
|
|
|
|
|
11
|
else { validate_integer_nonneg($low); } |
|
12461
|
2
|
|
|
|
|
43
|
validate_integer_nonneg($high); |
|
12462
|
|
|
|
|
|
|
|
|
12463
|
|
|
|
|
|
|
return reftyped($_[0], Math::Prime::Util::GMP::random_prime($low, $high)) |
|
12464
|
2
|
50
|
|
|
|
32
|
if $Math::Prime::Util::_GMPfunc{"random_prime"}; |
|
12465
|
|
|
|
|
|
|
|
|
12466
|
2
|
|
|
|
|
850
|
require Math::Prime::Util::RandomPrimes; |
|
12467
|
2
|
|
|
|
|
12
|
return Math::Prime::Util::RandomPrimes::random_prime($low,$high); |
|
12468
|
|
|
|
|
|
|
} |
|
12469
|
|
|
|
|
|
|
|
|
12470
|
|
|
|
|
|
|
sub random_ndigit_prime { |
|
12471
|
3
|
|
|
3
|
0
|
964
|
my($digits) = @_; |
|
12472
|
3
|
|
|
|
|
23
|
validate_integer_nonneg($digits); |
|
12473
|
3
|
50
|
|
|
|
111
|
croak "random_ndigit_prime digits must be >= 1" unless $digits >= 1; |
|
12474
|
|
|
|
|
|
|
return reftyped($_[0], Math::Prime::Util::GMP::random_ndigit_prime($digits)) |
|
12475
|
3
|
50
|
33
|
|
|
18
|
if $Math::Prime::Util::_GMPfunc{"random_ndigit_prime"} && !getconfig()->{'nobigint'}; |
|
12476
|
3
|
|
|
|
|
1235
|
require Math::Prime::Util::RandomPrimes; |
|
12477
|
3
|
|
|
|
|
23
|
return Math::Prime::Util::RandomPrimes::random_ndigit_prime($digits); |
|
12478
|
|
|
|
|
|
|
} |
|
12479
|
|
|
|
|
|
|
sub random_nbit_prime { |
|
12480
|
9
|
|
|
9
|
0
|
71693
|
my($bits) = @_; |
|
12481
|
9
|
|
|
|
|
52
|
validate_integer_nonneg($bits); |
|
12482
|
9
|
50
|
|
|
|
249
|
croak "random_nbit_prime bits must be >= 2" unless $bits >= 2; |
|
12483
|
|
|
|
|
|
|
return reftyped($_[0], Math::Prime::Util::GMP::random_nbit_prime($bits)) |
|
12484
|
9
|
50
|
|
|
|
38
|
if $Math::Prime::Util::_GMPfunc{"random_nbit_prime"}; |
|
12485
|
9
|
|
|
|
|
64
|
require Math::Prime::Util::RandomPrimes; |
|
12486
|
9
|
|
|
|
|
46
|
return Math::Prime::Util::RandomPrimes::random_nbit_prime($bits); |
|
12487
|
|
|
|
|
|
|
} |
|
12488
|
|
|
|
|
|
|
sub random_safe_prime { |
|
12489
|
2
|
|
|
2
|
0
|
9597
|
my($bits) = @_; |
|
12490
|
2
|
|
|
|
|
16
|
validate_integer_nonneg($bits); |
|
12491
|
2
|
50
|
|
|
|
139
|
croak "random_safe_prime bits must be >= 3" unless $bits >= 3; |
|
12492
|
|
|
|
|
|
|
return reftyped($_[0], eval "Math::Prime::Util::GMP::random_safe_prime($bits)") ## no critic qw(ProhibitStringyEval) |
|
12493
|
2
|
50
|
|
|
|
10
|
if $Math::Prime::Util::_GMPfunc{"random_safe_prime"}; |
|
12494
|
2
|
|
|
|
|
16
|
require Math::Prime::Util::RandomPrimes; |
|
12495
|
2
|
|
|
|
|
14
|
return Math::Prime::Util::RandomPrimes::random_safe_prime($bits); |
|
12496
|
|
|
|
|
|
|
} |
|
12497
|
|
|
|
|
|
|
sub random_strong_prime { |
|
12498
|
1
|
|
|
1
|
0
|
172
|
my($bits) = @_; |
|
12499
|
1
|
|
|
|
|
10
|
validate_integer_nonneg($bits); |
|
12500
|
1
|
50
|
|
|
|
99
|
croak "random_strong_prime bits must be >= 128" unless $bits >= 128; |
|
12501
|
|
|
|
|
|
|
return reftyped($_[0], eval "Math::Prime::Util::GMP::random_strong_prime($bits)") ## no critic qw(ProhibitStringyEval) |
|
12502
|
1
|
50
|
|
|
|
6
|
if $Math::Prime::Util::_GMPfunc{"random_strong_prime"}; |
|
12503
|
1
|
|
|
|
|
9
|
require Math::Prime::Util::RandomPrimes; |
|
12504
|
1
|
|
|
|
|
7
|
return Math::Prime::Util::RandomPrimes::random_strong_prime($bits); |
|
12505
|
|
|
|
|
|
|
} |
|
12506
|
|
|
|
|
|
|
|
|
12507
|
|
|
|
|
|
|
sub random_proven_prime { |
|
12508
|
0
|
|
|
0
|
0
|
0
|
random_maurer_prime(@_); |
|
12509
|
|
|
|
|
|
|
} |
|
12510
|
|
|
|
|
|
|
|
|
12511
|
|
|
|
|
|
|
sub random_maurer_prime { |
|
12512
|
1
|
|
|
1
|
0
|
111
|
my($bits) = @_; |
|
12513
|
1
|
|
|
|
|
5
|
validate_integer_nonneg($bits); |
|
12514
|
1
|
50
|
|
|
|
53
|
croak "random_maurer_prime bits must be >= 2" unless $bits >= 2; |
|
12515
|
|
|
|
|
|
|
|
|
12516
|
|
|
|
|
|
|
return reftyped($_[0], Math::Prime::Util::GMP::random_maurer_prime($bits)) |
|
12517
|
1
|
50
|
|
|
|
4
|
if $Math::Prime::Util::_GMPfunc{"random_maurer_prime"}; |
|
12518
|
|
|
|
|
|
|
|
|
12519
|
1
|
|
|
|
|
6
|
require Math::Prime::Util::RandomPrimes; |
|
12520
|
1
|
|
|
|
|
8
|
my ($n, $cert) = Math::Prime::Util::RandomPrimes::random_maurer_prime_with_cert($bits); |
|
12521
|
1
|
50
|
|
|
|
7
|
croak "maurer prime $n failed certificate verification!" |
|
12522
|
|
|
|
|
|
|
unless Math::Prime::Util::verify_prime($cert); |
|
12523
|
|
|
|
|
|
|
|
|
12524
|
1
|
|
|
|
|
12
|
return $n; |
|
12525
|
|
|
|
|
|
|
} |
|
12526
|
|
|
|
|
|
|
|
|
12527
|
|
|
|
|
|
|
sub random_shawe_taylor_prime { |
|
12528
|
0
|
|
|
0
|
0
|
0
|
my($bits) = @_; |
|
12529
|
0
|
|
|
|
|
0
|
validate_integer_nonneg($bits); |
|
12530
|
0
|
0
|
|
|
|
0
|
croak "random_shawe_taylor_prime bits must be >= 2" unless $bits >= 2; |
|
12531
|
|
|
|
|
|
|
|
|
12532
|
|
|
|
|
|
|
return reftyped($_[0], Math::Prime::Util::GMP::random_shawe_taylor_prime($bits)) |
|
12533
|
0
|
0
|
|
|
|
0
|
if $Math::Prime::Util::_GMPfunc{"random_shawe_taylor_prime"}; |
|
12534
|
|
|
|
|
|
|
|
|
12535
|
0
|
|
|
|
|
0
|
require Math::Prime::Util::RandomPrimes; |
|
12536
|
0
|
|
|
|
|
0
|
my ($n, $cert) = Math::Prime::Util::RandomPrimes::random_shawe_taylor_prime_with_cert($bits); |
|
12537
|
0
|
0
|
|
|
|
0
|
croak "shawe-taylor prime $n failed certificate verification!" |
|
12538
|
|
|
|
|
|
|
unless Math::Prime::Util::verify_prime($cert); |
|
12539
|
|
|
|
|
|
|
|
|
12540
|
0
|
|
|
|
|
0
|
return $n; |
|
12541
|
|
|
|
|
|
|
} |
|
12542
|
|
|
|
|
|
|
|
|
12543
|
|
|
|
|
|
|
sub miller_rabin_random { |
|
12544
|
3
|
|
|
3
|
0
|
2192
|
my($n, $k, $seed) = @_; |
|
12545
|
3
|
|
|
|
|
36
|
validate_integer($n); |
|
12546
|
3
|
50
|
|
|
|
134
|
if (scalar(@_) == 1 ) { $k = 1; } else { validate_integer_nonneg($k); } |
|
|
0
|
|
|
|
|
0
|
|
|
|
3
|
|
|
|
|
17
|
|
|
12547
|
|
|
|
|
|
|
|
|
12548
|
3
|
50
|
|
|
|
141
|
return 0 if $n < 2; |
|
12549
|
3
|
50
|
|
|
|
410
|
return 1 if $k <= 0; |
|
12550
|
|
|
|
|
|
|
|
|
12551
|
3
|
50
|
|
|
|
17
|
if ($Math::Prime::Util::_GMPfunc{"miller_rabin_random"}) { |
|
12552
|
0
|
0
|
|
|
|
0
|
return Math::Prime::Util::GMP::miller_rabin_random($n, $k, $seed) if defined $seed; |
|
12553
|
0
|
|
|
|
|
0
|
return Math::Prime::Util::GMP::miller_rabin_random($n, $k); |
|
12554
|
|
|
|
|
|
|
} |
|
12555
|
|
|
|
|
|
|
|
|
12556
|
|
|
|
|
|
|
# getconfig()->{'assume_rh'}) ==> 2*log(n)^2 |
|
12557
|
3
|
50
|
|
|
|
14
|
if ($k >= int(3*$n/4) ) { |
|
12558
|
0
|
|
|
|
|
0
|
for (2 .. int(3*$n/4)+2) { |
|
12559
|
0
|
0
|
|
|
|
0
|
return 0 unless Math::Prime::Util::is_strong_pseudoprime($n, $_); |
|
12560
|
|
|
|
|
|
|
} |
|
12561
|
0
|
|
|
|
|
0
|
return 1; |
|
12562
|
|
|
|
|
|
|
} |
|
12563
|
3
|
|
|
|
|
2026
|
my $brange = $n-2; |
|
12564
|
3
|
100
|
|
|
|
691
|
return 0 unless Math::Prime::Util::is_strong_pseudoprime($n, Murandomm($brange)+2 ); |
|
12565
|
1
|
|
|
|
|
11
|
$k--; |
|
12566
|
1
|
|
|
|
|
5
|
while ($k > 0) { |
|
12567
|
1
|
50
|
|
|
|
9
|
my $nbases = ($k >= 20) ? 20 : $k; |
|
12568
|
1
|
50
|
|
|
|
6
|
return 0 unless is_strong_pseudoprime($n, map { Murandomm($brange)+2 } 1 .. $nbases); |
|
|
19
|
|
|
|
|
13238
|
|
|
12569
|
1
|
|
|
|
|
32
|
$k -= $nbases; |
|
12570
|
|
|
|
|
|
|
} |
|
12571
|
1
|
|
|
|
|
12
|
1; |
|
12572
|
|
|
|
|
|
|
} |
|
12573
|
|
|
|
|
|
|
|
|
12574
|
|
|
|
|
|
|
sub random_semiprime { |
|
12575
|
1
|
|
|
1
|
0
|
17355
|
my($b) = @_; |
|
12576
|
1
|
|
|
|
|
7
|
validate_integer_nonneg($b); |
|
12577
|
1
|
50
|
|
|
|
5
|
croak "random_semiprime bits must be >= 4" unless $b >= 4; |
|
12578
|
|
|
|
|
|
|
|
|
12579
|
1
|
|
|
|
|
3
|
my $n; |
|
12580
|
1
|
|
|
|
|
80
|
my $min = Mpowint(2,$b-1); |
|
12581
|
1
|
|
|
|
|
272
|
my $max = $min + ($min - 1); |
|
12582
|
1
|
|
|
|
|
656
|
my $L = $b >> 1; |
|
12583
|
1
|
|
|
|
|
4
|
my $N = $b - $L; |
|
12584
|
1
|
|
66
|
|
|
3
|
do { |
|
12585
|
3
|
|
|
|
|
631
|
$n = Mmulint(random_nbit_prime($L), random_nbit_prime($N)); |
|
12586
|
|
|
|
|
|
|
} while $n < $min || $n > $max; |
|
12587
|
1
|
|
|
|
|
359
|
$n; |
|
12588
|
|
|
|
|
|
|
} |
|
12589
|
|
|
|
|
|
|
|
|
12590
|
|
|
|
|
|
|
sub random_unrestricted_semiprime { |
|
12591
|
1
|
|
|
1
|
0
|
21
|
my($b) = @_; |
|
12592
|
1
|
|
|
|
|
6
|
validate_integer_nonneg($b); |
|
12593
|
1
|
50
|
|
|
|
5
|
croak "random_unrestricted_semiprime bits must be >= 3" unless $b >= 3; |
|
12594
|
|
|
|
|
|
|
|
|
12595
|
1
|
|
|
|
|
3
|
my $n; |
|
12596
|
1
|
|
|
|
|
70
|
my $min = Mpowint(2,$b-1); |
|
12597
|
1
|
|
|
|
|
255
|
my $max = Maddint($min, $min - 1); |
|
12598
|
|
|
|
|
|
|
|
|
12599
|
1
|
50
|
|
|
|
298
|
if ($b <= MPU_MAXBITS) { |
|
12600
|
0
|
|
|
|
|
0
|
do { |
|
12601
|
0
|
|
|
|
|
0
|
$n = $min + Murandomb($b-1); |
|
12602
|
|
|
|
|
|
|
} while !Mis_semiprime($n); |
|
12603
|
|
|
|
|
|
|
} else { |
|
12604
|
|
|
|
|
|
|
# Try to get probabilities right for small divisors |
|
12605
|
1
|
|
|
|
|
95
|
my %M = ( |
|
12606
|
|
|
|
|
|
|
2 => 1.91218397452243, |
|
12607
|
|
|
|
|
|
|
3 => 1.33954826555021, |
|
12608
|
|
|
|
|
|
|
5 => 0.854756717114822, |
|
12609
|
|
|
|
|
|
|
7 => 0.635492301836862, |
|
12610
|
|
|
|
|
|
|
11 => 0.426616792046787, |
|
12611
|
|
|
|
|
|
|
13 => 0.368193843118344, |
|
12612
|
|
|
|
|
|
|
17 => 0.290512701603111, |
|
12613
|
|
|
|
|
|
|
19 => 0.263359264658156, |
|
12614
|
|
|
|
|
|
|
23 => 0.222406328935102, |
|
12615
|
|
|
|
|
|
|
29 => 0.181229250520242, |
|
12616
|
|
|
|
|
|
|
31 => 0.170874199059434, |
|
12617
|
|
|
|
|
|
|
37 => 0.146112155735473, |
|
12618
|
|
|
|
|
|
|
41 => 0.133427839963585, |
|
12619
|
|
|
|
|
|
|
43 => 0.127929010905662, |
|
12620
|
|
|
|
|
|
|
47 => 0.118254609086782, |
|
12621
|
|
|
|
|
|
|
53 => 0.106316418106489, |
|
12622
|
|
|
|
|
|
|
59 => 0.0966989675438643, |
|
12623
|
|
|
|
|
|
|
61 => 0.0938833658008547, |
|
12624
|
|
|
|
|
|
|
67 => 0.0864151823151671, |
|
12625
|
|
|
|
|
|
|
71 => 0.0820822953188297, |
|
12626
|
|
|
|
|
|
|
73 => 0.0800964416340746, |
|
12627
|
|
|
|
|
|
|
79 => 0.0747060914833344, |
|
12628
|
|
|
|
|
|
|
83 => 0.0714973706654851, |
|
12629
|
|
|
|
|
|
|
89 => 0.0672115468436284, |
|
12630
|
|
|
|
|
|
|
97 => 0.0622818892486191, |
|
12631
|
|
|
|
|
|
|
101 => 0.0600855891549939, |
|
12632
|
|
|
|
|
|
|
103 => 0.0590613570015407, |
|
12633
|
|
|
|
|
|
|
107 => 0.0570921135626976, |
|
12634
|
|
|
|
|
|
|
109 => 0.0561691667641485, |
|
12635
|
|
|
|
|
|
|
113 => 0.0544330141081874, |
|
12636
|
|
|
|
|
|
|
127 => 0.0490620204315701, |
|
12637
|
|
|
|
|
|
|
); |
|
12638
|
1
|
|
|
|
|
4
|
my ($p,$r); |
|
12639
|
1
|
|
|
|
|
5
|
$r = Math::Prime::Util::drand(); |
|
12640
|
1
|
|
|
|
|
5
|
for my $prime (2..113,127) { |
|
12641
|
113
|
100
|
|
|
|
275
|
next unless defined $M{$prime}; |
|
12642
|
31
|
|
|
|
|
63
|
my $PR = $M{$prime} / $b + 0.19556 / $prime; |
|
12643
|
31
|
50
|
|
|
|
64
|
if ($r <= $PR) { |
|
12644
|
0
|
|
|
|
|
0
|
$p = $prime; |
|
12645
|
0
|
|
|
|
|
0
|
last; |
|
12646
|
|
|
|
|
|
|
} |
|
12647
|
31
|
|
|
|
|
87
|
$r -= $PR; |
|
12648
|
|
|
|
|
|
|
} |
|
12649
|
1
|
50
|
|
|
|
5
|
if (!defined $p) { |
|
12650
|
|
|
|
|
|
|
# Idea from Charles Greathouse IV, 2010. The distribution is right |
|
12651
|
|
|
|
|
|
|
# at the high level (small primes weighted more and not far off what |
|
12652
|
|
|
|
|
|
|
# we get with the uniform selection), but there is a noticeable skew |
|
12653
|
|
|
|
|
|
|
# toward primes with a large gap after them. For instance 3 ends up |
|
12654
|
|
|
|
|
|
|
# being weighted as much as 2, and 7 more than 5. |
|
12655
|
|
|
|
|
|
|
# |
|
12656
|
|
|
|
|
|
|
# Since we handled small divisors earlier, this is less bothersome. |
|
12657
|
1
|
|
|
|
|
2
|
my $M = 0.26149721284764278375542683860869585905; |
|
12658
|
1
|
|
|
|
|
5
|
my $weight = $M + log($b * log(2)/2); |
|
12659
|
1
|
|
|
|
|
2
|
my $minr = log(log(131)); |
|
12660
|
1
|
|
|
|
|
3
|
do { |
|
12661
|
1
|
|
|
|
|
8
|
$r = Math::Prime::Util::drand($weight) - $M; |
|
12662
|
|
|
|
|
|
|
} while $r < $minr; |
|
12663
|
1
|
|
|
|
|
3
|
my $a; |
|
12664
|
1
|
50
|
|
|
|
5
|
if ($r <= 3.54) { |
|
|
|
0
|
|
|
|
|
|
|
12665
|
|
|
|
|
|
|
# result under 10^15, can do directly |
|
12666
|
1
|
|
|
|
|
5
|
$a = int( exp(exp($r)) + 0.5 ); |
|
12667
|
|
|
|
|
|
|
} elsif ($Math::Prime::Util::_GMPfunc{"expreal"}) { |
|
12668
|
|
|
|
|
|
|
# Use our fast arbitrary precision expreal. |
|
12669
|
0
|
0
|
|
|
|
0
|
my $digits = $r < 4.45 ? 40 : int(exp($r)/2.2 + 2); # overestimate |
|
12670
|
0
|
|
|
|
|
0
|
my $re = Math::Prime::Util::GMP::expreal($r,$digits); |
|
12671
|
0
|
|
|
|
|
0
|
$a = Math::Prime::Util::GMP::expreal($re,$digits); |
|
12672
|
0
|
|
|
|
|
0
|
$a = Mtoint($a); #_upgrade_to_float($a)->as_int; |
|
12673
|
|
|
|
|
|
|
} else { |
|
12674
|
|
|
|
|
|
|
# exp(x)=exp(x/n)^n |
|
12675
|
|
|
|
|
|
|
# We could use Math::BigFloat but it's sooooooooooo slow. |
|
12676
|
0
|
|
|
|
|
0
|
my $re = exp($r); |
|
12677
|
0
|
|
|
|
|
0
|
my $redd = 1+int($re/34.5); |
|
12678
|
0
|
|
|
|
|
0
|
$a = Mpowint(int(exp($re/$redd)+0.5), $redd); |
|
12679
|
|
|
|
|
|
|
} |
|
12680
|
1
|
50
|
|
|
|
14
|
$p = $a < 2 ? 2 : Mprev_prime($a+1); |
|
12681
|
|
|
|
|
|
|
} |
|
12682
|
1
|
|
|
|
|
9
|
my $ranmin = Mcdivint($min, $p); |
|
12683
|
1
|
|
|
|
|
6
|
my $ranmax = Mdivint($max, $p); |
|
12684
|
1
|
|
|
|
|
7
|
my $q = random_prime($ranmin, $ranmax); |
|
12685
|
1
|
|
|
|
|
93
|
$n = Mmulint($p,$q); |
|
12686
|
|
|
|
|
|
|
} |
|
12687
|
1
|
|
|
|
|
254
|
$n; |
|
12688
|
|
|
|
|
|
|
} |
|
12689
|
|
|
|
|
|
|
|
|
12690
|
|
|
|
|
|
|
sub random_factored_integer { |
|
12691
|
0
|
|
|
0
|
0
|
0
|
my($n) = @_; |
|
12692
|
0
|
|
|
|
|
0
|
validate_integer_positive($n); |
|
12693
|
|
|
|
|
|
|
|
|
12694
|
0
|
|
|
|
|
0
|
while (1) { |
|
12695
|
0
|
|
|
|
|
0
|
my @S = ($n); |
|
12696
|
|
|
|
|
|
|
# make s_i chain |
|
12697
|
0
|
|
|
|
|
0
|
push @S, 1 + Murandomm($S[-1]) while $S[-1] > 1; |
|
12698
|
|
|
|
|
|
|
# first is n, last is 1 |
|
12699
|
0
|
|
|
|
|
0
|
@S = grep { Mis_prime($_) } @S[1 .. $#S-1]; |
|
|
0
|
|
|
|
|
0
|
|
|
12700
|
0
|
|
|
|
|
0
|
my $r = Mvecprod(@S); |
|
12701
|
0
|
0
|
0
|
|
|
0
|
return ($r, [@S]) if $r <= $n && (1+Murandomm($n)) <= $r; |
|
12702
|
|
|
|
|
|
|
} |
|
12703
|
|
|
|
|
|
|
} |
|
12704
|
|
|
|
|
|
|
|
|
12705
|
|
|
|
|
|
|
################################################################################ |
|
12706
|
|
|
|
|
|
|
|
|
12707
|
|
|
|
|
|
|
sub prime_precalc { |
|
12708
|
2
|
|
|
2
|
0
|
22
|
my($n) = @_; |
|
12709
|
2
|
50
|
|
|
|
9
|
croak "Parameter '$n' must be a non-negative integer" unless _is_nonneg_int($n); |
|
12710
|
2
|
|
|
|
|
10
|
_expand_prime_cache($n); |
|
12711
|
|
|
|
|
|
|
} |
|
12712
|
|
|
|
|
|
|
my @_free_subs; |
|
12713
|
|
|
|
|
|
|
sub _register_free_sub { |
|
12714
|
308
|
|
|
308
|
|
798
|
push @_free_subs, shift; |
|
12715
|
|
|
|
|
|
|
} |
|
12716
|
|
|
|
|
|
|
sub prime_memfree { |
|
12717
|
|
|
|
|
|
|
# Make the internal callbacks that reset cached data. |
|
12718
|
11
|
|
|
11
|
0
|
116
|
$_->() for @_free_subs; |
|
12719
|
|
|
|
|
|
|
# Call GMP's free if we have it |
|
12720
|
11
|
50
|
33
|
|
|
70
|
eval { Math::Prime::Util::GMP::_GMP_memfree(); } |
|
|
0
|
|
|
|
|
0
|
|
|
12721
|
|
|
|
|
|
|
if defined $Math::Prime::Util::GMP::VERSION && $Math::Prime::Util::GMP::VERSION >= 0.49; |
|
12722
|
|
|
|
|
|
|
} |
|
12723
|
80
|
|
|
80
|
|
302
|
sub _get_prime_cache_size { $_precalc_size } |
|
12724
|
0
|
|
|
0
|
|
|
sub _prime_memfreeall { prime_memfree; } |
|
12725
|
|
|
|
|
|
|
|
|
12726
|
|
|
|
|
|
|
1; |
|
12727
|
|
|
|
|
|
|
|
|
12728
|
|
|
|
|
|
|
__END__ |