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