1package Math::Prime::Util::PPFE;
2use strict;
3use warnings;
4use Math::Prime::Util::PP;
5use Math::Prime::Util::Entropy;
6
7# The PP front end, only loaded if XS is not used.
8# It is intended to load directly into the MPU namespace.
9
10package Math::Prime::Util;
11use Carp qw/carp croak confess/;
12
13*_validate_num = \&Math::Prime::Util::PP::_validate_num;
14*_validate_integer = \&Math::Prime::Util::PP::_validate_integer;
15*_prime_memfreeall = \&Math::Prime::Util::PP::_prime_memfreeall;
16*prime_memfree  = \&Math::Prime::Util::PP::prime_memfree;
17*prime_precalc  = \&Math::Prime::Util::PP::prime_precalc;
18
19use Math::Prime::Util::ChaCha;
20*_is_csprng_well_seeded = \&Math::Prime::Util::ChaCha::_is_csprng_well_seeded;
21*_csrand = \&Math::Prime::Util::ChaCha::csrand;
22*_srand = \&Math::Prime::Util::ChaCha::srand;
23*random_bytes = \&Math::Prime::Util::ChaCha::random_bytes;
24*irand = \&Math::Prime::Util::ChaCha::irand;
25*irand64 = \&Math::Prime::Util::ChaCha::irand64;
26
27sub srand {
28  my($seed) = @_;
29  croak "secure option set, manual seeding disabled" if prime_get_config()->{'secure'};
30  if (!defined $seed) {
31    my $nbytes = (~0 == 4294967295) ? 4 : 8;
32    $seed = entropy_bytes( $nbytes );
33    $seed = unpack(($nbytes==4) ? "L" : "Q", $seed);
34  }
35  Math::Prime::Util::GMP::seed_csprng(8,pack("LL",$seed))
36    if $Math::Prime::Util::_GMPfunc{"seed_csprng"};
37  Math::Prime::Util::_srand($seed);
38}
39sub csrand {
40  my($seed) = @_;
41  croak "secure option set, manual seeding disabled" if defined $seed && prime_get_config()->{'secure'};
42  $seed = entropy_bytes( 64 ) unless defined $seed;
43  Math::Prime::Util::GMP::seed_csprng(length($seed),$seed)
44    if $Math::Prime::Util::_GMPfunc{"seed_csprng"};
45  Math::Prime::Util::_csrand($seed);
46  1; # Don't return the seed
47}
48sub entropy_bytes {
49  my($bytes) = @_;
50  croak "entropy_bytes: input must be integer bytes between 1 and 4294967295"
51    if !defined($bytes) || $bytes < 1 || $bytes > 4294967295 || $bytes != int($bytes);
52  my $data = Math::Prime::Util::Entropy::entropy_bytes($bytes);
53  if (!defined $data) {
54    # We can't find any entropy source!  Highly unusual.
55    Math::Prime::Util::_srand();
56    $data = random_bytes($bytes);
57  }
58  croak "entropy_bytes internal got wrong amount!" unless length($data) == $bytes;
59  $data;
60}
61
62# Fill all the mantissa bits for our NV, regardless of 32-bit or 64-bit Perl.
63{
64  use Config;
65  my $nvbits = (defined $Config{nvmantbits})  ? $Config{nvmantbits}
66             : (defined $Config{usequadmath}) ? 112
67             : 53;
68  my $uvbits = (~0 > 4294967295) ? 64 : 32;
69  my $rsub;
70  my $_tonv_32  = 1.0;        $_tonv_32 /= 2.0 for 1..32;
71  my $_tonv_64  = $_tonv_32;  $_tonv_64 /= 2.0 for 1..32;
72  my $_tonv_96  = $_tonv_64;  $_tonv_96 /= 2.0 for 1..32;
73  my $_tonv_128 = $_tonv_96;  $_tonv_128/= 2.0 for 1..32;
74  if ($uvbits == 64) {
75    if ($nvbits <= 32) {
76      *drand = sub { my $d = irand() * $_tonv_32;  $d *= $_[0] if $_[0];  $d; };
77    } elsif ($nvbits <= 64) {
78      *drand = sub { my $d = irand64() * $_tonv_64;  $d *= $_[0] if $_[0];  $d; };
79    } else {
80      *drand = sub { my $d = irand64() * $_tonv_64 + irand64() * $_tonv_128;  $d *= $_[0] if $_[0];  $d; };
81    }
82  } else {
83    if ($nvbits <= 32) {
84      *drand = sub { my $d = irand() * $_tonv_32;  $d *= $_[0] if $_[0];  $d; };
85    } elsif ($nvbits <= 64) {
86      *drand = sub { my $d = ((irand() >> 5) * 67108864.0 + (irand() >> 6)) / 9007199254740992.0;  $d *= $_[0] if $_[0];  $d; };
87    } else {
88      *drand = sub { my $d = irand() * $_tonv_32 + irand() * $_tonv_64 + irand() * $_tonv_96 + irand() * $_tonv_128;  $d *= $_[0] if $_[0];  $d; };
89    }
90  }
91  *rand = \&drand;
92}
93
94
95*urandomb = \&Math::Prime::Util::PP::urandomb;
96*urandomm = \&Math::Prime::Util::PP::urandomm;
97
98# TODO: Go through these and decide if they should be doing anything extra here,
99#       such as input validation.
100# TODO: If not, why not the other functions?
101*sumdigits = \&Math::Prime::Util::PP::sumdigits;
102*todigits = \&Math::Prime::Util::PP::todigits;
103*todigitstring = \&Math::Prime::Util::PP::todigitstring;
104*fromdigits = \&Math::Prime::Util::PP::fromdigits;
105*inverse_li = \&Math::Prime::Util::PP::inverse_li;
106*sieve_prime_cluster = \&Math::Prime::Util::PP::sieve_prime_cluster;
107*twin_prime_count = \&Math::Prime::Util::PP::twin_prime_count;
108*semiprime_count = \&Math::Prime::Util::PP::semiprime_count;
109*ramanujan_prime_count = \&Math::Prime::Util::PP::ramanujan_prime_count;
110*sum_primes = \&Math::Prime::Util::PP::sum_primes;
111*print_primes = \&Math::Prime::Util::PP::print_primes;
112*sieve_range = \&Math::Prime::Util::PP::sieve_range;
113*is_carmichael = \&Math::Prime::Util::PP::is_carmichael;
114*is_quasi_carmichael = \&Math::Prime::Util::PP::is_quasi_carmichael;
115*is_pillai = \&Math::Prime::Util::PP::is_pillai;
116*is_fundamental = \&Math::Prime::Util::PP::is_fundamental;
117*is_semiprime = \&Math::Prime::Util::PP::is_semiprime;
118*is_totient = \&Math::Prime::Util::PP::is_totient;
119*is_square = \&Math::Prime::Util::PP::is_square;
120
121*random_prime = \&Math::Prime::Util::PP::random_prime;
122*random_ndigit_prime = \&Math::Prime::Util::PP::random_ndigit_prime;
123*random_nbit_prime = \&Math::Prime::Util::PP::random_nbit_prime;
124*random_proven_prime = \&Math::Prime::Util::PP::random_maurer_prime; # redir
125*random_strong_prime = \&Math::Prime::Util::PP::random_strong_prime;
126*random_maurer_prime = \&Math::Prime::Util::PP::random_maurer_prime;
127*random_shawe_taylor_prime =\&Math::Prime::Util::PP::random_shawe_taylor_prime;
128*miller_rabin_random = \&Math::Prime::Util::PP::miller_rabin_random;
129*random_semiprime = \&Math::Prime::Util::PP::random_semiprime;
130*random_unrestricted_semiprime = \&Math::Prime::Util::PP::random_unrestricted_semiprime;
131*random_factored_integer = \&Math::Prime::Util::PP::random_factored_integer;
132
133*numtoperm = \&Math::Prime::Util::PP::numtoperm;
134*permtonum = \&Math::Prime::Util::PP::permtonum;
135*randperm = \&Math::Prime::Util::PP::randperm;
136*shuffle = \&Math::Prime::Util::PP::shuffle;
137
138*moebius = \&Math::Prime::Util::PP::moebius;
139*euler_phi = \&Math::Prime::Util::PP::euler_phi;
140*inverse_totient = \&Math::Prime::Util::PP::inverse_totient;
141
142sub jordan_totient {
143  my($k, $n) = @_;
144  _validate_positive_integer($k);
145  return 0 if defined $n && $n < 0;
146  _validate_positive_integer($n);
147  return Math::Prime::Util::PP::jordan_totient($k, $n);
148}
149sub ramanujan_sum {
150  my($k,$n) = @_;
151  _validate_positive_integer($k);
152  _validate_positive_integer($n);
153  return Math::Prime::Util::PP::ramanujan_sum($k, $n);
154}
155sub carmichael_lambda {
156  my($n) = @_;
157  _validate_positive_integer($n);
158  return Math::Prime::Util::PP::carmichael_lambda($n);
159}
160sub mertens {
161  my($n) = @_;
162  _validate_positive_integer($n);
163  return Math::Prime::Util::PP::mertens($n);
164}
165sub liouville {
166  my($n) = @_;
167  _validate_positive_integer($n);
168  return Math::Prime::Util::PP::liouville($n);
169}
170sub exp_mangoldt {
171  my($n) = @_;
172  return 1 if defined $n && $n <= 1;
173  _validate_positive_integer($n);
174  return Math::Prime::Util::PP::exp_mangoldt($n);
175}
176sub hclassno {
177  my($n) = @_;
178  return 0 if defined $n && int($n) < 0;
179  _validate_positive_integer($n);
180  return Math::Prime::Util::PP::hclassno($n);
181}
182
183
184sub next_prime {
185  my($n) = @_;
186  _validate_positive_integer($n);
187  return Math::Prime::Util::PP::next_prime($n);
188}
189sub prev_prime {
190  my($n) = @_;
191  _validate_positive_integer($n);
192  return Math::Prime::Util::PP::prev_prime($n);
193}
194sub nth_prime {
195  my($n) = @_;
196  _validate_positive_integer($n);
197  return Math::Prime::Util::PP::nth_prime($n);
198}
199sub nth_prime_lower {
200  my($n) = @_;
201  _validate_positive_integer($n);
202  return Math::Prime::Util::PP::nth_prime_lower($n);
203}
204sub nth_prime_upper {
205  my($n) = @_;
206  _validate_positive_integer($n);
207  return Math::Prime::Util::PP::nth_prime_upper($n);
208}
209sub nth_prime_approx {
210  my($n) = @_;
211  _validate_positive_integer($n);
212  return Math::Prime::Util::PP::nth_prime_approx($n);
213}
214sub prime_count_lower {
215  my($n) = @_;
216  _validate_positive_integer($n);
217  return Math::Prime::Util::PP::prime_count_lower($n);
218}
219sub prime_count_upper {
220  my($n) = @_;
221  _validate_positive_integer($n);
222  return Math::Prime::Util::PP::prime_count_upper($n);
223}
224sub prime_count_approx {
225  my($n) = @_;
226  _validate_positive_integer($n);
227  return Math::Prime::Util::PP::prime_count_approx($n);
228}
229sub twin_prime_count_approx {
230  my($n) = @_;
231  _validate_positive_integer($n);
232  return Math::Prime::Util::PP::twin_prime_count_approx($n);
233}
234sub semiprime_count_approx {
235  my($n) = @_;
236  _validate_positive_integer($n);
237  return Math::Prime::Util::PP::semiprime_count_approx($n);
238}
239sub ramanujan_prime_count_lower {
240  my($n) = @_;
241  _validate_positive_integer($n);
242  return Math::Prime::Util::PP::ramanujan_prime_count_lower($n);
243}
244sub ramanujan_prime_count_upper {
245  my($n) = @_;
246  _validate_positive_integer($n);
247  return Math::Prime::Util::PP::ramanujan_prime_count_upper($n);
248}
249sub ramanujan_prime_count_approx {
250  my($n) = @_;
251  _validate_positive_integer($n);
252  return Math::Prime::Util::PP::ramanujan_prime_count_approx($n);
253}
254sub nth_twin_prime {
255  my($n) = @_;
256  _validate_positive_integer($n);
257  return Math::Prime::Util::PP::nth_twin_prime($n);
258}
259sub nth_twin_prime_approx {
260  my($n) = @_;
261  _validate_positive_integer($n);
262  return Math::Prime::Util::PP::nth_twin_prime_approx($n);
263}
264sub nth_semiprime {
265  my($n) = @_;
266  _validate_positive_integer($n);
267  return Math::Prime::Util::PP::nth_semiprime($n);
268}
269sub nth_semiprime_approx {
270  my($n) = @_;
271  _validate_positive_integer($n);
272  return Math::Prime::Util::PP::nth_semiprime_approx($n);
273}
274sub nth_ramanujan_prime {
275  my($n) = @_;
276  _validate_positive_integer($n);
277  return Math::Prime::Util::PP::nth_ramanujan_prime($n);
278}
279sub nth_ramanujan_prime_lower {
280  my($n) = @_;
281  _validate_positive_integer($n);
282  return Math::Prime::Util::PP::nth_ramanujan_prime_lower($n);
283}
284sub nth_ramanujan_prime_upper {
285  my($n) = @_;
286  _validate_positive_integer($n);
287  return Math::Prime::Util::PP::nth_ramanujan_prime_upper($n);
288}
289sub nth_ramanujan_prime_approx {
290  my($n) = @_;
291  _validate_positive_integer($n);
292  return Math::Prime::Util::PP::nth_ramanujan_prime_approx($n);
293}
294
295
296*is_prime          = \&Math::Prime::Util::PP::is_prime;
297*is_prob_prime     = \&Math::Prime::Util::PP::is_prob_prime;
298*is_provable_prime = \&Math::Prime::Util::PP::is_provable_prime;
299*is_bpsw_prime     = \&Math::Prime::Util::PP::is_bpsw_prime;
300
301sub is_pseudoprime {
302  my($n, @bases) = @_;
303  return 0 if defined $n && int($n) < 0;
304  _validate_positive_integer($n);
305  croak "No bases given to is_strong_pseudoprime" unless @bases;
306  return Math::Prime::Util::PP::is_pseudoprime($n, @bases);
307}
308sub is_euler_pseudoprime {
309  my($n, @bases) = @_;
310  return 0 if defined $n && int($n) < 0;
311  _validate_positive_integer($n);
312  croak "No bases given to is_euler_pseudoprime" unless @bases;
313  return Math::Prime::Util::PP::is_euler_pseudoprime($n, @bases);
314}
315sub is_strong_pseudoprime {
316  my($n, @bases) = @_;
317  return 0 if defined $n && int($n) < 0;
318  _validate_positive_integer($n);
319  croak "No bases given to is_strong_pseudoprime" unless @bases;
320  return Math::Prime::Util::PP::is_strong_pseudoprime($n, @bases);
321}
322sub is_euler_plumb_pseudoprime {
323  my($n) = @_;
324  return 0 if defined $n && int($n) < 0;
325  _validate_positive_integer($n);
326  return Math::Prime::Util::PP::is_euler_plumb_pseudoprime($n);
327}
328sub is_lucas_pseudoprime {
329  my($n) = @_;
330  return 0 if defined $n && int($n) < 0;
331  _validate_positive_integer($n);
332  return Math::Prime::Util::PP::is_lucas_pseudoprime($n);
333}
334sub is_strong_lucas_pseudoprime {
335  my($n) = @_;
336  return 0 if defined $n && int($n) < 0;
337  _validate_positive_integer($n);
338  return Math::Prime::Util::PP::is_strong_lucas_pseudoprime($n);
339}
340sub is_extra_strong_lucas_pseudoprime {
341  my($n) = @_;
342  return 0 if defined $n && int($n) < 0;
343  _validate_positive_integer($n);
344  return Math::Prime::Util::PP::is_extra_strong_lucas_pseudoprime($n);
345}
346sub is_almost_extra_strong_lucas_pseudoprime {
347  my($n, $increment) = @_;
348  return 0 if defined $n && int($n) < 0;
349  _validate_positive_integer($n);
350  if (defined $increment) { _validate_positive_integer($increment, 1, 256);
351  } else                  { $increment = 1; }
352  return Math::Prime::Util::PP::is_almost_extra_strong_lucas_pseudoprime($n, $increment);
353}
354sub is_perrin_pseudoprime {
355  my($n,$restrict) = @_;
356  return 0 if defined $n && int($n) < 0;
357  $restrict = 0 unless defined $restrict;
358  _validate_positive_integer($n);
359  _validate_positive_integer($restrict);
360  return Math::Prime::Util::PP::is_perrin_pseudoprime($n, $restrict);
361}
362sub is_catalan_pseudoprime {
363  my($n) = @_;
364  return 0 if defined $n && int($n) < 0;
365  _validate_positive_integer($n);
366  return Math::Prime::Util::PP::is_catalan_pseudoprime($n);
367}
368sub is_frobenius_pseudoprime {
369  my($n, $P, $Q) = @_;
370  return 0 if defined $n && int($n) < 0;
371  _validate_positive_integer($n);
372  # TODO: validate P & Q
373  return Math::Prime::Util::PP::is_frobenius_pseudoprime($n, $P, $Q);
374}
375sub is_frobenius_underwood_pseudoprime {
376  my($n) = @_;
377  return 0 if defined $n && int($n) < 0;
378  _validate_positive_integer($n);
379  return Math::Prime::Util::PP::is_frobenius_underwood_pseudoprime($n);
380}
381sub is_frobenius_khashin_pseudoprime {
382  my($n) = @_;
383  return 0 if defined $n && int($n) < 0;
384  _validate_positive_integer($n);
385  return Math::Prime::Util::PP::is_frobenius_khashin_pseudoprime($n);
386}
387sub is_aks_prime {
388  my($n) = @_;
389  return 0 if defined $n && int($n) < 0;
390  _validate_positive_integer($n);
391  return Math::Prime::Util::PP::is_aks_prime($n);
392}
393sub is_ramanujan_prime {
394  my($n) = @_;
395  return 0 if defined $n && int($n) < 0;
396  _validate_positive_integer($n);
397  return Math::Prime::Util::PP::is_ramanujan_prime($n);
398}
399sub is_mersenne_prime {
400  my($p) = @_;
401  _validate_positive_integer($p);
402  return Math::Prime::Util::PP::is_mersenne_prime($p);
403}
404sub is_square_free {
405  my($n) = @_;
406  _validate_integer($n);
407  return Math::Prime::Util::PP::is_square_free($n);
408}
409sub is_primitive_root {
410  my($a,$n) = @_;
411  return 0 if $n == 0;
412  $n = -$n if defined $n && $n < 0;
413  $a %= $n if defined $a && $a < 0;
414  _validate_positive_integer($a);
415  _validate_positive_integer($n);
416  return Math::Prime::Util::PP::is_primitive_root($a,$n);
417}
418
419
420sub lucas_sequence {
421  my($n, $P, $Q, $k) = @_;
422  my ($vp, $vq) = ($P, $Q);
423  $vp = -$vp if defined $vp && $vp < 0;
424  $vq = -$vq if defined $vq && $vq < 0;
425  _validate_positive_integer($n);
426  _validate_positive_integer($vp);
427  _validate_positive_integer($vq);
428  _validate_positive_integer($k);
429  return Math::Prime::Util::PP::lucas_sequence(@_);
430}
431sub lucasu {
432  my($P, $Q, $k) = @_;
433  my ($vp, $vq) = ($P, $Q);
434  $vp = -$vp if defined $vp && $vp < 0;
435  $vq = -$vq if defined $vq && $vq < 0;
436  _validate_positive_integer($vp);
437  _validate_positive_integer($vq);
438  _validate_positive_integer($k);
439  return Math::Prime::Util::PP::lucasu(@_);
440}
441sub lucasv {
442  my($P, $Q, $k) = @_;
443  my ($vp, $vq) = ($P, $Q);
444  $vp = -$vp if defined $vp && $vp < 0;
445  $vq = -$vq if defined $vq && $vq < 0;
446  _validate_positive_integer($vp);
447  _validate_positive_integer($vq);
448  _validate_positive_integer($k);
449  return Math::Prime::Util::PP::lucasv(@_);
450}
451
452sub kronecker {
453  my($a, $b) = @_;
454  my ($va, $vb) = ($a, $b);
455  $va = -$va if defined $va && $va < 0;
456  $vb = -$vb if defined $vb && $vb < 0;
457  _validate_positive_integer($va);
458  _validate_positive_integer($vb);
459  return Math::Prime::Util::PP::kronecker(@_);
460}
461
462sub factorial {
463  my($n) = @_;
464  _validate_integer($n);
465  return Math::Prime::Util::PP::factorial($n);
466}
467
468sub factorialmod {
469  my($n, $m) = @_;
470  _validate_integer($n);
471  _validate_integer($m);
472  return Math::Prime::Util::PP::factorialmod($n, $m);
473}
474
475sub binomial {
476  my($n, $k) = @_;
477  _validate_integer($n);
478  _validate_integer($k);
479  return Math::Prime::Util::PP::binomial($n, $k);
480}
481
482sub stirling {
483  my($n, $k, $type) = @_;
484  _validate_positive_integer($n);
485  _validate_positive_integer($k);
486  _validate_positive_integer($type) if defined $type;
487  return Math::Prime::Util::PP::stirling($n, $k, $type);
488}
489
490sub znorder {
491  my($a, $n) = @_;
492  _validate_positive_integer($a);
493  _validate_positive_integer($n);
494  return Math::Prime::Util::PP::znorder($a, $n);
495}
496
497sub znlog {
498  my($a, $g, $p) = @_;
499  _validate_positive_integer($a);
500  _validate_positive_integer($g);
501  _validate_positive_integer($p);
502  return Math::Prime::Util::PP::znlog($a, $g, $p);
503}
504
505sub znprimroot {
506  my($n) = @_;
507  $n =~ s/^-(\d+)/$1/ if defined $n;
508  _validate_positive_integer($n);
509  return Math::Prime::Util::PP::znprimroot($n);
510}
511
512sub trial_factor {
513  my($n, $maxlim) = @_;
514  _validate_positive_integer($n);
515  if (defined $maxlim) {
516    _validate_positive_integer($maxlim);
517    return Math::Prime::Util::PP::trial_factor($n, $maxlim);
518  }
519  return Math::Prime::Util::PP::trial_factor($n);
520}
521sub fermat_factor {
522  my($n, $rounds) = @_;
523  _validate_positive_integer($n);
524  if (defined $rounds) {
525    _validate_positive_integer($rounds);
526    return Math::Prime::Util::PP::fermat_factor($n, $rounds);
527  }
528  return Math::Prime::Util::PP::fermat_factor($n);
529}
530sub holf_factor {
531  my($n, $rounds) = @_;
532  _validate_positive_integer($n);
533  if (defined $rounds) {
534    _validate_positive_integer($rounds);
535    return Math::Prime::Util::PP::holf_factor($n, $rounds);
536  }
537  return Math::Prime::Util::PP::holf_factor($n);
538}
539sub squfof_factor {
540  my($n, $rounds) = @_;
541  _validate_positive_integer($n);
542  if (defined $rounds) {
543    _validate_positive_integer($rounds);
544    return Math::Prime::Util::PP::squfof_factor($n, $rounds);
545  }
546  return Math::Prime::Util::PP::squfof_factor($n);
547}
548sub pbrent_factor {
549  my($n, $rounds, $pa) = @_;
550  _validate_positive_integer($n);
551  if (defined $rounds) { _validate_positive_integer($rounds);
552  } else               { $rounds = 4*1024*1024; }
553  if (defined $pa    ) { _validate_positive_integer($pa);
554  } else               { $pa = 3; }
555  return Math::Prime::Util::PP::pbrent_factor($n, $rounds, $pa);
556}
557sub prho_factor {
558  my($n, $rounds, $pa) = @_;
559  _validate_positive_integer($n);
560  if (defined $rounds) { _validate_positive_integer($rounds);
561  } else               { $rounds = 4*1024*1024; }
562  if (defined $pa    ) { _validate_positive_integer($pa);
563  } else               { $pa = 3; }
564  return Math::Prime::Util::PP::prho_factor($n, $rounds, $pa);
565}
566sub pminus1_factor {
567  my($n, $B1, $B2) = @_;
568  _validate_positive_integer($n);
569  _validate_positive_integer($B1) if defined $B1;
570  _validate_positive_integer($B2) if defined $B2;
571  Math::Prime::Util::PP::pminus1_factor($n, $B1, $B2);
572}
573*pplus1_factor = \&pminus1_factor;
574
575sub divisors {
576  my($n) = @_;
577  _validate_positive_integer($n);
578  return Math::Prime::Util::PP::divisors($n);
579}
580
581sub divisor_sum {
582  my($n, $k) = @_;
583  _validate_positive_integer($n);
584  _validate_positive_integer($k) if defined $k && ref($k) ne 'CODE';
585  return Math::Prime::Util::PP::divisor_sum($n, $k);
586}
587
588sub gcd {
589  my(@v) = @_;
590  _validate_integer($_) for @v;
591  return Math::Prime::Util::PP::gcd(@v);
592}
593sub lcm {
594  my(@v) = @_;
595  _validate_integer($_) for @v;
596  return Math::Prime::Util::PP::lcm(@v);
597}
598sub gcdext {
599  my($a,$b) = @_;
600  _validate_integer($a);
601  _validate_integer($b);
602  return Math::Prime::Util::PP::gcdext($a,$b);
603}
604sub chinese {
605  # TODO: make sure we're not modding their data
606  foreach my $aref (@_) {
607    die "chinese arguments are two-element array references"
608      unless ref($aref) eq 'ARRAY' && scalar @$aref == 2;
609    _validate_integer($aref->[0]);
610    _validate_integer($aref->[1]);
611  }
612  return Math::Prime::Util::PP::chinese(@_);
613}
614sub vecsum {
615  my(@v) = @_;
616  _validate_integer($_) for @v;
617  return Math::Prime::Util::PP::vecsum(@v);
618}
619sub vecprod {
620  my(@v) = @_;
621  _validate_integer($_) for @v;
622  return Math::Prime::Util::PP::vecprod(@v);
623}
624sub vecmin {
625  my(@v) = @_;
626  _validate_integer($_) for @v;
627  return Math::Prime::Util::PP::vecmin(@v);
628}
629sub vecmax {
630  my(@v) = @_;
631  _validate_integer($_) for @v;
632  return Math::Prime::Util::PP::vecmax(@v);
633}
634sub invmod {
635  my ($a, $n) = @_;
636  _validate_integer($a);
637  _validate_integer($n);
638  return Math::Prime::Util::PP::invmod($a,$n);
639}
640sub sqrtmod {
641  my ($a, $n) = @_;
642  _validate_integer($a);
643  _validate_integer($n);
644  return Math::Prime::Util::PP::sqrtmod($a,$n);
645}
646sub addmod {
647  my ($a, $b, $n) = @_;
648  _validate_integer($a); _validate_integer($b>=0?$b:-$b); _validate_integer($n);
649  return Math::Prime::Util::PP::addmod($a,$b, $n);
650}
651sub mulmod {
652  my ($a, $b, $n) = @_;
653  _validate_integer($a); _validate_integer($b>=0?$b:-$b); _validate_integer($n);
654  return Math::Prime::Util::PP::mulmod($a,$b, $n);
655}
656sub divmod {
657  my ($a, $b, $n) = @_;
658  _validate_integer($a); _validate_integer($b>=0?$b:-$b); _validate_integer($n);
659  return Math::Prime::Util::PP::divmod($a,$b, $n);
660}
661sub powmod {
662  my ($a, $b, $n) = @_;
663  _validate_integer($a); _validate_integer($b>=0?$b:-$b); _validate_integer($n);
664  return Math::Prime::Util::PP::powmod($a,$b, $n);
665}
666sub sqrtint {
667  my($n) = @_;
668  _validate_integer($n);
669  return Math::Prime::Util::PP::sqrtint($n);
670}
671sub rootint {
672  my($n, $k, $refp) = @_;
673  _validate_positive_integer($n);
674  _validate_positive_integer($k);
675  return Math::Prime::Util::PP::rootint($n, $k, $refp);
676}
677sub logint {
678  my($n, $b, $refp) = @_;
679  _validate_positive_integer($n);
680  _validate_positive_integer($b);
681  return Math::Prime::Util::PP::logint($n, $b, $refp);
682}
683
684sub legendre_phi {
685  my($x, $a) = @_;
686  _validate_positive_integer($x);
687  _validate_positive_integer($a);
688  return Math::Prime::Util::PP::legendre_phi($x, $a);
689}
690
691sub chebyshev_theta {
692  my($n) = @_;
693  _validate_positive_integer($n);
694  return Math::Prime::Util::PP::chebyshev_theta($n);
695}
696sub chebyshev_psi {
697  my($n) = @_;
698  _validate_positive_integer($n);
699  return Math::Prime::Util::PP::chebyshev_psi($n);
700}
701sub ramanujan_tau {
702  my($n) = @_;
703  _validate_positive_integer($n);
704  return Math::Prime::Util::PP::ramanujan_tau($n);
705}
706
707sub is_power {
708  my($n, $a, $refp) = @_;
709  my $vn = "$n";  $vn =~ s/^-//;
710  _validate_positive_integer($vn);
711  _validate_positive_integer($a) if defined $a;
712  $vn = '-'.$vn if $n < 0;
713  return Math::Prime::Util::PP::is_power($vn, $a, $refp);
714}
715sub is_prime_power {
716  my($n, $refp) = @_;
717  my $vn = "$n";  $vn =~ s/^-//;
718  _validate_positive_integer($vn);
719  $vn = '-'.$vn if $n < 0;
720  return Math::Prime::Util::PP::is_prime_power($vn, $refp);
721}
722sub is_polygonal {
723  my($x, $s, $refp) = @_;
724  my $vx = "$x";  $vx =~ s/^-//;
725  _validate_positive_integer($vx);
726  _validate_positive_integer($s);
727  $vx = '-'.$vx if $x < 0;
728  return Math::Prime::Util::PP::is_polygonal($vx, $s, $refp);
729}
730sub valuation {
731  my($n, $k) = @_;
732  $n = -$n if defined $n && $n < 0;
733  $k = -$k if defined $k && $k < 0;
734  _validate_positive_integer($n);
735  _validate_positive_integer($k);
736  return Math::Prime::Util::PP::valuation($n, $k);
737}
738sub hammingweight {
739  my($n) = @_;
740  $n = -$n if defined $n && $n < 0;
741  _validate_positive_integer($n);
742  return Math::Prime::Util::PP::hammingweight($n);
743}
744
745sub Pi {
746  my($digits) = @_;
747  _validate_positive_integer($digits) if defined $digits;
748  return Math::Prime::Util::PP::Pi($digits);
749}
750
751#############################################################################
752
753my $_exitloop = 0;
754sub lastfor { $_exitloop = 1; }
755sub _get_forexit { $_exitloop; }
756sub _start_for_loop { my $old = $_exitloop; $_exitloop = 0; $old; }
757sub _end_for_loop { $_exitloop = shift; }
758
759sub forprimes (&$;$) {    ## no critic qw(ProhibitSubroutinePrototypes)
760  my($sub, $beg, $end) = @_;
761  if (!defined $end) { $end = $beg; $beg = 2; }
762  _validate_num($beg) || _validate_positive_integer($beg);
763  _validate_num($end) || _validate_positive_integer($end);
764  $beg = 2 if $beg < 2;
765  my $oldforexit = _start_for_loop();
766  {
767    my $pp;
768    local *_ = \$pp;
769    for (my $p = next_prime($beg-1);  $p <= $end;  $p = next_prime($p)) {
770      $pp = $p;
771      $sub->();
772      last if $_exitloop;
773    }
774  }
775  _end_for_loop($oldforexit);
776}
777
778sub forcomposites(&$;$) { ## no critic qw(ProhibitSubroutinePrototypes)
779  Math::Prime::Util::_generic_forcomp_sub('composites', @_);
780}
781sub foroddcomposites(&$;$) { ## no critic qw(ProhibitSubroutinePrototypes)
782  Math::Prime::Util::_generic_forcomp_sub('oddcomposites', @_);
783}
784sub forsemiprimes(&$;$) { ## no critic qw(ProhibitSubroutinePrototypes)
785  Math::Prime::Util::_generic_forcomp_sub('semiprimes', @_);
786}
787
788sub forfactored(&$;$) { ## no critic qw(ProhibitSubroutinePrototypes)
789  Math::Prime::Util::_generic_forfac(0, @_);
790}
791sub forsquarefree(&$;$) { ## no critic qw(ProhibitSubroutinePrototypes)
792  Math::Prime::Util::_generic_forfac(1, @_);
793}
794
795sub fordivisors (&$) {    ## no critic qw(ProhibitSubroutinePrototypes)
796  my($sub, $n) = @_;
797  _validate_num($n) || _validate_positive_integer($n);
798  my @divisors = divisors($n);
799  my $oldforexit = _start_for_loop();
800  {
801    my $pp;
802    local *_ = \$pp;
803    foreach my $d (@divisors) {
804      $pp = $d;
805      $sub->();
806      last if $_exitloop;
807    }
808  }
809  _end_for_loop($oldforexit);
810}
811
812sub forpart (&$;$) {    ## no critic qw(ProhibitSubroutinePrototypes)
813  Math::Prime::Util::PP::forpart(@_);
814}
815sub forcomp (&$;$) {    ## no critic qw(ProhibitSubroutinePrototypes)
816  Math::Prime::Util::PP::forcomp(@_);
817}
818sub forcomb (&$;$) {    ## no critic qw(ProhibitSubroutinePrototypes)
819  Math::Prime::Util::PP::forcomb(@_);
820}
821sub forperm (&$;$) {    ## no critic qw(ProhibitSubroutinePrototypes)
822  Math::Prime::Util::PP::forperm(@_);
823}
824sub forderange (&$;$) {    ## no critic qw(ProhibitSubroutinePrototypes)
825  Math::Prime::Util::PP::forderange(@_);
826}
827
828sub forsetproduct (&@) {    ## no critic qw(ProhibitSubroutinePrototypes)
829  my($sub, @v) = @_;
830  croak 'Not a subroutine reference' unless (ref($sub) || '') eq 'CODE';
831  croak 'Not an array reference' if grep {(ref($_) || '') ne 'ARRAY'} @v;
832  # Exit if no arrays or any are empty.
833  return if scalar(@v) == 0 || grep { !@$_ } @v;
834
835  my @outv = map { $v[$_]->[0] } 0 .. $#v;
836  my @cnt = (0) x @v;
837
838  my $oldforexit = _start_for_loop();
839  my $i = 0;
840  while ($i >= 0) {
841    $sub->(@outv);
842    last if $_exitloop;
843    for ($i = $#v; $i >= 0; $i--) {
844      if ($cnt[$i] >= $#{$v[$i]}) { $cnt[$i] = 0; $outv[$i] = $v[$i]->[0]; }
845      else { $outv[$i] = $v[$i]->[++$cnt[$i]]; last; }
846    }
847  }
848  _end_for_loop($oldforexit);
849}
850
851sub vecreduce (&@) {    ## no critic qw(ProhibitSubroutinePrototypes)
852  my($sub, @v) = @_;
853
854  # Mastering Perl page 162, works with old Perl
855  my $caller = caller();
856  no strict 'refs'; ## no critic(strict)
857  local(*{$caller.'::a'}) = \my $a;
858  local(*{$caller.'::b'}) = \my $b;
859  $a = shift @v;
860  for my $v (@v) {
861    $b = $v;
862    $a = $sub->();
863  }
864  $a;
865}
866
867sub vecany (&@) {       ## no critic qw(ProhibitSubroutinePrototypes)
868  my $sub = shift;
869  $sub->() and return 1 foreach @_;
870  0;
871}
872sub vecall (&@) {       ## no critic qw(ProhibitSubroutinePrototypes)
873  my $sub = shift;
874  $sub->() or return 0 foreach @_;
875  1;
876}
877sub vecnone (&@) {      ## no critic qw(ProhibitSubroutinePrototypes)
878  my $sub = shift;
879  $sub->() and return 0 foreach @_;
880  1;
881}
882sub vecnotall (&@) {    ## no critic qw(ProhibitSubroutinePrototypes)
883  my $sub = shift;
884  $sub->() or return 1 foreach @_;
885  undef;
886}
887
888sub vecfirst (&@) {     ## no critic qw(ProhibitSubroutinePrototypes)
889  my $sub = shift;
890  $sub->() and return $_ foreach @_;
891  undef;
892}
893
894sub vecfirstidx (&@) {     ## no critic qw(ProhibitSubroutinePrototypes)
895  my $sub = shift;
896  my $i = 0;
897  ++$i and $sub->() and return $i-1 foreach @_;
898  -1;
899}
900
901sub vecextract {
902  my($aref, $mask) = @_;
903  croak "vecextract first argument must be an array reference"
904    unless ref($aref) eq 'ARRAY';
905  return Math::Prime::Util::PP::vecextract(@_);
906}
907
9081;
909
910__END__
911
912=pod
913
914=head1 NAME
915
916Math::Prime::Util::PPFE - PP front end for Math::Prime::Util
917
918=head1 SYNOPSIS
919
920This loads the PP code and adds input validation front ends.  It is only
921meant to be used when XS is not used.
922
923=head1 DESCRIPTION
924
925Loads PP module and implements PP front-end functions for all XS code.
926This is used only if the XS code is not loaded.
927
928=head1 SEE ALSO
929
930L<Math::Prime::Util>
931
932L<Math::Prime::Util::PP>
933
934=head1 AUTHORS
935
936Dana Jacobsen E<lt>dana@acm.orgE<gt>
937
938
939=head1 COPYRIGHT
940
941Copyright 2014-2016 by Dana Jacobsen E<lt>dana@acm.orgE<gt>
942
943This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
944
945=cut
946