Codebase list libmath-prime-util-perl / 3e8484c
Merge tag 'upstream/0.37' Upstream version 0.37 gregor herrmann 10 years ago
85 changed file(s) with 5747 addition(s) and 4994 deletion(s). Raw diff Collapse all Expand all
00 Revision history for Perl module Math::Prime::Util
1
2 0.37 2014-01-26
3
4 [FUNCTIONALITY AND PERFORMANCE]
5
6 - Simplified primes(). No longer takes an optional hashref as first arg,
7 which was awkward and never documented.
8
9 - Dynamically loads the PP code and Math::BigInt only when needed. This
10 removes a lot of bloat for the usual cases:
11
12 2.0 MB perl -E 'say 1'
13 4.2 MB MPU 0.37
14 4.5 MB Math::Prime::XS + Math::Factor::XS
15 5.3 MB Math::Pari
16 7.6 MB MPU 0.34
17 9.6 MB MPU 0.36
18 9.7 MB MPU 0.35
19
20 - Combined with the above, this reduces startup overhead a lot (~3x).
21
22 - Adjusted factor script to lower startup costs. Over 2x faster
23 with native integer (non-expression) arguments. This is just not
24 loading thousands of lines of Perl code that aren't used, which
25 was more time-consuming than the actual factoring.
26
27 - nth_prime_{lower,upper,approx} and prime_count_{lower,upper,approx}
28 moved to XS->PP. This helps us slim down and cut startup overhead.
29
30 - Fix doc for znlog: znlog(a,g,p) finds k s.t. a = g^k mod p
31
132
233 0.36 2014-01-13
334
44 lib/Math/Prime/Util/PrimeArray.pm
55 lib/Math/Prime/Util/PrimeIterator.pm
66 lib/Math/Prime/Util/PP.pm
7 lib/Math/Prime/Util/PPFE.pm
78 lib/Math/Prime/Util/ZetaBigFloat.pm
89 lib/Math/Prime/Util/ECAffinePoint.pm
910 lib/Math/Prime/Util/ECProjectivePoint.pm
1011 lib/Math/Prime/Util/PrimalityProving.pm
12 lib/Math/Prime/Util/RandomPrimes.pm
1113 LICENSE
1214 Makefile.PL
1315 MANIFEST
3537 sieve.c
3638 util.h
3739 util.c
40 bench/bench-factor.pl
41 bench/bench-factor-extra.pl
42 bench/bench-factor-semiprime.pl
43 bench/bench-is-prime.pl
44 bench/bench-isprime-bpsw.pl
45 bench/bench-miller-rabin.pl
46 bench/bench-nthprime.pl
47 bench/bench-pcapprox.pl
48 bench/bench-primearray.pl
49 bench/bench-primecount.pl
50 bench/bench-random-prime.pl
51 bench/bench-random-prime-bigint.pl
52 bench/bench-pp-count.pl
53 bench/bench-pp-isprime.pl
54 bench/bench-pp-sieve.pl
55 bench/bench-mp-nextprime.pl
56 bench/bench-mp-psrp.pl
57 bench/bench-mp-prime_count.pl
58 bench/factor-gnufactor.pl
3859 examples/README
39 examples/bench-factor.pl
40 examples/bench-factor-extra.pl
41 examples/bench-factor-semiprime.pl
42 examples/bench-is-prime.pl
43 examples/bench-isprime-bpsw.pl
44 examples/bench-miller-rabin.pl
45 examples/bench-nthprime.pl
46 examples/bench-pcapprox.pl
47 examples/bench-primearray.pl
48 examples/bench-primecount.pl
49 examples/bench-random-prime.pl
50 examples/bench-random-prime-bigint.pl
51 examples/bench-pp-count.pl
52 examples/bench-pp-isprime.pl
53 examples/bench-pp-sieve.pl
54 examples/bench-mp-nextprime.pl
55 examples/bench-mp-psrp.pl
56 examples/bench-mp-prime_count.pl
57 examples/test-factor-yafu.pl
58 examples/test-nextprime-yafu.pl
59 examples/test-primes-yafu.pl
6060 examples/sophie_germain.pl
6161 examples/twin_primes.pl
6262 examples/abundant.pl
6363 examples/find_mr_bases.pl
6464 examples/parallel_fibprime.pl
65 examples/test-factor-gnufactor.pl
65 examples/porter.pl
6666 examples/verify-gmp-ecpp-cert.pl
6767 examples/verify-sage-ecpp-cert.pl
6868 examples/verify-cert.pl
124124 xt/test-pcapprox.pl
125125 xt/test-primes-script.pl
126126 xt/test-primes-script2.pl
127 xt/test-factor-yafu.pl
128 xt/test-nextprime-yafu.pl
127129 .travis.yml
128130 META.yml Module YAML meta-data (added by MakeMaker)
129131 META.json Module JSON meta-data (added by MakeMaker)
33 "Dana A Jacobsen <dana@acm.org>"
44 ],
55 "dynamic_config" : 1,
6 "generated_by" : "ExtUtils::MakeMaker version 6.82, CPAN::Meta::Converter version 2.132830",
6 "generated_by" : "ExtUtils::MakeMaker version 6.86, CPAN::Meta::Converter version 2.133380",
77 "license" : [
88 "perl_5"
99 ],
2020 },
2121 "prereqs" : {
2222 "build" : {
23 "requires" : {
24 "ExtUtils::MakeMaker" : "0"
25 }
26 },
27 "configure" : {
2328 "requires" : {
2429 "ExtUtils::MakeMaker" : "0"
2530 }
6469 "url" : "https://github.com/danaj/Math-Prime-Util"
6570 }
6671 },
67 "version" : "0.36"
72 "version" : "0.37"
6873 }
55 ExtUtils::MakeMaker: 0
66 Test::More: 0.45
77 bignum: 0.22
8 configure_requires:
9 ExtUtils::MakeMaker: 0
810 dynamic_config: 1
9 generated_by: 'ExtUtils::MakeMaker version 6.82, CPAN::Meta::Converter version 2.132830'
11 generated_by: 'ExtUtils::MakeMaker version 6.86, CPAN::Meta::Converter version 2.133380'
1012 license: perl
1113 meta-spec:
1214 url: http://module-build.sourceforge.net/META-spec-v1.4.html
3638 homepage: https://github.com/danaj/Math-Prime-Util
3739 license: http://dev.perl.org/licenses/
3840 repository: https://github.com/danaj/Math-Prime-Util
39 version: 0.36
41 version: 0.37
0 Math::Prime::Util version 0.36
0 Math::Prime::Util version 0.37
11
22 A set of utilities related to prime numbers. These include multiple sieving
33 methods, is_prime, prime_count, nth_prime, approximations and bounds for
44 * use: -O2 -g -Wall -Wextra -Wdeclaration-after-statement -fsigned-char
55 * Test on 32-bit Perl. Test on Win32.
66
7
8 - Add test to check maxbits in compiled library vs. Perl
97
108 - Figure out documentation solution for PP.pm
119
2826 - Big features:
2927 - QS factoring
3028
31 - segment sieve should itself use a segment for its primes.
32 Today we'd need sqrt(2^64) max = 140MB. Segmenting would yield under 1MB.
33
3429 - Figure out a way to make the internal FOR_EACH_PRIME macros use a segmented
3530 sieve.
3631
3732 - Rewrite 23-primality-proofs.t for new format (keep some of the old tests?).
3833
3934 - Use Montgomery routines in more places: Factoring.
40
41 - Put euler_phi and moebius directly in XS.
42 (1) optional second argument. Easily handled, and not hard to do in
43 generic sub call.
44 (2) generic sub returns an array. This is the sticking point.
4535
4636 - Factoring in PP code is really wasteful -- we're calling _isprime7 before
4737 we've done enough trial division, and later we're calling it on known
6959 - Perhaps have main segment know the filled in range. That would allow
7060 a sieved next_prime, and might speed up some counts and the like.
7161
72 - Consider exporting is_bpsw_prime
73
74 - Add Inverse Li to API?
62 - Consider exporting is_bpsw_prime and inverse Li
7563
7664 - Benchmark simple SoEs, SoA. Include Sisyphus SoE hidden in Math::GMPz.
77
78 - Redo trial vs. segment test in Util.pm primes().
7965
8066 - commit Porter example
8167
8470 - Investigate optree constant folding in PP compilation for performance.
8571 Use B::Deparse to check.
8672
87 - Move more functions from _generic_... to PP::
88
8973 - Ensure a fast path for Math::GMP from MPU -> MPU:GMP -> GMP, and back.
9074
91 - znlog bignum tests, znlog better implementation
75 - znlog better implementation
+71
-41
XS.xs less more
175175 GV ** gvp = (GV**)hv_fetch(MY_CXT.MPUGMP,name,namelen,0);
176176 if (gvp) gv = *gvp;
177177 }
178 if (!gv && (stashflags & VCALL_PP))
179 perl_require_pv("Math/Prime/Util/PP.pm");
178180 if (!gv) {
179181 GV ** gvp = (GV**)hv_fetch(stashflags & VCALL_PP? MY_CXT.MPUPP : MY_CXT.MPUroot, name,namelen,0);
180182 if (gvp) gv = *gvp;
586588 ALIAS:
587589 prev_prime = 1
588590 nth_prime = 2
591 nth_prime_upper = 3
592 nth_prime_lower = 4
593 nth_prime_approx = 5
594 prime_count_upper = 6
595 prime_count_lower = 7
596 prime_count_approx = 8
589597 PPCODE:
590598 if (_validate_int(aTHX_ svn, 0)) {
591599 UV n = my_svuv(svn);
592 if ( ((ix == 0) && (n >= MPU_MAX_PRIME)) ||
593 ((ix == 2) && (n >= MPU_MAX_PRIME_IDX)) ) {
600 if ( (n >= MPU_MAX_PRIME && ix == 0) ||
601 (n >= MPU_MAX_PRIME_IDX && (ix==2 || ix==3 || ix==4 || ix==5)) ) {
594602 /* Out of range. Fall through to Perl. */
595603 } else {
596604 UV ret;
597605 switch (ix) {
598606 case 0: ret = next_prime(n); break;
599607 case 1: ret = (n < 3) ? 0 : prev_prime(n); break;
600 case 2:
601 default:ret = _XS_nth_prime(n); break;
608 case 2: ret = nth_prime(n); break;
609 case 3: ret = nth_prime_upper(n); break;
610 case 4: ret = nth_prime_lower(n); break;
611 case 5: ret = nth_prime_approx(n); break;
612 case 6: ret = prime_count_upper(n); break;
613 case 7: ret = prime_count_lower(n); break;
614 case 8:
615 default:ret = prime_count_approx(n); break;
602616 }
603617 XSRETURN_UV(ret);
604618 }
605619 }
606620 switch (ix) {
607 case 0: _vcallsub("_generic_next_prime"); break;
608 case 1: _vcallsub("_generic_prev_prime"); break;
609 default: _vcallsub_with_pp("nth_prime"); break;
621 case 0: _vcallsub("_generic_next_prime"); break;
622 case 1: _vcallsub("_generic_prev_prime"); break;
623 case 2: _vcallsub_with_pp("nth_prime"); break;
624 case 3: _vcallsub_with_pp("nth_prime_upper"); break;
625 case 4: _vcallsub_with_pp("nth_prime_lower"); break;
626 case 5: _vcallsub_with_pp("nth_prime_approx"); break;
627 case 6: _vcallsub_with_pp("prime_count_upper"); break;
628 case 7: _vcallsub_with_pp("prime_count_lower"); break;
629 case 8:
630 default: _vcallsub_with_pp("prime_count_approx"); break;
610631 }
611632 return; /* skip implicit PUTBACK */
612633
664685 switch (ix) {
665686 case 0: _vcallsubn(aTHX_ gimme_v, VCALL_ROOT, "_generic_factor", 1); break;
666687 case 1: _vcallsubn(aTHX_ gimme_v, VCALL_ROOT, "_generic_factor_exp", 1); break;
667 default: _vcallsubn(aTHX_ gimme_v, VCALL_ROOT, "_generic_divisors", 1); break;
688 default: _vcallsubn(aTHX_ gimme_v, VCALL_GMP|VCALL_PP, "divisors", 1); break;
668689 }
669690 return; /* skip implicit PUTBACK */
670691 }
684705 UV sigma = divisor_sum(n, k);
685706 if (sigma != 0) XSRETURN_UV(sigma); /* sigma 0 means overflow */
686707 }
687 _vcallsub("_generic_divisor_sum");
708 _vcallsub_with_gmp("divisor_sum");
688709 return; /* skip implicit PUTBACK */
689710
690711 void
717738 }
718739 overflow:
719740 switch (ix) {
720 case 0: _vcallsub_with_pp("znorder"); break;
741 case 0: _vcallsub_with_gmp("znorder"); break;
721742 case 1: _vcallsub_with_pp("jordan_totient"); break;
722743 case 2:
723744 default: _vcallsub_with_pp("legendre_phi"); break;
738759 if (ret == 0 && a > 1) XSRETURN_UNDEF;
739760 XSRETURN_UV(ret);
740761 }
741 _vcallsub_with_pp("znlog");
762 _vcallsub_with_gmp("znlog");
742763 return; /* skip implicit PUTBACK */
743764
744765 void
760781 int k = (abpositive) ? kronecker_uu(a,b) : kronecker_ss(a,b);
761782 RETURN_NPARITY(k);
762783 }
763 _vcallsub("_generic_kronecker");
784 _vcallsub_with_gmp("kronecker");
764785 return; /* skip implicit PUTBACK */
765786
766 double
787 NV
767788 _XS_ExponentialIntegral(IN SV* x)
768789 ALIAS:
769790 _XS_LogarithmicIntegral = 1
770791 _XS_RiemannZeta = 2
771792 _XS_RiemannR = 3
772 _XS_chebyshev_theta = 4
773 _XS_chebyshev_psi = 5
774 PREINIT:
775 double ret;
793 PREINIT:
794 NV nv, ret;
776795 CODE:
777 if (ix < 4) {
778 NV nv = SvNV(x);
779 switch (ix) {
780 case 0: ret = (NV) _XS_ExponentialIntegral(nv); break;
781 case 1: ret = (NV) _XS_LogarithmicIntegral(nv); break;
782 case 2: ret = (NV) ld_riemann_zeta(nv); break;
783 case 3:
784 default:ret = (NV) _XS_RiemannR(nv); break;
785 }
786 } else {
787 UV uv = SvUV(x);
788 ret = (NV) chebyshev_function(uv, ix-4);
796 nv = SvNV(x);
797 switch (ix) {
798 case 0: ret = (NV) _XS_ExponentialIntegral(nv); break;
799 case 1: ret = (NV) _XS_LogarithmicIntegral(nv); break;
800 case 2: ret = (NV) ld_riemann_zeta(nv); break;
801 case 3:
802 default:ret = (NV) _XS_RiemannR(nv); break;
789803 }
790804 RETVAL = ret;
791805 OUTPUT:
833847 /* Whatever we didn't handle above */
834848 U32 gimme_v = GIMME_V;
835849 switch (ix) {
836 case 0: _vcallsubn(aTHX_ gimme_v, VCALL_ROOT,"_generic_euler_phi", items);break;
850 case 0: _vcallsubn(aTHX_ gimme_v, VCALL_PP, "euler_phi", items);break;
837851 case 1:
838 default: _vcallsubn(aTHX_ gimme_v, VCALL_ROOT,"_generic_moebius", items); break;
852 default: _vcallsubn(aTHX_ gimme_v, VCALL_PP, "moebius", items); break;
839853 }
840854 return;
841855 }
844858 carmichael_lambda(IN SV* svn)
845859 ALIAS:
846860 mertens = 1
847 exp_mangoldt = 2
848 znprimroot = 3
861 liouville = 2
862 chebyshev_theta = 3
863 chebyshev_psi = 4
864 exp_mangoldt = 5
865 znprimroot = 6
849866 PREINIT:
850867 int status;
851868 PPCODE:
852 status = _validate_int(aTHX_ svn, (ix > 1) ? 1 : 0);
869 status = _validate_int(aTHX_ svn, (ix >= 5) ? 1 : 0);
853870 switch (ix) {
854871 case 0: if (status == 1) XSRETURN_UV(carmichael_lambda(my_svuv(svn)));
855 _vcallsub("_generic_carmichael_lambda");
872 _vcallsub_with_gmp("carmichael_lambda");
856873 break;
857874 case 1: if (status == 1) XSRETURN_IV(mertens(my_svuv(svn)));
858 _vcallsub("_generic_mertens");
875 _vcallsub_with_pp("mertens");
859876 break;
860 case 2: if (status ==-1) XSRETURN_UV(1);
861 if (status == 1) XSRETURN_UV(exp_mangoldt(my_svuv(svn)));
862 _vcallsub("_generic_exp_mangoldt");
877 case 2: if (status == 1) {
878 UV factors[MPU_MAX_FACTORS+1];
879 int nfactors = factor(my_svuv(svn), factors);
880 RETURN_NPARITY( (nfactors & 1) ? -1 : 1 );
881 }
882 _vcallsub_with_gmp("liouville");
863883 break;
864 case 3:
884 case 3: if (status == 1) XSRETURN_NV(chebyshev_function(my_svuv(svn),0));
885 _vcallsub_with_pp("chebyshev_theta");
886 break;
887 case 4: if (status == 1) XSRETURN_NV(chebyshev_function(my_svuv(svn),1));
888 _vcallsub_with_pp("chebyshev_psi");
889 break;
890 case 5: if (status != 0)
891 XSRETURN_UV( (status == -1) ? 1 : exp_mangoldt(my_svuv(svn)) );
892 _vcallsub_with_gmp("exp_mangoldt");
893 break;
894 case 6:
865895 default:if (status != 0) {
866896 UV r, n = my_svuv(svn);
867897 if (status == -1) n = -(IV)n;
871901 else
872902 XSRETURN_UV(r);
873903 }
874 _vcallsub("_generic_znprimroot");
904 _vcallsub_with_gmp("znprimroot");
875905 break;
876906 }
877907 return; /* skip implicit PUTBACK */
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 use Math::Prime::Util qw/-nobigint/;
4 use Benchmark qw/:all/;
5 use List::Util qw/min max/;
6 use Config;
7 my $count = shift || -2;
8 my $is64bit = (~0 > 4294967295);
9 my $maxdigits = ($is64bit) ? 20 : 10; # Noting the range is limited for max.
10
11 my $rgen = sub {
12 my $range = shift;
13 return 0 if $range <= 0;
14 my $rbits = 0; { my $t = $range; while ($t) { $rbits++; $t >>= 1; } }
15 while (1) {
16 my $rbitsleft = $rbits;
17 my $U = 0;
18 while ($rbitsleft > 0) {
19 my $usebits = ($rbitsleft > $Config{randbits}) ? $Config{randbits} : $rbitsleft;
20 $U = ($U << $usebits) + int(rand(1 << $usebits));
21 $rbitsleft -= $usebits;
22 }
23 return $U if $U <= $range;
24 }
25 };
26
27 srand(29);
28 my $rounds = 400;
29 my $sqrounds = 256*1024;
30 my $rsqrounds = 32*1024;
31 my $p1smooth = 1000;
32 my $hrounds = 10000;
33 my $num_nums = 1000;
34 test_at_digits($_) for ( 3 .. $maxdigits );
35
36
37 sub test_at_digits {
38 my $digits = shift;
39
40 die "Digits has to be >= 1" unless $digits >= 1;
41 die "Digits has to be <= $maxdigits" if $digits > $maxdigits;
42
43 my @nums = genrand($digits, $num_nums);
44 #my @nums = gensemi($digits, $num_nums, 23);
45 my $min_num = min @nums;
46 my $max_num = max @nums;
47
48 # Determine success rates
49 my %nfactored;
50 my $tfac = 0;
51 # Did we find any non-trivial factors?
52 my $calc_nfacs = sub { ((scalar grep { $_ > 5 } @_) > 1) ? 1 : 0 };
53 for (@nums) {
54 $tfac += $calc_nfacs->(Math::Prime::Util::factor($_));
55 $nfactored{'prho'} += $calc_nfacs->(Math::Prime::Util::prho_factor($_, $rounds));
56 $nfactored{'pbrent'} += $calc_nfacs->(Math::Prime::Util::pbrent_factor($_, $rounds));
57 $nfactored{'pminus1'} += $calc_nfacs->(Math::Prime::Util::pminus1_factor($_, $p1smooth));
58 $nfactored{'pplus1'} += $calc_nfacs->(Math::Prime::Util::pplus1_factor($_, $p1smooth));
59 $nfactored{'squfof'} += $calc_nfacs->(Math::Prime::Util::squfof_factor($_, $sqrounds));
60 #$nfactored{'trial'} += $calc_nfacs->(Math::Prime::Util::trial_factor($_));
61 #$nfactored{'fermat'} += $calc_nfacs->(Math::Prime::Util::fermat_factor($_, $rounds));
62 $nfactored{'holf'} += $calc_nfacs->(Math::Prime::Util::holf_factor($_, $hrounds));
63 }
64
65 print "factoring $num_nums random $digits-digit numbers ($min_num - $max_num)\n";
66 print "Factorizations: ",
67 join(", ", map { sprintf "%s %4.1f%%", $_, 100*$nfactored{$_}/$tfac }
68 grep { $_ ne 'fermat' }
69 sort {$nfactored{$a} <=> $nfactored{$b}} keys %nfactored),
70 "\n";
71
72 my $lref = {
73 "prho" => sub { Math::Prime::Util::prho_factor($_, $rounds) for @nums },
74 "pbrent" => sub { Math::Prime::Util::pbrent_factor($_, $rounds) for @nums },
75 "pminus1" => sub { Math::Prime::Util::pminus1_factor($_, $rounds) for @nums },
76 "pplus1" => sub { Math::Prime::Util::pplus1_factor($_, $rounds) for @nums},
77 "fermat" => sub { Math::Prime::Util::fermat_factor($_, $rounds) for @nums},
78 "holf" => sub { Math::Prime::Util::holf_factor($_, $hrounds) for @nums },
79 "squfof" => sub { Math::Prime::Util::squfof_factor($_, $sqrounds) for @nums },
80 "trial" => sub { Math::Prime::Util::trial_factor($_) for @nums },
81 };
82 delete $lref->{'fermat'} if $digits >= 9;
83 delete $lref->{'holf'} if $digits >= 17;
84 delete $lref->{'trial'} if $digits >= 15;
85 cmpthese($count, $lref);
86 print "\n";
87 }
88
89
90 sub genrand {
91 my $digits = shift;
92 my $num = shift;
93
94 my $base = ($digits == 1) ? 0 : int(10 ** ($digits-1));
95 my $max = int(10 ** $digits);
96 $max = ~0 if $max > ~0;
97 my @nums = map { $base + $rgen->($max-$base) } (1 .. $num);
98 return @nums;
99 }
100
101 sub gensemi {
102 my $digits = shift;
103 my $num = shift;
104 my $smallest_factor = shift;
105
106 my $base = ($digits == 1) ? 0 : int(10 ** ($digits-1));
107 my $max = int(10 ** $digits);
108 $max = (~0-4) if $max > (~0-4);
109 my @semiprimes;
110
111 foreach my $i (1 .. $num) {
112 my @factors;
113 my $n;
114 while (1) {
115 $n = $base + $rgen->($max-$base);
116 $n += (1,0,5,4,3,2,1,0,3,2,1,0,1,0,3,2,1,0,1,0,3,2,1,0,5,4,3,2,1,0)[$n%30];
117 @factors = Math::Prime::Util::factor($n);
118 next if scalar @factors != 2;
119 next if $factors[0] < $smallest_factor;
120 next if $factors[1] < $smallest_factor;
121 last if scalar @factors == 2;
122 }
123 die "ummm... $n != $factors[0] * $factors[1]\n" unless $n == $factors[0] * $factors[1];
124 push @semiprimes, $n;
125 }
126 return @semiprimes;
127 }
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 $| = 1; # fast pipes
4 srand(377);
5
6 use Math::Prime::Util qw/factor/;
7 use Math::Factor::XS qw/prime_factors/;
8 use Math::Pari qw/factorint/;
9 use Benchmark qw/:all/;
10 use Data::Dumper;
11 use Config;
12 my $digits = shift || 15;
13 my $count = shift || -3;
14
15 my $rgen = sub {
16 my $range = shift;
17 return 0 if $range <= 0;
18 my $rbits = 0; { my $t = $range; while ($t) { $rbits++; $t >>= 1; } }
19 while (1) {
20 my $rbitsleft = $rbits;
21 my $U = 0;
22 while ($rbitsleft > 0) {
23 my $usebits = ($rbitsleft > $Config{randbits}) ? $Config{randbits} : $rbitsleft;
24 $U = ($U << $usebits) + int(rand(1 << $usebits));
25 $rbitsleft -= $usebits;
26 }
27 return $U if $U <= $range;
28 }
29 };
30
31 my @min_factors_by_digit = (2,2,3,3,5,11,17,47,97);
32 my $smallest_factor_allowed = $min_factors_by_digit[$digits];
33 $smallest_factor_allowed = $min_factors_by_digit[-1] unless defined $smallest_factor_allowed;
34 my $numprimes = 200;
35
36 die "Digits has to be >= 2" unless $digits >= 2;
37 die "Digits has to be <= 10" if (~0 == 4294967295) && ($digits > 10);
38 die "Digits has to be <= 19" if $digits > 19;
39
40 my $skip_mfxs = ($digits > 17);
41
42 # Construct some semiprimes of the appropriate number of digits
43 # There are much cleverer ways of doing this, using randomly selected
44 # nth_primes, and so on, but this works well until we get lots of digits.
45 print "Generating $numprimes random $digits-digit semiprimes (min factor $smallest_factor_allowed) ";
46 my @semiprimes;
47 foreach my $i ( 1 .. $numprimes ) {
48 my $base = int(10 ** ($digits-1));
49 my $add = int(10 ** ($digits)) - $base;
50 my @factors;
51 my $n;
52 while (1) {
53 $n = $base + $rgen->($add);
54 next if $n > (~0 - 4);
55 $n += (1,0,5,4,3,2,1,0,3,2,1,0,1,0,3,2,1,0,1,0,3,2,1,0,5,4,3,2,1,0)[$n%30];
56 @factors = factor($n);
57 next if scalar @factors != 2;
58 next if $factors[0] < $smallest_factor_allowed;
59 next if $factors[1] < $smallest_factor_allowed;
60 last if scalar @factors == 2;
61 }
62 die "ummm... $n != $factors[0] * $factors[1]\n" unless $n == $factors[0] * $factors[1];
63 #print "$n == $factors[0] * $factors[1]\n";
64 push @semiprimes, $n;
65 print "." if ($i % ($numprimes/10)) == 0;
66 }
67 print "done.\n";
68
69 print "Verifying Math::Prime::Util $Math::Prime::Util::VERSION ...";
70 foreach my $sp (@semiprimes) {
71 my @factors = factor($sp);
72 die "wrong for $sp\n" unless ($#factors == 1) && ($factors[0] * $factors[1]) == $sp;
73 }
74 print "OK\n";
75 if (!$skip_mfxs) {
76 print "Verifying Math::Factor::XS $Math::Factor::XS::VERSION ...";
77 foreach my $sp (@semiprimes) {
78 my @factors = prime_factors($sp);
79 die "wrong for $sp\n" unless ($#factors == 1) && ($factors[0] * $factors[1]) == $sp;
80 }
81 print "OK\n";
82 } else {
83 print "Math::Factor::XS is too slow for $digits digits. Skipping.\n";
84 }
85 print "Verifying Math::Pari $Math::Pari::VERSION ...";
86 foreach my $sp (@semiprimes) {
87 my @factors;
88 my ($pn,$pc) = @{factorint($sp)};
89 push @factors, (int($pn->[$_])) x $pc->[$_] for (0 .. $#{$pn});
90 die "wrong for $sp\n" unless ($#factors == 1) && ($factors[0] * $factors[1]) == $sp;
91 }
92 print "OK\n";
93
94 my %compare = (
95 'MPU' => sub { do { my @f = factor($_) } for @semiprimes; },
96 'MFXS' => sub { do { my @f = prime_factors($_) } for @semiprimes; },
97 'Pari' => sub { do { my ($pn,$pc) = @{factorint($_)}; my @f = map { int($pn->[$_]) x $pc->[$_] } 0 .. $#$pn; } for @semiprimes; },
98 );
99 delete $compare{'MFXS'} if $skip_mfxs;
100
101 cmpthese($count, \%compare);
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 use Math::Prime::Util qw/factor/;
4 # Compare to Math::Factor::XS, which uses trial division.
5 use Math::Factor::XS qw/prime_factors/;
6
7 use Benchmark qw/:all/;
8 use List::Util qw/min max reduce/;
9 my $count = shift || -2;
10 my $is64bit = (~0 > 4294967295);
11 my $maxdigits = ($is64bit) ? 20 : 10; # Noting the range is limited for max.
12 my $semiprimes = 0;
13 my $howmany = 1000;
14
15 for my $d ( 3 .. $maxdigits ) {
16 print "Factor $howmany $d-digit numbers\n";
17 test_at_digits($d, $howmany);
18 }
19
20 sub test_at_digits {
21 my $digits = shift;
22 die "Digits has to be >= 1" unless $digits >= 1;
23 die "Digits has to be <= $maxdigits" if $digits > $maxdigits;
24 my $quantity = shift;
25
26 my @rnd = ndigit_rand($digits, $quantity);
27 my @smp = genrough($digits, $quantity);
28
29 # verify (can be _really_ slow for 18+ digits)
30 foreach my $p (@rnd, @smp) {
31 next if $p < 2;
32 verify_factor($p, [prime_factors($p)], [factor($p)], "Math::Prime::Util $Math::Prime::Util::VERSION");
33 }
34
35 #my $min_num = min @nums;
36 #my $max_num = max @nums;
37 #my $whatstr = "$digits-digit ", $semiprimes ? "semiprime" : "random";
38 #print "factoring 1000 $digits-digit ",
39 # $semiprimes ? "semiprimes" : "random numbers",
40 # " ($min_num - $max_num)\n";
41
42 my $lref = {
43 "MPU random" => sub { my@a=factor($_) for @rnd },
44 "MPU nonsmooth" => sub { my@a=factor($_) for @smp },
45 "MFXS random" => sub { my@a=prime_factors($_) for @rnd },
46 "MFXS nonsmooth" => sub { my@a=prime_factors($_) for @smp },
47 };
48 cmpthese($count, $lref);
49 }
50
51 sub verify_factor {
52 my ($n, $aref1, $aref2, $name) = @_;
53
54 return 1 if "@$aref1" eq "@$aref2";
55
56 my @master = @$aref1;
57 my @check = @$aref2;
58 die "Factor $n master fail!" unless $n == reduce { $a * $b } @master;
59 die "Factor $n fail: $name" unless $#check == $#master;
60 die "Factor $n fail: $name" unless $n == reduce { $a * $b } @check;
61 for (0 .. $#master) {
62 die "Factor $n fail: $name" unless $master[$_] == $check[$_];
63 }
64 1;
65 }
66
67 sub genrough {
68 my ($digits, $num) = @_;
69
70 my @min_factors_by_digit = (2,2,3,5,7,13,23,47,97);
71 my $smallest_factor = $min_factors_by_digit[$digits];
72 $smallest_factor = $min_factors_by_digit[-1] unless defined $smallest_factor;
73
74 my @semiprimes;
75 foreach my $i (1 .. $num) {
76 my $n;
77 my @facn;
78 do {
79 $n = ndigit_rand($digits, 1);
80 @facn = Math::Prime::Util::trial_factor($n,$smallest_factor);
81 } while scalar(@facn) > 1;
82 push @semiprimes, $n;
83 }
84 return @semiprimes;
85 }
86
87 use Bytes::Random::Secure qw/random_string_from/;
88 sub ndigit_rand {
89 my($digits, $howmany) = @_;
90 die "digits must be > 0" if $digits < 1;
91 $howmany = 1 unless defined $howmany;
92 # TODO: need to skip things larger than ~0 for this module
93 my @nums = map { random_string_from("123456789",1) . random_string_from("0123456789",$digits-1) } 1 .. $howmany;
94 if (10**$digits > ~0) { @nums = map { Math::BigInt->new($_) } @nums; }
95 else { @nums = map { int($_) } @nums; }
96 return wantarray ? @nums : $nums[0];
97 }
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 #use Math::Primality;
4 use Math::Prime::XS;
5 use Math::Prime::Util;
6 #use Math::Pari;
7 #use Math::Prime::FastSieve;
8 use Benchmark qw/:all/;
9 use List::Util qw/min max/;
10 my $count = shift || -5;
11 my $numbers = 1000;
12
13 my $is64bit = (~0 > 4294967295);
14 my $maxdigits = ($is64bit) ? 20 : 10; # Noting the range is limited for max.
15 my $randf = Math::Prime::Util::_get_rand_func();
16
17 my $rand_ndigit_gen = sub {
18 my $digits = shift;
19 die "Digits must be > 0" unless $digits > 0;
20 my $howmany = shift || 1;
21 my ($base, $max);
22
23 if ( 10**$digits < ~0) {
24 $base = ($digits == 1) ? 0 : int(10 ** ($digits-1));
25 $max = int(10 ** $digits);
26 $max = ~0 if $max > ~0;
27 } else {
28 $base = Math::BigInt->new(10)->bpow($digits-1);
29 $max = Math::BigInt->new(10)->bpow($digits) - 1;
30 }
31 my @nums = map { $base + $randf->($max-$base) } (1 .. $howmany);
32 return (wantarray) ? @nums : $nums[0];
33 };
34
35 srand(29);
36 test_at_digits($_) for (3 .. $maxdigits);
37
38
39 sub test_at_digits {
40 my $digits = shift;
41 die "Digits must be > 0" unless $digits > 0;
42
43 my @nums = $rand_ndigit_gen->($digits, $numbers);
44 my $min_num = min @nums;
45 my $max_num = max @nums;
46
47 #my $sieve = Math::Prime::FastSieve::Sieve->new(10 ** $magnitude + 1);
48 #Math::Prime::Util::prime_precalc(10 ** $magnitude + 1);
49
50 print "is_prime for $numbers random $digits-digit numbers ($min_num - $max_num)\n";
51
52 cmpthese($count,{
53 #'Math::Primality' => sub { Math::Primality::is_prime($_) for @nums },
54 'M::P::XS' => sub { Math::Prime::XS::is_prime($_) for @nums },
55 #'M::P::FS' => sub { $sieve->isprime($_) for @nums },
56 'M::P::U' => sub { Math::Prime::Util::is_prime($_) for @nums },
57 'MPU prob' => sub { Math::Prime::Util::is_prob_prime($_) for @nums },
58 #'Math::Pari' => sub { Math::Pari::isprime($_) for @nums },
59 });
60 print "\n";
61 }
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 $| = 1; # fast pipes
4
5 use Math::Prime::Util;
6 use Math::Primality;
7
8 my $count = shift || -1;
9
10 # GMP is ~3x faster than Calc or Pari for these operations
11 use bigint try=>'GMP';
12 srand(500);
13 use Config;
14
15 my $rgen = sub {
16 my $range = shift;
17 return 0 if $range <= 0;
18 my $rbits = 0; { my $t = $range; while ($t) { $rbits++; $t >>= 1; } }
19 while (1) {
20 my $rbitsleft = $rbits;
21 my $U = $range - $range; # 0 or bigint 0
22 while ($rbitsleft > 0) {
23 my $usebits = ($rbitsleft > $Config{randbits}) ? $Config{randbits} : $rbitsleft;
24 $U = ($U << $usebits) + int(rand(1 << $usebits));
25 $rbitsleft -= $usebits;
26 }
27 return $U if $U <= $range;
28 }
29 };
30
31 my @rns;
32 while (@rns < 50) {
33 my $n = $rgen->( Math::BigInt->new(2)->bpow(81) );
34 $n++ if ($n % 2) == 0;
35 next unless ($n % 2) != 0;
36 push @rns, $n;
37 }
38 map { $_ = int($_->bstr) if $_ <= ~0 } @rns;
39 #print "$_\n" for @rns;
40 no bigint; # Benchmark doesn't work with bigint on.
41
42 print "Verifying";
43 for my $n (@rns) {
44 die "bad MR for $n" unless Math::Prime::Util::is_strong_pseudoprime($n,2) == Math::Primality::is_strong_pseudoprime("$n","2");
45 die "bad LP for $n" unless Math::Prime::Util::is_strong_lucas_pseudoprime($n) == Math::Primality::is_strong_lucas_pseudoprime("$n");
46 die "bad IP for $n" unless (Math::Prime::Util::is_prime($n)?1:0) == (Math::Primality::is_prime("$n")?1:0);
47 print ".";
48 }
49 print "OK\n";
50
51 use Benchmark qw/:all/;
52 my $sum = 0;
53 cmpthese($count, {
54 "MP MR" => sub { $sum += Math::Primality::is_strong_pseudoprime("$_","2") for @rns; },
55 "MPU MR" => sub { $sum += Math::Prime::Util::GMP::is_strong_pseudoprime($_,2) for @rns; },
56 #"MPUxMR" => sub { Math::Prime::Util::miller_rabin($_,2) for @rns; },
57 "MP LP" => sub { $sum += Math::Primality::is_strong_lucas_pseudoprime("$_") for @rns;},
58 "MPU LP" => sub { $sum += Math::Prime::Util::GMP::is_strong_lucas_pseudoprime($_) for @rns;},
59 "MPU ELP" => sub { $sum += Math::Prime::Util::GMP::is_extra_strong_lucas_pseudoprime($_) for @rns;},
60 #"MPU AELP" => sub { $sum += Math::Prime::Util::GMP::is_almost_extra_strong_lucas_pseudoprime($_) for @rns;},
61 "MP IP" => sub { $sum += Math::Primality::is_prime("$_") for @rns;},
62 "MPU IP" => sub { $sum += Math::Prime::Util::is_prime($_) for @rns;},
63 #"MPUxIP" => sub { Math::Prime::Util::is_prime($_) for @rns;},
64 });
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 use Math::Primality;
4 use Math::Prime::XS;
5 use Math::Prime::Util;
6 use Math::Prime::Util::GMP;
7 #use Math::Prime::FastSieve;
8 use Benchmark qw/:all/;
9 use List::Util qw/min max/;
10 my $count = shift || -5;
11
12 srand(29);
13 test_at_digits($_) for (5..18);
14
15
16 sub test_at_digits {
17 my $digits = shift;
18 die "Digits must be > 0" unless $digits > 0;
19
20 my @nums = ndigit_rand($digits, 1000);
21 my $min_num = min @nums;
22 my $max_num = max @nums;
23
24 #my $sieve = Math::Prime::FastSieve::Sieve->new(10 ** $magnitude + 1);
25 #Math::Prime::Util::prime_precalc(10 ** $magnitude + 1);
26
27 print "miller_rabin for 1000 random $digits-digit numbers ($min_num - $max_num)\n";
28
29 cmpthese($count,{
30 'MPU' => sub { Math::Prime::Util::is_strong_pseudoprime($_,2,3,5,7,11,13,17) for @nums },
31 'MPU GMP' => sub { Math::Prime::Util::GMP::is_strong_pseudoprime($_,2,3,5,7,11,13,17) for @nums },
32 'M:Primality' => sub { for (@nums) {
33 Math::Primality::is_strong_pseudoprime($_,2) &&
34 Math::Primality::is_strong_pseudoprime($_,3) &&
35 Math::Primality::is_strong_pseudoprime($_,5) &&
36 Math::Primality::is_strong_pseudoprime($_,7) &&
37 Math::Primality::is_strong_pseudoprime($_,11) &&
38 Math::Primality::is_strong_pseudoprime($_,13) &&
39 Math::Primality::is_strong_pseudoprime($_,17); } },
40 });
41 print "\n";
42 }
43
44 use Bytes::Random::Secure qw/random_string_from/;
45 sub ndigit_rand {
46 my($digits, $howmany) = @_;
47 die "digits must be > 0" if $digits < 1;
48 $howmany = 1 unless defined $howmany;
49 my @nums = map { random_string_from("123456789",1) . random_string_from("0123456789",$digits-1) } 1 .. $howmany;
50 @nums = map { Math::BigInt->new($_) } @nums if 10**$digits > ~0;
51 return @nums;
52 }
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 use Math::Prime::Util;
4 use Math::Prime::Util::GMP;
5 use Math::Primality;
6 use Benchmark qw/:all/;
7 my $count = shift || -2;
8 srand(29); # So we have repeatable results
9 Math::Prime::Util::prime_set_config(irand => sub { int(rand(4294967295)) });
10
11 test_at_digits($_, 1000) for (5, 15, 25, 50, 200);
12
13 sub test_at_digits {
14 my($digits, $numbers) = @_;
15 die "Digits must be > 0" unless $digits > 0;
16
17 my $start = Math::Prime::Util::random_ndigit_prime($digits) - 3;
18 my $end = $start;
19 $end = Math::Prime::Util::GMP::next_prime($end) for 1 .. $numbers;
20
21 print "next_prime x $numbers starting at $start\n";
22
23 cmpthese($count,{
24 'MP' => sub { my $n = $start; $n = Math::Primality::next_prime($n) for 1..$numbers; die "MP ended with $n instead of $end" unless $n == $end; },
25 'MPU' => sub { my $n = $start; $n = Math::Prime::Util::next_prime($n) for 1..$numbers; die "MPU ended with $n instead of $end" unless $n == $end; },
26 'MPU GMP' => sub { my $n = $start; $n = Math::Prime::Util::GMP::next_prime($n) for 1..$numbers; die "MPU GMP ended with $n instead of $end" unless $n == $end; },
27 });
28 }
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 use Math::Prime::Util;
4 use Math::Prime::Util::GMP;
5 use Math::Primality;
6 use Benchmark qw/:all/;
7 my $count = shift || -2;
8
9 #my($n, $exp) = (100000,9592);
10 my($n, $exp) = (1000000,78498);
11 #my($n, $exp) = (10000000,664579);
12 cmpthese($count,{
13 'MP' =>sub { die unless $exp == Math::Primality::prime_count($n); },
14 'MPU default' =>sub { die unless $exp == Math::Prime::Util::prime_count($n); },
15 'MPU XS Sieve' =>sub { die unless $exp == Math::Prime::Util::_XS_prime_count($n); },
16 'MPU XS Lehmer'=>sub { die unless $exp == Math::Prime::Util::_XS_lehmer_pi($n); },
17 'MPU PP Sieve' =>sub { die unless $exp == Math::Prime::Util::PP::_sieve_prime_count($n); },
18 'MPU PP Lehmer'=>sub { die unless $exp == Math::Prime::Util::PP::_lehmer_pi($n); },
19 'MPU GMP Trial'=>sub { die unless $exp == Math::Prime::Util::GMP::prime_count(2,$n); },
20 });
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 use Math::Prime::Util;
4 use Math::Prime::Util::GMP;
5 use Math::Primality;
6 use Benchmark qw/:all/;
7 use List::Util qw/min max/;
8 my $count = shift || -2;
9 srand(29); # So we have repeatable results
10
11 test_at_digits($_, 1000) for (5, 15, 25, 50, 200);
12
13 sub test_at_digits {
14 my($digits, $numbers) = @_;
15 die "Digits must be > 0" unless $digits > 0;
16
17 # We get a mix of primes and non-primes.
18 my @nums = map { Math::Prime::Util::random_ndigit_prime($digits)+2 } 1 .. $numbers;
19 print "is_strong_pseudoprime for $numbers random $digits-digit numbers",
20 " (", min(@nums), " - ", max(@nums), ")\n";
21
22 cmpthese($count,{
23 'MP' =>sub {Math::Primality::is_strong_pseudoprime($_,3) for @nums;},
24 'MPU' =>sub {Math::Prime::Util::is_strong_pseudoprime($_,3) for @nums;},
25 'MPU PP' =>sub {Math::Prime::Util::PP::miller_rabin($_,3) for @nums;},
26 'MPU GMP' =>sub {Math::Prime::Util::GMP::is_strong_pseudoprime($_,3) for @nums;},
27 });
28 }
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 use Math::Prime::Util qw/nth_prime prime_precalc/;
4 use Benchmark qw/:all :hireswallclock/;
5 use Data::Dumper;
6
7 my $count = shift || -5;
8
9 #prime_precalc(1000000000);
10
11 srand(29);
12 my @darray;
13 push @darray, [gendigits($_,int(5400/($_*$_*$_)))] for 2 .. 13;
14
15 my $sum;
16 foreach my $digits (3 .. 12) {
17 my @digarray = @{$darray[$digits-2]};
18 my $numitems = scalar @digarray;
19 my $timing = cmpthese(
20 $count,
21 { "$digits" => sub { $sum += nth_prime($_) for @digarray }, },
22 'none',
23 );
24 my $secondsper = $timing->[1]->[1];
25 if ($timing->[0]->[1] eq 'Rate') {
26 $secondsper =~ s/\/s$//;
27 $secondsper = 1.0 / $secondsper;
28 }
29 $secondsper /= $numitems;
30 my $timestr = (1.0 / $secondsper) . "/s per number";
31 printf "%4d %2d-digit numbers: %s\n", $numitems, $digits, $timestr;
32 }
33
34 sub gendigits {
35 my $digits = shift;
36 die "Digits must be > 0" unless $digits > 0;
37 my $num = shift;
38
39 my $base = ($digits == 1) ? 0 : int(10 ** ($digits-1));
40 my $max = int(10 ** $digits);
41 $max = ~0 if $max > ~0;
42 my @nums = map { $base+int(rand($max-$base)) } (1 .. $num);
43 return @nums;
44 }
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 use Math::Prime::Util ":all";
4 use Benchmark qw/:all/;
5 use List::Util qw/min max/;
6 my $maxdigits = (~0 <= 4294967295) ? 10 : 20;
7
8 my $count = shift || -5;
9
10 srand(29);
11 test_at_digits($_) for (5 .. $maxdigits);
12
13
14 sub test_at_digits {
15 my $digits = shift;
16 die "Digits must be > 0" unless $digits > 0;
17
18 my $base = ($digits == 1) ? 0 : int(10 ** ($digits-1));
19 my $max = int(10 ** $digits);
20 $max = ~0 if $max > ~0;
21 my @nums = map { $base+int(rand($max-$base)) } (1 .. 1000);
22 my $min_num = min @nums;
23 my $max_num = max @nums;
24
25 #print "miller_rabin for 1000 random $digits-digit numbers ($min_num - $max_num)\n";
26
27 my $sum;
28 cmpthese($count,{
29 'lower' => sub { $sum += prime_count_lower($_) for @nums },
30 'luapprox' => sub { $sum += (prime_count_lower($_)+prime_count_upper($_))/2 for @nums },
31 'approx' => sub { $sum += prime_count_approx($_) for @nums },
32 'li' => sub { $sum += LogarithmicIntegral($_) for @nums },
33 'R' => sub { $sum += RiemannR($_) for @nums },
34 });
35 print "\n";
36 }
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3
4 use Benchmark qw/:all/;
5 #use Devel::Size qw/total_size/;
6 #use Math::Prime::Util;
7 #use Math::Prime::FastSieve;
8 #*mpu_erat = \&Math::Prime::Util::erat_primes;
9 #*fs_erat = \&Math::Prime::FastSieve::primes;
10
11 my $upper = shift || 8192;
12 my $count = shift || -1;
13 my $countarg;
14
15 #atkin2(100); exit(0);
16
17 # Shows sizes for sieving to 100k, and rate/second for sieving to 16k
18 my $pc_subs = {
19 "Rosetta 4" => sub { rosetta4($countarg) }, # 25k 60/s
20 "Atkin MPTA" => sub { atkin($countarg) }, # 3430k 90/s
21 "Merlyn" => sub { merlyn($countarg)}, # 13k 96/s
22 "Rosetta 2" => sub { rosetta2($countarg) }, # 13k 109/s
23 "Atkin 2" => sub { atkin2($countarg) }, # 1669k 110/s
24 "DO Vec" => sub {daoswald_vec($countarg)}, # 13k 112/s
25 "Rosetta 3" => sub { rosetta3($countarg) }, # 4496k 165/s
26 "Rosetta 1" => sub { rosetta1($countarg) }, # 3449k 187/s
27 "Shootout" => sub { shootout($countarg) }, # 3200k 231/s
28 "DJ Vec" => sub { dj1($countarg) }, # 7k 245/s
29 "Scriptol" => sub { scriptol($countarg) }, # 3200k 290/s
30 "DO Array" => sub {daoswald_array($countarg)},# 3200k 306/s
31 "DJ Array" => sub { dj2($countarg) }, # 1494k 475/s
32 "In Many" => sub { inmany($countarg) }, # 2018k 666/s
33 "DJ String1" => sub { dj3($countarg) }, # 50k 981/s
34 "DJ String2" => sub { dj4($countarg) }, # 50k 1682/s
35 # "MPU Sieve" => sub {
36 # scalar @{mpu_erat(2,$countarg)}; }, # 3k 14325/s
37 # "MPFS Sieve" => sub {
38 # scalar @{fs_erat($countarg)}; }, # 7k 14325/s
39 };
40
41 my %verify = (
42 10 => 4,
43 11 => 5,
44 100 => 25,
45 112 => 29,
46 113 => 30,
47 114 => 30,
48 1000 => 168,
49 10000 => 1229,
50 100000 => 9592,
51 );
52
53 # Verify
54 while (my($name, $sub) = each (%$pc_subs)) {
55 while (my($n, $pin) = each (%verify)) {
56 $countarg = $n;
57 my $picount = $sub->();
58 die "$name ($n) = $picount, should be $pin" unless $picount == $pin;
59 }
60 }
61 print "Done with verification, starting benchmark\n";
62
63 $countarg = $upper;
64 cmpthese($count, $pc_subs);
65
66
67
68 # www.scriptol.com/programming/sieve.php
69 sub scriptol {
70 my($max) = @_;
71 return 0 if $max < 2;
72 return 1 if $max < 3;
73
74 my @flags = (0 .. $max);
75 for my $i (2 .. int(sqrt($max)) + 1)
76 {
77 next unless defined $flags[$i];
78 for (my $k=$i+$i; $k <= $max; $k+=$i)
79 {
80 undef $flags[$k];
81 }
82 }
83 #print "scriptol size: ", total_size(\@flags), "\n" if $max > 90000;
84 my $count = 0;
85 for my $j (2 .. $max) {
86 $count++ if defined $flags[$j];
87 }
88 $count;
89 }
90
91 # http://dada.perl.it/shootout/sieve.perl.html
92 sub shootout {
93 my($max) = @_;
94 return 0 if $max < 2;
95 return 1 if $max < 3;
96
97 my $count = 0;
98 my @flags = (0 .. $max);
99 for my $i (2 .. $max) {
100 next unless defined $flags[$i];
101 for (my $k=$i+$i; $k <= $max; $k+=$i) {
102 undef $flags[$k];
103 }
104 $count++;
105 }
106 #print "shootout size: ", total_size(\@flags), "\n" if $max > 90000;
107 $count;
108 }
109
110 # http://c2.com/cgi/wiki?SieveOfEratosthenesInManyProgrammingLanguages
111 sub inmany {
112 my($max) = @_;
113 return 0 if $max < 2;
114 return 1 if $max < 3;
115 $max++;
116
117 my @c;
118 for(my $t=3; $t*$t<$max; $t+=2) {
119 if (!$c[$t]) {
120 for(my $s=$t*$t; $s<$max; $s+=$t*2) { $c[$s]++ }
121 }
122 }
123 #print "inmany size: ", total_size(\@c), "\n" if $max > 90000;
124 my $count = 1;
125 for(my $t=3; $t<$max; $t+=2) {
126 $c[$t] || $count++;
127 }
128 $count;
129 }
130
131 # http://rosettacode.org/wiki/Sieve_of_Eratosthenes#Perl
132 sub rosetta1 {
133 my($max) = @_;
134 return 0 if $max < 2;
135 return 1 if $max < 3;
136
137 my $count = 0; #my @primes;
138 my @tested = (1);
139 my $j = 1;
140 while ($j < $max) {
141 next if $tested[$j++];
142 $count++; #push @primes, $j;
143 for (my $k= $j; $k <= $max; $k+=$j) {
144 $tested[$k-1]= 1;
145 }
146 }
147 #print "R1 size: ", total_size(\@tested), "\n" if $max > 90000;
148 $count; #scalar @primes;
149 }
150
151 # http://rosettacode.org/wiki/Sieve_of_Eratosthenes#Perl
152 sub rosetta2 {
153 my($max) = @_;
154 return 0 if $max < 2;
155 return 1 if $max < 3;
156
157 my $count = 0; #my @primes;
158 my $nonPrimes = '';
159 foreach my $p (2 .. $max) {
160 unless (vec($nonPrimes, $p, 1)) {
161 for (my $i = $p * $p; $i <= $max; $i += $p) {
162 vec($nonPrimes, $i, 1) = 1;
163 }
164 $count++; #push @primes, $p;
165 }
166 }
167 #print "R2 size: ", total_size(\$nonPrimes), "\n" if $max > 90000;
168 $count; #scalar @primes;
169 }
170
171 # http://rosettacode.org/wiki/Sieve_of_Eratosthenes#Perl
172 sub rosetta3 {
173 my($max) = @_;
174 return 0 if $max < 2;
175 return 1 if $max < 3;
176
177 my $i;
178 my @s;
179 my $count = scalar
180 grep { not $s[ $i = $_ ] and do
181 { $s[ $i += $_ ]++ while $i <= $max; 1 }
182 } 2 .. $max;
183 #print "R3 size: ", total_size(\@s), "\n" if $max > 90000;
184 $count; #scalar @primes;
185 }
186
187 # http://rosettacode.org/wiki/Sieve_of_Eratosthenes#Perl
188 sub rosetta4 {
189 my($max) = @_;
190 return 0 if $max < 2;
191 return 1 if $max < 3;
192
193 my $i;
194 my $s = '';
195 my $count = scalar
196 grep { not vec $s, $i = $_, 1 and do
197 { (vec $s, $i += $_, 1) = 1 while $i <= $max; 1 }
198 } 2 .. $max;
199 #print "R4 size: ", total_size(\$s), "\n" if $max > 90000;
200 $count; #scalar @primes;
201 }
202
203 # From Math::Primes::TiedArray
204 sub atkin {
205 my($max) = @_;
206 return 0 if $max < 2;
207 return 1 if $max < 3;
208 return 2 if $max < 5;
209
210 my $sqrt = sqrt($max);
211 my %sieve;
212 foreach my $x ( 1 .. $sqrt ) {
213
214 foreach my $y ( 1 .. $sqrt ) {
215
216 my $n = 3 * $x**2 - $y**2;
217 if ( $x > $y
218 and $n <= $max
219 and $n % 12 == 11 )
220 {
221 $sieve{$n} = not $sieve{$n};
222 }
223
224 $n = 3 * $x**2 + $y**2;
225 if ( $n <= $max and $n % 12 == 7 ) {
226 $sieve{$n} = not $sieve{$n};
227 }
228
229 $n = 4 * $x**2 + $y**2;
230 if ( $n <= $max
231 and ( $n % 12 == 1 or $n % 12 == 5 ) )
232 {
233 $sieve{$n} = not $sieve{$n};
234 }
235 }
236 }
237 # eliminate composites by sieving
238 foreach my $n ( 5 .. $sqrt ) {
239
240 next unless $sieve{$n};
241
242 my $k = int(1/$n**2) * $n**2;
243 while ( $k <= $max ) {
244 $sieve{$k} = 0;
245 $k += $n**2;
246 }
247 }
248 $sieve{2} = 1;
249 $sieve{3} = 1;
250 #print "Atkin size: ", total_size(\%sieve), "\n" if $max > 90000;
251
252 # save the found primes in our cache
253 my $count = 0;
254 foreach my $n ( 2 .. $max ) {
255 next unless $sieve{$n};
256 $count++;
257 }
258 $count;
259 }
260
261 # Naive Sieve of Atkin, basically straight from Wikipedia.
262 #
263 # <rant>
264 #
265 # First thing to note about SoA, is that people love to quote things like
266 # "memory use is O(N^(1/2+o(1)))" then proceed to _clearly_ use N bytes in
267 # their implementation. If your data structures between SoA and SoE are the
268 # same, then all talk about comparative O(blah..blah) memory use is stupid.
269 #
270 # Secondly, assuming you're not Dan Bernstein, if your Sieve of Atkin is
271 # faster than your Sieve of Eratosthenes, then I strongly suggest you verify
272 # your code actually _works_, and secondly I would bet you made stupid mistakes
273 # in your SoE implementation. If your SoA code even remotely resembles the
274 # Wikipedia code and it comes out faster than SoE, then I *guarantee* your
275 # SoE is borked.
276 #
277 # SoA does have a slightly better asymptotic operation count O(N/loglogN) vs.
278 # O(N) for SoE. The Wikipedia-like code that most people use is O(N) so it
279 # isn't even theoretically better unless you pull lots of stunts like primegen
280 # does. Even if you do, loglogN is essentially a small constant for most uses
281 # (it's under 4 for all 64-bit values), so you need to make sure all the rest
282 # of your overhead is controlled.
283 #
284 # Sumarizing, in practice the SoE is faster, and often a LOT faster.
285 #
286 # </rant>
287 #
288 sub atkin2 {
289 my($max) = @_;
290 return 0 if $max < 2;
291 return 1 if $max < 3;
292
293 my @sieve;
294
295 my $sqrt = int(sqrt($max));
296 for my $x (1 .. $sqrt) {
297 for my $y (1 .. $sqrt) {
298 my $n;
299
300 $n = 4*$x*$x + $y*$y;
301 if ( ($n <= $max) && ( (($n%12) == 1) || (($n%12) == 5) ) ) {
302 $sieve[$n] ^= 1;
303 }
304 $n = 3*$x*$x + $y*$y;
305 if ( ($n <= $max) && (($n%12) == 7) ) {
306 $sieve[$n] ^= 1;
307 }
308 $n = 3*$x*$x - $y*$y;
309 if ( ($x > $y) && ($n <= $max) && (($n%12) == 11) ) {
310 $sieve[$n] ^= 1;
311 }
312 }
313 }
314
315 for my $n (5 .. $sqrt) {
316 if ($sieve[$n]) {
317 my $k = $n*$n;
318 my $z = $k;
319 while ($z <= $max) {
320 $sieve[$z] = 0;
321 $z += $k;
322 }
323 }
324 }
325 $sieve[2] = 1;
326 $sieve[3] = 1;
327 #print "Atkin size: ", total_size(\@sieve), "\n" if $max > 90000;
328
329 my $count = scalar grep { $sieve[$_] } 2 .. $#sieve;
330 $count;
331 }
332
333 # https://github.com/daoswald/Inline-C-Perl-Mongers-Talk/blob/master/primesbench.pl
334 sub daoswald_array {
335 my($top) = @_;
336 return 0 if $top < 2;
337 return 1 if $top < 3;
338 $top++;
339
340 my @primes = (1) x $top;
341 my $i_times_j;
342 for my $i ( 2 .. sqrt $top ) {
343 if ( $primes[$i] ) {
344 for ( my $j = $i; ( $i_times_j = $i * $j ) < $top; $j++ ) {
345 undef $primes[$i_times_j];
346 }
347 }
348 }
349 #print "do_array size: ", total_size(\@primes), "\n" if $top > 90000;
350 my $count = scalar grep { $primes[$_] } 2 .. $#primes;
351 $count;
352 }
353
354 sub daoswald_vec {
355 my($top) = @_;
356 return 0 if $top < 2;
357 return 1 if $top < 3;
358
359 my $primes = '';
360 vec( $primes, $top, 1 ) = 0;
361 my $i_times_j;
362 for my $i ( 2 .. sqrt $top ) {
363 if ( !vec( $primes, $i, 1 ) ) {
364 for ( my $j = $i; ( $i_times_j = $i * $j ) <= $top; $j++ ) {
365 vec( $primes, $i_times_j, 1 ) = 1;
366 }
367 }
368 }
369 #print "do_vec size: ", total_size(\$primes), "\n" if $top > 90000;
370 my $count = scalar grep { !vec( $primes, $_, 1 ) } 2 .. $top ;
371 $count;
372 }
373
374 # Merlyn's Unix Review Column 26, June 1999
375 # http://www.stonehenge.com/merlyn/UnixReview/col26.html
376 sub merlyn {
377 my($UPPER) = @_;
378 return 0 if $UPPER < 2;
379 return 1 if $UPPER < 3;
380
381 my $count = 0;
382 my $sieve = "";
383 GUESS: for (my $guess = 2; $guess <= $UPPER; $guess++) {
384 next GUESS if vec($sieve,$guess,1);
385 $count++;
386 for (my $mults = $guess * $guess; $mults <= $UPPER; $mults += $guess) {
387 vec($sieve,$mults,1) = 1;
388 }
389 }
390 #print "Merlyn size: ", total_size(\$sieve), "\n" if $UPPER > 90000;
391 $count;
392 }
393
394
395 sub dj1 {
396 my($end) = @_;
397 return 0 if $end < 2;
398 return 1 if $end < 3;
399
400 # vector
401 my $sieve = '';
402 my $n = 3;
403 while ( ($n*$n) <= $end ) {
404 my $s = $n*$n;
405 while ($s <= $end) {
406 vec($sieve, $s >> 1, 1) = 1;
407 $s += 2*$n;
408 }
409 do { $n += 2 } while vec($sieve, $n >> 1, 1) != 0;
410 }
411 #print "DJ1 size: ", total_size(\$sieve), "\n" if $end > 90000;
412 my $count = 1;
413 $n = 3;
414 while ($n <= $end) {
415 $count++ if !vec($sieve, $n >> 1, 1);
416 $n += 2;
417 }
418 $count;
419 }
420
421 sub dj2 {
422 my($end) = @_;
423 return 0 if $end < 2;
424 return 1 if $end < 3;
425
426 # array
427 my @sieve;
428 my $n = 3;
429 while ( ($n*$n) <= $end ) {
430 my $s = $n*$n;
431 while ($s <= $end) {
432 $sieve[$s>>1] = 1;
433 $s += 2*$n;
434 }
435 do { $n += 2 } while $sieve[$n>>1];
436 }
437 #print "DJ2 size: ", total_size(\@sieve), "\n" if $end > 90000;
438 my $count = 1;
439 $n = 3;
440 while ($n <= $end) {
441 $count++ if !$sieve[$n>>1];
442 $n += 2;
443 }
444 $count;
445 }
446
447 # ~2x faster than inmany, lots faster than the others. Only loses to dj4,
448 # which is just this code with a presieve added.
449 sub dj3 {
450 my($end) = @_;
451 return 0 if $end < 2;
452 return 1 if $end < 3;
453 $end-- if ($end & 1) == 0;
454
455 # string
456 my $sieve = '1' . '0' x ($end>>1);
457 my $n = 3;
458 while ( ($n*$n) <= $end ) {
459 my $s = $n*$n;
460 my $filter_s = $s >> 1;
461 my $filter_end = $end >> 1;
462 while ($filter_s <= $filter_end) {
463 substr($sieve, $filter_s, 1) = '1';
464 $filter_s += $n;
465 }
466 do { $n += 2 } while substr($sieve, $n>>1, 1);
467 }
468 #print "DJ3 size: ", total_size(\$sieve), "\n" if $end > 90000;
469 my $count = 1 + $sieve =~ tr/0//;
470 $count;
471 }
472
473 # 2-3x faster than inmany, 6-7x faster than any of the other non-DJ methods.
474 sub dj4 {
475 my($end) = @_;
476 return 0 if $end < 2;
477 return 1 if $end < 3;
478 $end-- if ($end & 1) == 0;
479
480 # string with prefill
481 my $whole = int( ($end>>1) / 15);
482 my $sieve = '100010010010110' . '011010010010110' x $whole;
483 substr($sieve, ($end>>1)+1) = '';
484 my $n = 7;
485 while ( ($n*$n) <= $end ) {
486 my $s = $n*$n;
487 my $filter_s = $s >> 1;
488 my $filter_end = $end >> 1;
489 while ($filter_s <= $filter_end) {
490 substr($sieve, $filter_s, 1) = '1';
491 $filter_s += $n;
492 }
493 do { $n += 2 } while substr($sieve, $n>>1, 1);
494 }
495 #print "DJ4 size: ", total_size(\$sieve), "\n" if $end > 90000;
496 my $count = 1 + $sieve =~ tr/0//;
497 $count;
498 }
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3
4 use Benchmark qw/:all/;
5 use Devel::Size qw/total_size/;
6 use Math::Prime::Util;
7 *mpu_isprime = \&Math::Prime::Util::is_prime;
8
9 my $count = shift || -1;
10
11 my @numlist;
12 my @testnums = (0..1000, 5_000_000 .. 5_001_000, 30037, 20359*41117, 92987*65171, 27361*31249, 70790191, 3211717*9673231);
13
14 my $ip_subs = {
15 #"Abigail" => sub { my$r;$r=abigail($_) for @numlist; $r;},
16 "Rosetta" => sub { my$r;$r=rosetta($_) for @numlist; $r;},
17 "Rosetta2"=> sub { my$r;$r=rosetta2($_) for @numlist; $r;},
18 "DJ" => sub { my$r;$r=dj($_) for @numlist; $r;},
19 "DJ2" => sub { my$r;$r=dj2($_) for @numlist; $r;},
20 "DJ3" => sub { my$r;$r=dj3($_) for @numlist; $r;},
21 "DJ4" => sub { my$r;$r=dj4($_) for @numlist; $r;},
22 "MPU" => sub { my$r;$r=mpu_isprime($_) for @numlist; $r;},
23 };
24
25 my %verify = (
26 0 => 0,
27 1 => 0,
28 2 => 1,
29 3 => 1,
30 4 => 0,
31 5 => 1,
32 6 => 0,
33 7 => 1,
34 13 => 1,
35 20 => 0,
36 377 => 0,
37 70790191 => 1,
38 );
39
40 # Verify
41 while (my($name, $sub) = each (%$ip_subs)) {
42 while (my($n, $v_ip) = each (%verify)) {
43 @numlist = ($n);
44 #print "$name($n): ", $sub->(), "\n";
45 my $isprime = ($sub->() ? 1 : 0);
46 die "$name($n) = $isprime, should be $v_ip\n" unless $isprime == $v_ip;
47 }
48 }
49 for my $n (0 .. 50000) {
50 die "dj($n) != mpu($n)" unless dj($n) == mpu_isprime($n);
51 die "dj2($n) != mpu($n)" unless dj2($n) == mpu_isprime($n);
52 die "dj3($n) != mpu($n)" unless dj3($n) == mpu_isprime($n);
53 die "dj4($n) != mpu($n)" unless dj4($n) == mpu_isprime($n);
54 die "rosetta($n) != mpu($n)" unless rosetta($n) == mpu_isprime($n)/2;
55 die "rosetta2($n) != mpu($n)" unless rosetta2($n) == mpu_isprime($n)/2;
56 }
57 print "Done with verification, starting benchmark\n";
58
59 @numlist = @testnums;
60 cmpthese($count, $ip_subs);
61
62
63 sub rosetta {
64 my $n = shift;
65 $n % $_ or return 0 for 2 .. sqrt $n;
66 $n > 1;
67 }
68
69 sub rosetta2 {
70 my $p = shift;
71 if ($p == 2) {
72 return 1;
73 } elsif ($p <= 1 || $p % 2 == 0) {
74 return 0;
75 } else {
76 my $limit = sqrt($p);
77 for (my $i = 3; $i <= $limit; $i += 2) {
78 return 0 if $p % $i == 0;
79 }
80 return 1;
81 }
82 }
83
84 # Terrifically clever, but useless for large numbers
85 sub abigail {
86 ('1' x shift) !~ /^1?$|^(11+?)\1+$/
87 }
88
89 sub dj {
90 my($n) = @_;
91 return 0 if $n < 2; # 0 and 1 are composite
92 return 2 if ($n == 2) || ($n == 3) || ($n == 5); # 2, 3, 5 are prime
93 # multiples of 2,3,5 are composite
94 return 0 if (($n % 2) == 0) || (($n % 3) == 0) || (($n % 5) == 0);
95
96 my $q;
97 foreach my $i (qw/7 11 13 17 19 23 29 31 37 41 43 47 53 59/) {
98 $q = int($n/$i); return 2 if $q < $i; return 0 if $n == ($q*$i);
99 }
100
101 my $i = 61; # mod-30 loop
102 while (1) {
103 $q = int($n/$i); last if $q < $i; return 0 if $n == ($q*$i); $i += 6;
104 $q = int($n/$i); last if $q < $i; return 0 if $n == ($q*$i); $i += 4;
105 $q = int($n/$i); last if $q < $i; return 0 if $n == ($q*$i); $i += 2;
106 $q = int($n/$i); last if $q < $i; return 0 if $n == ($q*$i); $i += 4;
107 $q = int($n/$i); last if $q < $i; return 0 if $n == ($q*$i); $i += 2;
108 $q = int($n/$i); last if $q < $i; return 0 if $n == ($q*$i); $i += 4;
109 $q = int($n/$i); last if $q < $i; return 0 if $n == ($q*$i); $i += 6;
110 $q = int($n/$i); last if $q < $i; return 0 if $n == ($q*$i); $i += 2;
111 }
112 2;
113 }
114
115 sub dj2 {
116 my($n) = @_;
117 return 2 if ($n == 2) || ($n == 3) || ($n == 5); # 2, 3, 5 are prime
118 return 0 if $n < 7; # everything else below 7 is composite
119 # multiples of 2,3,5 are composite
120 return 0 if (($n % 2) == 0) || (($n % 3) == 0) || (($n % 5) == 0);
121
122 foreach my $i (qw/7 11 13 17 19 23 29 31 37 41 43 47 53 59/) {
123 return 2 if $i*$i > $n;
124 return 0 if ($n % $i) == 0;
125 }
126 my $limit = int(sqrt($n));
127
128 my $i = 61; # mod-30 loop
129 while (1) {
130 return 0 if ($n % $i) == 0; $i += 6; last if $i > $limit;
131 return 0 if ($n % $i) == 0; $i += 4; last if $i > $limit;
132 return 0 if ($n % $i) == 0; $i += 2; last if $i > $limit;
133 return 0 if ($n % $i) == 0; $i += 4; last if $i > $limit;
134 return 0 if ($n % $i) == 0; $i += 2; last if $i > $limit;
135 return 0 if ($n % $i) == 0; $i += 4; last if $i > $limit;
136 return 0 if ($n % $i) == 0; $i += 6; last if $i > $limit;
137 return 0 if ($n % $i) == 0; $i += 2; last if $i > $limit;
138 }
139 2;
140 }
141
142 sub dj3 {
143 my($n) = @_;
144 return 2 if ($n == 2) || ($n == 3) || ($n == 5); # 2, 3, 5 are prime
145 return 0 if $n < 7; # everything else below 7 is composite
146 # multiples of 2,3,5 are composite
147 return 0 if (($n % 2) == 0) || (($n % 3) == 0) || (($n % 5) == 0);
148
149 foreach my $i (qw/7 11 13 17 19 23 29 31 37 41 43 47 53 59/) {
150 return 2 if $i*$i > $n;
151 return 0 if ($n % $i) == 0;
152 }
153 my $limit = int(sqrt($n));
154
155 my $i = 61; # mod-30 loop
156 while (($i+30) <= $limit) {
157 return 0 if ($n % $i) == 0; $i += 6;
158 return 0 if ($n % $i) == 0; $i += 4;
159 return 0 if ($n % $i) == 0; $i += 2;
160 return 0 if ($n % $i) == 0; $i += 4;
161 return 0 if ($n % $i) == 0; $i += 2;
162 return 0 if ($n % $i) == 0; $i += 4;
163 return 0 if ($n % $i) == 0; $i += 6;
164 return 0 if ($n % $i) == 0; $i += 2;
165 }
166 while (1) {
167 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 6;
168 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 4;
169 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 2;
170 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 4;
171 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 2;
172 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 4;
173 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 6;
174 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 2;
175 }
176 2;
177 }
178
179 sub dj4 {
180 my($n) = @_;
181 return 2 if ($n == 2) || ($n == 3) || ($n == 5); # 2, 3, 5 are prime
182 return 0 if $n < 7; # everything else below 7 is composite
183 # multiples of 2,3,5 are composite
184 return 0 if (($n % 2) == 0) || (($n % 3) == 0) || (($n % 5) == 0);
185
186 foreach my $i (qw/7 11 13 17 19 23 29/) {
187 return 2 if $i*$i > $n;
188 return 0 if ($n % $i) == 0;
189 }
190 my $limit = int(sqrt($n));
191
192 my $i = 31;
193 while (($i+30) <= $limit) {
194 return 0 if ($n % $i) == 0; $i += 6;
195 return 0 if ($n % $i) == 0; $i += 4;
196 return 0 if ($n % $i) == 0; $i += 2;
197 return 0 if ($n % $i) == 0; $i += 4;
198 return 0 if ($n % $i) == 0; $i += 2;
199 return 0 if ($n % $i) == 0; $i += 4;
200 return 0 if ($n % $i) == 0; $i += 6;
201 return 0 if ($n % $i) == 0; $i += 2;
202 }
203 while (1) {
204 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 6;
205 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 4;
206 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 2;
207 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 4;
208 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 2;
209 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 4;
210 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 6;
211 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 2;
212 }
213 2;
214 }
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3
4 use Benchmark qw/:all/;
5 #use Devel::Size qw/total_size/;
6 use Math::Prime::Util;
7 use Math::Prime::FastSieve;
8 *mpu_erat = \&Math::Prime::Util::erat_primes;
9 *fs_erat = \&Math::Prime::FastSieve::primes;
10
11 my $upper = shift || 8192;
12 my $count = shift || -1;
13 my $countarg;
14 my $sum;
15
16 # This is like counting, but we want an array returned.
17 # The subs will compute a sum on the results.
18
19 # In practice you would probably want to return a ref to your array, or return
20 # a ref to your sieve structure and let the caller decode it as needed.
21
22 # Times for 100k.
23 # Vs. MPU sieve, as we move from 8k to 10M:
24 # Atkin MPTA, Rosetta 3 & 1, Shootout, Scriptol, DO Array, DJ Array, and
25 # InMany all slow down. Atkin 2 speeds up (from 65x slower to 54x slower).
26 # The DJ string methods have almost no relative slowdown, so stretch out their
27 # advantage over the other fast ones (In Many, DJ Array, DJ Vec, and DO Array).
28 my $pc_subs = {
29 "Rosetta 4" => sub {$sum=0; $sum+=$_ for rosetta4($countarg);$sum;}, # 9/s
30 "Atkin MPTA"=> sub {$sum=0; $sum+=$_ for atkin($countarg);$sum;}, # 11/s
31 "Merlyn" => sub {$sum=0; $sum+=$_ for merlyn($countarg);$sum;}, # 15/s
32 "Rosetta 2" => sub {$sum=0; $sum+=$_ for rosetta2($countarg);$sum; }, # 16/s
33 "DO Vec" => sub {$sum=0; $sum+=$_ for daos_vec($countarg);$sum;}, # 16/s
34 "Atkin 2" => sub {$sum=0; $sum+=$_ for atkin2($countarg);$sum; }, # 17/s
35 "Rosetta 3" => sub {$sum=0; $sum+=$_ for rosetta3($countarg);$sum; }, # 23/s
36 "Rosetta 1" => sub {$sum=0; $sum+=$_ for rosetta1($countarg);$sum; }, # 26/s
37 "Shootout" => sub {$sum=0; $sum+=$_ for shootout($countarg);$sum; }, # 30/s
38 "Scriptol" => sub {$sum=0; $sum+=$_ for scriptol($countarg);$sum; }, # 33/s
39 "DJ Vec" => sub {$sum=0; $sum+=$_ for dj1($countarg);$sum; }, # 34/s
40 "DO Array" => sub {$sum=0; $sum+=$_ for daos_array($countarg);$sum;},# 41/s
41 "DJ Array" => sub {$sum=0; $sum+=$_ for dj2($countarg);$sum; }, # 63/s
42 "In Many" => sub {$sum=0; $sum+=$_ for inmany($countarg);$sum; }, # 86/s
43 "DJ String1"=> sub {$sum=0; $sum+=$_ for dj3($countarg);$sum; }, # 99/s
44 "DJ String2"=> sub {$sum=0; $sum+=$_ for dj4($countarg);$sum; }, # 134/s
45 "MPFS Sieve"=> sub { # 1216/s
46 $sum=0; $sum+=$_ for @{fs_erat($countarg)};;$sum; },
47 "MPU Sieve" => sub { # 1290/s
48 $sum=0; $sum+=$_ for @{mpu_erat(2,$countarg)};;$sum; },
49 };
50
51 my %verify = (
52 10 => 17,
53 11 => 28,
54 100 => 1060,
55 112 => 1480,
56 113 => 1593,
57 114 => 1593,
58 1000 => 76127,
59 10000 => 5736396,
60 100000 => 454396537,
61 );
62
63 # Verify
64 while (my($name, $sub) = each (%$pc_subs)) {
65 while (my($n, $v_pi_sum) = each (%verify)) {
66 $countarg = $n;
67 my $pi_sum = $sub->();
68 die "$name ($n) = $pi_sum, should be $v_pi_sum" unless $pi_sum == $v_pi_sum;
69 }
70 }
71 print "Done with verification, starting benchmark\n";
72
73 $countarg = $upper;
74 cmpthese($count, $pc_subs);
75
76
77
78 # www.scriptol.com/programming/sieve.php
79 sub scriptol {
80 my($max) = @_;
81 return 0 if $max < 2;
82 return 1 if $max < 3;
83
84 my @flags = (0 .. $max);
85 for my $i (2 .. int(sqrt($max)) + 1)
86 {
87 next unless defined $flags[$i];
88 for (my $k=$i+$i; $k <= $max; $k+=$i)
89 {
90 undef $flags[$k];
91 }
92 }
93 return grep { defined $flags[$_] } 2 .. $max;
94 }
95
96 # http://dada.perl.it/shootout/sieve.perl.html
97 sub shootout {
98 my($max) = @_;
99 return 0 if $max < 2;
100 return 1 if $max < 3;
101
102 my @primes;
103 my @flags = (0 .. $max);
104 for my $i (2 .. $max) {
105 next unless defined $flags[$i];
106 for (my $k=$i+$i; $k <= $max; $k+=$i) {
107 undef $flags[$k];
108 }
109 push @primes, $i;
110 }
111 @primes;
112 }
113
114 # http://c2.com/cgi/wiki?SieveOfEratosthenesInManyProgrammingLanguages
115 sub inmany {
116 my($max) = @_;
117 return 0 if $max < 2;
118 return 1 if $max < 3;
119
120 my @c;
121 for(my $t=3; $t*$t<=$max; $t+=2) {
122 if (!$c[$t]) {
123 for(my $s=$t*$t; $s<=$max; $s+=$t*2) { $c[$s]++ }
124 }
125 }
126 my @primes = (2);
127 for(my $t=3; $t<=$max; $t+=2) {
128 $c[$t] || push @primes, $t;
129 }
130 @primes;
131 # grep { $c[$_] } 3 .. $max;
132 }
133
134 # http://rosettacode.org/wiki/Sieve_of_Eratosthenes#Perl
135 sub rosetta1 {
136 my($max) = @_;
137 return 0 if $max < 2;
138 return 1 if $max < 3;
139
140 my @primes;
141 my @tested = (1);
142 my $j = 1;
143 while ($j < $max) {
144 next if $tested[$j++];
145 push @primes, $j;
146 for (my $k= $j; $k <= $max; $k+=$j) {
147 $tested[$k-1]= 1;
148 }
149 }
150 @primes;
151 }
152
153 # http://rosettacode.org/wiki/Sieve_of_Eratosthenes#Perl
154 sub rosetta2 {
155 my($max) = @_;
156 return 0 if $max < 2;
157 return 1 if $max < 3;
158
159 my @primes;
160 my $nonPrimes = '';
161 foreach my $p (2 .. $max) {
162 unless (vec($nonPrimes, $p, 1)) {
163 for (my $i = $p * $p; $i <= $max; $i += $p) {
164 vec($nonPrimes, $i, 1) = 1;
165 }
166 push @primes, $p;
167 }
168 }
169 @primes;
170 }
171
172 # http://rosettacode.org/wiki/Sieve_of_Eratosthenes#Perl
173 sub rosetta3 {
174 my($max) = @_;
175 return 0 if $max < 2;
176 return 1 if $max < 3;
177
178 my(@s, $i);
179 grep { not $s[ $i = $_ ] and do
180 { $s[ $i += $_ ]++ while $i <= $max; 1 }
181 } 2 .. $max;
182 }
183
184 # http://rosettacode.org/wiki/Sieve_of_Eratosthenes#Perl
185 sub rosetta4 {
186 my($max) = @_;
187 return 0 if $max < 2;
188 return 1 if $max < 3;
189
190 my $i;
191 my $s = '';
192 grep { not vec $s, $i = $_, 1 and do
193 { (vec $s, $i += $_, 1) = 1 while $i <= $max; 1 }
194 } 2 .. $max;
195 }
196
197 # From Math::Primes::TiedArray
198 sub atkin {
199 my($max) = @_;
200 return 0 if $max < 2;
201 return 1 if $max < 3;
202 return 2 if $max < 5;
203
204 my $sqrt = sqrt($max);
205 my %sieve;
206 foreach my $x ( 1 .. $sqrt ) {
207
208 foreach my $y ( 1 .. $sqrt ) {
209
210 my $n = 3 * $x**2 - $y**2;
211 if ( $x > $y
212 and $n <= $max
213 and $n % 12 == 11 )
214 {
215 $sieve{$n} = not $sieve{$n};
216 }
217
218 $n = 3 * $x**2 + $y**2;
219 if ( $n <= $max and $n % 12 == 7 ) {
220 $sieve{$n} = not $sieve{$n};
221 }
222
223 $n = 4 * $x**2 + $y**2;
224 if ( $n <= $max
225 and ( $n % 12 == 1 or $n % 12 == 5 ) )
226 {
227 $sieve{$n} = not $sieve{$n};
228 }
229 }
230 }
231 # eliminate composites by sieving
232 foreach my $n ( 5 .. $sqrt ) {
233
234 next unless $sieve{$n};
235
236 my $k = int(1/$n**2) * $n**2;
237 while ( $k <= $max ) {
238 $sieve{$k} = 0;
239 $k += $n**2;
240 }
241 }
242 my @primes = (2, 3);
243 push @primes, grep { $sieve{$_} } 5 .. $max;
244 @primes;
245 }
246
247 # Naive Sieve of Atkin, basically straight from Wikipedia.
248 #
249 # <rant>
250 #
251 # First thing to note about SoA, is that people love to quote things like
252 # "memory use is O(N^(1/2+o(1)))" then proceed to _clearly_ use N bytes in
253 # their implementation. If your data structures between SoA and SoE are the
254 # same, then all talk about comparative O(blah..blah) memory use is stupid.
255 #
256 # Secondly, assuming you're not Dan Bernstein, if your Sieve of Atkin is
257 # faster than your Sieve of Eratosthenes, then I strongly suggest you verify
258 # your code actually _works_, and secondly I would bet you made stupid mistakes
259 # in your SoE implementation. If your SoA code even remotely resembles the
260 # Wikipedia code and it comes out faster than SoE, then I _guarantee_ your
261 # SoE is borked.
262 #
263 # SoA does have a slightly better asymptotic operation count O(N/loglogN) vs.
264 # O(N) for SoE. The Wikipedia-like code that most people use is O(N) so it
265 # isn't even theoretically better unless you pull lots of stunts like primegen
266 # does. Even if you do, loglogN is essentially a small constant for most uses
267 # (it's under 4 for all 64-bit values), so you need to make sure all the rest
268 # of your overhead is controlled.
269 #
270 # Sumarizing, in practice the SoE is faster, and often a LOT faster.
271 #
272 # </rant>
273 #
274 sub atkin2 {
275 my($max) = @_;
276 return 0 if $max < 2;
277 return 1 if $max < 3;
278
279 my @sieve;
280
281 my $sqrt = int(sqrt($max));
282 for my $x (1 .. $sqrt) {
283 for my $y (1 .. $sqrt) {
284 my $n;
285
286 $n = 4*$x*$x + $y*$y;
287 if ( ($n <= $max) && ( (($n%12) == 1) || (($n%12) == 5) ) ) {
288 $sieve[$n] ^= 1;
289 }
290 $n = 3*$x*$x + $y*$y;
291 if ( ($n <= $max) && (($n%12) == 7) ) {
292 $sieve[$n] ^= 1;
293 }
294 $n = 3*$x*$x - $y*$y;
295 if ( ($x > $y) && ($n <= $max) && (($n%12) == 11) ) {
296 $sieve[$n] ^= 1;
297 }
298 }
299 }
300
301 for my $n (5 .. $sqrt) {
302 if ($sieve[$n]) {
303 my $k = $n*$n;
304 my $z = $k;
305 while ($z <= $max) {
306 $sieve[$z] = 0;
307 $z += $k;
308 }
309 }
310 }
311
312 $sieve[2] = 1;
313 $sieve[3] = 1;
314 grep { $sieve[$_] } 2 .. $max;
315 }
316
317 # https://github.com/daoswald/Inline-C-Perl-Mongers-Talk/blob/master/primesbench.pl
318 sub daos_array {
319 my($top) = @_;
320 return 0 if $top < 2;
321 return 1 if $top < 3;
322 $top++;
323
324 my @primes = (1) x $top;
325 my $i_times_j;
326 for my $i ( 2 .. sqrt $top ) {
327 if ( $primes[$i] ) {
328 for ( my $j = $i; ( $i_times_j = $i * $j ) < $top; $j++ ) {
329 undef $primes[$i_times_j];
330 }
331 }
332 }
333 return grep { $primes[$_] } 2 .. $#primes;
334 }
335
336 sub daos_vec {
337 my($top) = @_;
338 return 0 if $top < 2;
339 return 1 if $top < 3;
340
341 my $primes = '';
342 vec( $primes, $top, 1 ) = 0;
343 my $i_times_j;
344 for my $i ( 2 .. sqrt $top ) {
345 if ( !vec( $primes, $i, 1 ) ) {
346 for ( my $j = $i; ( $i_times_j = $i * $j ) <= $top; $j++ ) {
347 vec( $primes, $i_times_j, 1 ) = 1;
348 }
349 }
350 }
351 return grep { !vec( $primes, $_, 1 ) } 2 .. $top;
352 }
353
354 # Merlyn's Unix Review Column 26, June 1999
355 # http://www.stonehenge.com/merlyn/UnixReview/col26.html
356 sub merlyn {
357 my($UPPER) = @_;
358 return 0 if $UPPER < 2;
359 return 1 if $UPPER < 3;
360
361 my @primes;
362 my $sieve = "";
363 GUESS: for (my $guess = 2; $guess <= $UPPER; $guess++) {
364 next GUESS if vec($sieve,$guess,1);
365 push @primes, $guess;
366 for (my $mults = $guess * $guess; $mults <= $UPPER; $mults += $guess) {
367 vec($sieve,$mults,1) = 1;
368 }
369 }
370 @primes;
371 }
372
373
374 sub dj1 {
375 my($end) = @_;
376 return 0 if $end < 2;
377 return 1 if $end < 3;
378
379 # vector
380 my $sieve = '';
381 my $n = 3;
382 while ( ($n*$n) <= $end ) {
383 my $s = $n*$n;
384 while ($s <= $end) {
385 vec($sieve, $s >> 1, 1) = 1;
386 $s += 2*$n;
387 }
388 do { $n += 2 } while vec($sieve, $n >> 1, 1) != 0;
389 }
390
391 my @primes = (2);
392 $n = 3;
393 while ($n <= $end) {
394 push @primes, $n if !vec($sieve, $n >> 1, 1);
395 $n += 2;
396 }
397 @primes;
398 }
399
400 sub dj2 {
401 my($end) = @_;
402 return 0 if $end < 2;
403 return 1 if $end < 3;
404
405 # array
406 my @sieve;
407 my $n = 3;
408 while ( ($n*$n) <= $end ) {
409 my $s = $n*$n;
410 while ($s <= $end) {
411 $sieve[$s>>1] = 1;
412 $s += 2*$n;
413 }
414 do { $n += 2 } while $sieve[$n>>1];
415 }
416 my @primes = (2);
417 $n = 3;
418 while ($n <= $end) {
419 push @primes, $n if !$sieve[$n>>1];
420 $n += 2;
421 }
422 @primes;
423 }
424
425 sub dj3 {
426 my($end) = @_;
427 return 0 if $end < 2;
428 return 1 if $end < 3;
429 $end-- if ($end & 1) == 0;
430
431 # string
432 my $sieve = '1' . '0' x ($end>>1);
433 my $n = 3;
434 while ( ($n*$n) <= $end ) {
435 my $s = $n*$n;
436 my $filter_s = $s >> 1;
437 my $filter_end = $end >> 1;
438 while ($filter_s <= $filter_end) {
439 substr($sieve, $filter_s, 1) = '1';
440 $filter_s += $n;
441 }
442 do { $n += 2 } while substr($sieve, $n>>1, 1);
443 }
444 my @primes = (2);
445 $n = 3-2;
446 foreach my $s (split("0", substr($sieve, 1), -1)) {
447 $n += 2 + 2 * length($s);
448 push @primes, $n if $n <= $end;
449 }
450 @primes;
451 }
452
453 sub dj4 {
454 my($end) = @_;
455 return 0 if $end < 2;
456 return 1 if $end < 3;
457 $end-- if ($end & 1) == 0;
458
459 # string with prefill
460 my $whole = int( ($end>>1) / 15);
461 my $sieve = '100010010010110' . '011010010010110' x $whole;
462 substr($sieve, ($end>>1)+1) = '';
463 my $n = 7;
464 while ( ($n*$n) <= $end ) {
465 my $s = $n*$n;
466 my $filter_s = $s >> 1;
467 my $filter_end = $end >> 1;
468 while ($filter_s <= $filter_end) {
469 substr($sieve, $filter_s, 1) = '1';
470 $filter_s += $n;
471 }
472 do { $n += 2 } while substr($sieve, $n>>1, 1);
473 }
474 my @primes = (2, 3, 5);
475 $n = 7-2;
476 foreach my $s (split("0", substr($sieve, 3), -1)) {
477 $n += 2 + 2 * length($s);
478 push @primes, $n if $n <= $end;
479 }
480 @primes;
481 }
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 use Math::Prime::Util qw/:all/;
4 use Math::Prime::Util::PrimeArray;
5 use Math::NumSeq::Primes;
6 use Math::Prime::TiedArray;
7 use Benchmark qw/:all/;
8 use List::Util qw/min max/;
9 my $count = shift || -2;
10
11 my ($s, $nlimit, $ilimit, $expect);
12
13 if (1) {
14 print '-' x 79, "\n";
15 print "summation to 100k, looking for best methods (typically slice)\n";
16 $nlimit = 100000;
17 $ilimit = prime_count($nlimit)-1;
18 $expect = 0; forprimes { $expect += $_ } $nlimit;
19
20 cmpthese($count,{
21 'pa index' => sub { $s=0; tie my @primes, "Math::Prime::Util::PrimeArray";
22 $s += $primes[$_] for 0..$ilimit;
23 die unless $s == $expect; },
24 'pa loop' => sub { $s=0; tie my @primes, "Math::Prime::Util::PrimeArray";
25 for (@primes) { last if $_ > $nlimit; $s += $_; }
26 die $s unless $s == $expect; },
27 'pa slice' => sub { $s=0; tie my @primes, "Math::Prime::Util::PrimeArray";
28 $s += $_ for @primes[0..$ilimit];
29 die unless $s == $expect; },
30 'pa each' => sub { $s=0; tie my @primes, "Math::Prime::Util::PrimeArray";
31 while(my(undef,$v) = each @primes) { last if $v > $nlimit; $s += $v; }
32 die $s unless $s == $expect; },
33 'pa shift' => sub { $s=0; tie my @primes, "Math::Prime::Util::PrimeArray";
34 while ((my $p = shift @primes) <= $nlimit) { $s += $p; }
35 die unless $s == $expect; },
36 });
37 }
38
39 if (1) {
40 print '-' x 79, "\n";
41 print "summation to 100k, looking for best MPTA extension (typically ~1000)\n";
42 $nlimit = 100000;
43 $ilimit = prime_count($nlimit)-1;
44 $expect = 0; forprimes { $expect += $_ } $nlimit;
45
46 cmpthese($count,{
47 'MPTA' => sub { $s=0; tie my @primes, "Math::Prime::TiedArray";
48 $s += $primes[$_] for 0..$ilimit;
49 die unless $s == $expect; },
50 'MPTA 400' => sub { $s=0; tie my @primes, "Math::Prime::TiedArray", extend_step => 400;
51 $s += $primes[$_] for 0..$ilimit;
52 die unless $s == $expect; },
53 'MPTA 1000' => sub { $s=0; tie my @primes, "Math::Prime::TiedArray", extend_step => 1000;
54 $s += $primes[$_] for 0..$ilimit;
55 die unless $s == $expect; },
56 'MPTA 4000' => sub { $s=0; tie my @primes, "Math::Prime::TiedArray", extend_step => 4000;
57 $s += $primes[$_] for 0..$ilimit;
58 die unless $s == $expect; },
59 });
60 }
61
62 if (1) {
63 print '-' x 79, "\n";
64 print "summation to 100k\n";
65 print "Note: MPU::PrimeArray is about 30x faster than MPTA here.\n";
66 print " Math::NumSeq::Primes is reasonable fast (not random access)\n";
67 print " MPU's forprimes smashes everything else (not random access)\n";
68 $nlimit = 100000;
69 $ilimit = prime_count($nlimit)-1;
70 $expect = 0; forprimes { $expect += $_ } $nlimit;
71
72 cmpthese($count,{
73 'primes' => sub { $s=0; $s += $_ for @{primes($nlimit)}; die unless $s == $expect; },
74 'forprimes' => sub { $s=0; forprimes { $s += $_ } $nlimit; die unless $s == $expect; },
75 'iterator' => sub { $s=0; my $it = prime_iterator();
76 $s += $it->() for 0..$ilimit;
77 die unless $s == $expect; },
78 'OO iter' => sub { $s=0; my $it = prime_iterator_object();
79 $s += $it->iterate() for 0..$ilimit;
80 die unless $s == $expect; },
81 'pa slice' => sub { $s=0; tie my @primes, "Math::Prime::Util::PrimeArray";
82 $s += $_ for @primes[0..$ilimit];
83 die unless $s == $expect; },
84 'NumSeq' => sub { $s=0; my $seq = Math::NumSeq::Primes->new;
85 while (1) { my($undev,$v) = $seq->next; last if $v > $nlimit; $s += $v; }
86 die $s unless $s == $expect; },
87 # This was slightly faster than slice or shift
88 'MPTA' => sub { $s=0; tie my @primes, "Math::Prime::TiedArray", extend_step => 1000;
89 $s += $primes[$_] for 0..$ilimit;
90 die unless $s == $expect; },
91 });
92 }
93
94 if (0) {
95 print '-' x 79, "\n";
96 print "summation to 10M\n";
97 print "Note: Math::Prime::TiedArray takes too long\n";
98 print " Math::NumSeq::Primes is now ~2x slower than PrimeArray\n";
99 print " forprimes is still the fastest solution for sequential access\n";
100 $nlimit = 10_000_000;
101 $ilimit = prime_count($nlimit)-1;
102 $expect = 0; forprimes { $expect += $_ } $nlimit;
103
104 cmpthese($count,{
105 'primes' => sub { $s=0; $s += $_ for @{primes($nlimit)}; die unless $s == $expect; },
106 'forprimes' => sub { $s=0; forprimes { $s += $_ } $nlimit; die unless $s == $expect; },
107 'pa index' => sub { $s=0; tie my @primes, "Math::Prime::Util::PrimeArray";
108 $s += $primes[$_] for 0..$ilimit;
109 die unless $s == $expect; },
110 'pa loop' => sub { $s=0; tie my @primes, "Math::Prime::Util::PrimeArray";
111 for (@primes) { last if $_ > $nlimit; $s += $_; }
112 die $s unless $s == $expect; },
113 'pa slice' => sub { $s=0; tie my @primes, "Math::Prime::Util::PrimeArray";
114 $s += $_ for @primes[0..$ilimit];
115 die unless $s == $expect; },
116 'pa each' => sub { $s=0; tie my @primes, "Math::Prime::Util::PrimeArray";
117 while(my(undef,$v) = each @primes) { last if $v > $nlimit; $s += $v; }
118 die $s unless $s == $expect; },
119 'pa shift' => sub { $s=0; tie my @primes, "Math::Prime::Util::PrimeArray";
120 while ((my $p = shift @primes) <= $nlimit) { $s += $p; }
121 die unless $s == $expect; },
122 'numseq' => sub { $s=0; my $seq = Math::NumSeq::Primes->new;
123 while (1) { my($undev,$v) = $seq->next; last if $v > $nlimit; $s += $v; }
124 die $s unless $s == $expect; },
125 });
126 }
127
128 if (1) {
129 print '-' x 79, "\n";
130 print "Walk primes backwards from 1M\n";
131 print "Note: MPTA takes 4x longer than just calling MPU's nth_prime!\n";
132 $nlimit = 1_000_000;
133 $ilimit = prime_count($nlimit)-1;
134 $expect = 0; forprimes { $expect += $_ } $nlimit;
135
136 cmpthese($count,{
137 'rev primes'=> sub { $s=0; $s += $_ for reverse @{primes($nlimit)}; die unless $s == $expect; },
138 'nthprime' => sub { $s=0; $s += nth_prime($_) for reverse 1..$ilimit+1; die unless $s == $expect; },
139 'pa index' => sub { $s=0; tie my @primes, "Math::Prime::Util::PrimeArray";
140 $s += $primes[$_] for reverse 0..$ilimit;
141 die unless $s == $expect; },
142 'OO iter' => sub { $s=0; my $it = prime_iterator_object($nlimit);
143 $s += $it->prev->value() for 0..$ilimit;
144 die unless $s == $expect; },
145 'tiedarray' => sub { $s=0; tie my @primes, "Math::Prime::TiedArray", extend_step => 1000;
146 $s += $primes[$_] for reverse 0..$ilimit;
147 die unless $s == $expect; },
148 });
149 }
150
151 if (1) {
152 print '-' x 79, "\n";
153 print "Random walk in 1M\n";
154 print "MPTA takes about 2 minutes and lots of RAM per iteration.\n";
155 srand(29);
156 my @rindex;
157 do { push @rindex, int(rand(1000000)) } for 1..10000;
158 $expect = 0; $expect += nth_prime($_+1) for @rindex;
159
160 cmpthese($count,{
161 'nthprime' => sub { $s=0; $s += nth_prime($_+1) for @rindex; },
162 'pa index' => sub { $s=0; tie my @primes, "Math::Prime::Util::PrimeArray";
163 $s += $primes[$_] for @rindex;
164 die unless $s == $expect; },
165 # Argh! Is it possible to write a slower sieve than the one MPTA uses?
166 #'tiedarray' => sub { $s=0; tie my @primes, "Math::Prime::TiedArray", extend_step => 10000;
167 # $s += $primes[$_] for @rindex;
168 # die unless $s == $expect; },
169 });
170 }
171
172 print '-' x 79, "\n";
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 use Math::Prime::Util ":all";
4 use Benchmark qw/:all/;
5 my $maxdigits = (~0 <= 4294967295) ? 10 : 20;
6 my $nnums = 100;
7
8 my $count = shift || -5;
9
10 srand(29);
11 my @darray;
12 push @darray, [gendigits($_)] for (2 .. 10);
13 my $sum;
14
15 print "Direct sieving:\n";
16 cmpthese($count,{
17 ' 2' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_segment_pi($_) for @{$darray[2-2]} },
18 ' 3' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_segment_pi($_) for @{$darray[3-2]} },
19 ' 4' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_segment_pi($_) for @{$darray[4-2]} },
20 ' 5' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_segment_pi($_) for @{$darray[5-2]} },
21 ' 6' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_segment_pi($_) for @{$darray[6-2]} },
22 ' 7' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_segment_pi($_) for @{$darray[7-2]} },
23 ' 8' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_segment_pi($_) for @{$darray[8-2]} },
24 #' 9' => sub { $sum += Math::Prime::Util::_XS_segment_pi($_) for @{$darray[9-2]} },
25 #'10' => sub { $sum += Math::Prime::Util::_XS_segment_pi($_) for @{$darray[10-2]} },
26 });
27 if (0) {
28 print "\n";
29 print "Direct Lehmer:\n";
30 cmpthese($count,{
31 ' 2' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_lehmer_pi($_) for @{$darray[2-2]} },
32 ' 3' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_lehmer_pi($_) for @{$darray[3-2]} },
33 ' 4' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_lehmer_pi($_) for @{$darray[4-2]} },
34 ' 5' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_lehmer_pi($_) for @{$darray[5-2]} },
35 ' 6' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_lehmer_pi($_) for @{$darray[6-2]} },
36 ' 7' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_lehmer_pi($_) for @{$darray[7-2]} },
37 ' 8' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_lehmer_pi($_) for @{$darray[8-2]} },
38 ' 9' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_lehmer_pi($_) for @{$darray[9-2]} },
39 '10' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_lehmer_pi($_) for @{$darray[10-2]} },
40 });
41 }
42 print "\n";
43 print "Direct LMO:\n";
44 cmpthese($count,{
45 ' 2' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_LMO_pi($_) for @{$darray[2-2]} },
46 ' 3' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_LMO_pi($_) for @{$darray[3-2]} },
47 ' 4' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_LMO_pi($_) for @{$darray[4-2]} },
48 ' 5' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_LMO_pi($_) for @{$darray[5-2]} },
49 ' 6' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_LMO_pi($_) for @{$darray[6-2]} },
50 ' 7' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_LMO_pi($_) for @{$darray[7-2]} },
51 ' 8' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_LMO_pi($_) for @{$darray[8-2]} },
52 ' 9' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_LMO_pi($_) for @{$darray[9-2]} },
53 '10' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_LMO_pi($_) for @{$darray[10-2]} },
54 });
55 print "\n";
56
57 sub gendigits {
58 my $digits = shift;
59 die "Digits must be > 0" unless $digits > 0;
60
61 my $base = ($digits == 1) ? 0 : int(10 ** ($digits-1));
62 my $max = int(10 ** $digits);
63 $max = ~0 if $max > ~0;
64 my @nums = map { $base+int(rand($max-$base)) } (1 .. $nnums);
65 return @nums;
66 }
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3
4 use Math::Prime::Util qw/random_nbit_prime/;
5 use Math::BigInt try=>'GMP';
6 use Benchmark qw/:all/;
7 use List::Util qw/min max/;
8 my $count = shift || -3;
9
10 srand(29);
11 test_at_bits($_) for (15, 30, 60, 128, 256, 512, 1024, 2048, 4096);
12
13 sub test_at_bits {
14 my $bits = shift;
15 die "Digits must be > 0" unless $bits > 0;
16
17 cmpthese($count,{
18 "$bits bits" => sub { random_nbit_prime($bits); },
19 });
20 }
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3
4 use Math::Prime::Util qw/-nobigint random_prime random_ndigit_prime/;
5 use Benchmark qw/:all/;
6 use List::Util qw/min max/;
7 my $count = shift || -3;
8 my $maxdigits = (~0 <= 4294967295) ? 10 : 20;
9
10 srand(29);
11 test_at_digits($_) for (2 .. $maxdigits);
12
13 sub test_at_digits {
14 my $digits = shift;
15 die "Digits must be > 0" unless $digits > 0;
16
17 cmpthese($count,{
18 "$digits digits" => sub { random_ndigit_prime($digits) for (1..1000) },
19 });
20 }
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 use Math::Prime::Util qw/factor/;
4 use File::Temp qw/tempfile/;
5 use Math::BigInt try => 'GMP,Pari';
6 use Config;
7 use autodie;
8 use Text::Diff;
9 use Time::HiRes qw(gettimeofday tv_interval);
10 my $maxdigits = 100;
11 $| = 1; # fast pipes
12 srand(87431);
13 my $num = 1000;
14
15 # Note: If you have factor from coreutils 8.20 or later (e.g. you're running
16 # Fedora), then GNU factor will be very fast and support at least 128-bit
17 # inputs (~44 digits). Its growth is not great however, so 25+ digits starts
18 # getting slow. The authors wrote on a forum that a future version will
19 # include a TinyQS, which should make it really rock for medium-size inputs.
20 #
21 # On the other hand, if you have the older factor (e.g. you're running
22 # Ubuntu) then GNU factor uses trial division so will be very painful for
23 # large numbers. You'll probably want to turn it off here as it will be
24 # many thousands of times slower than MPU and Pari.
25
26 # A benchmarking note: in this script, getting MPU and Pari results are done
27 # by calling a function, where getting GNU factor results are done via
28 # multiple shells to /usr/bin/factor with the inputs as command line
29 # arguments. This adds a lot of overhead that has nothing to do with their
30 # implementation. For comparison, I've included an option for getting MPU
31 # factoring via calling the factor.pl script. Weep at the startup cost.
32
33 my $do_gnu = 1;
34 my $do_pari = 1;
35 my $use_mpu_factor_script = 0;
36
37 if ($do_pari) {
38 $do_pari = 0 unless eval { require Math::Pari; Math::Pari->import(); 1; };
39 }
40
41 my $rgen = sub {
42 my $range = shift;
43 return 0 if $range <= 0;
44 my $rbits = 0; { my $t = $range; while ($t) { $rbits++; $t >>= 1; } }
45 while (1) {
46 my $rbitsleft = $rbits;
47 my $U = $range - $range; # 0 or bigint 0
48 while ($rbitsleft > 0) {
49 my $usebits = ($rbitsleft > $Config{randbits}) ? $Config{randbits} : $rbitsleft;
50 $U = ($U << $usebits) + int(rand(1 << $usebits));
51 $rbitsleft -= $usebits;
52 }
53 return $U if $U <= $range;
54 }
55 };
56
57 { # Test from 2 to 10000
58 print " 2 - 1000"; test_array( 2 .. 1000);
59 print " 1001 - 5000"; test_array( 1001 .. 5000);
60 print " 5001 - 10000"; test_array( 5001 .. 10000);
61 }
62
63 foreach my $digits (5 .. $maxdigits) {
64 printf "%5d %2d-digit numbers", $num, $digits;
65 my @narray = gendigits($digits, $num);
66 test_array(@narray);
67 $num = int($num * 0.9) + 1; # reduce as we go
68 }
69
70 sub test_array {
71 my @narray = @_;
72 my($start, $mpusec, $gnusec, $parisec, $diff);
73 my(@mpuarray, @gnuarray, @pariarray);
74
75 print ".";
76 $start = [gettimeofday];
77 @mpuarray = mpu_factors(@narray);
78 $mpusec = tv_interval($start);
79
80 if ($do_gnu) {
81 print ".";
82 $start = [gettimeofday];
83 @gnuarray = gnu_factors(@narray);
84 $gnusec = tv_interval($start);
85 }
86
87 if ($do_pari) {
88 print ".";
89 $start = [gettimeofday];
90 @pariarray = pari_factors(@narray);
91 $parisec = tv_interval($start);
92 }
93
94 print ".";
95 die "MPU got ", scalar @mpuarray, " factors. GNU factor got ",
96 scalar @gnuarray, "\n" unless !$do_gnu || $#mpuarray == $#gnuarray;
97 die "MPU got ", scalar @mpuarray, " factors. Pari factor got ",
98 scalar @pariarray, "\n" unless !$do_pari || $#mpuarray == $#pariarray;
99 foreach my $n (@narray) {
100 my @mpu = @{shift @mpuarray};
101 die "mpu array is for the wrong n?" unless $n == shift @mpu;
102 if ($do_gnu) {
103 my @gnu = @{shift @gnuarray};
104 die "gnu array is for the wrong n?" unless $n == shift @gnu;
105 $diff = diff \@mpu, \@gnu, { STYLE => 'Table' };
106 die "factor($n): MPU/GNU\n$diff\n" if length($diff) > 0;
107 }
108 if ($do_pari) {
109 my @pari = @{shift @pariarray};
110 die "pari array is for the wrong n?" unless $n == shift @pari;
111 my $diff = diff \@mpu, \@pari, { STYLE => 'Table' };
112 die "factor($n): MPU/Pari\n$diff\n" if length($diff) > 0;
113 }
114 }
115 print ".";
116 # We should ignore the small digits, since we're comparing direct
117 # Perl functions with multiple command line invocations. It really
118 # doesn't make sense until we're over 1ms per number.
119 printf " MPU:%8.4f ms", (($mpusec*1000) / scalar @narray);
120 printf(" GNU:%8.4f ms", (($gnusec*1000) / scalar @narray)) if $do_gnu;
121 printf(" Pari:%8.4f ms", (($parisec*1000) / scalar @narray)) if $do_pari;
122 print "\n";
123 }
124
125 sub gendigits {
126 my $digits = shift;
127 die "Digits must be > 0" unless $digits > 0;
128 my $howmany = shift;
129 my ($base, $max);
130
131 if ( 10**$digits < ~0) {
132 $base = ($digits == 1) ? 0 : int(10 ** ($digits-1));
133 $max = int(10 ** $digits);
134 $max = ~0 if $max > ~0;
135 } else {
136 $base = Math::BigInt->new(10)->bpow($digits-1);
137 $max = Math::BigInt->new(10)->bpow($digits) - 1;
138 }
139 my @nums = map { $base + $rgen->($max-$base) } (1 .. $howmany);
140 return @nums;
141 }
142
143 sub mpu_factors {
144 my @piarray;
145
146 if (!$use_mpu_factor_script) {
147 push @piarray, [$_, factor($_)] for @_;
148 } else {
149 my @ns = @_;
150 my $numpercommand = int( (4000-30)/(length($ns[-1])+1) );
151 while (@ns) {
152 my $cs = join(" ", 'perl -Iblib/lib -Iblib/arch bin/factor.pl', splice(@ns, 0, $numpercommand));
153 my $fout = qx{$cs};
154 my @flines = split(/\n/, $fout);
155 foreach my $fline (@flines) {
156 $fline =~ s/^(\d+): //;
157 push @piarray, [$1, split(/ /, $fline)];
158 }
159 }
160 }
161 @piarray;
162 }
163
164 sub gnu_factors {
165 my @ns = @_;
166 my @piarray;
167 my $numpercommand = int( (4000-30)/(length($ns[-1])+1) );
168
169 while (@ns) {
170 my $cs = join(" ", '/usr/bin/factor', splice(@ns, 0, $numpercommand));
171 my $fout = qx{$cs};
172 my @flines = split(/\n/, $fout);
173 foreach my $fline (@flines) {
174 $fline =~ s/^(\d+): //;
175 push @piarray, [$1, split(/ /, $fline)];
176 }
177 }
178 @piarray;
179 }
180
181 sub pari_factors {
182 my @piarray;
183 foreach my $n (@_) {
184 my @factors;
185 my ($pn,$pc) = @{Math::Pari::factorint($n)};
186 # Map the Math::Pari objects returned into Math::BigInts, because Pari will
187 # throw a hissy fit later when we try to compare them to anything else.
188 push @piarray, [ $n, map { (Math::BigInt->new($pn->[$_])) x $pc->[$_] } (0 .. $#$pn) ];
189 }
190 @piarray;
191 }
11 use strict;
22 use warnings;
33 use Getopt::Long;
4 use bigint try => 'GMP';
54 use Math::Prime::Util qw/factor nth_prime prime_set_config/;
65 $| = 1;
7 no bigint;
86
97 # Allow execution of any of these functions in the command line
108 my @mpu_funcs = (qw/next_prime prev_prime prime_count nth_prime random_prime
2220 ) || die_usage();
2321 if (exists $opts{'version'}) {
2422 my $version_str =
25 "factor.pl version 1.1 using Math::Prime::Util $Math::Prime::Util::VERSION";
23 "factor.pl version 1.2 using Math::Prime::Util $Math::Prime::Util::VERSION";
2624 $version_str .= " and MPU::GMP $Math::Prime::Util::GMP::VERSION"
2725 if Math::Prime::Util::prime_get_config->{'gmp'};
2826 $version_str .= "\nWritten by Dana Jacobsen.\n";
6866 $expr =~ s/:$mpu_func_map{$func}\(/Math::Prime::Util::$func(/g;
6967 }
7068 $expr =~ s/(\d+)/ Math::BigInt->new("$1") /g;
69 $expr = 'use Math::BigInt try=>"GMP"; ' . $expr;
7170 my $res = eval $expr; ## no critic
7271 die "Cannot eval: $expr\n" if !defined $res;
7372 $res = int($res->bstr) if ref($res) eq 'Math::BigInt' && $res <= ~0;
157157 #endif
158158 }
159159
160 #ifdef USE_ITHREADS
160161 void release_prime_cache(const unsigned char* mem) {
161162 (void)mem; /* We don't currently care about the pointer */
162163 READ_LOCK_END;
163164 }
165 #endif
164166
165167
166168
2929 */
3030 extern UV get_prime_cache(UV n, const unsigned char** sieve);
3131 /* Inform the system we're done using the primary cache if we got a ptr. */
32 #ifdef USE_ITHREADS
3233 extern void release_prime_cache(const unsigned char* sieve);
34 #else
35 #define release_prime_cache(mem)
36 #endif
3337
3438 /* Get the segment cache. Set size to its size. */
3539 extern unsigned char* get_prime_segment(UV* size);
00
1 There are two main types of scripts here: benchmarks and correctness tests.
1 abundant.pl
22
3 The test-* scripts are generally trying to test one part of the module
4 against another part of the module, an external module, or an external program.
5 These usually consist of a combination of fixed tests and a long sequence of
6 testing with random numbers, trying to find things the standard testing might
7 have missed.
3 Prints the first N abundant (or deficient, or perfect) numbers. E.g:
4
5 perl abundant.pl 100 abundant
6 perl abundant.pl 100 deficient
7 perl abundant.pl 15 perfect
88
99
10 test-factor-yafu.pl
10 sophie_germain.pl
1111
12 Tests factorization compared with YAFU (v1.31.1). No arguments.
12 Prints the first N Sophie-Germain primes. E.g.:
1313
14 test-factor-mpxs.pl
14 perl sophia_germain.pl 100000
1515
16 Tests factorization compared with Math::Factor::XS (v0.26).
17 One argument gives the number of random tests to perform.
1816
19 test-nextprime-yafu.pl
17 twin_primes.pl
2018
21 Tests next_prime() compared with YAFU (v1.31.1). No arguments.
19 Prints the first N twin-primes (first value of the pair). E.g.:
2220
23 test-primes-yafu.pl
21 perl twin_primes.pl 100000
2422
25 Tests primes($a,$b+$interval) compared with YAFU (v1.31.1). No arguments.
26 The interval is currently 8000.
2723
28 test-holf.pl
24 find_mr_bases.pl
25
26 An example using threads to do a parallel search for good deterministic
27 bases for a Miller-Rabin test. This is definitely not the fastest way
28 to find these, but it's a decent example of quickly trying out an idea.
29 Be sure to set $nthreads to the right value for your machine. It should
30 fully load your CPUs.
2931
30 Tests the holf_factor() function vs. the factor() function. Given enough
31 rounds, HOLF (like Fermat) should be able to factor a number. We keep
32 calling it on each non-prime return value until it's done.
3332
34 test-nthapprox.pl
33 parallel_fibprime.pl
3534
36 Tests the nth_prime approximation and upper/lower bounds vs. known values
37 for the nth prime on large values.
35 Find Fibonacci primes, in parallel. You will want Math::Prime::Util::GMP
36 installed, as these are many-thousand-digit numbers.
3837
39 test-pcapprox.pl
4038
41 Tests the prime_count approximation and upper/lower bounds vs. known values
42 for Pi(x) on large values. Also examines the Schoenfeld and Stoll
43 inequalities.
39 porter.pl
4440
45 bench-factor-extra.pl
41 Various ways of constructing a sequence suggested by Michael B. Porter:
42 a(n) = m s.t. sigma(m) + sigma(m+1) + ... + sigma(m+n-1) is prime.
43 Includes comparison to Pari/GP.
4644
47 Benchmarks the various factoring options (prho, pbrent, pminus1, fermat, holf,
48 squfof, trial) on random n-digit numbers. Also gives the percent of the time
49 solutions were found with the given number of rounds (256k for SQUFOF, 2000
50 for HOLF, and 400 for probabilistic methods).
5145
52 bench-factor.pl
5346
54 Benchmarks factoring random and semiprime n-digit numbers using the factor
55 method, and compares vs. Math::Factor::XS (v0.26). The latter uses a trial
56 division algorithm. MPU 0.05 and later use a threshold of 10M (8 digits)
57 to switch between trial division and methods like SQUFOF, Pollard's Rho, and
58 HOLF.
47 verify-cert.pl
5948
60 bench-factor-semiprime.pl
49 Takes an MPU or Primo primality certificate and verifies it. This is
50 obsolete, as Math::Prime::Util::GMP now includes C code for this.
6151
62 Benchmarks factoring semiprimes, and compares with Math::Prime::XS and
63 Math::Pari. Takes two optional arguments: the number of digits (default 15)
64 and the benchmark count (default -2, meaning 2 seconds).
52 verify-gmp-ecpp-cert.pl
6553
66 bench-is-prime.pl
54 Parses the verbose output of GMP-ECPP to construct a certificate, then
55 runs it through the verification process.
6756
68 Benchmarks is_prime on random n-digit numbers, n from 5 to 10/20. Compares
69 MPU's is_prime and is_prob_prime vs. Math::Prime::XS and optionally
70 Math::Primality, Math::Pari, and Math::Prime::FastSieve. The first two of
71 the optional modules use methods more appropriate for big numbers, so are up
72 to an order of magnitude slower for 64-bit numbers. The last module (MPFS)
73 is extremely fast, but requires presieving to at least the number to be
74 tested, which is great for small numbers, but not for large.
75 Also, no additional precalc is done for MPU. If you really want blazing
76 fast is_prime and don't care about the memory and time to sieve, run
77 prime_precalc to the limit of your numbers and is_prime will turn into a
78 sub-100 microsecond bit array lookup for any number in the range.
79 Takes one optional argument of the benchmark count (default -5).
57 verify-sage-ecpp-cert.pl
8058
81 bench-miller-rabin.pl
82
83 Benchmarks the strong miller_rabin test using 7 bases at various digit counts.
84 Takes one optional argument of the benchmark count (default -5).
85
86 bench-nthprime.pl
87
88 Benchmarks the speed of nth_prime with various digit sizes.
89
90 bench-pcapprox.pl
91
92 Benchmarks the speed of prime_count related functions for random n-digit
93 numbers (n = 5 to 10/20). This includes lower bound, lower/upper average,
94 the prime_count_approx function, li(x), and R(x).
95 Takes one optional argument of the benchmark count (default -5).
96
97 bench-primecount.pl
98
99 Benchmarks the speed of prime_count on random n-digit numbers (n = 2 .. 8).
100 Takes one optional argument of the benchmark count (default -5).
101 I'll note you can easily see the transition from where we're just counting
102 existing value to where we have to sieve. Adding a prime_precalc(10**9)
103 line will speed up the 5-,6-,7-, and 8-digit prime_counts greatly.
104
105 bench-random-prime.pl
106
107 Benchmarks the speed of random_ndigit_prime for various digits.
59 Verifies the output of SAGE's ECPP. The SAGE module looks like it died
60 in development and never got into SAGE. NZMath's ECPP doesn't seem to
61 output a certificate, which makes it much less useful.
44 # Find the first N abundant, deficient, or perfect numbers.
55
66 use Math::Prime::Util qw/divisor_sum next_prime is_prime/;
7 use Math::BigInt try => "GMP,Pari";
87
98 my $count = shift || 20;
109 my $type = lc(shift || 'abundant');
2524 # We just look for 2^(p-1)*(2^p-1) where 2^p-1 is prime.
2625 # Basically we're just finding Mersenne primes.
2726 # It's possible there are odd perfect numbers larger than 10^1500.
27 do { require Math::BigInt; Math::BigInt->import(try=>"GMP,Pari"); };
2828 while ($count-- > 0) {
2929 while (1) {
3030 $p = next_prime($p);
+0
-128
examples/bench-factor-extra.pl less more
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 use Math::Prime::Util qw/-nobigint/;
4 use Benchmark qw/:all/;
5 use List::Util qw/min max/;
6 use Config;
7 my $count = shift || -2;
8 my $is64bit = (~0 > 4294967295);
9 my $maxdigits = ($is64bit) ? 20 : 10; # Noting the range is limited for max.
10
11 my $rgen = sub {
12 my $range = shift;
13 return 0 if $range <= 0;
14 my $rbits = 0; { my $t = $range; while ($t) { $rbits++; $t >>= 1; } }
15 while (1) {
16 my $rbitsleft = $rbits;
17 my $U = 0;
18 while ($rbitsleft > 0) {
19 my $usebits = ($rbitsleft > $Config{randbits}) ? $Config{randbits} : $rbitsleft;
20 $U = ($U << $usebits) + int(rand(1 << $usebits));
21 $rbitsleft -= $usebits;
22 }
23 return $U if $U <= $range;
24 }
25 };
26
27 srand(29);
28 my $rounds = 400;
29 my $sqrounds = 256*1024;
30 my $rsqrounds = 32*1024;
31 my $p1smooth = 1000;
32 my $hrounds = 10000;
33 my $num_nums = 1000;
34 test_at_digits($_) for ( 3 .. $maxdigits );
35
36
37 sub test_at_digits {
38 my $digits = shift;
39
40 die "Digits has to be >= 1" unless $digits >= 1;
41 die "Digits has to be <= $maxdigits" if $digits > $maxdigits;
42
43 my @nums = genrand($digits, $num_nums);
44 #my @nums = gensemi($digits, $num_nums, 23);
45 my $min_num = min @nums;
46 my $max_num = max @nums;
47
48 # Determine success rates
49 my %nfactored;
50 my $tfac = 0;
51 # Did we find any non-trivial factors?
52 my $calc_nfacs = sub { ((scalar grep { $_ > 5 } @_) > 1) ? 1 : 0 };
53 for (@nums) {
54 $tfac += $calc_nfacs->(Math::Prime::Util::factor($_));
55 $nfactored{'prho'} += $calc_nfacs->(Math::Prime::Util::prho_factor($_, $rounds));
56 $nfactored{'pbrent'} += $calc_nfacs->(Math::Prime::Util::pbrent_factor($_, $rounds));
57 $nfactored{'pminus1'} += $calc_nfacs->(Math::Prime::Util::pminus1_factor($_, $p1smooth));
58 $nfactored{'pplus1'} += $calc_nfacs->(Math::Prime::Util::pplus1_factor($_, $p1smooth));
59 $nfactored{'squfof'} += $calc_nfacs->(Math::Prime::Util::squfof_factor($_, $sqrounds));
60 #$nfactored{'trial'} += $calc_nfacs->(Math::Prime::Util::trial_factor($_));
61 #$nfactored{'fermat'} += $calc_nfacs->(Math::Prime::Util::fermat_factor($_, $rounds));
62 $nfactored{'holf'} += $calc_nfacs->(Math::Prime::Util::holf_factor($_, $hrounds));
63 }
64
65 print "factoring $num_nums random $digits-digit numbers ($min_num - $max_num)\n";
66 print "Factorizations: ",
67 join(", ", map { sprintf "%s %4.1f%%", $_, 100*$nfactored{$_}/$tfac }
68 grep { $_ ne 'fermat' }
69 sort {$nfactored{$a} <=> $nfactored{$b}} keys %nfactored),
70 "\n";
71
72 my $lref = {
73 "prho" => sub { Math::Prime::Util::prho_factor($_, $rounds) for @nums },
74 "pbrent" => sub { Math::Prime::Util::pbrent_factor($_, $rounds) for @nums },
75 "pminus1" => sub { Math::Prime::Util::pminus1_factor($_, $rounds) for @nums },
76 "pplus1" => sub { Math::Prime::Util::pplus1_factor($_, $rounds) for @nums},
77 "fermat" => sub { Math::Prime::Util::fermat_factor($_, $rounds) for @nums},
78 "holf" => sub { Math::Prime::Util::holf_factor($_, $hrounds) for @nums },
79 "squfof" => sub { Math::Prime::Util::squfof_factor($_, $sqrounds) for @nums },
80 "trial" => sub { Math::Prime::Util::trial_factor($_) for @nums },
81 };
82 delete $lref->{'fermat'} if $digits >= 9;
83 delete $lref->{'holf'} if $digits >= 17;
84 delete $lref->{'trial'} if $digits >= 15;
85 cmpthese($count, $lref);
86 print "\n";
87 }
88
89
90 sub genrand {
91 my $digits = shift;
92 my $num = shift;
93
94 my $base = ($digits == 1) ? 0 : int(10 ** ($digits-1));
95 my $max = int(10 ** $digits);
96 $max = ~0 if $max > ~0;
97 my @nums = map { $base + $rgen->($max-$base) } (1 .. $num);
98 return @nums;
99 }
100
101 sub gensemi {
102 my $digits = shift;
103 my $num = shift;
104 my $smallest_factor = shift;
105
106 my $base = ($digits == 1) ? 0 : int(10 ** ($digits-1));
107 my $max = int(10 ** $digits);
108 $max = (~0-4) if $max > (~0-4);
109 my @semiprimes;
110
111 foreach my $i (1 .. $num) {
112 my @factors;
113 my $n;
114 while (1) {
115 $n = $base + $rgen->($max-$base);
116 $n += (1,0,5,4,3,2,1,0,3,2,1,0,1,0,3,2,1,0,1,0,3,2,1,0,5,4,3,2,1,0)[$n%30];
117 @factors = Math::Prime::Util::factor($n);
118 next if scalar @factors != 2;
119 next if $factors[0] < $smallest_factor;
120 next if $factors[1] < $smallest_factor;
121 last if scalar @factors == 2;
122 }
123 die "ummm... $n != $factors[0] * $factors[1]\n" unless $n == $factors[0] * $factors[1];
124 push @semiprimes, $n;
125 }
126 return @semiprimes;
127 }
+0
-102
examples/bench-factor-semiprime.pl less more
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 $| = 1; # fast pipes
4 srand(377);
5
6 use Math::Prime::Util qw/factor/;
7 use Math::Factor::XS qw/prime_factors/;
8 use Math::Pari qw/factorint/;
9 use Benchmark qw/:all/;
10 use Data::Dumper;
11 use Config;
12 my $digits = shift || 15;
13 my $count = shift || -3;
14
15 my $rgen = sub {
16 my $range = shift;
17 return 0 if $range <= 0;
18 my $rbits = 0; { my $t = $range; while ($t) { $rbits++; $t >>= 1; } }
19 while (1) {
20 my $rbitsleft = $rbits;
21 my $U = 0;
22 while ($rbitsleft > 0) {
23 my $usebits = ($rbitsleft > $Config{randbits}) ? $Config{randbits} : $rbitsleft;
24 $U = ($U << $usebits) + int(rand(1 << $usebits));
25 $rbitsleft -= $usebits;
26 }
27 return $U if $U <= $range;
28 }
29 };
30
31 my @min_factors_by_digit = (2,2,3,3,5,11,17,47,97);
32 my $smallest_factor_allowed = $min_factors_by_digit[$digits];
33 $smallest_factor_allowed = $min_factors_by_digit[-1] unless defined $smallest_factor_allowed;
34 my $numprimes = 200;
35
36 die "Digits has to be >= 2" unless $digits >= 2;
37 die "Digits has to be <= 10" if (~0 == 4294967295) && ($digits > 10);
38 die "Digits has to be <= 19" if $digits > 19;
39
40 my $skip_mfxs = ($digits > 17);
41
42 # Construct some semiprimes of the appropriate number of digits
43 # There are much cleverer ways of doing this, using randomly selected
44 # nth_primes, and so on, but this works well until we get lots of digits.
45 print "Generating $numprimes random $digits-digit semiprimes (min factor $smallest_factor_allowed) ";
46 my @semiprimes;
47 foreach my $i ( 1 .. $numprimes ) {
48 my $base = int(10 ** ($digits-1));
49 my $add = int(10 ** ($digits)) - $base;
50 my @factors;
51 my $n;
52 while (1) {
53 $n = $base + $rgen->($add);
54 next if $n > (~0 - 4);
55 $n += (1,0,5,4,3,2,1,0,3,2,1,0,1,0,3,2,1,0,1,0,3,2,1,0,5,4,3,2,1,0)[$n%30];
56 @factors = factor($n);
57 next if scalar @factors != 2;
58 next if $factors[0] < $smallest_factor_allowed;
59 next if $factors[1] < $smallest_factor_allowed;
60 last if scalar @factors == 2;
61 }
62 die "ummm... $n != $factors[0] * $factors[1]\n" unless $n == $factors[0] * $factors[1];
63 #print "$n == $factors[0] * $factors[1]\n";
64 push @semiprimes, $n;
65 print "." if ($i % ($numprimes/10)) == 0;
66 }
67 print "done.\n";
68
69 print "Verifying Math::Prime::Util $Math::Prime::Util::VERSION ...";
70 foreach my $sp (@semiprimes) {
71 my @factors = factor($sp);
72 die "wrong for $sp\n" unless ($#factors == 1) && ($factors[0] * $factors[1]) == $sp;
73 }
74 print "OK\n";
75 if (!$skip_mfxs) {
76 print "Verifying Math::Factor::XS $Math::Factor::XS::VERSION ...";
77 foreach my $sp (@semiprimes) {
78 my @factors = prime_factors($sp);
79 die "wrong for $sp\n" unless ($#factors == 1) && ($factors[0] * $factors[1]) == $sp;
80 }
81 print "OK\n";
82 } else {
83 print "Math::Factor::XS is too slow for $digits digits. Skipping.\n";
84 }
85 print "Verifying Math::Pari $Math::Pari::VERSION ...";
86 foreach my $sp (@semiprimes) {
87 my @factors;
88 my ($pn,$pc) = @{factorint($sp)};
89 push @factors, (int($pn->[$_])) x $pc->[$_] for (0 .. $#{$pn});
90 die "wrong for $sp\n" unless ($#factors == 1) && ($factors[0] * $factors[1]) == $sp;
91 }
92 print "OK\n";
93
94 my %compare = (
95 'MPU' => sub { do { my @f = factor($_) } for @semiprimes; },
96 'MFXS' => sub { do { my @f = prime_factors($_) } for @semiprimes; },
97 'Pari' => sub { do { my ($pn,$pc) = @{factorint($_)}; my @f = map { int($pn->[$_]) x $pc->[$_] } 0 .. $#$pn; } for @semiprimes; },
98 );
99 delete $compare{'MFXS'} if $skip_mfxs;
100
101 cmpthese($count, \%compare);
+0
-98
examples/bench-factor.pl less more
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 use Math::Prime::Util qw/factor/;
4 # Compare to Math::Factor::XS, which uses trial division.
5 use Math::Factor::XS qw/prime_factors/;
6
7 use Benchmark qw/:all/;
8 use List::Util qw/min max reduce/;
9 my $count = shift || -2;
10 my $is64bit = (~0 > 4294967295);
11 my $maxdigits = ($is64bit) ? 20 : 10; # Noting the range is limited for max.
12 my $semiprimes = 0;
13 my $howmany = 1000;
14
15 for my $d ( 3 .. $maxdigits ) {
16 print "Factor $howmany $d-digit numbers\n";
17 test_at_digits($d, $howmany);
18 }
19
20 sub test_at_digits {
21 my $digits = shift;
22 die "Digits has to be >= 1" unless $digits >= 1;
23 die "Digits has to be <= $maxdigits" if $digits > $maxdigits;
24 my $quantity = shift;
25
26 my @rnd = ndigit_rand($digits, $quantity);
27 my @smp = genrough($digits, $quantity);
28
29 # verify (can be _really_ slow for 18+ digits)
30 foreach my $p (@rnd, @smp) {
31 next if $p < 2;
32 verify_factor($p, [prime_factors($p)], [factor($p)], "Math::Prime::Util $Math::Prime::Util::VERSION");
33 }
34
35 #my $min_num = min @nums;
36 #my $max_num = max @nums;
37 #my $whatstr = "$digits-digit ", $semiprimes ? "semiprime" : "random";
38 #print "factoring 1000 $digits-digit ",
39 # $semiprimes ? "semiprimes" : "random numbers",
40 # " ($min_num - $max_num)\n";
41
42 my $lref = {
43 "MPU random" => sub { my@a=factor($_) for @rnd },
44 "MPU nonsmooth" => sub { my@a=factor($_) for @smp },
45 "MFXS random" => sub { my@a=prime_factors($_) for @rnd },
46 "MFXS nonsmooth" => sub { my@a=prime_factors($_) for @smp },
47 };
48 cmpthese($count, $lref);
49 }
50
51 sub verify_factor {
52 my ($n, $aref1, $aref2, $name) = @_;
53
54 return 1 if "@$aref1" eq "@$aref2";
55
56 my @master = @$aref1;
57 my @check = @$aref2;
58 die "Factor $n master fail!" unless $n == reduce { $a * $b } @master;
59 die "Factor $n fail: $name" unless $#check == $#master;
60 die "Factor $n fail: $name" unless $n == reduce { $a * $b } @check;
61 for (0 .. $#master) {
62 die "Factor $n fail: $name" unless $master[$_] == $check[$_];
63 }
64 1;
65 }
66
67 sub genrough {
68 my ($digits, $num) = @_;
69
70 my @min_factors_by_digit = (2,2,3,5,7,13,23,47,97);
71 my $smallest_factor = $min_factors_by_digit[$digits];
72 $smallest_factor = $min_factors_by_digit[-1] unless defined $smallest_factor;
73
74 my @semiprimes;
75 foreach my $i (1 .. $num) {
76 my $n;
77 my @facn;
78 do {
79 $n = ndigit_rand($digits, 1);
80 @facn = Math::Prime::Util::trial_factor($n,$smallest_factor);
81 } while scalar(@facn) > 1;
82 push @semiprimes, $n;
83 }
84 return @semiprimes;
85 }
86
87 use Bytes::Random::Secure qw/random_string_from/;
88 sub ndigit_rand {
89 my($digits, $howmany) = @_;
90 die "digits must be > 0" if $digits < 1;
91 $howmany = 1 unless defined $howmany;
92 # TODO: need to skip things larger than ~0 for this module
93 my @nums = map { random_string_from("123456789",1) . random_string_from("0123456789",$digits-1) } 1 .. $howmany;
94 if (10**$digits > ~0) { @nums = map { Math::BigInt->new($_) } @nums; }
95 else { @nums = map { int($_) } @nums; }
96 return wantarray ? @nums : $nums[0];
97 }
+0
-62
examples/bench-is-prime.pl less more
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 #use Math::Primality;
4 use Math::Prime::XS;
5 use Math::Prime::Util;
6 #use Math::Pari;
7 #use Math::Prime::FastSieve;
8 use Benchmark qw/:all/;
9 use List::Util qw/min max/;
10 my $count = shift || -5;
11 my $numbers = 1000;
12
13 my $is64bit = (~0 > 4294967295);
14 my $maxdigits = ($is64bit) ? 20 : 10; # Noting the range is limited for max.
15 my $randf = Math::Prime::Util::_get_rand_func();
16
17 my $rand_ndigit_gen = sub {
18 my $digits = shift;
19 die "Digits must be > 0" unless $digits > 0;
20 my $howmany = shift || 1;
21 my ($base, $max);
22
23 if ( 10**$digits < ~0) {
24 $base = ($digits == 1) ? 0 : int(10 ** ($digits-1));
25 $max = int(10 ** $digits);
26 $max = ~0 if $max > ~0;
27 } else {
28 $base = Math::BigInt->new(10)->bpow($digits-1);
29 $max = Math::BigInt->new(10)->bpow($digits) - 1;
30 }
31 my @nums = map { $base + $randf->($max-$base) } (1 .. $howmany);
32 return (wantarray) ? @nums : $nums[0];
33 };
34
35 srand(29);
36 test_at_digits($_) for (3 .. $maxdigits);
37
38
39 sub test_at_digits {
40 my $digits = shift;
41 die "Digits must be > 0" unless $digits > 0;
42
43 my @nums = $rand_ndigit_gen->($digits, $numbers);
44 my $min_num = min @nums;
45 my $max_num = max @nums;
46
47 #my $sieve = Math::Prime::FastSieve::Sieve->new(10 ** $magnitude + 1);
48 #Math::Prime::Util::prime_precalc(10 ** $magnitude + 1);
49
50 print "is_prime for $numbers random $digits-digit numbers ($min_num - $max_num)\n";
51
52 cmpthese($count,{
53 #'Math::Primality' => sub { Math::Primality::is_prime($_) for @nums },
54 'M::P::XS' => sub { Math::Prime::XS::is_prime($_) for @nums },
55 #'M::P::FS' => sub { $sieve->isprime($_) for @nums },
56 'M::P::U' => sub { Math::Prime::Util::is_prime($_) for @nums },
57 'MPU prob' => sub { Math::Prime::Util::is_prob_prime($_) for @nums },
58 #'Math::Pari' => sub { Math::Pari::isprime($_) for @nums },
59 });
60 print "\n";
61 }
+0
-65
examples/bench-isprime-bpsw.pl less more
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 $| = 1; # fast pipes
4
5 use Math::Prime::Util;
6 use Math::Primality;
7
8 my $count = shift || -1;
9
10 # GMP is ~3x faster than Calc or Pari for these operations
11 use bigint try=>'GMP';
12 srand(500);
13 use Config;
14
15 my $rgen = sub {
16 my $range = shift;
17 return 0 if $range <= 0;
18 my $rbits = 0; { my $t = $range; while ($t) { $rbits++; $t >>= 1; } }
19 while (1) {
20 my $rbitsleft = $rbits;
21 my $U = $range - $range; # 0 or bigint 0
22 while ($rbitsleft > 0) {
23 my $usebits = ($rbitsleft > $Config{randbits}) ? $Config{randbits} : $rbitsleft;
24 $U = ($U << $usebits) + int(rand(1 << $usebits));
25 $rbitsleft -= $usebits;
26 }
27 return $U if $U <= $range;
28 }
29 };
30
31 my @rns;
32 while (@rns < 50) {
33 my $n = $rgen->( Math::BigInt->new(2)->bpow(81) );
34 $n++ if ($n % 2) == 0;
35 next unless ($n % 2) != 0;
36 push @rns, $n;
37 }
38 map { $_ = int($_->bstr) if $_ <= ~0 } @rns;
39 #print "$_\n" for @rns;
40 no bigint; # Benchmark doesn't work with bigint on.
41
42 print "Verifying";
43 for my $n (@rns) {
44 die "bad MR for $n" unless Math::Prime::Util::is_strong_pseudoprime($n,2) == Math::Primality::is_strong_pseudoprime("$n","2");
45 die "bad LP for $n" unless Math::Prime::Util::is_strong_lucas_pseudoprime($n) == Math::Primality::is_strong_lucas_pseudoprime("$n");
46 die "bad IP for $n" unless (Math::Prime::Util::is_prime($n)?1:0) == (Math::Primality::is_prime("$n")?1:0);
47 print ".";
48 }
49 print "OK\n";
50
51 use Benchmark qw/:all/;
52 my $sum = 0;
53 cmpthese($count, {
54 "MP MR" => sub { $sum += Math::Primality::is_strong_pseudoprime("$_","2") for @rns; },
55 "MPU MR" => sub { $sum += Math::Prime::Util::GMP::is_strong_pseudoprime($_,2) for @rns; },
56 #"MPUxMR" => sub { Math::Prime::Util::miller_rabin($_,2) for @rns; },
57 "MP LP" => sub { $sum += Math::Primality::is_strong_lucas_pseudoprime("$_") for @rns;},
58 "MPU LP" => sub { $sum += Math::Prime::Util::GMP::is_strong_lucas_pseudoprime($_) for @rns;},
59 "MPU ELP" => sub { $sum += Math::Prime::Util::GMP::is_extra_strong_lucas_pseudoprime($_) for @rns;},
60 #"MPU AELP" => sub { $sum += Math::Prime::Util::GMP::is_almost_extra_strong_lucas_pseudoprime($_) for @rns;},
61 "MP IP" => sub { $sum += Math::Primality::is_prime("$_") for @rns;},
62 "MPU IP" => sub { $sum += Math::Prime::Util::is_prime($_) for @rns;},
63 #"MPUxIP" => sub { Math::Prime::Util::is_prime($_) for @rns;},
64 });
+0
-53
examples/bench-miller-rabin.pl less more
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 use Math::Primality;
4 use Math::Prime::XS;
5 use Math::Prime::Util;
6 use Math::Prime::Util::GMP;
7 #use Math::Prime::FastSieve;
8 use Benchmark qw/:all/;
9 use List::Util qw/min max/;
10 my $count = shift || -5;
11
12 srand(29);
13 test_at_digits($_) for (5..18);
14
15
16 sub test_at_digits {
17 my $digits = shift;
18 die "Digits must be > 0" unless $digits > 0;
19
20 my @nums = ndigit_rand($digits, 1000);
21 my $min_num = min @nums;
22 my $max_num = max @nums;
23
24 #my $sieve = Math::Prime::FastSieve::Sieve->new(10 ** $magnitude + 1);
25 #Math::Prime::Util::prime_precalc(10 ** $magnitude + 1);
26
27 print "miller_rabin for 1000 random $digits-digit numbers ($min_num - $max_num)\n";
28
29 cmpthese($count,{
30 'MPU' => sub { Math::Prime::Util::is_strong_pseudoprime($_,2,3,5,7,11,13,17) for @nums },
31 'MPU GMP' => sub { Math::Prime::Util::GMP::is_strong_pseudoprime($_,2,3,5,7,11,13,17) for @nums },
32 'M:Primality' => sub { for (@nums) {
33 Math::Primality::is_strong_pseudoprime($_,2) &&
34 Math::Primality::is_strong_pseudoprime($_,3) &&
35 Math::Primality::is_strong_pseudoprime($_,5) &&
36 Math::Primality::is_strong_pseudoprime($_,7) &&
37 Math::Primality::is_strong_pseudoprime($_,11) &&
38 Math::Primality::is_strong_pseudoprime($_,13) &&
39 Math::Primality::is_strong_pseudoprime($_,17); } },
40 });
41 print "\n";
42 }
43
44 use Bytes::Random::Secure qw/random_string_from/;
45 sub ndigit_rand {
46 my($digits, $howmany) = @_;
47 die "digits must be > 0" if $digits < 1;
48 $howmany = 1 unless defined $howmany;
49 my @nums = map { random_string_from("123456789",1) . random_string_from("0123456789",$digits-1) } 1 .. $howmany;
50 @nums = map { Math::BigInt->new($_) } @nums if 10**$digits > ~0;
51 return @nums;
52 }
+0
-29
examples/bench-mp-nextprime.pl less more
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 use Math::Prime::Util;
4 use Math::Prime::Util::GMP;
5 use Math::Primality;
6 use Benchmark qw/:all/;
7 my $count = shift || -2;
8 srand(29); # So we have repeatable results
9 Math::Prime::Util::prime_set_config(irand => sub { int(rand(4294967295)) });
10
11 test_at_digits($_, 1000) for (5, 15, 25, 50, 200);
12
13 sub test_at_digits {
14 my($digits, $numbers) = @_;
15 die "Digits must be > 0" unless $digits > 0;
16
17 my $start = Math::Prime::Util::random_ndigit_prime($digits) - 3;
18 my $end = $start;
19 $end = Math::Prime::Util::GMP::next_prime($end) for 1 .. $numbers;
20
21 print "next_prime x $numbers starting at $start\n";
22
23 cmpthese($count,{
24 'MP' => sub { my $n = $start; $n = Math::Primality::next_prime($n) for 1..$numbers; die "MP ended with $n instead of $end" unless $n == $end; },
25 'MPU' => sub { my $n = $start; $n = Math::Prime::Util::next_prime($n) for 1..$numbers; die "MPU ended with $n instead of $end" unless $n == $end; },
26 'MPU GMP' => sub { my $n = $start; $n = Math::Prime::Util::GMP::next_prime($n) for 1..$numbers; die "MPU GMP ended with $n instead of $end" unless $n == $end; },
27 });
28 }
+0
-21
examples/bench-mp-prime_count.pl less more
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 use Math::Prime::Util;
4 use Math::Prime::Util::GMP;
5 use Math::Primality;
6 use Benchmark qw/:all/;
7 my $count = shift || -2;
8
9 #my($n, $exp) = (100000,9592);
10 my($n, $exp) = (1000000,78498);
11 #my($n, $exp) = (10000000,664579);
12 cmpthese($count,{
13 'MP' =>sub { die unless $exp == Math::Primality::prime_count($n); },
14 'MPU default' =>sub { die unless $exp == Math::Prime::Util::prime_count($n); },
15 'MPU XS Sieve' =>sub { die unless $exp == Math::Prime::Util::_XS_prime_count($n); },
16 'MPU XS Lehmer'=>sub { die unless $exp == Math::Prime::Util::_XS_lehmer_pi($n); },
17 'MPU PP Sieve' =>sub { die unless $exp == Math::Prime::Util::PP::_sieve_prime_count($n); },
18 'MPU PP Lehmer'=>sub { die unless $exp == Math::Prime::Util::PP::_lehmer_pi($n); },
19 'MPU GMP Trial'=>sub { die unless $exp == Math::Prime::Util::GMP::prime_count(2,$n); },
20 });
+0
-29
examples/bench-mp-psrp.pl less more
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 use Math::Prime::Util;
4 use Math::Prime::Util::GMP;
5 use Math::Primality;
6 use Benchmark qw/:all/;
7 use List::Util qw/min max/;
8 my $count = shift || -2;
9 srand(29); # So we have repeatable results
10
11 test_at_digits($_, 1000) for (5, 15, 25, 50, 200);
12
13 sub test_at_digits {
14 my($digits, $numbers) = @_;
15 die "Digits must be > 0" unless $digits > 0;
16
17 # We get a mix of primes and non-primes.
18 my @nums = map { Math::Prime::Util::random_ndigit_prime($digits)+2 } 1 .. $numbers;
19 print "is_strong_pseudoprime for $numbers random $digits-digit numbers",
20 " (", min(@nums), " - ", max(@nums), ")\n";
21
22 cmpthese($count,{
23 'MP' =>sub {Math::Primality::is_strong_pseudoprime($_,3) for @nums;},
24 'MPU' =>sub {Math::Prime::Util::is_strong_pseudoprime($_,3) for @nums;},
25 'MPU PP' =>sub {Math::Prime::Util::PP::miller_rabin($_,3) for @nums;},
26 'MPU GMP' =>sub {Math::Prime::Util::GMP::is_strong_pseudoprime($_,3) for @nums;},
27 });
28 }
+0
-45
examples/bench-nthprime.pl less more
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 use Math::Prime::Util qw/nth_prime prime_precalc/;
4 use Benchmark qw/:all :hireswallclock/;
5 use Data::Dumper;
6
7 my $count = shift || -5;
8
9 #prime_precalc(1000000000);
10
11 srand(29);
12 my @darray;
13 push @darray, [gendigits($_,int(5400/($_*$_*$_)))] for 2 .. 13;
14
15 my $sum;
16 foreach my $digits (3 .. 12) {
17 my @digarray = @{$darray[$digits-2]};
18 my $numitems = scalar @digarray;
19 my $timing = cmpthese(
20 $count,
21 { "$digits" => sub { $sum += nth_prime($_) for @digarray }, },
22 'none',
23 );
24 my $secondsper = $timing->[1]->[1];
25 if ($timing->[0]->[1] eq 'Rate') {
26 $secondsper =~ s/\/s$//;
27 $secondsper = 1.0 / $secondsper;
28 }
29 $secondsper /= $numitems;
30 my $timestr = (1.0 / $secondsper) . "/s per number";
31 printf "%4d %2d-digit numbers: %s\n", $numitems, $digits, $timestr;
32 }
33
34 sub gendigits {
35 my $digits = shift;
36 die "Digits must be > 0" unless $digits > 0;
37 my $num = shift;
38
39 my $base = ($digits == 1) ? 0 : int(10 ** ($digits-1));
40 my $max = int(10 ** $digits);
41 $max = ~0 if $max > ~0;
42 my @nums = map { $base+int(rand($max-$base)) } (1 .. $num);
43 return @nums;
44 }
+0
-37
examples/bench-pcapprox.pl less more
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 use Math::Prime::Util ":all";
4 use Benchmark qw/:all/;
5 use List::Util qw/min max/;
6 my $maxdigits = (~0 <= 4294967295) ? 10 : 20;
7
8 my $count = shift || -5;
9
10 srand(29);
11 test_at_digits($_) for (5 .. $maxdigits);
12
13
14 sub test_at_digits {
15 my $digits = shift;
16 die "Digits must be > 0" unless $digits > 0;
17
18 my $base = ($digits == 1) ? 0 : int(10 ** ($digits-1));
19 my $max = int(10 ** $digits);
20 $max = ~0 if $max > ~0;
21 my @nums = map { $base+int(rand($max-$base)) } (1 .. 1000);
22 my $min_num = min @nums;
23 my $max_num = max @nums;
24
25 #print "miller_rabin for 1000 random $digits-digit numbers ($min_num - $max_num)\n";
26
27 my $sum;
28 cmpthese($count,{
29 'lower' => sub { $sum += prime_count_lower($_) for @nums },
30 'luapprox' => sub { $sum += (prime_count_lower($_)+prime_count_upper($_))/2 for @nums },
31 'approx' => sub { $sum += prime_count_approx($_) for @nums },
32 'li' => sub { $sum += LogarithmicIntegral($_) for @nums },
33 'R' => sub { $sum += RiemannR($_) for @nums },
34 });
35 print "\n";
36 }
+0
-499
examples/bench-pp-count.pl less more
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3
4 use Benchmark qw/:all/;
5 #use Devel::Size qw/total_size/;
6 #use Math::Prime::Util;
7 #use Math::Prime::FastSieve;
8 #*mpu_erat = \&Math::Prime::Util::erat_primes;
9 #*fs_erat = \&Math::Prime::FastSieve::primes;
10
11 my $upper = shift || 8192;
12 my $count = shift || -1;
13 my $countarg;
14
15 #atkin2(100); exit(0);
16
17 # Shows sizes for sieving to 100k, and rate/second for sieving to 16k
18 my $pc_subs = {
19 "Rosetta 4" => sub { rosetta4($countarg) }, # 25k 60/s
20 "Atkin MPTA" => sub { atkin($countarg) }, # 3430k 90/s
21 "Merlyn" => sub { merlyn($countarg)}, # 13k 96/s
22 "Rosetta 2" => sub { rosetta2($countarg) }, # 13k 109/s
23 "Atkin 2" => sub { atkin2($countarg) }, # 1669k 110/s
24 "DO Vec" => sub {daoswald_vec($countarg)}, # 13k 112/s
25 "Rosetta 3" => sub { rosetta3($countarg) }, # 4496k 165/s
26 "Rosetta 1" => sub { rosetta1($countarg) }, # 3449k 187/s
27 "Shootout" => sub { shootout($countarg) }, # 3200k 231/s
28 "DJ Vec" => sub { dj1($countarg) }, # 7k 245/s
29 "Scriptol" => sub { scriptol($countarg) }, # 3200k 290/s
30 "DO Array" => sub {daoswald_array($countarg)},# 3200k 306/s
31 "DJ Array" => sub { dj2($countarg) }, # 1494k 475/s
32 "In Many" => sub { inmany($countarg) }, # 2018k 666/s
33 "DJ String1" => sub { dj3($countarg) }, # 50k 981/s
34 "DJ String2" => sub { dj4($countarg) }, # 50k 1682/s
35 # "MPU Sieve" => sub {
36 # scalar @{mpu_erat(2,$countarg)}; }, # 3k 14325/s
37 # "MPFS Sieve" => sub {
38 # scalar @{fs_erat($countarg)}; }, # 7k 14325/s
39 };
40
41 my %verify = (
42 10 => 4,
43 11 => 5,
44 100 => 25,
45 112 => 29,
46 113 => 30,
47 114 => 30,
48 1000 => 168,
49 10000 => 1229,
50 100000 => 9592,
51 );
52
53 # Verify
54 while (my($name, $sub) = each (%$pc_subs)) {
55 while (my($n, $pin) = each (%verify)) {
56 $countarg = $n;
57 my $picount = $sub->();
58 die "$name ($n) = $picount, should be $pin" unless $picount == $pin;
59 }
60 }
61 print "Done with verification, starting benchmark\n";
62
63 $countarg = $upper;
64 cmpthese($count, $pc_subs);
65
66
67
68 # www.scriptol.com/programming/sieve.php
69 sub scriptol {
70 my($max) = @_;
71 return 0 if $max < 2;
72 return 1 if $max < 3;
73
74 my @flags = (0 .. $max);
75 for my $i (2 .. int(sqrt($max)) + 1)
76 {
77 next unless defined $flags[$i];
78 for (my $k=$i+$i; $k <= $max; $k+=$i)
79 {
80 undef $flags[$k];
81 }
82 }
83 #print "scriptol size: ", total_size(\@flags), "\n" if $max > 90000;
84 my $count = 0;
85 for my $j (2 .. $max) {
86 $count++ if defined $flags[$j];
87 }
88 $count;
89 }
90
91 # http://dada.perl.it/shootout/sieve.perl.html
92 sub shootout {
93 my($max) = @_;
94 return 0 if $max < 2;
95 return 1 if $max < 3;
96
97 my $count = 0;
98 my @flags = (0 .. $max);
99 for my $i (2 .. $max) {
100 next unless defined $flags[$i];
101 for (my $k=$i+$i; $k <= $max; $k+=$i) {
102 undef $flags[$k];
103 }
104 $count++;
105 }
106 #print "shootout size: ", total_size(\@flags), "\n" if $max > 90000;
107 $count;
108 }
109
110 # http://c2.com/cgi/wiki?SieveOfEratosthenesInManyProgrammingLanguages
111 sub inmany {
112 my($max) = @_;
113 return 0 if $max < 2;
114 return 1 if $max < 3;
115 $max++;
116
117 my @c;
118 for(my $t=3; $t*$t<$max; $t+=2) {
119 if (!$c[$t]) {
120 for(my $s=$t*$t; $s<$max; $s+=$t*2) { $c[$s]++ }
121 }
122 }
123 #print "inmany size: ", total_size(\@c), "\n" if $max > 90000;
124 my $count = 1;
125 for(my $t=3; $t<$max; $t+=2) {
126 $c[$t] || $count++;
127 }
128 $count;
129 }
130
131 # http://rosettacode.org/wiki/Sieve_of_Eratosthenes#Perl
132 sub rosetta1 {
133 my($max) = @_;
134 return 0 if $max < 2;
135 return 1 if $max < 3;
136
137 my $count = 0; #my @primes;
138 my @tested = (1);
139 my $j = 1;
140 while ($j < $max) {
141 next if $tested[$j++];
142 $count++; #push @primes, $j;
143 for (my $k= $j; $k <= $max; $k+=$j) {
144 $tested[$k-1]= 1;
145 }
146 }
147 #print "R1 size: ", total_size(\@tested), "\n" if $max > 90000;
148 $count; #scalar @primes;
149 }
150
151 # http://rosettacode.org/wiki/Sieve_of_Eratosthenes#Perl
152 sub rosetta2 {
153 my($max) = @_;
154 return 0 if $max < 2;
155 return 1 if $max < 3;
156
157 my $count = 0; #my @primes;
158 my $nonPrimes = '';
159 foreach my $p (2 .. $max) {
160 unless (vec($nonPrimes, $p, 1)) {
161 for (my $i = $p * $p; $i <= $max; $i += $p) {
162 vec($nonPrimes, $i, 1) = 1;
163 }
164 $count++; #push @primes, $p;
165 }
166 }
167 #print "R2 size: ", total_size(\$nonPrimes), "\n" if $max > 90000;
168 $count; #scalar @primes;
169 }
170
171 # http://rosettacode.org/wiki/Sieve_of_Eratosthenes#Perl
172 sub rosetta3 {
173 my($max) = @_;
174 return 0 if $max < 2;
175 return 1 if $max < 3;
176
177 my $i;
178 my @s;
179 my $count = scalar
180 grep { not $s[ $i = $_ ] and do
181 { $s[ $i += $_ ]++ while $i <= $max; 1 }
182 } 2 .. $max;
183 #print "R3 size: ", total_size(\@s), "\n" if $max > 90000;
184 $count; #scalar @primes;
185 }
186
187 # http://rosettacode.org/wiki/Sieve_of_Eratosthenes#Perl
188 sub rosetta4 {
189 my($max) = @_;
190 return 0 if $max < 2;
191 return 1 if $max < 3;
192
193 my $i;
194 my $s = '';
195 my $count = scalar
196 grep { not vec $s, $i = $_, 1 and do
197 { (vec $s, $i += $_, 1) = 1 while $i <= $max; 1 }
198 } 2 .. $max;
199 #print "R4 size: ", total_size(\$s), "\n" if $max > 90000;
200 $count; #scalar @primes;
201 }
202
203 # From Math::Primes::TiedArray
204 sub atkin {
205 my($max) = @_;
206 return 0 if $max < 2;
207 return 1 if $max < 3;
208 return 2 if $max < 5;
209
210 my $sqrt = sqrt($max);
211 my %sieve;
212 foreach my $x ( 1 .. $sqrt ) {
213
214 foreach my $y ( 1 .. $sqrt ) {
215
216 my $n = 3 * $x**2 - $y**2;
217 if ( $x > $y
218 and $n <= $max
219 and $n % 12 == 11 )
220 {
221 $sieve{$n} = not $sieve{$n};
222 }
223
224 $n = 3 * $x**2 + $y**2;
225 if ( $n <= $max and $n % 12 == 7 ) {
226 $sieve{$n} = not $sieve{$n};
227 }
228
229 $n = 4 * $x**2 + $y**2;
230 if ( $n <= $max
231 and ( $n % 12 == 1 or $n % 12 == 5 ) )
232 {
233 $sieve{$n} = not $sieve{$n};
234 }
235 }
236 }
237 # eliminate composites by sieving
238 foreach my $n ( 5 .. $sqrt ) {
239
240 next unless $sieve{$n};
241
242 my $k = int(1/$n**2) * $n**2;
243 while ( $k <= $max ) {
244 $sieve{$k} = 0;
245 $k += $n**2;
246 }
247 }
248 $sieve{2} = 1;
249 $sieve{3} = 1;
250 #print "Atkin size: ", total_size(\%sieve), "\n" if $max > 90000;
251
252 # save the found primes in our cache
253 my $count = 0;
254 foreach my $n ( 2 .. $max ) {
255 next unless $sieve{$n};
256 $count++;
257 }
258 $count;
259 }
260
261 # Naive Sieve of Atkin, basically straight from Wikipedia.
262 #
263 # <rant>
264 #
265 # First thing to note about SoA, is that people love to quote things like
266 # "memory use is O(N^(1/2+o(1)))" then proceed to _clearly_ use N bytes in
267 # their implementation. If your data structures between SoA and SoE are the
268 # same, then all talk about comparative O(blah..blah) memory use is stupid.
269 #
270 # Secondly, assuming you're not Dan Bernstein, if your Sieve of Atkin is
271 # faster than your Sieve of Eratosthenes, then I strongly suggest you verify
272 # your code actually _works_, and secondly I would bet you made stupid mistakes
273 # in your SoE implementation. If your SoA code even remotely resembles the
274 # Wikipedia code and it comes out faster than SoE, then I *guarantee* your
275 # SoE is borked.
276 #
277 # SoA does have a slightly better asymptotic operation count O(N/loglogN) vs.
278 # O(N) for SoE. The Wikipedia-like code that most people use is O(N) so it
279 # isn't even theoretically better unless you pull lots of stunts like primegen
280 # does. Even if you do, loglogN is essentially a small constant for most uses
281 # (it's under 4 for all 64-bit values), so you need to make sure all the rest
282 # of your overhead is controlled.
283 #
284 # Sumarizing, in practice the SoE is faster, and often a LOT faster.
285 #
286 # </rant>
287 #
288 sub atkin2 {
289 my($max) = @_;
290 return 0 if $max < 2;
291 return 1 if $max < 3;
292
293 my @sieve;
294
295 my $sqrt = int(sqrt($max));
296 for my $x (1 .. $sqrt) {
297 for my $y (1 .. $sqrt) {
298 my $n;
299
300 $n = 4*$x*$x + $y*$y;
301 if ( ($n <= $max) && ( (($n%12) == 1) || (($n%12) == 5) ) ) {
302 $sieve[$n] ^= 1;
303 }
304 $n = 3*$x*$x + $y*$y;
305 if ( ($n <= $max) && (($n%12) == 7) ) {
306 $sieve[$n] ^= 1;
307 }
308 $n = 3*$x*$x - $y*$y;
309 if ( ($x > $y) && ($n <= $max) && (($n%12) == 11) ) {
310 $sieve[$n] ^= 1;
311 }
312 }
313 }
314
315 for my $n (5 .. $sqrt) {
316 if ($sieve[$n]) {
317 my $k = $n*$n;
318 my $z = $k;
319 while ($z <= $max) {
320 $sieve[$z] = 0;
321 $z += $k;
322 }
323 }
324 }
325 $sieve[2] = 1;
326 $sieve[3] = 1;
327 #print "Atkin size: ", total_size(\@sieve), "\n" if $max > 90000;
328
329 my $count = scalar grep { $sieve[$_] } 2 .. $#sieve;
330 $count;
331 }
332
333 # https://github.com/daoswald/Inline-C-Perl-Mongers-Talk/blob/master/primesbench.pl
334 sub daoswald_array {
335 my($top) = @_;
336 return 0 if $top < 2;
337 return 1 if $top < 3;
338 $top++;
339
340 my @primes = (1) x $top;
341 my $i_times_j;
342 for my $i ( 2 .. sqrt $top ) {
343 if ( $primes[$i] ) {
344 for ( my $j = $i; ( $i_times_j = $i * $j ) < $top; $j++ ) {
345 undef $primes[$i_times_j];
346 }
347 }
348 }
349 #print "do_array size: ", total_size(\@primes), "\n" if $top > 90000;
350 my $count = scalar grep { $primes[$_] } 2 .. $#primes;
351 $count;
352 }
353
354 sub daoswald_vec {
355 my($top) = @_;
356 return 0 if $top < 2;
357 return 1 if $top < 3;
358
359 my $primes = '';
360 vec( $primes, $top, 1 ) = 0;
361 my $i_times_j;
362 for my $i ( 2 .. sqrt $top ) {
363 if ( !vec( $primes, $i, 1 ) ) {
364 for ( my $j = $i; ( $i_times_j = $i * $j ) <= $top; $j++ ) {
365 vec( $primes, $i_times_j, 1 ) = 1;
366 }
367 }
368 }
369 #print "do_vec size: ", total_size(\$primes), "\n" if $top > 90000;
370 my $count = scalar grep { !vec( $primes, $_, 1 ) } 2 .. $top ;
371 $count;
372 }
373
374 # Merlyn's Unix Review Column 26, June 1999
375 # http://www.stonehenge.com/merlyn/UnixReview/col26.html
376 sub merlyn {
377 my($UPPER) = @_;
378 return 0 if $UPPER < 2;
379 return 1 if $UPPER < 3;
380
381 my $count = 0;
382 my $sieve = "";
383 GUESS: for (my $guess = 2; $guess <= $UPPER; $guess++) {
384 next GUESS if vec($sieve,$guess,1);
385 $count++;
386 for (my $mults = $guess * $guess; $mults <= $UPPER; $mults += $guess) {
387 vec($sieve,$mults,1) = 1;
388 }
389 }
390 #print "Merlyn size: ", total_size(\$sieve), "\n" if $UPPER > 90000;
391 $count;
392 }
393
394
395 sub dj1 {
396 my($end) = @_;
397 return 0 if $end < 2;
398 return 1 if $end < 3;
399
400 # vector
401 my $sieve = '';
402 my $n = 3;
403 while ( ($n*$n) <= $end ) {
404 my $s = $n*$n;
405 while ($s <= $end) {
406 vec($sieve, $s >> 1, 1) = 1;
407 $s += 2*$n;
408 }
409 do { $n += 2 } while vec($sieve, $n >> 1, 1) != 0;
410 }
411 #print "DJ1 size: ", total_size(\$sieve), "\n" if $end > 90000;
412 my $count = 1;
413 $n = 3;
414 while ($n <= $end) {
415 $count++ if !vec($sieve, $n >> 1, 1);
416 $n += 2;
417 }
418 $count;
419 }
420
421 sub dj2 {
422 my($end) = @_;
423 return 0 if $end < 2;
424 return 1 if $end < 3;
425
426 # array
427 my @sieve;
428 my $n = 3;
429 while ( ($n*$n) <= $end ) {
430 my $s = $n*$n;
431 while ($s <= $end) {
432 $sieve[$s>>1] = 1;
433 $s += 2*$n;
434 }
435 do { $n += 2 } while $sieve[$n>>1];
436 }
437 #print "DJ2 size: ", total_size(\@sieve), "\n" if $end > 90000;
438 my $count = 1;
439 $n = 3;
440 while ($n <= $end) {
441 $count++ if !$sieve[$n>>1];
442 $n += 2;
443 }
444 $count;
445 }
446
447 # ~2x faster than inmany, lots faster than the others. Only loses to dj4,
448 # which is just this code with a presieve added.
449 sub dj3 {
450 my($end) = @_;
451 return 0 if $end < 2;
452 return 1 if $end < 3;
453 $end-- if ($end & 1) == 0;
454
455 # string
456 my $sieve = '1' . '0' x ($end>>1);
457 my $n = 3;
458 while ( ($n*$n) <= $end ) {
459 my $s = $n*$n;
460 my $filter_s = $s >> 1;
461 my $filter_end = $end >> 1;
462 while ($filter_s <= $filter_end) {
463 substr($sieve, $filter_s, 1) = '1';
464 $filter_s += $n;
465 }
466 do { $n += 2 } while substr($sieve, $n>>1, 1);
467 }
468 #print "DJ3 size: ", total_size(\$sieve), "\n" if $end > 90000;
469 my $count = 1 + $sieve =~ tr/0//;
470 $count;
471 }
472
473 # 2-3x faster than inmany, 6-7x faster than any of the other non-DJ methods.
474 sub dj4 {
475 my($end) = @_;
476 return 0 if $end < 2;
477 return 1 if $end < 3;
478 $end-- if ($end & 1) == 0;
479
480 # string with prefill
481 my $whole = int( ($end>>1) / 15);
482 my $sieve = '100010010010110' . '011010010010110' x $whole;
483 substr($sieve, ($end>>1)+1) = '';
484 my $n = 7;
485 while ( ($n*$n) <= $end ) {
486 my $s = $n*$n;
487 my $filter_s = $s >> 1;
488 my $filter_end = $end >> 1;
489 while ($filter_s <= $filter_end) {
490 substr($sieve, $filter_s, 1) = '1';
491 $filter_s += $n;
492 }
493 do { $n += 2 } while substr($sieve, $n>>1, 1);
494 }
495 #print "DJ4 size: ", total_size(\$sieve), "\n" if $end > 90000;
496 my $count = 1 + $sieve =~ tr/0//;
497 $count;
498 }
+0
-215
examples/bench-pp-isprime.pl less more
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3
4 use Benchmark qw/:all/;
5 use Devel::Size qw/total_size/;
6 use Math::Prime::Util;
7 *mpu_isprime = \&Math::Prime::Util::is_prime;
8
9 my $count = shift || -1;
10
11 my @numlist;
12 my @testnums = (0..1000, 5_000_000 .. 5_001_000, 30037, 20359*41117, 92987*65171, 27361*31249, 70790191, 3211717*9673231);
13
14 my $ip_subs = {
15 #"Abigail" => sub { my$r;$r=abigail($_) for @numlist; $r;},
16 "Rosetta" => sub { my$r;$r=rosetta($_) for @numlist; $r;},
17 "Rosetta2"=> sub { my$r;$r=rosetta2($_) for @numlist; $r;},
18 "DJ" => sub { my$r;$r=dj($_) for @numlist; $r;},
19 "DJ2" => sub { my$r;$r=dj2($_) for @numlist; $r;},
20 "DJ3" => sub { my$r;$r=dj3($_) for @numlist; $r;},
21 "DJ4" => sub { my$r;$r=dj4($_) for @numlist; $r;},
22 "MPU" => sub { my$r;$r=mpu_isprime($_) for @numlist; $r;},
23 };
24
25 my %verify = (
26 0 => 0,
27 1 => 0,
28 2 => 1,
29 3 => 1,
30 4 => 0,
31 5 => 1,
32 6 => 0,
33 7 => 1,
34 13 => 1,
35 20 => 0,
36 377 => 0,
37 70790191 => 1,
38 );
39
40 # Verify
41 while (my($name, $sub) = each (%$ip_subs)) {
42 while (my($n, $v_ip) = each (%verify)) {
43 @numlist = ($n);
44 #print "$name($n): ", $sub->(), "\n";
45 my $isprime = ($sub->() ? 1 : 0);
46 die "$name($n) = $isprime, should be $v_ip\n" unless $isprime == $v_ip;
47 }
48 }
49 for my $n (0 .. 50000) {
50 die "dj($n) != mpu($n)" unless dj($n) == mpu_isprime($n);
51 die "dj2($n) != mpu($n)" unless dj2($n) == mpu_isprime($n);
52 die "dj3($n) != mpu($n)" unless dj3($n) == mpu_isprime($n);
53 die "dj4($n) != mpu($n)" unless dj4($n) == mpu_isprime($n);
54 die "rosetta($n) != mpu($n)" unless rosetta($n) == mpu_isprime($n)/2;
55 die "rosetta2($n) != mpu($n)" unless rosetta2($n) == mpu_isprime($n)/2;
56 }
57 print "Done with verification, starting benchmark\n";
58
59 @numlist = @testnums;
60 cmpthese($count, $ip_subs);
61
62
63 sub rosetta {
64 my $n = shift;
65 $n % $_ or return 0 for 2 .. sqrt $n;
66 $n > 1;
67 }
68
69 sub rosetta2 {
70 my $p = shift;
71 if ($p == 2) {
72 return 1;
73 } elsif ($p <= 1 || $p % 2 == 0) {
74 return 0;
75 } else {
76 my $limit = sqrt($p);
77 for (my $i = 3; $i <= $limit; $i += 2) {
78 return 0 if $p % $i == 0;
79 }
80 return 1;
81 }
82 }
83
84 # Terrifically clever, but useless for large numbers
85 sub abigail {
86 ('1' x shift) !~ /^1?$|^(11+?)\1+$/
87 }
88
89 sub dj {
90 my($n) = @_;
91 return 0 if $n < 2; # 0 and 1 are composite
92 return 2 if ($n == 2) || ($n == 3) || ($n == 5); # 2, 3, 5 are prime
93 # multiples of 2,3,5 are composite
94 return 0 if (($n % 2) == 0) || (($n % 3) == 0) || (($n % 5) == 0);
95
96 my $q;
97 foreach my $i (qw/7 11 13 17 19 23 29 31 37 41 43 47 53 59/) {
98 $q = int($n/$i); return 2 if $q < $i; return 0 if $n == ($q*$i);
99 }
100
101 my $i = 61; # mod-30 loop
102 while (1) {
103 $q = int($n/$i); last if $q < $i; return 0 if $n == ($q*$i); $i += 6;
104 $q = int($n/$i); last if $q < $i; return 0 if $n == ($q*$i); $i += 4;
105 $q = int($n/$i); last if $q < $i; return 0 if $n == ($q*$i); $i += 2;
106 $q = int($n/$i); last if $q < $i; return 0 if $n == ($q*$i); $i += 4;
107 $q = int($n/$i); last if $q < $i; return 0 if $n == ($q*$i); $i += 2;
108 $q = int($n/$i); last if $q < $i; return 0 if $n == ($q*$i); $i += 4;
109 $q = int($n/$i); last if $q < $i; return 0 if $n == ($q*$i); $i += 6;
110 $q = int($n/$i); last if $q < $i; return 0 if $n == ($q*$i); $i += 2;
111 }
112 2;
113 }
114
115 sub dj2 {
116 my($n) = @_;
117 return 2 if ($n == 2) || ($n == 3) || ($n == 5); # 2, 3, 5 are prime
118 return 0 if $n < 7; # everything else below 7 is composite
119 # multiples of 2,3,5 are composite
120 return 0 if (($n % 2) == 0) || (($n % 3) == 0) || (($n % 5) == 0);
121
122 foreach my $i (qw/7 11 13 17 19 23 29 31 37 41 43 47 53 59/) {
123 return 2 if $i*$i > $n;
124 return 0 if ($n % $i) == 0;
125 }
126 my $limit = int(sqrt($n));
127
128 my $i = 61; # mod-30 loop
129 while (1) {
130 return 0 if ($n % $i) == 0; $i += 6; last if $i > $limit;
131 return 0 if ($n % $i) == 0; $i += 4; last if $i > $limit;
132 return 0 if ($n % $i) == 0; $i += 2; last if $i > $limit;
133 return 0 if ($n % $i) == 0; $i += 4; last if $i > $limit;
134 return 0 if ($n % $i) == 0; $i += 2; last if $i > $limit;
135 return 0 if ($n % $i) == 0; $i += 4; last if $i > $limit;
136 return 0 if ($n % $i) == 0; $i += 6; last if $i > $limit;
137 return 0 if ($n % $i) == 0; $i += 2; last if $i > $limit;
138 }
139 2;
140 }
141
142 sub dj3 {
143 my($n) = @_;
144 return 2 if ($n == 2) || ($n == 3) || ($n == 5); # 2, 3, 5 are prime
145 return 0 if $n < 7; # everything else below 7 is composite
146 # multiples of 2,3,5 are composite
147 return 0 if (($n % 2) == 0) || (($n % 3) == 0) || (($n % 5) == 0);
148
149 foreach my $i (qw/7 11 13 17 19 23 29 31 37 41 43 47 53 59/) {
150 return 2 if $i*$i > $n;
151 return 0 if ($n % $i) == 0;
152 }
153 my $limit = int(sqrt($n));
154
155 my $i = 61; # mod-30 loop
156 while (($i+30) <= $limit) {
157 return 0 if ($n % $i) == 0; $i += 6;
158 return 0 if ($n % $i) == 0; $i += 4;
159 return 0 if ($n % $i) == 0; $i += 2;
160 return 0 if ($n % $i) == 0; $i += 4;
161 return 0 if ($n % $i) == 0; $i += 2;
162 return 0 if ($n % $i) == 0; $i += 4;
163 return 0 if ($n % $i) == 0; $i += 6;
164 return 0 if ($n % $i) == 0; $i += 2;
165 }
166 while (1) {
167 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 6;
168 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 4;
169 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 2;
170 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 4;
171 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 2;
172 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 4;
173 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 6;
174 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 2;
175 }
176 2;
177 }
178
179 sub dj4 {
180 my($n) = @_;
181 return 2 if ($n == 2) || ($n == 3) || ($n == 5); # 2, 3, 5 are prime
182 return 0 if $n < 7; # everything else below 7 is composite
183 # multiples of 2,3,5 are composite
184 return 0 if (($n % 2) == 0) || (($n % 3) == 0) || (($n % 5) == 0);
185
186 foreach my $i (qw/7 11 13 17 19 23 29/) {
187 return 2 if $i*$i > $n;
188 return 0 if ($n % $i) == 0;
189 }
190 my $limit = int(sqrt($n));
191
192 my $i = 31;
193 while (($i+30) <= $limit) {
194 return 0 if ($n % $i) == 0; $i += 6;
195 return 0 if ($n % $i) == 0; $i += 4;
196 return 0 if ($n % $i) == 0; $i += 2;
197 return 0 if ($n % $i) == 0; $i += 4;
198 return 0 if ($n % $i) == 0; $i += 2;
199 return 0 if ($n % $i) == 0; $i += 4;
200 return 0 if ($n % $i) == 0; $i += 6;
201 return 0 if ($n % $i) == 0; $i += 2;
202 }
203 while (1) {
204 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 6;
205 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 4;
206 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 2;
207 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 4;
208 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 2;
209 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 4;
210 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 6;
211 last if $i > $limit; return 0 if ($n % $i) == 0; $i += 2;
212 }
213 2;
214 }
+0
-482
examples/bench-pp-sieve.pl less more
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3
4 use Benchmark qw/:all/;
5 #use Devel::Size qw/total_size/;
6 use Math::Prime::Util;
7 use Math::Prime::FastSieve;
8 *mpu_erat = \&Math::Prime::Util::erat_primes;
9 *fs_erat = \&Math::Prime::FastSieve::primes;
10
11 my $upper = shift || 8192;
12 my $count = shift || -1;
13 my $countarg;
14 my $sum;
15
16 # This is like counting, but we want an array returned.
17 # The subs will compute a sum on the results.
18
19 # In practice you would probably want to return a ref to your array, or return
20 # a ref to your sieve structure and let the caller decode it as needed.
21
22 # Times for 100k.
23 # Vs. MPU sieve, as we move from 8k to 10M:
24 # Atkin MPTA, Rosetta 3 & 1, Shootout, Scriptol, DO Array, DJ Array, and
25 # InMany all slow down. Atkin 2 speeds up (from 65x slower to 54x slower).
26 # The DJ string methods have almost no relative slowdown, so stretch out their
27 # advantage over the other fast ones (In Many, DJ Array, DJ Vec, and DO Array).
28 my $pc_subs = {
29 "Rosetta 4" => sub {$sum=0; $sum+=$_ for rosetta4($countarg);$sum;}, # 9/s
30 "Atkin MPTA"=> sub {$sum=0; $sum+=$_ for atkin($countarg);$sum;}, # 11/s
31 "Merlyn" => sub {$sum=0; $sum+=$_ for merlyn($countarg);$sum;}, # 15/s
32 "Rosetta 2" => sub {$sum=0; $sum+=$_ for rosetta2($countarg);$sum; }, # 16/s
33 "DO Vec" => sub {$sum=0; $sum+=$_ for daos_vec($countarg);$sum;}, # 16/s
34 "Atkin 2" => sub {$sum=0; $sum+=$_ for atkin2($countarg);$sum; }, # 17/s
35 "Rosetta 3" => sub {$sum=0; $sum+=$_ for rosetta3($countarg);$sum; }, # 23/s
36 "Rosetta 1" => sub {$sum=0; $sum+=$_ for rosetta1($countarg);$sum; }, # 26/s
37 "Shootout" => sub {$sum=0; $sum+=$_ for shootout($countarg);$sum; }, # 30/s
38 "Scriptol" => sub {$sum=0; $sum+=$_ for scriptol($countarg);$sum; }, # 33/s
39 "DJ Vec" => sub {$sum=0; $sum+=$_ for dj1($countarg);$sum; }, # 34/s
40 "DO Array" => sub {$sum=0; $sum+=$_ for daos_array($countarg);$sum;},# 41/s
41 "DJ Array" => sub {$sum=0; $sum+=$_ for dj2($countarg);$sum; }, # 63/s
42 "In Many" => sub {$sum=0; $sum+=$_ for inmany($countarg);$sum; }, # 86/s
43 "DJ String1"=> sub {$sum=0; $sum+=$_ for dj3($countarg);$sum; }, # 99/s
44 "DJ String2"=> sub {$sum=0; $sum+=$_ for dj4($countarg);$sum; }, # 134/s
45 "MPFS Sieve"=> sub { # 1216/s
46 $sum=0; $sum+=$_ for @{fs_erat($countarg)};;$sum; },
47 "MPU Sieve" => sub { # 1290/s
48 $sum=0; $sum+=$_ for @{mpu_erat(2,$countarg)};;$sum; },
49 };
50
51 my %verify = (
52 10 => 17,
53 11 => 28,
54 100 => 1060,
55 112 => 1480,
56 113 => 1593,
57 114 => 1593,
58 1000 => 76127,
59 10000 => 5736396,
60 100000 => 454396537,
61 );
62
63 # Verify
64 while (my($name, $sub) = each (%$pc_subs)) {
65 while (my($n, $v_pi_sum) = each (%verify)) {
66 $countarg = $n;
67 my $pi_sum = $sub->();
68 die "$name ($n) = $pi_sum, should be $v_pi_sum" unless $pi_sum == $v_pi_sum;
69 }
70 }
71 print "Done with verification, starting benchmark\n";
72
73 $countarg = $upper;
74 cmpthese($count, $pc_subs);
75
76
77
78 # www.scriptol.com/programming/sieve.php
79 sub scriptol {
80 my($max) = @_;
81 return 0 if $max < 2;
82 return 1 if $max < 3;
83
84 my @flags = (0 .. $max);
85 for my $i (2 .. int(sqrt($max)) + 1)
86 {
87 next unless defined $flags[$i];
88 for (my $k=$i+$i; $k <= $max; $k+=$i)
89 {
90 undef $flags[$k];
91 }
92 }
93 return grep { defined $flags[$_] } 2 .. $max;
94 }
95
96 # http://dada.perl.it/shootout/sieve.perl.html
97 sub shootout {
98 my($max) = @_;
99 return 0 if $max < 2;
100 return 1 if $max < 3;
101
102 my @primes;
103 my @flags = (0 .. $max);
104 for my $i (2 .. $max) {
105 next unless defined $flags[$i];
106 for (my $k=$i+$i; $k <= $max; $k+=$i) {
107 undef $flags[$k];
108 }
109 push @primes, $i;
110 }
111 @primes;
112 }
113
114 # http://c2.com/cgi/wiki?SieveOfEratosthenesInManyProgrammingLanguages
115 sub inmany {
116 my($max) = @_;
117 return 0 if $max < 2;
118 return 1 if $max < 3;
119
120 my @c;
121 for(my $t=3; $t*$t<=$max; $t+=2) {
122 if (!$c[$t]) {
123 for(my $s=$t*$t; $s<=$max; $s+=$t*2) { $c[$s]++ }
124 }
125 }
126 my @primes = (2);
127 for(my $t=3; $t<=$max; $t+=2) {
128 $c[$t] || push @primes, $t;
129 }
130 @primes;
131 # grep { $c[$_] } 3 .. $max;
132 }
133
134 # http://rosettacode.org/wiki/Sieve_of_Eratosthenes#Perl
135 sub rosetta1 {
136 my($max) = @_;
137 return 0 if $max < 2;
138 return 1 if $max < 3;
139
140 my @primes;
141 my @tested = (1);
142 my $j = 1;
143 while ($j < $max) {
144 next if $tested[$j++];
145 push @primes, $j;
146 for (my $k= $j; $k <= $max; $k+=$j) {
147 $tested[$k-1]= 1;
148 }
149 }
150 @primes;
151 }
152
153 # http://rosettacode.org/wiki/Sieve_of_Eratosthenes#Perl
154 sub rosetta2 {
155 my($max) = @_;
156 return 0 if $max < 2;
157 return 1 if $max < 3;
158
159 my @primes;
160 my $nonPrimes = '';
161 foreach my $p (2 .. $max) {
162 unless (vec($nonPrimes, $p, 1)) {
163 for (my $i = $p * $p; $i <= $max; $i += $p) {
164 vec($nonPrimes, $i, 1) = 1;
165 }
166 push @primes, $p;
167 }
168 }
169 @primes;
170 }
171
172 # http://rosettacode.org/wiki/Sieve_of_Eratosthenes#Perl
173 sub rosetta3 {
174 my($max) = @_;
175 return 0 if $max < 2;
176 return 1 if $max < 3;
177
178 my(@s, $i);
179 grep { not $s[ $i = $_ ] and do
180 { $s[ $i += $_ ]++ while $i <= $max; 1 }
181 } 2 .. $max;
182 }
183
184 # http://rosettacode.org/wiki/Sieve_of_Eratosthenes#Perl
185 sub rosetta4 {
186 my($max) = @_;
187 return 0 if $max < 2;
188 return 1 if $max < 3;
189
190 my $i;
191 my $s = '';
192 grep { not vec $s, $i = $_, 1 and do
193 { (vec $s, $i += $_, 1) = 1 while $i <= $max; 1 }
194 } 2 .. $max;
195 }
196
197 # From Math::Primes::TiedArray
198 sub atkin {
199 my($max) = @_;
200 return 0 if $max < 2;
201 return 1 if $max < 3;
202 return 2 if $max < 5;
203
204 my $sqrt = sqrt($max);
205 my %sieve;
206 foreach my $x ( 1 .. $sqrt ) {
207
208 foreach my $y ( 1 .. $sqrt ) {
209
210 my $n = 3 * $x**2 - $y**2;
211 if ( $x > $y
212 and $n <= $max
213 and $n % 12 == 11 )
214 {
215 $sieve{$n} = not $sieve{$n};
216 }
217
218 $n = 3 * $x**2 + $y**2;
219 if ( $n <= $max and $n % 12 == 7 ) {
220 $sieve{$n} = not $sieve{$n};
221 }
222
223 $n = 4 * $x**2 + $y**2;
224 if ( $n <= $max
225 and ( $n % 12 == 1 or $n % 12 == 5 ) )
226 {
227 $sieve{$n} = not $sieve{$n};
228 }
229 }
230 }
231 # eliminate composites by sieving
232 foreach my $n ( 5 .. $sqrt ) {
233
234 next unless $sieve{$n};
235
236 my $k = int(1/$n**2) * $n**2;
237 while ( $k <= $max ) {
238 $sieve{$k} = 0;
239 $k += $n**2;
240 }
241 }
242 my @primes = (2, 3);
243 push @primes, grep { $sieve{$_} } 5 .. $max;
244 @primes;
245 }
246
247 # Naive Sieve of Atkin, basically straight from Wikipedia.
248 #
249 # <rant>
250 #
251 # First thing to note about SoA, is that people love to quote things like
252 # "memory use is O(N^(1/2+o(1)))" then proceed to _clearly_ use N bytes in
253 # their implementation. If your data structures between SoA and SoE are the
254 # same, then all talk about comparative O(blah..blah) memory use is stupid.
255 #
256 # Secondly, assuming you're not Dan Bernstein, if your Sieve of Atkin is
257 # faster than your Sieve of Eratosthenes, then I strongly suggest you verify
258 # your code actually _works_, and secondly I would bet you made stupid mistakes
259 # in your SoE implementation. If your SoA code even remotely resembles the
260 # Wikipedia code and it comes out faster than SoE, then I _guarantee_ your
261 # SoE is borked.
262 #
263 # SoA does have a slightly better asymptotic operation count O(N/loglogN) vs.
264 # O(N) for SoE. The Wikipedia-like code that most people use is O(N) so it
265 # isn't even theoretically better unless you pull lots of stunts like primegen
266 # does. Even if you do, loglogN is essentially a small constant for most uses
267 # (it's under 4 for all 64-bit values), so you need to make sure all the rest
268 # of your overhead is controlled.
269 #
270 # Sumarizing, in practice the SoE is faster, and often a LOT faster.
271 #
272 # </rant>
273 #
274 sub atkin2 {
275 my($max) = @_;
276 return 0 if $max < 2;
277 return 1 if $max < 3;
278
279 my @sieve;
280
281 my $sqrt = int(sqrt($max));
282 for my $x (1 .. $sqrt) {
283 for my $y (1 .. $sqrt) {
284 my $n;
285
286 $n = 4*$x*$x + $y*$y;
287 if ( ($n <= $max) && ( (($n%12) == 1) || (($n%12) == 5) ) ) {
288 $sieve[$n] ^= 1;
289 }
290 $n = 3*$x*$x + $y*$y;
291 if ( ($n <= $max) && (($n%12) == 7) ) {
292 $sieve[$n] ^= 1;
293 }
294 $n = 3*$x*$x - $y*$y;
295 if ( ($x > $y) && ($n <= $max) && (($n%12) == 11) ) {
296 $sieve[$n] ^= 1;
297 }
298 }
299 }
300
301 for my $n (5 .. $sqrt) {
302 if ($sieve[$n]) {
303 my $k = $n*$n;
304 my $z = $k;
305 while ($z <= $max) {
306 $sieve[$z] = 0;
307 $z += $k;
308 }
309 }
310 }
311
312 $sieve[2] = 1;
313 $sieve[3] = 1;
314 grep { $sieve[$_] } 2 .. $max;
315 }
316
317 # https://github.com/daoswald/Inline-C-Perl-Mongers-Talk/blob/master/primesbench.pl
318 sub daos_array {
319 my($top) = @_;
320 return 0 if $top < 2;
321 return 1 if $top < 3;
322 $top++;
323
324 my @primes = (1) x $top;
325 my $i_times_j;
326 for my $i ( 2 .. sqrt $top ) {
327 if ( $primes[$i] ) {
328 for ( my $j = $i; ( $i_times_j = $i * $j ) < $top; $j++ ) {
329 undef $primes[$i_times_j];
330 }
331 }
332 }
333 return grep { $primes[$_] } 2 .. $#primes;
334 }
335
336 sub daos_vec {
337 my($top) = @_;
338 return 0 if $top < 2;
339 return 1 if $top < 3;
340
341 my $primes = '';
342 vec( $primes, $top, 1 ) = 0;
343 my $i_times_j;
344 for my $i ( 2 .. sqrt $top ) {
345 if ( !vec( $primes, $i, 1 ) ) {
346 for ( my $j = $i; ( $i_times_j = $i * $j ) <= $top; $j++ ) {
347 vec( $primes, $i_times_j, 1 ) = 1;
348 }
349 }
350 }
351 return grep { !vec( $primes, $_, 1 ) } 2 .. $top;
352 }
353
354 # Merlyn's Unix Review Column 26, June 1999
355 # http://www.stonehenge.com/merlyn/UnixReview/col26.html
356 sub merlyn {
357 my($UPPER) = @_;
358 return 0 if $UPPER < 2;
359 return 1 if $UPPER < 3;
360
361 my @primes;
362 my $sieve = "";
363 GUESS: for (my $guess = 2; $guess <= $UPPER; $guess++) {
364 next GUESS if vec($sieve,$guess,1);
365 push @primes, $guess;
366 for (my $mults = $guess * $guess; $mults <= $UPPER; $mults += $guess) {
367 vec($sieve,$mults,1) = 1;
368 }
369 }
370 @primes;
371 }
372
373
374 sub dj1 {
375 my($end) = @_;
376 return 0 if $end < 2;
377 return 1 if $end < 3;
378
379 # vector
380 my $sieve = '';
381 my $n = 3;
382 while ( ($n*$n) <= $end ) {
383 my $s = $n*$n;
384 while ($s <= $end) {
385 vec($sieve, $s >> 1, 1) = 1;
386 $s += 2*$n;
387 }
388 do { $n += 2 } while vec($sieve, $n >> 1, 1) != 0;
389 }
390
391 my @primes = (2);
392 $n = 3;
393 while ($n <= $end) {
394 push @primes, $n if !vec($sieve, $n >> 1, 1);
395 $n += 2;
396 }
397 @primes;
398 }
399
400 sub dj2 {
401 my($end) = @_;
402 return 0 if $end < 2;
403 return 1 if $end < 3;
404
405 # array
406 my @sieve;
407 my $n = 3;
408 while ( ($n*$n) <= $end ) {
409 my $s = $n*$n;
410 while ($s <= $end) {
411 $sieve[$s>>1] = 1;
412 $s += 2*$n;
413 }
414 do { $n += 2 } while $sieve[$n>>1];
415 }
416 my @primes = (2);
417 $n = 3;
418 while ($n <= $end) {
419 push @primes, $n if !$sieve[$n>>1];
420 $n += 2;
421 }
422 @primes;
423 }
424
425 sub dj3 {
426 my($end) = @_;
427 return 0 if $end < 2;
428 return 1 if $end < 3;
429 $end-- if ($end & 1) == 0;
430
431 # string
432 my $sieve = '1' . '0' x ($end>>1);
433 my $n = 3;
434 while ( ($n*$n) <= $end ) {
435 my $s = $n*$n;
436 my $filter_s = $s >> 1;
437 my $filter_end = $end >> 1;
438 while ($filter_s <= $filter_end) {
439 substr($sieve, $filter_s, 1) = '1';
440 $filter_s += $n;
441 }
442 do { $n += 2 } while substr($sieve, $n>>1, 1);
443 }
444 my @primes = (2);
445 $n = 3-2;
446 foreach my $s (split("0", substr($sieve, 1), -1)) {
447 $n += 2 + 2 * length($s);
448 push @primes, $n if $n <= $end;
449 }
450 @primes;
451 }
452
453 sub dj4 {
454 my($end) = @_;
455 return 0 if $end < 2;
456 return 1 if $end < 3;
457 $end-- if ($end & 1) == 0;
458
459 # string with prefill
460 my $whole = int( ($end>>1) / 15);
461 my $sieve = '100010010010110' . '011010010010110' x $whole;
462 substr($sieve, ($end>>1)+1) = '';
463 my $n = 7;
464 while ( ($n*$n) <= $end ) {
465 my $s = $n*$n;
466 my $filter_s = $s >> 1;
467 my $filter_end = $end >> 1;
468 while ($filter_s <= $filter_end) {
469 substr($sieve, $filter_s, 1) = '1';
470 $filter_s += $n;
471 }
472 do { $n += 2 } while substr($sieve, $n>>1, 1);
473 }
474 my @primes = (2, 3, 5);
475 $n = 7-2;
476 foreach my $s (split("0", substr($sieve, 3), -1)) {
477 $n += 2 + 2 * length($s);
478 push @primes, $n if $n <= $end;
479 }
480 @primes;
481 }
+0
-173
examples/bench-primearray.pl less more
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 use Math::Prime::Util qw/:all/;
4 use Math::Prime::Util::PrimeArray;
5 use Math::NumSeq::Primes;
6 use Math::Prime::TiedArray;
7 use Benchmark qw/:all/;
8 use List::Util qw/min max/;
9 my $count = shift || -2;
10
11 my ($s, $nlimit, $ilimit, $expect);
12
13 if (1) {
14 print '-' x 79, "\n";
15 print "summation to 100k, looking for best methods (typically slice)\n";
16 $nlimit = 100000;
17 $ilimit = prime_count($nlimit)-1;
18 $expect = 0; forprimes { $expect += $_ } $nlimit;
19
20 cmpthese($count,{
21 'pa index' => sub { $s=0; tie my @primes, "Math::Prime::Util::PrimeArray";
22 $s += $primes[$_] for 0..$ilimit;
23 die unless $s == $expect; },
24 'pa loop' => sub { $s=0; tie my @primes, "Math::Prime::Util::PrimeArray";
25 for (@primes) { last if $_ > $nlimit; $s += $_; }
26 die $s unless $s == $expect; },
27 'pa slice' => sub { $s=0; tie my @primes, "Math::Prime::Util::PrimeArray";
28 $s += $_ for @primes[0..$ilimit];
29 die unless $s == $expect; },
30 'pa each' => sub { $s=0; tie my @primes, "Math::Prime::Util::PrimeArray";
31 while(my(undef,$v) = each @primes) { last if $v > $nlimit; $s += $v; }
32 die $s unless $s == $expect; },
33 'pa shift' => sub { $s=0; tie my @primes, "Math::Prime::Util::PrimeArray";
34 while ((my $p = shift @primes) <= $nlimit) { $s += $p; }
35 die unless $s == $expect; },
36 });
37 }
38
39 if (1) {
40 print '-' x 79, "\n";
41 print "summation to 100k, looking for best MPTA extension (typically ~1000)\n";
42 $nlimit = 100000;
43 $ilimit = prime_count($nlimit)-1;
44 $expect = 0; forprimes { $expect += $_ } $nlimit;
45
46 cmpthese($count,{
47 'MPTA' => sub { $s=0; tie my @primes, "Math::Prime::TiedArray";
48 $s += $primes[$_] for 0..$ilimit;
49 die unless $s == $expect; },
50 'MPTA 400' => sub { $s=0; tie my @primes, "Math::Prime::TiedArray", extend_step => 400;
51 $s += $primes[$_] for 0..$ilimit;
52 die unless $s == $expect; },
53 'MPTA 1000' => sub { $s=0; tie my @primes, "Math::Prime::TiedArray", extend_step => 1000;
54 $s += $primes[$_] for 0..$ilimit;
55 die unless $s == $expect; },
56 'MPTA 4000' => sub { $s=0; tie my @primes, "Math::Prime::TiedArray", extend_step => 4000;
57 $s += $primes[$_] for 0..$ilimit;
58 die unless $s == $expect; },
59 });
60 }
61
62 if (1) {
63 print '-' x 79, "\n";
64 print "summation to 100k\n";
65 print "Note: MPU::PrimeArray is about 30x faster than MPTA here.\n";
66 print " Math::NumSeq::Primes is reasonable fast (not random access)\n";
67 print " MPU's forprimes smashes everything else (not random access)\n";
68 $nlimit = 100000;
69 $ilimit = prime_count($nlimit)-1;
70 $expect = 0; forprimes { $expect += $_ } $nlimit;
71
72 cmpthese($count,{
73 'primes' => sub { $s=0; $s += $_ for @{primes($nlimit)}; die unless $s == $expect; },
74 'forprimes' => sub { $s=0; forprimes { $s += $_ } $nlimit; die unless $s == $expect; },
75 'iterator' => sub { $s=0; my $it = prime_iterator();
76 $s += $it->() for 0..$ilimit;
77 die unless $s == $expect; },
78 'OO iter' => sub { $s=0; my $it = prime_iterator_object();
79 $s += $it->iterate() for 0..$ilimit;
80 die unless $s == $expect; },
81 'pa slice' => sub { $s=0; tie my @primes, "Math::Prime::Util::PrimeArray";
82 $s += $_ for @primes[0..$ilimit];
83 die unless $s == $expect; },
84 'NumSeq' => sub { $s=0; my $seq = Math::NumSeq::Primes->new;
85 while (1) { my($undev,$v) = $seq->next; last if $v > $nlimit; $s += $v; }
86 die $s unless $s == $expect; },
87 # This was slightly faster than slice or shift
88 'MPTA' => sub { $s=0; tie my @primes, "Math::Prime::TiedArray", extend_step => 1000;
89 $s += $primes[$_] for 0..$ilimit;
90 die unless $s == $expect; },
91 });
92 }
93
94 if (0) {
95 print '-' x 79, "\n";
96 print "summation to 10M\n";
97 print "Note: Math::Prime::TiedArray takes too long\n";
98 print " Math::NumSeq::Primes is now ~2x slower than PrimeArray\n";
99 print " forprimes is still the fastest solution for sequential access\n";
100 $nlimit = 10_000_000;
101 $ilimit = prime_count($nlimit)-1;
102 $expect = 0; forprimes { $expect += $_ } $nlimit;
103
104 cmpthese($count,{
105 'primes' => sub { $s=0; $s += $_ for @{primes($nlimit)}; die unless $s == $expect; },
106 'forprimes' => sub { $s=0; forprimes { $s += $_ } $nlimit; die unless $s == $expect; },
107 'pa index' => sub { $s=0; tie my @primes, "Math::Prime::Util::PrimeArray";
108 $s += $primes[$_] for 0..$ilimit;
109 die unless $s == $expect; },
110 'pa loop' => sub { $s=0; tie my @primes, "Math::Prime::Util::PrimeArray";
111 for (@primes) { last if $_ > $nlimit; $s += $_; }
112 die $s unless $s == $expect; },
113 'pa slice' => sub { $s=0; tie my @primes, "Math::Prime::Util::PrimeArray";
114 $s += $_ for @primes[0..$ilimit];
115 die unless $s == $expect; },
116 'pa each' => sub { $s=0; tie my @primes, "Math::Prime::Util::PrimeArray";
117 while(my(undef,$v) = each @primes) { last if $v > $nlimit; $s += $v; }
118 die $s unless $s == $expect; },
119 'pa shift' => sub { $s=0; tie my @primes, "Math::Prime::Util::PrimeArray";
120 while ((my $p = shift @primes) <= $nlimit) { $s += $p; }
121 die unless $s == $expect; },
122 'numseq' => sub { $s=0; my $seq = Math::NumSeq::Primes->new;
123 while (1) { my($undev,$v) = $seq->next; last if $v > $nlimit; $s += $v; }
124 die $s unless $s == $expect; },
125 });
126 }
127
128 if (1) {
129 print '-' x 79, "\n";
130 print "Walk primes backwards from 1M\n";
131 print "Note: MPTA takes 4x longer than just calling MPU's nth_prime!\n";
132 $nlimit = 1_000_000;
133 $ilimit = prime_count($nlimit)-1;
134 $expect = 0; forprimes { $expect += $_ } $nlimit;
135
136 cmpthese($count,{
137 'rev primes'=> sub { $s=0; $s += $_ for reverse @{primes($nlimit)}; die unless $s == $expect; },
138 'nthprime' => sub { $s=0; $s += nth_prime($_) for reverse 1..$ilimit+1; die unless $s == $expect; },
139 'pa index' => sub { $s=0; tie my @primes, "Math::Prime::Util::PrimeArray";
140 $s += $primes[$_] for reverse 0..$ilimit;
141 die unless $s == $expect; },
142 'OO iter' => sub { $s=0; my $it = prime_iterator_object($nlimit);
143 $s += $it->prev->value() for 0..$ilimit;
144 die unless $s == $expect; },
145 'tiedarray' => sub { $s=0; tie my @primes, "Math::Prime::TiedArray", extend_step => 1000;
146 $s += $primes[$_] for reverse 0..$ilimit;
147 die unless $s == $expect; },
148 });
149 }
150
151 if (1) {
152 print '-' x 79, "\n";
153 print "Random walk in 1M\n";
154 print "MPTA takes about 2 minutes and lots of RAM per iteration.\n";
155 srand(29);
156 my @rindex;
157 do { push @rindex, int(rand(1000000)) } for 1..10000;
158 $expect = 0; $expect += nth_prime($_+1) for @rindex;
159
160 cmpthese($count,{
161 'nthprime' => sub { $s=0; $s += nth_prime($_+1) for @rindex; },
162 'pa index' => sub { $s=0; tie my @primes, "Math::Prime::Util::PrimeArray";
163 $s += $primes[$_] for @rindex;
164 die unless $s == $expect; },
165 # Argh! Is it possible to write a slower sieve than the one MPTA uses?
166 #'tiedarray' => sub { $s=0; tie my @primes, "Math::Prime::TiedArray", extend_step => 10000;
167 # $s += $primes[$_] for @rindex;
168 # die unless $s == $expect; },
169 });
170 }
171
172 print '-' x 79, "\n";
+0
-67
examples/bench-primecount.pl less more
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 use Math::Prime::Util ":all";
4 use Benchmark qw/:all/;
5 my $maxdigits = (~0 <= 4294967295) ? 10 : 20;
6 my $nnums = 100;
7
8 my $count = shift || -5;
9
10 srand(29);
11 my @darray;
12 push @darray, [gendigits($_)] for (2 .. 10);
13 my $sum;
14
15 print "Direct sieving:\n";
16 cmpthese($count,{
17 ' 2' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_segment_pi($_) for @{$darray[2-2]} },
18 ' 3' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_segment_pi($_) for @{$darray[3-2]} },
19 ' 4' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_segment_pi($_) for @{$darray[4-2]} },
20 ' 5' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_segment_pi($_) for @{$darray[5-2]} },
21 ' 6' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_segment_pi($_) for @{$darray[6-2]} },
22 ' 7' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_segment_pi($_) for @{$darray[7-2]} },
23 ' 8' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_segment_pi($_) for @{$darray[8-2]} },
24 #' 9' => sub { $sum += Math::Prime::Util::_XS_segment_pi($_) for @{$darray[9-2]} },
25 #'10' => sub { $sum += Math::Prime::Util::_XS_segment_pi($_) for @{$darray[10-2]} },
26 });
27 if (0) {
28 print "\n";
29 print "Direct Lehmer:\n";
30 cmpthese($count,{
31 ' 2' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_lehmer_pi($_) for @{$darray[2-2]} },
32 ' 3' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_lehmer_pi($_) for @{$darray[3-2]} },
33 ' 4' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_lehmer_pi($_) for @{$darray[4-2]} },
34 ' 5' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_lehmer_pi($_) for @{$darray[5-2]} },
35 ' 6' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_lehmer_pi($_) for @{$darray[6-2]} },
36 ' 7' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_lehmer_pi($_) for @{$darray[7-2]} },
37 ' 8' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_lehmer_pi($_) for @{$darray[8-2]} },
38 ' 9' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_lehmer_pi($_) for @{$darray[9-2]} },
39 '10' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_lehmer_pi($_) for @{$darray[10-2]} },
40 });
41 }
42 print "\n";
43 print "Direct LMO:\n";
44 cmpthese($count,{
45 ' 2' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_LMO_pi($_) for @{$darray[2-2]} },
46 ' 3' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_LMO_pi($_) for @{$darray[3-2]} },
47 ' 4' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_LMO_pi($_) for @{$darray[4-2]} },
48 ' 5' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_LMO_pi($_) for @{$darray[5-2]} },
49 ' 6' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_LMO_pi($_) for @{$darray[6-2]} },
50 ' 7' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_LMO_pi($_) for @{$darray[7-2]} },
51 ' 8' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_LMO_pi($_) for @{$darray[8-2]} },
52 ' 9' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_LMO_pi($_) for @{$darray[9-2]} },
53 '10' => sub { prime_memfree(); $sum += Math::Prime::Util::_XS_LMO_pi($_) for @{$darray[10-2]} },
54 });
55 print "\n";
56
57 sub gendigits {
58 my $digits = shift;
59 die "Digits must be > 0" unless $digits > 0;
60
61 my $base = ($digits == 1) ? 0 : int(10 ** ($digits-1));
62 my $max = int(10 ** $digits);
63 $max = ~0 if $max > ~0;
64 my @nums = map { $base+int(rand($max-$base)) } (1 .. $nnums);
65 return @nums;
66 }
+0
-21
examples/bench-random-prime-bigint.pl less more
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3
4 use Math::Prime::Util qw/random_nbit_prime/;
5 use Math::BigInt try=>'GMP';
6 use Benchmark qw/:all/;
7 use List::Util qw/min max/;
8 my $count = shift || -3;
9
10 srand(29);
11 test_at_bits($_) for (15, 30, 60, 128, 256, 512, 1024, 2048, 4096);
12
13 sub test_at_bits {
14 my $bits = shift;
15 die "Digits must be > 0" unless $bits > 0;
16
17 cmpthese($count,{
18 "$bits bits" => sub { random_nbit_prime($bits); },
19 });
20 }
+0
-21
examples/bench-random-prime.pl less more
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3
4 use Math::Prime::Util qw/-nobigint random_prime random_ndigit_prime/;
5 use Benchmark qw/:all/;
6 use List::Util qw/min max/;
7 my $count = shift || -3;
8 my $maxdigits = (~0 <= 4294967295) ? 10 : 20;
9
10 srand(29);
11 test_at_digits($_) for (2 .. $maxdigits);
12
13 sub test_at_digits {
14 my $digits = shift;
15 die "Digits must be > 0" unless $digits > 0;
16
17 cmpthese($count,{
18 "$digits digits" => sub { random_ndigit_prime($digits) for (1..1000) },
19 });
20 }
22 use strict;
33 use threads;
44 use threads::shared;
5 use Math::Prime::Util qw/is_prime is_strong_pseudoprime/;
6 my $nthreads = 12;
5 use Math::Prime::Util qw/is_prime is_strong_pseudoprime forcomposites/;
6 my $nthreads = 4;
77
88 # Single base.
99
1010 my @composites;
11 for my $n (3 .. 1000000) {
12 push @composites, $n if $n % 2 && !is_prime($n);
13 }
11 forcomposites { push @composites, $_ if $_ % 2; } 1_000_000;
1412
1513 # Serial:
1614 # my $base = 2;
3028
3129 # Parallel:
3230 my $maxn :shared;
33 my $start = int(2**59+2**41); # People have mined below 2^55
31 my $start = int(2**60+2**41); # People have mined below 2^55
3432 $maxn = 2047;
35 my $nextn = 2049;
3633 my @threads;
37 push @threads, threads->create('search_bases', $start, $_) for (0..$nthreads-1);
34 push @threads, threads->create('search_bases', $start, $_) for 1..$nthreads;
3835 # We should sit here doing cond_waits on a results array.
3936 $_->join() for (@threads);
4037
4138 sub search_bases {
4239 my($start, $t) = @_;
43 my $base = $start + $t;
44 while (1) {
45 do { $base += $t; next; } if is_strong_pseudoprime($nextn, $base);
40 for (my $base = $start + $t - 1; 1; $base += $t) {
41 next if is_strong_pseudoprime(4, $base) || is_strong_pseudoprime(6, $base);
4642 for my $n (@composites) {
4743 if (is_strong_pseudoprime($n,$base)) {
4844 if ($n > $maxn) {
4945 lock($maxn);
50 print "base $base good up to $n\n";
46 print "base $base good up to $n\n" if $n > $maxn;
5147 $maxn = $n;
52 $nextn = $n+2; $nextn++ while is_prime($nextn);
5348 }
5449 last;
5550 }
5651 }
57 $base += $t;
5852 }
5953 }
6054
6155 __END__
6256
6357 base 2 good up to 2047
64 base 1320 good up to 4097
65 base 4712 good up to 4711
66 base 5628 good up to 5627
67 base 7252 good up to 7251
68 base 7852 good up to 7851
69 base 14787 good up to 9409
70 base 17340 good up to 10261
71 base 61380 good up to 11359
72 base 78750 good up to 13747
58 base 3273 good up to 2209
59 base 4414 good up to 2443
60 base 5222 good up to 2611
61 base 8286 good up to 4033
62 base 10822 good up to 5411
63 base 13011 good up to 6505
64 base 67910 good up to 9073
65 base 82967 good up to 10371
7366 base 254923 good up to 18299
74 base 486605 good up to 25761
75 base 1804842 good up to 32761
67 base 2974927 good up to 18721
7668 base 4095086 good up to 38323
77 base 12772344 good up to 40501
78 base 42162995 good up to 97921
69 base 70903283 good up to 38503
7970
8071 (best results known, not found with this program)
8172 2011-02-12 base 814494960528 good up to 132239
8374 2012-10-15 base 1769236083487960 good up to 192001
8475 2012-10-17 base 1948244569546278 good up to 212321
8576 2013-01-14 base 34933608779780163 good up to 218245
77 2013-03-03 base 9345883071009581737 good up to 341531
22 use warnings;
33 use threads;
44 use threads::shared;
5 use Math::BigInt lib => 'GMP';
5
6 # Overkill, but let's try to select a good bigint module.
7 my $bigint_class;
8 if (eval { require Math::GMPz; 1; }) {
9 $bigint_class = "Math::GMPz";
10 } elsif (eval { require Math::GMP; 1; }) {
11 $bigint_class = "Math::GMP";
12 } else {
13 require Math::BigInt;
14 Math::BigInt->import(try=>"GMP,Pari");
15 $bigint_class = "Math::BigInt";
16 }
17
618 use Math::Prime::Util ':all';
719 use Time::HiRes qw(gettimeofday tv_interval);
820 $| = 1;
5062 my @karray : shared; # array of min k for each thread
5163
5264 my @threads;
53 push @threads, threads->create('fibprime', $_) for (1..$nthreads);
65 push @threads, threads->create('fibprime', $_) for 1 .. $nthreads;
5466
5567 # Let the threads work for a little before starting the display loop
5668 sleep 2;
7991
8092 sub fib_n {
8193 my ($n, $fibstate) = @_;
82 @$fibstate = (1, Math::BigInt->new(0), Math::BigInt->new(1))
94 @$fibstate = (1, $bigint_class->new(0), $bigint_class->new(1))
8395 unless defined $fibstate->[0];
8496 my ($curn, $a, $b) = @$fibstate;
8597 die "fib_n only increases" if $n < $curn;
0 #!/usr/bin/env perl
1 use warnings;
2 use strict;
3 use 5.14.0;
4 use Math::Prime::Util qw/:all/;
5 use List::Util qw/sum/;
6 use Benchmark qw/:all/;
7
8 my $lim = shift || 1000;
9
10 # Michael B Porter proposed this OEIS sequence:
11 #
12 # a(n) = m such that sigma(m) + sigma(m+1) + ... + sigma(m+n-1) is prime
13 #
14 # http://oeis.org/wiki/User:Michael_B._Porter
15 #
16 # Charles R Greathouse IV suggested this as an efficient computation:
17 # a(n)=my(t=sum(i=1,n,sigma(i)),k=1);while(!isprime(t),t-=sigma(k)-sigma(n+k);k++);k
18 # which can be turned into a vector as:
19 # vector(1000,i,a(i))
20 #
21 # Pari does this for 10k elements in ~15 seconds.
22 # Version opt2 does it in Perl in 3.0s.
23 # For 20k it's 63s in Pari, 12s in Perl.
24 # Of course Pari could be optimized as well.
25
26 sub simple {
27 my $lim = shift;
28 my @list;
29 foreach my $n (1 .. $lim) {
30 my($m, $sum) = (1, 0);
31 while (!is_prime($sum)) {
32 $sum = 0;
33 $sum += divisor_sum($m+$_) for 0..$n-1;
34 $m++;
35 }
36 push @list, $m-1;
37 }
38 return @list;
39 }
40 # perl -MMath::Prime::Util=:all -E 'my @list; foreach my $n (1 .. 1000) { my ($m,$sum) = (1,0); while (!is_prime($sum)) { $sum = 0; $sum += divisor_sum($m+$_) for 0..$n-1; $m++; } push @list, $m-1; } say join ",", @list;'
41
42 sub crg4 {
43 my $lim = shift;
44 my @list;
45 foreach my $n (1 .. $lim) {
46 my($k, $t) = (1,0);
47 $t += divisor_sum($_) for 1..$n;
48 while (!is_prime($t)) {
49 $t -= divisor_sum($k)-divisor_sum($n+$k);
50 $k++;
51 }
52 push @list,$k;
53 }
54 return @list;
55 }
56 # perl -MMath::Prime::Util=:all -E 'my @list; foreach my $n (1 .. 10000) { my($k,$t)=(1,0); $t += divisor_sum($_) for 1..$n; while (!is_prime($t)) { $t -= divisor_sum($k)-divisor_sum($n+$k); $k++; } push @list, $k; } say join ",", @list;'
57 # 9.8s for 10k
58
59 sub opt1 {
60 my $lim = shift;
61 my @list = map {
62 my($n,$t,$k) = ($_,0,1);
63 $t += divisor_sum($_) for 1..$n;
64 while (!is_prime($t)) {
65 $t -= divisor_sum($k) - divisor_sum($n+$k);
66 $k++;
67 }
68 $k;
69 } 1 .. $lim;
70 return @list;
71 }
72 # perl -MMath::Prime::Util=:all -E 'say join ",", map { my($n,$t,$k) = ($_,0,1); $t += divisor_sum($_) for 1..$n; while (!is_prime($t)) { $t -= divisor_sum($k) - divisor_sum($n+$k); $k++; } $k; } 1 .. 10000'
73 # 9.5s for 10k
74
75 sub opt2 {
76 my $lim = shift;
77 my @ds;
78 my @list = map {
79 my($n,$t,$k) = ($_,0,1);
80 $ds[$n] //= divisor_sum($n);
81 $t += $ds[$_] for 1..$n;
82 while (!is_prime($t)) {
83 $ds[$n+$k] //= divisor_sum($n+$k);
84 $t -= $ds[$k] - $ds[$n+$k];
85 $k++;
86 }
87 $k;
88 } 1 .. $lim;
89 return @list;
90 }
91 # perl -MMath::Prime::Util=:all -E '@ds = (1,1); say join ",", map { my($n,$t,$k) = ($_,0,1); $t += $ds[$_] for 1..$n; while (!is_prime($t)) { $ds[$n+$k] //= divisor_sum($n+$k); $t -= $ds[$k] - $ds[$n+$k]; $k++; } $k; } 1..10000'
92 # 3.0s for 10k
93
94 # Verify
95 {
96 my $vlim = 100;
97 my @a1 = simple($vlim);
98 my @a2 = crg4($vlim);
99 my @a3 = opt1($vlim);
100 my @a4 = opt2($vlim);
101 foreach my $i (0 .. $vlim-1) {
102 die "Mismatch in crg4 at $i" unless $a1[$i] == $a2[$i];
103 die "Mismatch in opt1 at $i" unless $a1[$i] == $a3[$i];
104 die "Mismatch in opt2 at $i" unless $a1[$i] == $a4[$i];
105 }
106 }
107
108 cmpthese(-5, {
109 #'simple' => sub { simple($lim) },
110 'crg4' => sub { crg4($lim) },
111 'opt1' => sub { opt1($lim) },
112 'opt2' => sub { opt2($lim) },
113 });
114
115 #say join ", ", opt1($lim);
55 next_prime nth_prime_upper prime_precalc forprimes/;
66
77 my $count = shift || 20;
8 my $method = shift || 'forprimes';
9 my $precalc = 0; # If set, precalc all the values we'll call is_prime on
810
911 # Find Sophie Germain primes (numbers where p and 2p+1 are both prime).
1012
11 # In this method, we add a filter in front of our iterator, to create a
12 # Sophie-Germain-prime iterator. This isn't the fastest way, but it's still
13 # 20x faster than Math::NumSeq::SophieGermainPrimes at 300k. If we add the
14 # two-line precalc shown below, we can get another 4x or more.
13 # Four methods are shown: forprimes, iter, iter2, and MNS.
14
15 # Times for 300k:
1516 #
16 # Example:
17 # time perl examples/sophie_germain.pl 300000 | md5sum
18 # d380d31256cc9bc54eb5f236b3edc16d -
19 # 9.673s
20 #
21 # time perl -MMath::NumSeq::SophieGermainPrimes -E 'my $seq = Math::NumSeq::SophieGermainPrimes->new; do { say 0+($seq->next)[1] } for 1..300000' | md5sum
22 # d380d31256cc9bc54eb5f236b3edc16d -
23 # 4m11.5s
24 #
25 # With method 2:
26 # time perl examples/sophie_germain.pl 300000 | md5sum
27 # d380d31256cc9bc54eb5f236b3edc16d -
28 # 1.828s
17 # 300k 1M
18 # precalc:
19 # forprimes 1.3s 9.0MB 7.1s 21.6MB
20 # iter 2.8s 8.7MB 12.6s 21.4MB
21 # iter2 1.9s 8.7MB 9.4s 21.4MB
22 # no precalc:
23 # forprimes 1.5s 4.5MB 5.6s 4.5MB
24 # iter 9.5s 4.3MB 37.5s 4.3MB
25 # iter2 8.5s 4.3MB 33.9s 4.3MB
26 # MNS 254.3s 11.3MB >1500s >15 MB
27
28 if ($precalc) {
29 prime_precalc(2 * sg_upper_bound($count));
30 }
2931
3032
31 sub get_sophie_germain_iterator {
32 my $p = shift || 2;
33 my $it = prime_iterator($p);
34 return sub {
35 do { $p = $it->() } while !is_prime(2*$p+1);
36 $p;
37 };
33 if ($method eq 'forprimes') {
34
35 my $estimate = sg_upper_bound($count);
36 my $numfound = 0;
37 forprimes {
38 if ($numfound < $count && is_prime(2*$_+1)) {
39 print "$_\n";
40 $numfound++;
41 }
42 } $estimate;
43 die "Estimate too low" unless $numfound >= $count;
44
45 } elsif ($method eq 'iter') {
46
47 # Wrap the standard iterator
48 sub get_sophie_germain_iterator {
49 my $p = shift || 2;
50 my $it = prime_iterator($p);
51 return sub {
52 do { $p = $it->() } while !is_prime(2*$p+1);
53 $p;
54 };
55 }
56 my $sgit = get_sophie_germain_iterator();
57 print $sgit->(), "\n" for 1 .. $count;
58
59 } elsif ($method eq 'iter2') {
60
61 # Iterate directly using next_prime
62 my $prime = 2;
63 for (1 .. $count) {
64 $prime = next_prime($prime) while !is_prime(2*$prime+1);
65 print "$prime\n";
66 $prime = next_prime($prime);
67 }
68
69 } elsif ($method eq 'MNS') {
70
71 # Use Math::NumSeq
72 require Math::NumSeq::SophieGermainPrimes;
73 my $seq = Math::NumSeq::SophieGermainPrimes->new;
74 for (1 .. $count) {
75 print 0+($seq->next)[1];
76 }
77
3878 }
39 my $sgit = get_sophie_germain_iterator();
40 print $sgit->(), "\n" for 1 .. $count;
4179
42 # Method 2. At 300k this is 70x faster than Math::NumSeq::SophieGermainPrimes.
43 #
44 #my $estimate = 100 + int( nth_prime_upper($count) * 1.6 * log($count) );
45 #prime_precalc(2 * $estimate);
46 #
47 #my $prime = 2;
48 #for (1..$count) {
49 # $prime = next_prime($prime) while (!is_prime(2*$prime+1));
50 # print "$prime\n";
51 # $prime = next_prime($prime);
52 #}
80 # Used for precalc and the forprimes example
81 sub sg_upper_bound {
82 my $count = shift;
83 my $nth = nth_prime_upper($count);
84 # For lack of a better formula, do this step-wise estimate.
85 my $estimate = ($count < 5000) ? 150 + int( $nth * log($nth) * 1.2 )
86 : ($count < 19000) ? int( $nth * log($nth) * 1.135 )
87 : ($count < 45000) ? int( $nth * log($nth) * 1.10 )
88 : ($count < 100000) ? int( $nth * log($nth) * 1.08 )
89 : ($count < 165000) ? int( $nth * log($nth) * 1.06 )
90 : ($count < 360000) ? int( $nth * log($nth) * 1.05 )
91 : ($count < 750000) ? int( $nth * log($nth) * 1.04 )
92 : ($count <1700000) ? int( $nth * log($nth) * 1.03 )
93 : int( $nth * log($nth) * 1.02 );
5394
54 # Alternate method, 10-20% faster, would benefit from a tighter estimate.
55 #
56 # my $numfound = 0;
57 # forprimes {
58 # if ($numfound < $count && is_prime(2*$_+1)) {
59 # print "$_\n";
60 # $numfound++;
61 # }
62 # } $estimate;
63 # die "Estimate too low" unless $numfound >= $count;
95 return $estimate;
96 }
+0
-192
examples/test-factor-gnufactor.pl less more
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 use Math::Prime::Util qw/factor/;
4 use File::Temp qw/tempfile/;
5 use Math::BigInt try => 'GMP,Pari';
6 use Config;
7 use autodie;
8 use Text::Diff;
9 use Time::HiRes qw(gettimeofday tv_interval);
10 my $maxdigits = 100;
11 $| = 1; # fast pipes
12 srand(87431);
13 my $num = 1000;
14
15 # Note: If you have factor from coreutils 8.20 or later (e.g. you're running
16 # Fedora), then GNU factor will be very fast and support at least 128-bit
17 # inputs (~44 digits). Its growth is not great however, so 25+ digits starts
18 # getting slow. The authors wrote on a forum that a future version will
19 # include a TinyQS, which should make it really rock for medium-size inputs.
20 #
21 # On the other hand, if you have the older factor (e.g. you're running
22 # Ubuntu) then GNU factor uses trial division so will be very painful for
23 # large numbers. You'll probably want to turn it off here as it will be
24 # many thousands of times slower than MPU and Pari.
25
26 # A benchmarking note: in this script, getting MPU and Pari results are done
27 # by calling a function, where getting GNU factor results are done via
28 # multiple shells to /usr/bin/factor with the inputs as command line
29 # arguments. This adds a lot of overhead that has nothing to do with their
30 # implementation. For comparison, I've included an option for getting MPU
31 # factoring via calling the factor.pl script. Weep at the startup cost.
32
33 my $do_gnu = 1;
34 my $do_pari = 1;
35 my $use_mpu_factor_script = 0;
36
37 if ($do_pari) {
38 $do_pari = 0 unless eval { require Math::Pari; Math::Pari->import(); 1; };
39 }
40
41 my $rgen = sub {
42 my $range = shift;
43 return 0 if $range <= 0;
44 my $rbits = 0; { my $t = $range; while ($t) { $rbits++; $t >>= 1; } }
45 while (1) {
46 my $rbitsleft = $rbits;
47 my $U = $range - $range; # 0 or bigint 0
48 while ($rbitsleft > 0) {
49 my $usebits = ($rbitsleft > $Config{randbits}) ? $Config{randbits} : $rbitsleft;
50 $U = ($U << $usebits) + int(rand(1 << $usebits));
51 $rbitsleft -= $usebits;
52 }
53 return $U if $U <= $range;
54 }
55 };
56
57 { # Test from 2 to 10000
58 print " 2 - 1000"; test_array( 2 .. 1000);
59 print " 1001 - 5000"; test_array( 1001 .. 5000);
60 print " 5001 - 10000"; test_array( 5001 .. 10000);
61 }
62
63 foreach my $digits (5 .. $maxdigits) {
64 printf "%5d %2d-digit numbers", $num, $digits;
65 my @narray = gendigits($digits, $num);
66 test_array(@narray);
67 $num = int($num * 0.9) + 1; # reduce as we go
68 }
69
70 sub test_array {
71 my @narray = @_;
72 my($start, $mpusec, $gnusec, $parisec, $diff);
73 my(@mpuarray, @gnuarray, @pariarray);
74
75 print ".";
76 $start = [gettimeofday];
77 @mpuarray = mpu_factors(@narray);
78 $mpusec = tv_interval($start);
79
80 if ($do_gnu) {
81 print ".";
82 $start = [gettimeofday];
83 @gnuarray = gnu_factors(@narray);
84 $gnusec = tv_interval($start);
85 }
86
87 if ($do_pari) {
88 print ".";
89 $start = [gettimeofday];
90 @pariarray = pari_factors(@narray);
91 $parisec = tv_interval($start);
92 }
93
94 print ".";
95 die "MPU got ", scalar @mpuarray, " factors. GNU factor got ",
96 scalar @gnuarray, "\n" unless !$do_gnu || $#mpuarray == $#gnuarray;
97 die "MPU got ", scalar @mpuarray, " factors. Pari factor got ",
98 scalar @pariarray, "\n" unless !$do_pari || $#mpuarray == $#pariarray;
99 foreach my $n (@narray) {
100 my @mpu = @{shift @mpuarray};
101 die "mpu array is for the wrong n?" unless $n == shift @mpu;
102 if ($do_gnu) {
103 my @gnu = @{shift @gnuarray};
104 die "gnu array is for the wrong n?" unless $n == shift @gnu;
105 $diff = diff \@mpu, \@gnu, { STYLE => 'Table' };
106 die "factor($n): MPU/GNU\n$diff\n" if length($diff) > 0;
107 }
108 if ($do_pari) {
109 my @pari = @{shift @pariarray};
110 die "pari array is for the wrong n?" unless $n == shift @pari;
111 my $diff = diff \@mpu, \@pari, { STYLE => 'Table' };
112 die "factor($n): MPU/Pari\n$diff\n" if length($diff) > 0;
113 }
114 }
115 print ".";
116 # We should ignore the small digits, since we're comparing direct
117 # Perl functions with multiple command line invocations. It really
118 # doesn't make sense until we're over 1ms per number.
119 printf " MPU:%8.4f ms", (($mpusec*1000) / scalar @narray);
120 printf(" GNU:%8.4f ms", (($gnusec*1000) / scalar @narray)) if $do_gnu;
121 printf(" Pari:%8.4f ms", (($parisec*1000) / scalar @narray)) if $do_pari;
122 print "\n";
123 }
124
125 sub gendigits {
126 my $digits = shift;
127 die "Digits must be > 0" unless $digits > 0;
128 my $howmany = shift;
129 my ($base, $max);
130
131 if ( 10**$digits < ~0) {
132 $base = ($digits == 1) ? 0 : int(10 ** ($digits-1));
133 $max = int(10 ** $digits);
134 $max = ~0 if $max > ~0;
135 } else {
136 $base = Math::BigInt->new(10)->bpow($digits-1);
137 $max = Math::BigInt->new(10)->bpow($digits) - 1;
138 }
139 my @nums = map { $base + $rgen->($max-$base) } (1 .. $howmany);
140 return @nums;
141 }
142
143 sub mpu_factors {
144 my @piarray;
145
146 if (!$use_mpu_factor_script) {
147 push @piarray, [$_, factor($_)] for @_;
148 } else {
149 my @ns = @_;
150 my $numpercommand = int( (4000-30)/(length($ns[-1])+1) );
151 while (@ns) {
152 my $cs = join(" ", 'factor.pl', splice(@ns, 0, $numpercommand));
153 my $fout = qx{$cs};
154 my @flines = split(/\n/, $fout);
155 foreach my $fline (@flines) {
156 $fline =~ s/^(\d+): //;
157 push @piarray, [$1, split(/ /, $fline)];
158 }
159 }
160 }
161 @piarray;
162 }
163
164 sub gnu_factors {
165 my @ns = @_;
166 my @piarray;
167 my $numpercommand = int( (4000-30)/(length($ns[-1])+1) );
168
169 while (@ns) {
170 my $cs = join(" ", '/usr/bin/factor', splice(@ns, 0, $numpercommand));
171 my $fout = qx{$cs};
172 my @flines = split(/\n/, $fout);
173 foreach my $fline (@flines) {
174 $fline =~ s/^(\d+): //;
175 push @piarray, [$1, split(/ /, $fline)];
176 }
177 }
178 @piarray;
179 }
180
181 sub pari_factors {
182 my @piarray;
183 foreach my $n (@_) {
184 my @factors;
185 my ($pn,$pc) = @{Math::Pari::factorint($n)};
186 # Map the Math::Pari objects returned into Math::BigInts, because Pari will
187 # throw a hissy fit later when we try to compare them to anything else.
188 push @piarray, [ $n, map { (Math::BigInt->new($pn->[$_])) x $pc->[$_] } (0 .. $#$pn) ];
189 }
190 @piarray;
191 }
+0
-128
examples/test-factor-yafu.pl less more
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 use Math::Prime::Util qw/factor/;
4 use File::Temp qw/tempfile/;
5 use Math::BigInt try => 'GMP,Pari';
6 use Config;
7 use autodie;
8 use Text::Diff;
9 my $maxdigits = 50;
10 $| = 1; # fast pipes
11 my $num = 10000;
12 my $yafu_fname = "yafu_batchfile_$$.txt";
13 $SIG{'INT'} = \&gotsig;
14
15 my $rgen = sub {
16 my $range = shift;
17 return 0 if $range <= 0;
18 my $rbits = 0; { my $t = $range; while ($t) { $rbits++; $t >>= 1; } }
19 while (1) {
20 my $rbitsleft = $rbits;
21 my $U = $range - $range; # 0 or bigint 0
22 while ($rbitsleft > 0) {
23 my $usebits = ($rbitsleft > $Config{randbits}) ? $Config{randbits} : $rbitsleft;
24 $U = ($U << $usebits) + int(rand(1 << $usebits));
25 $rbitsleft -= $usebits;
26 }
27 return $U if $U <= $range;
28 }
29 };
30
31 { # Test from 2 to 10000
32 print " 2 - 1000"; test_array( 2 .. 1000);
33 print " 1001 - 5000"; test_array( 1001 .. 5000);
34 print " 5001 - 10000"; test_array( 5001 .. 10000);
35 }
36
37 foreach my $digits (5 .. $maxdigits) {
38 printf "%5d %2d-digit numbers", $num, $digits;
39 my @narray = gendigits($digits, $num);
40 test_array(@narray);
41 $num = int($num * 0.9) + 1; # reduce as we go
42 }
43
44 sub test_array {
45 my @narray = @_;
46 print ".";
47 my @mpuarray = mpu_factors(@narray);
48 print ".";
49 my @yafuarray = yafu_factors(@narray);
50 print ".";
51 if ($#mpuarray != $#yafuarray) {
52 die "MPU got $#mpuarray primes, YAFU got $#yafuarray\n";
53 }
54 foreach my $n (@narray) {
55 my @mpu = @{shift @mpuarray};
56 my @yafu = @{shift @yafuarray};
57 die "mpu array is for the wrong n?" unless $n == shift @mpu;
58 die "yafu array is for the wrong n?" unless $n == shift @yafu;
59 my $diff = diff \@mpu, \@yafu, { STYLE => 'Table' };
60 die "factor($n):\n$diff\n" if length($diff) > 0;
61 }
62 print ".";
63 print "OK\n";
64 }
65
66 sub gendigits {
67 my $digits = shift;
68 die "Digits must be > 0" unless $digits > 0;
69 my $howmany = shift;
70 my ($base, $max);
71
72 if ( 10**$digits < ~0) {
73 $base = ($digits == 1) ? 0 : int(10 ** ($digits-1));
74 $max = int(10 ** $digits);
75 $max = ~0 if $max > ~0;
76 } else {
77 $base = Math::BigInt->new(10)->bpow($digits-1);
78 $max = Math::BigInt->new(10)->bpow($digits) - 1;
79 }
80 my @nums = map { $base + $rgen->($max-$base) } (1 .. $howmany);
81 return @nums;
82 }
83
84 sub mpu_factors {
85 my @piarray;
86 push @piarray, [$_, factor($_)] for @_;
87 @piarray;
88 }
89
90 sub yafu_factors {
91 my @ns = @_;
92 my @piarray;
93
94 #my $fh = File::Temp->new; # .... autodie
95 #print $fh, "$_\n" for @_;
96 #$fh->flush;
97
98 # Shudder. Yafu must have a file in the current directory.
99 open(my $fh, '>', $yafu_fname);
100 print $fh "$_\n" for @ns;
101 close $fh;
102
103 open my $yafu, "yafu \"factor(\@)\" -batchfile $yafu_fname |";
104 my @curfactors;
105 while (<$yafu>) {
106 chomp;
107 if (/^P(RP)?\d+ = (\d+)/) {
108 push @curfactors, $2;
109 } elsif (/^C\d+ = (\d+)/) {
110 # Yafu didn't factor this one completely. Sneakily do it ourselves.
111 push @curfactors, factor( Math::BigInt->new("$1") );
112 } elsif (/ans = (\d+)/) {
113 push @piarray, [shift @ns, sort {$a<=>$b} @curfactors];
114 @curfactors = ();
115 }
116 }
117 close($yafu);
118 @piarray;
119 }
120 sub gotsig { my $sig = shift; die "Die because SIG$sig\n"; }
121 END {
122 unlink $yafu_fname if -e $yafu_fname;
123 # YAFU leaves stuff around
124 unlink "__tmpbatchfile" if -e "__tmpbatchfile";
125 unlink "session.log" if -e "session.log";
126 unlink "factor.log" if -e "factor.log";
127 }
+0
-82
examples/test-nextprime-yafu.pl less more
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 use Math::Prime::Util qw/next_prime/;
4 use File::Temp qw/tempfile/;
5 use autodie;
6 my $maxdigits = (~0 <= 4294967295) ? 10 : 20;
7 $| = 1; # fast pipes
8 my $num = shift || 10000;
9 my $yafu_fname = "yafu_batchfile_$$.txt";
10 $SIG{'INT'} = \&gotsig;
11
12 foreach my $digits (4 .. $maxdigits) {
13 printf "%2d-digit numbers", $digits;
14 my @narray = gendigits($digits, $num);
15 print ".";
16 my @mpuarray = mpu_next_primes(@narray);
17 print ".";
18 die "mpu_next_primes didn't get enough numbers" unless $#mpuarray == $#narray;
19 my @yafuarray = yafu_next_primes(@narray);
20 die "yafunext_primes didn't get enough numbers" unless $#yafuarray == $#narray;
21 print ".";
22 foreach my $n (@narray) {
23 my $mpu = shift @mpuarray;
24 my $yafu = shift @yafuarray;
25 die "next_prime($n): MPU: $mpu YAFU: $yafu\n" unless $mpu == $yafu;
26 }
27 print ".";
28 print "OK\n";
29 }
30
31 sub gendigits {
32 my $digits = shift;
33 die "Digits must be > 0" unless $digits > 0;
34 my $howmany = shift;
35
36 my $base = ($digits == 1) ? 0 : int(10 ** ($digits-1));
37 my $max = int(10 ** $digits);
38 $max = ~0 if $max > ~0;
39 my @nums = map { $base+int(rand($max-$base)) } (1 .. $howmany);
40 return @nums;
41 }
42
43 sub mpu_next_primes {
44 my @nparray;
45 push @nparray, next_prime($_) for @_;
46 @nparray;
47 }
48
49 sub yafu_next_primes {
50 my @nparray;
51 # Yafu 1.31 seems to go out of its way to make it hard to process more than
52 # one number at a time. The batchfile system will infinite loop if the data
53 # file isn't in the current directory.
54 # It does its darndest to see if you're on a terminal or not, and if not it
55 # just cuts you off after one number. So any sort of tempfile or pipe stuff
56 # just plain doesn't work. Faking it using IO::*tty* would probably work.
57
58 #my $fh = File::Temp->new; # .... autodie
59 #print $fh, "$_\n" for @_;
60 #$fh->flush;
61
62 # Shudder. Read comments above about why I have to do this.
63 open(my $fh, '>', $yafu_fname);
64 print $fh "$_\n" for @_;
65 close $fh;
66
67 open my $yafu, "yafu \"nextprime(\@)\" -batchfile $yafu_fname |";
68 while (<$yafu>) {
69 next unless /ans = (\d+)/;
70 push @nparray, $1;
71 }
72 close($yafu);
73 @nparray;
74 }
75 sub gotsig { my $sig = shift; die "Die because SIG$sig\n"; }
76 END {
77 unlink $yafu_fname if -e $yafu_fname;
78 # YAFU leaves stuff around
79 unlink "__tmpbatchfile" if -e "__tmpbatchfile";
80 unlink "session.log" if -e "session.log";
81 }
+0
-107
examples/test-primes-yafu.pl less more
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 use Math::Prime::Util qw/primes/;
4 use File::Temp qw/tempfile/;
5 use autodie;
6 use Text::Diff;
7 my $maxdigits = (~0 <= 4294967295) ? 10 : 18;
8 $| = 1; # fast pipes
9 my $num = 5000;
10 my $interval = 8000;
11 my $yafu_fname = "yafu_batchfile_$$.txt";
12 $SIG{'INT'} = \&gotsig;
13
14
15 # Note -- yafu 1.31 will not sieve 19 digit numbers. E.g.:
16 # primes(8631424695497106432,8631424695497114432,0)
17 # gives:
18 # input too high
19
20
21 foreach my $digits (3 .. $maxdigits) {
22 printf "%5d %2d-digit numbers", $num, $digits;
23 my @narray = gendigits($digits, $num);
24 print ".";
25 my @mpuarray = mpu_primes(@narray);
26 print ".";
27 #die "mpu_next_primes didn't get enough numbers" unless $#mpuarray-1 == $#narray;
28 my @yafuarray = yafu_primes(@narray);
29 #die "yafunext_primes didn't get enough numbers" unless $#yafuarray-1 == $#narray;
30 print ".";
31 if ($#mpuarray != $#yafuarray) {
32 die "MPU got $#mpuarray primes, YAFU got $#yafuarray\n";
33 }
34 foreach my $n (@narray) {
35 my @mpu = @{shift @mpuarray};
36 my @yafu = @{shift @yafuarray};
37 die "mpu array is for the wrong n?" unless $n == shift @mpu;
38 die "yafu array is for the wrong n?" unless $n == shift @yafu;
39 my $diff = diff \@mpu, \@yafu, { STYLE => 'Table' };
40 die "primes($n,$n+$interval):\n$diff\n" if length($diff) > 0;
41 }
42 print ".";
43 print "OK\n";
44 $num = int($num * 0.75); # reduce as we go
45 }
46
47 sub gendigits {
48 my $digits = shift;
49 die "Digits must be > 0" unless $digits > 0;
50 my $howmany = shift;
51
52 my $base = ($digits == 1) ? 0 : int(10 ** ($digits-1));
53 my $max = int(10 ** $digits);
54 #$max = ~0 if $max > ~0;
55 $max = ~0-$interval if $max > (~0-$interval); # special for us
56 my @nums = map { $base+int(rand($max-$base)) } (1 .. $howmany);
57 return @nums;
58 }
59
60 sub mpu_primes {
61 my @piarray;
62 push @piarray, [$_, @{primes($_, $_+$interval)}] for @_;
63 @piarray;
64 }
65
66 sub yafu_primes {
67 my @ns = @_;
68 my @piarray;
69 # Yafu 1.31 seems to go out of its way to make it hard to process more than
70 # one number at a time. The batchfile system will infinite loop if the data
71 # file isn't in the current directory.
72 # It does its darndest to see if you're on a terminal or not, and if not it
73 # just cuts you off after one number. So any sort of tempfile or pipe stuff
74 # just plain doesn't work. Faking it using IO::*tty* would probably work.
75
76 #my $fh = File::Temp->new; # .... autodie
77 #print $fh, "$_\n" for @_;
78 #$fh->flush;
79
80 # Shudder. Read comments above about why I have to do this.
81 open(my $fh, '>', $yafu_fname);
82 print $fh "$_,", $_+$interval, ",0\n" for @ns;
83 close $fh;
84
85 open my $yafu, "yafu \"primes(\@)\" -pscreen -batchfile $yafu_fname |";
86 my @curprimes;
87 while (<$yafu>) {
88 chomp;
89 if (/^\d+/) {
90 push @curprimes, split(/ /);
91 } elsif (/ans = (\d+)/) {
92 foreach my $p (@curprimes) { die "Entry is '$p'" unless $p =~ /^\d+$/; }
93 push @piarray, [shift @ns, @curprimes];
94 @curprimes = ();
95 }
96 }
97 close($yafu);
98 @piarray;
99 }
100 sub gotsig { my $sig = shift; die "Die because SIG$sig\n"; }
101 END {
102 unlink $yafu_fname if -e $yafu_fname;
103 # YAFU leaves stuff around
104 unlink "__tmpbatchfile" if -e "__tmpbatchfile";
105 unlink "session.log" if -e "session.log";
106 }
11 use strict;
22 use warnings;
33
4 use Math::Prime::Util qw/-nobigint
5 prime_iterator prime_iterator_object
4 use Math::Prime::Util qw/prime_iterator prime_iterator_object
65 next_prime is_prime
76 nth_prime_upper prime_precalc/;
87
1110 # Find twin primes (numbers where p and p+2 are prime)
1211
1312 # Time for the first 300k:
13 #
14 # Not iterators:
15 # 0.6s forprimes { say $l if $l+2==$_; $l=$_; } 64764841
1416 # 1.0s bin/primes.pl --twin 2 64764839
15 # 1.4s get_twin_prime_iterator2
16 # 2.3s get_twin_prime_iterator1
17 # 4.1s get_twin_prime_iterator3
18 # 6.1s get_twin_prime_iterator3 (object iterator)
19 # 7.6s get_twin_prime_iterator2 without precalc
20 # 8.4s get_twin_prime_iterator1 without precalc
21 # 10.9s get_twin_prime_iterator3 without precalc
22 # 13.1s get_twin_prime_iterator3 without precalc (object iterator)
23 # 219.8s Math::NumSeq::TwinPrimes (Perl 5.19.4 with v66)
17 #
18 # Iterators with precalc:
19 # 1.6s get_twin_prime_iterator2
20 # 2.4s get_twin_prime_iterator1
21 # 4.2s get_twin_prime_iterator3
22 # 4.5s get_twin_prime_iterator4 (object iterator)
23 #
24 # Iterators without precalc:
25 # 7.7s get_twin_prime_iterator2
26 # 8.5s get_twin_prime_iterator1
27 # 10.8s get_twin_prime_iterator3
28 # 16.7s get_twin_prime_iterator4 (object iterator)
29 #
30 # Alternatives:
31 # 251.9s Math::NumSeq::TwinPrimes (Perl 5.19.7, Math::NumSeq 67)
2432
2533 # This speeds things up, but isn't necessary.
2634 my $estimate = 5000 + int( nth_prime_upper($count) * 1.4 * log($count) );
366366 fail "BLS15: $n failed 2Q-1 > sqrt(N)" unless 2*$q-1 > $n->copy->bsqrt();
367367 my $D = $lp*$lp - 4*$lq;
368368 fail "BLS15: $n failed D != 0" unless $D != 0;
369 fail "BLS15: $n failed jacobi(D,N) = -1" unless _jacobi($D,$n) == -1;
369 fail "BLS15: $n failed jacobi(D,N) = -1" unless kronecker($D,$n) == -1;
370370 fail "BLS15: $n failed V_{m/2} mod N != 0"
371371 unless (lucas_sequence($n, $lp, $lq, $m/2))[1] != 0;
372372 fail "BLS15: $n failed V_{(N+1)/2} mod N == 0"
562562 }
563563 0;
564564 }
565
566 # Calculate Jacobi symbol (M|N)
567 sub _jacobi {
568 my($n, $m) = @_;
569 return 0 if $m <= 0 || ($m % 2) == 0;
570 my $j = 1;
571 if ($n < 0) {
572 $n = -$n;
573 $j = -$j if ($m % 4) == 3;
574 }
575 # Split loop so we can reduce n/m to non-bigints after first iteration.
576 if ($n != 0) {
577 while (($n % 2) == 0) {
578 $n >>= 1;
579 $j = -$j if ($m % 8) == 3 || ($m % 8) == 5;
580 }
581 ($n, $m) = ($m, $n);
582 $j = -$j if ($n % 4) == 3 && ($m % 4) == 3;
583 $n = $n % $m;
584 $n = int($n->bstr) if ref($n) eq 'Math::BigInt' && $n <= ''.~0;
585 $m = int($m->bstr) if ref($m) eq 'Math::BigInt' && $m <= ''.~0;
586 }
587 while ($n != 0) {
588 while (($n % 2) == 0) {
589 $n >>= 1;
590 $j = -$j if ($m % 8) == 3 || ($m % 8) == 5;
591 }
592 ($n, $m) = ($m, $n);
593 $j = -$j if ($n % 4) == 3 && ($m % 4) == 3;
594 $n = $n % $m;
595 }
596 return ($m == 1) ? $j : 0;
597 }
8989
9090 /* loop over each remaining factor, until ntofac == 0 */
9191 do {
92 while ( (n >= f*f) && (!_XS_is_prime(n)) ) {
92 //while ( (n >= f*f) && (!_XS_is_prime(n)) ) {
93 while ( (n >= f*f) && (!is_prob_prime(n)) ) {
9394 int split_success = 0;
9495 /* Adjust the number of rounds based on the number size */
95 UV const br_rounds = ((n>>29) < 100000) ? 1500 : 2000;
96 UV const br_rounds = ((n>>29) < 100000) ? 1500 : 4000;
9697 UV const sq_rounds =100000; /* 20k 91%, 40k 98%, 80k 99.9%, 120k 99.99% */
9798
9899 /* 99.7% of 32-bit, 94% of 64-bit random inputs factored here */
106107 if (verbose) printf("squfof %d\n", split_success);
107108 }
108109 /* At this point we should only have 16+ digit semiprimes. */
109 /* This p-1 gets about 2/3 of what makes it through the above */
110110 if (!split_success) {
111 split_success = pminus1_factor(n, tofac_stack+ntofac, 5000, 100000)-1;
111 split_success = pminus1_factor(n, tofac_stack+ntofac, 8000, 120000)-1;
112112 if (verbose) printf("pminus1 %d\n", split_success);
113 }
114 /* Some rounds of HOLF, good for close to perfect squares which are
115 * the worst case for the next step */
116 if (!split_success) {
117 split_success = holf_factor(n, tofac_stack+ntofac, 2000)-1;
118 if (verbose) printf("holf %d\n", split_success);
119 }
120 /* The catch-all. Should factor anything. */
121 if (!split_success) {
122 split_success = prho_factor(n, tofac_stack+ntofac, 256*1024)-1;
123 if (verbose) printf("long prho %d\n", split_success);
113 /* Get the stragglers */
114 if (!split_success) {
115 split_success = prho_factor(n, tofac_stack+ntofac, 120000)-1;
116 if (verbose) printf("long prho %d\n", split_success);
117 if (!split_success) {
118 split_success = pbrent_factor(n, tofac_stack+ntofac, 500000, 7)-1;
119 if (verbose) printf("long pbrent %d\n", split_success);
120 }
121 }
124122 }
125123
126124 if (split_success) {
130128 croak("bad factor\n");
131129 n = tofac_stack[ntofac]; /* Set n to the other one */
132130 } else {
133 /* Factor via trial division. Nothing should make it here. */
131 /* Factor via trial division. Nothing should ever get here. */
134132 UV m = f % 30;
135133 UV limit = isqrt(n);
136134 if (verbose) printf("doing trial on %"UVuf"\n", n);
660658 }
661659
662660 /* Simple Williams p+1 */
663 static void pp1_pow(UV *cX, unsigned long exp, UV n)
661 static void pp1_pow(UV *cX, UV exp, UV n)
664662 {
665663 UV X0 = *cX;
666664 UV X = *cX;
667665 UV Y = mulsubmod(X, X, 2, n);
668 unsigned long bit = 1UL << (clz(exp)-1);
666 UV bit = UVCONST(1) << (clz(exp)-1);
669667 while (bit) {
670668 UV T = mulsubmod(X, Y, X0, n);
671669 if ( exp & bit ) {
909907 }
910908
911909 UV dlp_trial(UV a, UV g, UV p, UV maxrounds) {
912 UV t, n = 1;
910 UV t, k = 1;
913911 if (maxrounds > p) maxrounds = p;
914 for (n = 1; n < maxrounds; n++) {
915 t = powmod(g, n, p);
912 for (k = 1; k < maxrounds; k++) {
913 t = powmod(g, k, p);
916914 if (t == a)
917 return n;
915 return k;
918916 }
919917 return 0;
920918 }
939937 pollard_rho_cycle(u,v,w,p,n,a,g); /* xi, ai, bi */
940938 pollard_rho_cycle(U,V,W,p,n,a,g);
941939 pollard_rho_cycle(U,V,W,p,n,a,g); /* x2i, a2i, b2i */
942 if (verbose > 3) printf( "%3lu %4lu %3lu %3lu %4lu %3lu %3lu\n", i, u, v, w, U, V, W );
940 if (verbose > 3) printf( "%3"UVuf" %4"UVuf" %3"UVuf" %3"UVuf" %4"UVuf" %3"UVuf" %3"UVuf"\n", i, u, v, w, U, V, W );
943941 if (u == U) {
944942 UV r1, r2, k;
945943 r1 = submod(v, V, n);
950948 r2 = submod(W, w, n);
951949 k = divmod(r2, r1, n);
952950 if (powmod(g,k,p) != a) {
953 if (verbose > 2) printf("r1 = %lu r2 = %lu k = %lu\n", r1, r2, k);
954 if (verbose) printf("Incorrect DLP Rho solution: %lu\n", k);
951 if (verbose > 2) printf("r1 = %"UVuf" r2 = %"UVuf" k = %"UVuf"\n", r1, r2, k);
952 if (verbose) printf("Incorrect DLP Rho solution: %"UVuf"\n", k);
955953 return 0;
956954 }
957 if (verbose) printf("DLP Rho solution found after %lu steps\n", i);
955 if (verbose) printf("DLP Rho solution found after %"UVuf" steps\n", i);
958956 return k;
959957 }
960958 }
44
55 BEGIN {
66 $Math::Prime::Util::ECAffinePoint::AUTHORITY = 'cpan:DANAJ';
7 $Math::Prime::Util::ECAffinePoint::VERSION = '0.36';
7 $Math::Prime::Util::ECAffinePoint::VERSION = '0.37';
88 }
99
1010 BEGIN {
198198
199199 =head1 VERSION
200200
201 Version 0.36
201 Version 0.37
202202
203203
204204 =head1 SYNOPSIS
44
55 BEGIN {
66 $Math::Prime::Util::ECProjectivePoint::AUTHORITY = 'cpan:DANAJ';
7 $Math::Prime::Util::ECProjectivePoint::VERSION = '0.36';
7 $Math::Prime::Util::ECProjectivePoint::VERSION = '0.37';
88 }
99
1010 BEGIN {
206206
207207 =head1 VERSION
208208
209 Version 0.36
209 Version 0.37
210210
211211
212212 =head1 SYNOPSIS
33
44 BEGIN {
55 $Math::Prime::Util::MemFree::AUTHORITY = 'cpan:DANAJ';
6 $Math::Prime::Util::MemFree::VERSION = '0.36';
6 $Math::Prime::Util::MemFree::VERSION = '0.37';
77 }
88
99 use base qw( Exporter );
4343
4444 =head1 VERSION
4545
46 Version 0.36
46 Version 0.37
4747
4848
4949 =head1 SYNOPSIS
44
55 BEGIN {
66 $Math::Prime::Util::PP::AUTHORITY = 'cpan:DANAJ';
7 $Math::Prime::Util::PP::VERSION = '0.36';
7 $Math::Prime::Util::PP::VERSION = '0.37';
88 }
99
1010 BEGIN {
3939 use constant BTWO => Math::BigInt->new(2);
4040 use constant B_PRIM759 => Math::BigInt->new("64092011671807087969");
4141 use constant B_PRIM235 => Math::BigInt->new("30");
42 use constant PI_TIMES_8 => 25.13274122871834590770114707;
4243 }
4344
4445 {
7172 }
7273
7374 sub _bigint_to_int {
74 return (OLD_PERL_VERSION) ? unpack(UVPACKLET,pack(UVPACKLET,$_[0]->bstr))
75 : int($_[0]->bstr);
76 }
75 return (OLD_PERL_VERSION) ? unpack(UVPACKLET,pack(UVPACKLET,"$_[0]"))
76 : int("$_[0]");
77 }
78
79 sub _upgrade_to_float {
80 do { require Math::BigFloat; Math::BigFloat->import(); }
81 if !defined $Math::BigFloat::VERSION;
82 return Math::BigFloat->new($_[0]);
83 }
84
85 # Get the accuracy of variable x, or the max default from BigInt/BigFloat
86 # One might think to use ref($x)->accuracy() but numbers get upgraded and
87 # downgraded willy-nilly, and it will do the wrong thing from the user's
88 # perspective.
89 sub _find_big_acc {
90 my($x) = @_;
91
92 $b = $x->accuracy();
93 return $b if defined $b;
94
95 my ($i,$f) = (Math::BigInt->accuracy(), Math::BigFloat->accuracy());
96 return (($i > $f) ? $i : $f) if defined $i && defined $f;
97 return $i if defined $i;
98 return $f if defined $f;
99
100 ($i,$f) = (Math::BigInt->div_scale(), Math::BigFloat->div_scale());
101 return (($i > $f) ? $i : $f) if defined $i && defined $f;
102 return $i if defined $i;
103 return $f if defined $f;
104 return 18;
105 }
106
77107
78108 sub _validate_num {
79109 my($n, $min, $max) = @_;
123153 101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,
124154 193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,
125155 293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,
126 409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499);
127 my @_prime_count_small = (
128 0,0,1,2,2,3,3,4,4,4,4,5,5,6,6,6,6,7,7,8,8,8,8,9,9,9,9,9,9,10,10,
129 11,11,11,11,11,11,12,12,12,12,13,13,14,14,14,14,15,15,15,15,15,15,
130 16,16,16,16,16,16,17,17,18,18,18,18,18,18,19);
156 409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509);
131157 my @_prime_next_small = (
132158 2,2,3,5,5,7,7,11,11,11,11,13,13,17,17,17,17,19,19,23,23,23,23,
133159 29,29,29,29,29,29,31,31,37,37,37,37,37,37,41,41,41,41,43,43,47,
137163 my @_prime_indices = (1, 7, 11, 13, 17, 19, 23, 29);
138164 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);
139165 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);
166
167 sub _tiny_prime_count {
168 my($n) = @_;
169 return if $n >= $_primes_small[-1];
170 my $j = $#_primes_small;
171 my $i = 1 + ($n >> 4);
172 while ($i < $j) {
173 my $mid = ($i+$j)>>1;
174 if ($_primes_small[$mid] <= $n) { $i = $mid+1; }
175 else { $j = $mid; }
176 }
177 return $i-1;
178 }
140179
141180 sub _is_prime7 { # n must not be divisible by 2, 3, or 5
142181 my($n) = @_;
211250
212251 sub is_prime {
213252 my($n) = @_;
214 return 0 if defined $n && int($n) < 0;
253 return 0 if int($n) < 0;
215254 _validate_positive_integer($n);
216255
217256 if (ref($n) eq 'Math::BigInt') {
370409 }
371410
372411 sub primes {
373 my $optref = (ref $_[0] eq 'HASH') ? shift : {};
374 croak "no parameters to primes" unless scalar @_ > 0;
375 croak "too many parameters to primes" unless scalar @_ <= 2;
376 my $low = (@_ == 2) ? shift : 2;
377 my $high = shift;
412 my($low,$high) = @_;
413 if (scalar @_ > 1) {
414 _validate_positive_integer($low);
415 _validate_positive_integer($high);
416 } else {
417 ($low,$high) = (2, $low);
418 _validate_positive_integer($high);
419 }
378420 my $sref = [];
379
380 _validate_positive_integer($low);
381 _validate_positive_integer($high);
382
383421 return $sref if ($low > $high) || ($high < 2);
384
385 # Ignore method options in this code
386422
387423 # At some point even the pretty-fast pure perl sieve is going to be a
388424 # dog, and we should move to trials. This is typical with a small range
493529 #$d*30+$m;
494530 }
495531
532 sub partitions {
533 my $n = shift;
534
535 my $d = int(sqrt($n+1));
536 my @pent = (1, map { (($_*(3*$_+1))>>1, (($_+1)*(3*$_+2))>>1) } 1 .. $d);
537 my @part = (Math::BigInt->bone);
538 foreach my $j (scalar @part .. $n) {
539 my ($psum1, $psum2, $k) = (Math::BigInt->bzero, Math::BigInt->bzero, 1);
540 foreach my $p (@pent) {
541 last if $p > $j;
542 if ((++$k) & 2) { $psum1->badd( $part[ $j - $p ] ); }
543 else { $psum2->badd( $part[ $j - $p ] ); }
544 }
545 $part[$j] = $psum1 - $psum2;
546 }
547 return $part[$n];
548 }
549
550 sub primorial {
551 my $n = shift;
552
553 my $max = (MPU_32BIT) ? 29 : (OLD_PERL_VERSION) ? 43 : 53;
554 my $pn = (ref($_[0]) eq 'Math::BigInt') ? $_[0]->copy->bone()
555 : ($n >= $max) ? Math::BigInt->bone()
556 : 1;
557 if (ref($pn) eq 'Math::BigInt') {
558 my $start = 2;
559 if ($n >= 97) {
560 $start = 101;
561 $pn->bdec->badd(Math::BigInt->new("2305567963945518424753102147331756070"));
562 }
563 my @plist = @{primes($start,$n)};
564 while (@plist > 2 && $plist[2] < 1625) {
565 $pn->bmul( Math::BigInt->new(shift(@plist)*shift(@plist)*shift(@plist)) );
566 }
567 while (@plist > 1 && $plist[1] < 65536) {
568 $pn->bmul( Math::BigInt->new(shift(@plist)*shift(@plist)) );
569 }
570 $pn->bmul($_) for @plist;
571 } else {
572 foreach my $p (@{primes($n)}) { $pn *= $p; }
573 }
574 return $pn;
575 }
576
577 sub consecutive_integer_lcm {
578 my $n = shift;
579
580 my $max = (MPU_32BIT) ? 22 : (OLD_PERL_VERSION) ? 37 : 46;
581 my $pn = ref($n) ? ref($n)->new(1) : ($n >= $max) ? Math::BigInt->bone() : 1;
582 for (my $p = 2; $p <= $n; $p = next_prime($p)) {
583 my($p_power, $pmin) = ($p, int($n/$p));
584 $p_power *= $p while $p_power <= $pmin;
585 $pn *= $p_power;
586 }
587 $pn = _bigint_to_int($pn) if $pn <= ''.~0;
588 return $pn;
589 }
590
496591 sub jordan_totient {
497592 my($k, $n) = @_;
498 _validate_num($k) || _validate_positive_integer($k);
499593 return ($n == 1) ? 1 : 0 if $k == 0;
500594 return euler_phi($n) if $k == 1;
501 return 0 if defined $n && $n < 0; # Following SAGE's logic here.
502 _validate_num($n) || _validate_positive_integer($n);
595 return 0 if $n < 0;
503596 return ($n == 1) ? 1 : 0 if $n <= 1;
504597
505598 my @pe = Math::Prime::Util::factor_exp($n);
517610 }
518611
519612 sub euler_phi {
613 return euler_phi_range(@_) if scalar @_ > 1;
520614 my($n) = @_;
521615 return 0 if $n < 0;
522616 return $n if $n <= 1;
566660 }
567661
568662 sub moebius {
663 return moebius_range(@_) if scalar @_ > 1;
569664 my($n) = @_;
570665 return ($n == 1) ? 1 : 0 if $n <= 1;
571666 return 0 if ($n >= 49) && (!($n % 4) || !($n % 9) || !($n % 25) || !($n%49) );
613708 return @mu;
614709 }
615710
711 sub mertens {
712 my($n) = @_;
713 # This is the most basic Deléglise and Rivat algorithm. u = n^1/2
714 # and no segmenting is done. Their algorithm uses u = n^1/3, breaks
715 # the summation into two parts, and calculates those in segments. Their
716 # computation time growth is half of this code.
717 return $n if $n <= 1;
718 my $u = int(sqrt($n));
719 my @mu = (0, Math::Prime::Util::moebius(1, $u)); # Hold values of mu for 0-u
720 my $musum = 0;
721 my @M = map { $musum += $_; } @mu; # Hold values of M for 0-u
722 my $sum = $M[$u];
723 foreach my $m (1 .. $u) {
724 next if $mu[$m] == 0;
725 my $inner_sum = 0;
726 my $lower = int($u/$m) + 1;
727 my $last_nmk = int($n/($m*$lower));
728 my ($denom, $this_k, $next_k) = ($m, 0, int($n/($m*1)));
729 for my $nmk (1 .. $last_nmk) {
730 $denom += $m;
731 $this_k = int($n/$denom);
732 next if $this_k == $next_k;
733 ($this_k, $next_k) = ($next_k, $this_k);
734 $inner_sum += $M[$nmk] * ($this_k - $next_k);
735 }
736 $sum -= $mu[$m] * $inner_sum;
737 }
738 return $sum;
739 }
740
741 sub liouville {
742 my($n) = @_;
743 my $l = (-1) ** scalar factor($n);
744 return $l;
745 }
746
747 # Exponential of Mangoldt function (A014963).
748 # Return p if n = p^m [p prime, m >= 1], 1 otherwise.
749 sub exp_mangoldt {
750 my($n) = @_;
751 return 1 if defined $n && $n <= 1; # n <= 1
752 return 2 if ($n & ($n-1)) == 0; # n power of 2
753 return 1 unless $n & 1; # even n can't be p^m
754
755 my @pe = Math::Prime::Util::factor_exp($n);
756 return 1 if scalar @pe > 1;
757 return $pe[0]->[0];
758 }
759
760 sub carmichael_lambda {
761 my($n) = @_;
762 return euler_phi($n) if $n < 8; # = phi(n) for n < 8
763 return euler_phi($n)/2 if ($n & ($n-1)) == 0; # = phi(n)/2 for 2^k, k>2
764
765 my @pe = Math::Prime::Util::factor_exp($n);
766 $pe[0]->[1]-- if $pe[0]->[0] == 2 && $pe[0]->[1] > 2;
767
768 my $lcm = Math::BigInt::blcm(
769 map { $_->[0]->copy->bpow($_->[1]->copy->bdec)->bmul($_->[0]->copy->bdec) }
770 map { [ map { Math::BigInt->new("$_") } @$_ ] }
771 @pe
772 );
773 $lcm = _bigint_to_int($lcm) if $lcm->bacmp(''.~0) <= 0;
774 return $lcm;
775 }
776
777
616778 my @_ds_overflow = # We'll use BigInt math if the input is larger than this.
617779 (~0 > 4294967295)
618780 ? (124, 3000000000000000000, 3000000000, 2487240, 64260, 7026)
619781 : ( 50, 845404560, 52560, 1548, 252, 84);
620782 sub divisor_sum {
621783 my($n, $k) = @_;
622 return 1 if defined $n && $n == 1;
784 return 1 if $n == 1;
623785
624786 if (defined $k && ref($k) eq 'CODE') {
625787 my $sum = $n-$n;
626 if (ref($n) eq 'Math::BigInt') {
627 # If the original number was a bigint, make sure all divisors are.
628 foreach my $d (Math::Prime::Util::divisors($n)) {
629 $sum += $k->(Math::BigInt->new("$d"));
630 }
631 } else {
632 foreach my $d (Math::Prime::Util::divisors($n)) {
633 $sum += $k->($d);
634 }
788 my $refn = ref($n);
789 foreach my $d (Math::Prime::Util::divisors($n)) {
790 $sum += $k->( $refn ? $refn->new("$d") : $d );
635791 }
636792 return $sum;
637793 }
9091065 $prime;
9101066 }
9111067
1068 # The nth prime will be less or equal to this number
1069 sub nth_prime_upper {
1070 my($n) = @_;
1071 _validate_positive_integer($n);
1072
1073 return $_primes_small[$n] if $n <= $#_primes_small;
1074
1075 $n = _upgrade_to_float($n) if $n > MPU_MAXPRIMEIDX || $n > 2**45;
1076
1077 my $flogn = log($n);
1078 my $flog2n = log($flogn); # Note distinction between log_2(n) and log^2(n)
1079
1080 my $upper;
1081 if ($n >= 688383) { # Dusart 2010 page 2
1082 $upper = $n * ( $flogn + $flog2n - 1.0 + (($flog2n-2.00)/$flogn) );
1083 } elsif ($n >= 178974) { # Dusart 2010 page 7
1084 $upper = $n * ( $flogn + $flog2n - 1.0 + (($flog2n-1.95)/$flogn) );
1085 } elsif ($n >= 39017) { # Dusart 1999 page 14
1086 $upper = $n * ( $flogn + $flog2n - 0.9484 );
1087 } elsif ($n >= 6) { # Modified Robin 1983, for 6-39016 only
1088 $upper = $n * ( $flogn + 0.6000 * $flog2n );
1089 } else {
1090 $upper = $n * ( $flogn + $flog2n );
1091 }
1092
1093 return int($upper + 1.0);
1094 }
1095
1096 # The nth prime will be greater than or equal to this number
1097 sub nth_prime_lower {
1098 my($n) = @_;
1099 _validate_num($n) || _validate_positive_integer($n);
1100
1101 return $_primes_small[$n] if $n <= $#_primes_small;
1102
1103 $n = _upgrade_to_float($n) if $n > MPU_MAXPRIMEIDX || $n > 2**45;
1104
1105 my $flogn = log($n);
1106 my $flog2n = log($flogn); # Note distinction between log_2(n) and log^2(n)
1107
1108 # Dusart 1999 page 14, for all n >= 2
1109 #my $lower = $n * ($flogn + $flog2n - 1.0 + (($flog2n-2.25)/$flogn));
1110 # Dusart 2010 page 2, for all n >= 3
1111 my $lower = $n * ($flogn + $flog2n - 1.0 + (($flog2n-2.10)/$flogn));
1112
1113 return int($lower);
1114 }
1115
1116 sub nth_prime_approx {
1117 my($n) = @_;
1118 _validate_num($n) || _validate_positive_integer($n);
1119
1120 return $_primes_small[$n] if $n <= $#_primes_small;
1121
1122 $n = _upgrade_to_float($n)
1123 if ref($n) eq 'Math::BigInt' || $n >= MPU_MAXPRIMEIDX;
1124
1125 my $flogn = log($n);
1126 my $flog2n = log($flogn);
1127
1128 # Cipolla 1902:
1129 # m=0 fn * ( flogn + flog2n - 1 );
1130 # m=1 + ((flog2n - 2)/flogn) );
1131 # m=2 - (((flog2n*flog2n) - 6*flog2n + 11) / (2*flogn*flogn))
1132 # + O((flog2n/flogn)^3)
1133 #
1134 # Shown in Dusart 1999 page 12, as well as other sources such as:
1135 # http://www.emis.de/journals/JIPAM/images/153_02_JIPAM/153_02.pdf
1136 # where the main issue you run into is that you're doing polynomial
1137 # interpolation, so it oscillates like crazy with many high-order terms.
1138 # Hence I'm leaving it at m=2.
1139
1140 my $approx = $n * ( $flogn + $flog2n - 1
1141 + (($flog2n - 2)/$flogn)
1142 - ((($flog2n*$flog2n) - 6*$flog2n + 11) / (2*$flogn*$flogn))
1143 );
1144
1145 # Apply a correction to help keep values close.
1146 my $order = $flog2n/$flogn;
1147 $order = $order*$order*$order * $n;
1148
1149 if ($n < 259) { $approx += 10.4 * $order; }
1150 elsif ($n < 775) { $approx += 7.52* $order; }
1151 elsif ($n < 1271) { $approx += 5.6 * $order; }
1152 elsif ($n < 2000) { $approx += 5.2 * $order; }
1153 elsif ($n < 4000) { $approx += 4.3 * $order; }
1154 elsif ($n < 12000) { $approx += 3.0 * $order; }
1155 elsif ($n < 150000) { $approx += 2.1 * $order; }
1156 elsif ($n < 200000000) { $approx += 0.0 * $order; }
1157 else { $approx += -0.010 * $order; }
1158 # $approx = -0.025 is better for the last, but it gives problems with some
1159 # other code that always wants the asymptotic approximation to be >= actual.
1160
1161 return int($approx + 0.5);
1162 }
1163
1164 #############################################################################
1165
1166 sub prime_count_approx {
1167 my($x) = @_;
1168 _validate_num($x) || _validate_positive_integer($x);
1169
1170 # Turn on high precision FP if they gave us a big number.
1171 $x = _upgrade_to_float($x) if ref($_[0]) eq 'Math::BigInt';
1172 # Method 10^10 %error 10^19 %error
1173 # ----------------- ------------ ------------
1174 # n/(log(n)-1) .22% .06%
1175 # average bounds .01% .0002%
1176 # li(n) .0007% .00000004%
1177 # li(n)-li(n^.5)/2 .0004% .00000001%
1178 # R(n) .0004% .00000001%
1179 #
1180 # Also consider: http://trac.sagemath.org/sage_trac/ticket/8135
1181
1182 # my $result = int( (prime_count_upper($x) + prime_count_lower($x)) / 2);
1183 # my $result = int( LogarithmicIntegral($x) );
1184 # my $result = int(LogarithmicIntegral($x) - LogarithmicIntegral(sqrt($x))/2);
1185 # my $result = RiemannR($x) + 0.5;
1186
1187 # Sadly my Perl RiemannR function is really slow for big values. If MPFR
1188 # is available, then use it -- it rocks. Otherwise, switch to LiCorr for
1189 # very big values. This is hacky and shouldn't be necessary.
1190 my $result;
1191 if ( $x < 1e36 || _MPFR_available() ) {
1192 if (ref($x) eq 'Math::BigFloat') {
1193 # Make sure we get enough accuracy, and also not too much more than needed
1194 $x->accuracy(length($x->bfloor->bstr())+2);
1195 }
1196 $result = RiemannR($x) + 0.5;
1197 } else {
1198 $result = int(LogarithmicIntegral($x) - LogarithmicIntegral(sqrt($x))/2);
1199 }
1200
1201 return Math::BigInt->new($result->bfloor->bstr()) if ref($result) eq 'Math::BigFloat';
1202 return int($result);
1203 }
1204
1205 sub prime_count_lower {
1206 my($x) = @_;
1207 _validate_num($x) || _validate_positive_integer($x);
1208
1209 return _tiny_prime_count($x) if $x < $_primes_small[-1];
1210
1211 $x = _upgrade_to_float($x)
1212 if ref($x) eq 'Math::BigInt' || ref($_[0]) eq 'Math::BigInt';
1213
1214 my $flogx = log($x);
1215
1216 # Chebyshev: 1*x/logx x >= 17
1217 # Rosser & Schoenfeld: x/(logx-1/2) x >= 67
1218 # Dusart 1999: x/logx*(1+1/logx+1.8/logxlogx) x >= 32299
1219 # Dusart 2010: x/logx*(1+1/logx+2.0/logxlogx) x >= 88783
1220 # The Dusart (1999 or 2010) bounds are far, far better than the others.
1221
1222 my $result;
1223 if ($x > 1000_000_000_000 && Math::Prime::Util::prime_get_config()->{'assume_rh'}) {
1224 # Schoenfeld bound
1225 my $lix = LogarithmicIntegral($x);
1226 my $sqx = sqrt($x);
1227 if (ref($x) eq 'Math::BigFloat') {
1228 my $xdigits = _find_big_acc($x);
1229 $result = $lix - (($sqx*$flogx) / (Math::BigFloat->bpi($xdigits)*8));
1230 } else {
1231 $result = $lix - (($sqx*$flogx) / PI_TIMES_8);
1232 }
1233 } elsif ($x < 599) {
1234 $result = $x / ($flogx - 0.7); # For smaller numbers this works out well.
1235 } else {
1236 my $a;
1237 # Hand tuned for small numbers (< 60_000M)
1238 if ($x < 2700) { $a = 0.30; }
1239 elsif ($x < 5500) { $a = 0.90; }
1240 elsif ($x < 19400) { $a = 1.30; }
1241 elsif ($x < 32299) { $a = 1.60; }
1242 elsif ($x < 176000) { $a = 1.80; }
1243 elsif ($x < 315000) { $a = 2.10; }
1244 elsif ($x < 1100000) { $a = 2.20; }
1245 elsif ($x < 4500000) { $a = 2.31; }
1246 elsif ($x < 233000000) { $a = 2.36; }
1247 elsif ($x < 5433800000) { $a = 2.32; }
1248 elsif ($x <60000000000) { $a = 2.15; }
1249 else { $a = 2.00; } # Dusart 2010, page 2
1250 $result = ($x/$flogx) * (1.0 + 1.0/$flogx + $a/($flogx*$flogx));
1251 }
1252
1253 return Math::BigInt->new($result->bfloor->bstr()) if ref($result) eq 'Math::BigFloat';
1254 return int($result);
1255 }
1256
1257 sub prime_count_upper {
1258 my($x) = @_;
1259 _validate_num($x) || _validate_positive_integer($x);
1260
1261 # Give an exact answer for what we have in our little table.
1262 return _tiny_prime_count($x) if $x < $_primes_small[-1];
1263
1264 $x = _upgrade_to_float($x)
1265 if ref($x) eq 'Math::BigInt' || ref($_[0]) eq 'Math::BigInt';
1266
1267 # Chebyshev: 1.25506*x/logx x >= 17
1268 # Rosser & Schoenfeld: x/(logx-3/2) x >= 67
1269 # Dusart 1999: x/logx*(1+1/logx+2.51/logxlogx) x >= 355991
1270 # Dusart 2010: x/logx*(1+1/logx+2.334/logxlogx) x >= 2_953_652_287
1271
1272 # As with the lower bounds, Dusart bounds are best by far.
1273
1274 # Another possibility here for numbers under 3000M is to use Li(x)
1275 # minus a correction.
1276
1277 my $flogx = log($x);
1278
1279 my $result;
1280 if ($x > 10000_000_000_000 && Math::Prime::Util::prime_get_config()->{'assume_rh'}) {
1281 # Schoenfeld bound
1282 my $lix = LogarithmicIntegral($x);
1283 my $sqx = sqrt($x);
1284 if (ref($x) eq 'Math::BigFloat') {
1285 my $xdigits = _find_big_acc($x);
1286 $result = $lix + (($sqx*$flogx) / (Math::BigFloat->bpi($xdigits)*8));
1287 } else {
1288 $result = $lix + (($sqx*$flogx) / PI_TIMES_8);
1289 }
1290 } elsif ($x < 1621) { $result = ($x / ($flogx - 1.048)) + 1.0; }
1291 elsif ($x < 5000) { $result = ($x / ($flogx - 1.071)) + 1.0; }
1292 elsif ($x < 15900) { $result = ($x / ($flogx - 1.098)) + 1.0; }
1293 else {
1294 my $a;
1295 # Hand tuned for small numbers (< 60_000M)
1296 if ($x < 24000) { $a = 2.30; }
1297 elsif ($x < 59000) { $a = 2.48; }
1298 elsif ($x < 350000) { $a = 2.52; }
1299 elsif ($x < 355991) { $a = 2.54; }
1300 elsif ($x < 356000) { $a = 2.51; }
1301 elsif ($x < 3550000) { $a = 2.50; }
1302 elsif ($x < 3560000) { $a = 2.49; }
1303 elsif ($x < 5000000) { $a = 2.48; }
1304 elsif ($x < 8000000) { $a = 2.47; }
1305 elsif ($x < 13000000) { $a = 2.46; }
1306 elsif ($x < 18000000) { $a = 2.45; }
1307 elsif ($x < 31000000) { $a = 2.44; }
1308 elsif ($x < 41000000) { $a = 2.43; }
1309 elsif ($x < 48000000) { $a = 2.42; }
1310 elsif ($x < 119000000) { $a = 2.41; }
1311 elsif ($x < 182000000) { $a = 2.40; }
1312 elsif ($x < 192000000) { $a = 2.395; }
1313 elsif ($x < 213000000) { $a = 2.390; }
1314 elsif ($x < 271000000) { $a = 2.385; }
1315 elsif ($x < 322000000) { $a = 2.380; }
1316 elsif ($x < 400000000) { $a = 2.375; }
1317 elsif ($x < 510000000) { $a = 2.370; }
1318 elsif ($x < 682000000) { $a = 2.367; }
1319 elsif ($x < 2953652287) { $a = 2.362; }
1320 else { $a = 2.334; } # Dusart 2010, page 2
1321 #elsif ($x <60000000000) { $a = 2.362; }
1322 #else { $a = 2.51; } # Dusart 1999, page 14
1323
1324 # Old versions of Math::BigFloat will do the Wrong Thing with this.
1325 $result = ($x/$flogx) * (1.0 + 1.0/$flogx + $a/($flogx*$flogx)) + 1.0;
1326 }
1327
1328 return Math::BigInt->new($result->bfloor->bstr()) if ref($result) eq 'Math::BigFloat';
1329 return int($result);
1330 }
1331
1332
1333 #############################################################################
1334
9121335 sub _mulmod {
9131336 my($x, $y, $n) = @_;
9141337 return (($x * $y) % $n) if ($x|$y) < MPU_HALFWORD;
10201443
10211444 sub is_pseudoprime {
10221445 my($n, $base) = @_;
1023 return 0 if defined $n && int($n) < 0;
1446 return 0 if int($n) < 0;
10241447 _validate_positive_integer($n);
1025 _validate_positive_integer($base);
10261448
10271449 if ($n < 5) { return ($n == 2) || ($n == 3) ? 1 : 0; }
10281450 croak "Base $base is invalid" if $base < 2;
10931515
10941516 sub is_strong_pseudoprime {
10951517 my($n, @bases) = @_;
1096 return 0 if defined $n && int($n) < 0;
1518 return 0 if int($n) < 0;
10971519 _validate_positive_integer($n);
1098 croak "No bases given to miller_rabin" unless @bases;
10991520
11001521 return 0+($n >= 2) if $n < 4;
11011522 return 0 if ($n % 2) == 0;
12331654
12341655 sub znorder {
12351656 my($a, $n) = @_;
1236 _validate_num($a) || _validate_positive_integer($a);
1237 _validate_num($n) || _validate_positive_integer($n);
12381657 return if $n <= 0;
12391658 return (undef,1)[$a] if $a <= 1;
12401659 return 1 if $n == 1;
12751694 sub znlog {
12761695 my ($a,$g,$p) =
12771696 map { ref($_) eq 'Math::BigInt' ? $_ : Math::BigInt->new("$_") } @_;
1278 for (my $n = BONE->copy; $n < $p; $n->binc) {
1279 my $t = $g->copy->bmodpow($n, $p);
1697 for (my $k = BONE->copy; $k < $p; $k->binc) {
1698 my $t = $g->copy->bmodpow($k, $p);
12801699 if ($t == $a) {
1281 $n = _bigint_to_int($n) if $n->bacmp(''.~0) <= 0;
1282 return $n;
1700 $k = _bigint_to_int($k) if $k->bacmp(''.~0) <= 0;
1701 return $k;
12831702 }
12841703 }
12851704 return;
12861705 }
1706
1707 sub znprimroot {
1708 my($n) = @_;
1709 $n = -$n if $n < 0;
1710 if ($n <= 4) {
1711 return if $n == 0;
1712 return $n-1;
1713 }
1714 return if $n % 4 == 0;
1715 my $a = 1;
1716 my $phi = euler_phi($n);
1717 # Check that a primitive root exists.
1718 return if !is_prob_prime($n) && $phi != Math::Prime::Util::carmichael_lambda($n);
1719 my @exp = map { Math::BigInt->new("$_") }
1720 map { int($phi/$_->[0]) }
1721 Math::Prime::Util::factor_exp($phi);
1722 #print "phi: $phi factors: ", join(",",factor($phi)), "\n";
1723 #print " exponents: ", join(",", @exp), "\n";
1724 my $bign = (ref($n) eq 'Math::BigInt') ? $n : Math::BigInt->new("$n");
1725 while (1) {
1726 my $fail = 0;
1727 do { $a++ } while kronecker($a,$n) == 0;
1728 return if $a >= $n;
1729 foreach my $f (@exp) {
1730 if ( Math::BigInt->new($a)->bmodpow($f, $bign)->is_one ) {
1731 $fail = 1;
1732 last;
1733 }
1734 }
1735 return $a if !$fail;
1736 }
1737 }
1738
12871739
12881740 # Find first D in sequence (5,-7,9,-11,13,-15,...) where (D|N) == -1
12891741 sub _lucas_selfridge_params {
14161868
14171869 sub is_lucas_pseudoprime {
14181870 my($n) = @_;
1419 return 0 if defined $n && int($n) < 0;
1420 _validate_positive_integer($n);
14211871
14221872 return 0+($n >= 2) if $n < 4;
14231873 return 0 if ($n % 2) == 0 || _is_perfect_square($n);
14321882
14331883 sub is_strong_lucas_pseudoprime {
14341884 my($n) = @_;
1435 return 0 if defined $n && int($n) < 0;
1436 _validate_positive_integer($n);
14371885
14381886 return 0+($n >= 2) if $n < 4;
14391887 return 0 if ($n % 2) == 0 || _is_perfect_square($n);
14631911
14641912 sub is_extra_strong_lucas_pseudoprime {
14651913 my($n) = @_;
1466 return 0 if defined $n && int($n) < 0;
1467 _validate_positive_integer($n);
14681914
14691915 return 0+($n >= 2) if $n < 4;
14701916 return 0 if ($n % 2) == 0 || _is_perfect_square($n);
14951941
14961942 sub is_almost_extra_strong_lucas_pseudoprime {
14971943 my($n, $increment) = @_;
1498 return 0 if defined $n && int($n) < 0;
1499 _validate_positive_integer($n);
1500 if (defined $increment) {
1501 _validate_positive_integer($increment, 1, 256);
1502 } else {
1503 $increment = 1;
1504 }
1944 $increment = 1 unless defined $increment;
15051945
15061946 return 0+($n >= 2) if $n < 4;
15071947 return 0 if ($n % 2) == 0 || _is_perfect_square($n);
15401980
15411981 sub is_frobenius_underwood_pseudoprime {
15421982 my($n) = @_;
1543 return 0 if defined $n && int($n) < 0;
1544 _validate_positive_integer($n);
15451983 return 0+($n >= 2) if $n < 4;
15461984 return 0 if ($n % 2) == 0 || _is_perfect_square($n);
15471985
16582096
16592097 sub is_aks_prime {
16602098 my $n = shift;
1661 return 0 if defined $n && int($n) < 0;
1662 _validate_positive_integer($n);
1663
1664 return 0 if $n < 2;
1665 return 0 if _is_perfect_power($n);
2099 return 0 if $n < 2 || _is_perfect_power($n);
16662100
16672101 my($log2n, $limit);
16682102 if ($n > 2**48) {
17272161 while ( !($_[0] % 3) ) { push @factors, 3; $_[0] = int($_[0] / 3); }
17282162 while ( !($_[0] % 5) ) { push @factors, 5; $_[0] = int($_[0] / 5); }
17292163 } else {
2164 # Without this, the bdivs will try to convert the results to BigFloat
2165 # and lose precision.
2166 $_[0]->upgrade(undef) if ref($_[0]) && $_[0]->upgrade();
17302167 if (!Math::BigInt::bgcd($_[0], B_PRIM235)->is_one) {
17312168 while ( $_[0]->is_even) { push @factors, 2; $_[0]->brsft(BONE); }
17322169 foreach my $div (3, 5) {
19212358
19222359 sub prho_factor {
19232360 my($n, $rounds, $pa) = @_;
1924 _validate_positive_integer($n);
19252361 $rounds = 4*1024*1024 unless defined $rounds;
19262362 $pa = 3 unless defined $pa;
19272363
19912427
19922428 sub pbrent_factor {
19932429 my($n, $rounds, $pa) = @_;
1994 _validate_positive_integer($n);
19952430 $rounds = 4*1024*1024 unless defined $rounds;
19962431 $pa = 3 unless defined $pa;
19972432
20722507
20732508 sub pminus1_factor {
20742509 my($n, $B1, $B2) = @_;
2075 _validate_positive_integer($n);
20762510
20772511 my @factors = _basic_factor($n);
20782512 return @factors if $n < 4;
22212655
22222656 sub holf_factor {
22232657 my($n, $rounds, $startrounds) = @_;
2224 _validate_positive_integer($n);
22252658 $rounds = 64*1024*1024 unless defined $rounds;
22262659 $startrounds = 1 unless defined $startrounds;
22272660 $startrounds = 1 if $startrounds < 1;
22682701
22692702 sub fermat_factor {
22702703 my($n, $rounds) = @_;
2271 _validate_positive_integer($n);
22722704 $rounds = 64*1024*1024 unless defined $rounds;
22732705
22742706 my @factors = _basic_factor($n);
23182750
23192751 sub ecm_factor {
23202752 my($n, $B1, $B2, $ncurves) = @_;
2321 _validate_positive_integer($n);
23222753
23232754 my @factors = _basic_factor($n);
23242755 return @factors if $n < 4;
23722803 # }
23732804 #}
23742805
2375 if (!defined $Math::Prime::Util::ECProjectivePoint::VERSION) {
2376 eval { require Math::Prime::Util::ECProjectivePoint; 1; }
2377 or do { croak "Cannot load Math::Prime::Util::ECProjectivePoint"; };
2378 }
2806 require Math::Prime::Util::ECProjectivePoint;
2807 require Math::Prime::Util::RandomPrimes;
23792808
23802809 # With multiple curves, it's better to get all the primes at once.
23812810 # The downside is this can kill memory with a very large B1.
23872816 $q = $k;
23882817 }
23892818 my @b2primes = ($B2 > $B1) ? @{primes($B1+1, $B2)} : ();
2390 my $irandf = Math::Prime::Util::_get_randf();
2819 my $irandf = Math::Prime::Util::RandomPrimes::get_randf();
23912820
23922821 foreach my $curve (1 .. $ncurves) {
23932822 my $sigma = $irandf->($n-1-6) + 6;
24982927 @factors;
24992928 }
25002929
2501
2930 sub divisors {
2931 my($n) = @_;
2932 _validate_positive_integer($n);
2933
2934 # In scalar context, returns sigma_0(n). Very fast.
2935 return Math::Prime::Util::divisor_sum($n,0) unless wantarray;
2936 return ($n == 0) ? (0,1) : (1) if $n <= 1;
2937
2938 my %all_factors;
2939 my @factors = Math::Prime::Util::factor($n);
2940 return (1,$n) if scalar @factors == 1;
2941
2942 if (ref($n) eq 'Math::BigInt') {
2943 foreach my $f1 (@factors) {
2944 my $big_f1 = Math::BigInt->new("$f1");
2945 my @to_add = map { ($_ <= ''.~0) ? _bigint_to_int($_) : $_ }
2946 grep { $_ < $n }
2947 map { $big_f1 * $_ }
2948 keys %all_factors;
2949 undef @all_factors{ $f1, @to_add };
2950 }
2951 } else {
2952 foreach my $f1 (@factors) {
2953 my @to_add = grep { $_ < $n }
2954 map { $f1 * $_ }
2955 keys %all_factors;
2956 undef @all_factors{ $f1, @to_add };
2957 }
2958 }
2959 # Add 1 and n
2960 undef $all_factors{1};
2961 undef $all_factors{$n};
2962 my @divisors = sort {$a<=>$b} keys %all_factors;
2963 return @divisors;
2964 }
2965
2966
2967 sub chebyshev_theta {
2968 my($n) = @_;
2969 my $sum = 0.0;
2970 for (my $p = 2; $p <= $n; $p = next_prime($p)) {
2971 $sum += log($p);
2972 }
2973 return $sum;
2974 }
2975
2976 sub chebyshev_psi {
2977 my($n) = @_;
2978 return 0 if $n <= 1;
2979
2980 my ($sum, $p, $logn, $sqrtn) = (0.0, 2, log($n), int(sqrt($n)));
2981
2982 for ( ; $p <= $sqrtn; $p = next_prime($p)) {
2983 my $logp = log($p);
2984 $sum += $logp * int($logn/$logp+1e-15);
2985 }
2986
2987 for ( ; $p <= $n; $p = next_prime($p)) {
2988 $sum += log($p);
2989 }
2990
2991 return $sum;
2992 }
25022993
25032994 sub ExponentialIntegral {
25042995 my($x) = @_;
25143005 do { require Math::BigFloat; Math::BigFloat->import(); }
25153006 if !defined $Math::BigFloat::VERSION;
25163007 $x = Math::BigFloat->new("$x") if ref($x) ne 'Math::BigFloat';
2517 $wantbf = 1;
2518 $xdigits = $x->accuracy || Math::BigFloat->accuracy() || Math::BigFloat->div_scale();
3008 $wantbf = _find_big_acc($x);
3009 $xdigits = $wantbf;
25193010 }
25203011 my $rnd = 0; # MPFR_RNDN;
25213012 my $bit_precision = int($xdigits * 3.322) + 4;
25263017 Math::MPFR::Rmpfr_set_prec($eix, $bit_precision);
25273018 Math::MPFR::Rmpfr_eint($eix, $rx, $rnd);
25283019 my $strval = Math::MPFR::Rmpfr_get_str($eix, 10, 0, $rnd);
2529 return ($wantbf) ? Math::BigFloat->new($strval) : 0.0 + $strval;
3020 return ($wantbf) ? Math::BigFloat->new($strval,$wantbf) : 0.0 + $strval;
25303021 }
25313022
25323023 $x = Math::BigFloat->new("$x") if defined $bignum::VERSION && ref($x) ne 'Math::BigFloat';
26133104 my $wantbf = 0;
26143105 my $xdigits = 18;
26153106 if (defined $bignum::VERSION || ref($x) =~ /^Math::Big/) {
2616 $wantbf = 1;
2617 $xdigits = $x->accuracy || Math::BigInt->accuracy() || Math::BigInt->div_scale();
3107 $wantbf = _find_big_acc($x);
3108 $xdigits = $wantbf;
26183109 }
26193110 $xdigits += length(int(log(0.0+"$x"))) + 1;
26203111 my $rnd = 0; # MPFR_RNDN;
26273118 Math::MPFR::Rmpfr_set_prec($lix, $bit_precision);
26283119 Math::MPFR::Rmpfr_eint($lix, $rx, $rnd);
26293120 my $strval = Math::MPFR::Rmpfr_get_str($lix, 10, 0, $rnd);
2630 return Math::BigFloat->new($strval, ($x->accuracy || Math::BigInt->accuracy() || Math::BigInt->div_scale()))
2631 if $wantbf;
2632 return 0.0 + $strval;
3121 return ($wantbf) ? Math::BigFloat->new($strval,$wantbf) : 0.0 + $strval;
26333122 }
26343123
26353124 if ($x == 2) {
26483137 my $xdigits = 0;
26493138 my $finalacc = 0;
26503139 if (ref($x) =~ /^Math::Big/) {
2651 $xdigits = $x->accuracy || Math::BigFloat->accuracy() || Math::BigFloat->div_scale();
3140 $xdigits = _find_big_acc($x);
26523141 my $xlen = length($x->bfloor->bstr());
26533142 $xdigits = $xlen if $xdigits < $xlen;
26543143 $finalacc = $xdigits;
27613250 $x->accuracy($xacc) if $xacc;
27623251 }
27633252 $x = Math::BigFloat->new("$x") if ref($x) ne 'Math::BigFloat';
2764 $wantbf = 1;
2765 $xdigits = $x->accuracy || Math::BigFloat->accuracy() || Math::BigFloat->div_scale();
3253 $wantbf = _find_big_acc($x);
3254 $xdigits = $wantbf;
27663255 }
27673256 my $rnd = 0; # MPFR_RNDN;
27683257 my $bit_precision = int($xdigits * 3.322) + 7;
27763265 Math::MPFR::Rmpfr_zeta($zetax, $rx, $rnd);
27773266 Math::MPFR::Rmpfr_sub_ui($zetax, $zetax, 1, $rnd);
27783267 my $strval = Math::MPFR::Rmpfr_get_str($zetax, 10, $xdigits, $rnd);
2779 return ($wantbf) ? Math::BigFloat->new($strval) : 0.0 + $strval;
3268 return ($wantbf) ? Math::BigFloat->new($strval,$wantbf) : 0.0 + $strval;
27803269 }
27813270
27823271 if (defined $bignum::VERSION || ref($x) =~ /^Math::Big/) {
28503339 $x->accuracy($xacc) if $xacc;
28513340 }
28523341 $x = Math::BigFloat->new("$x") if ref($x) ne 'Math::BigFloat';
2853 $wantbf = 1;
2854 $xdigits = $x->accuracy || Math::BigFloat->accuracy() || Math::BigFloat->div_scale();
3342 $wantbf = _find_big_acc($x);
3343 $xdigits = $wantbf;
28553344 }
28563345 my $rnd = 0; # MPFR_RNDN;
28573346 my $bit_precision = int($xdigits * 3.322) + 8; # Add some extra
28923381 Math::MPFR::Rmpfr_add($rsum, $rsum, $rterm, $rnd);
28933382 }
28943383 my $strval = Math::MPFR::Rmpfr_get_str($rsum, 10, $xdigits, $rnd);
2895 return ($wantbf) ? Math::BigFloat->new($strval) : 0.0 + $strval;
3384 return ($wantbf) ? Math::BigFloat->new($strval,$wantbf) : 0.0 + $strval;
28963385 }
28973386
28983387 if (defined $bignum::VERSION || ref($x) =~ /^Math::Big/) {
29413430
29423431 =head1 VERSION
29433432
2944 Version 0.36
3433 Version 0.37
29453434
29463435
29473436 =head1 SYNOPSIS
0 package Math::Prime::Util::PPFE;
1 use strict;
2 use warnings;
3 use Math::Prime::Util::PP;
4 use Carp qw/carp croak confess/;
5
6 # The PP front end, only loaded if XS is not used.
7 # It is intended to load directly into the MPU namespace.
8
9 package Math::Prime::Util;
10
11 *_validate_num = \&Math::Prime::Util::PP::_validate_num;
12 *_prime_memfreeall = \&Math::Prime::Util::PP::_prime_memfreeall;
13 *prime_memfree = \&Math::Prime::Util::PP::prime_memfree;
14 *prime_precalc = \&Math::Prime::Util::PP::prime_precalc;
15
16
17 sub moebius {
18 if (scalar @_ <= 1) {
19 my($n) = @_;
20 return 0 if defined $n && $n < 0;
21 _validate_num($n) || _validate_positive_integer($n);
22 return Math::Prime::Util::PP::moebius($n);
23 }
24 my($lo, $hi) = @_;
25 _validate_num($lo) || _validate_positive_integer($lo);
26 _validate_num($hi) || _validate_positive_integer($hi);
27 return Math::Prime::Util::PP::moebius_range($lo, $hi);
28 }
29
30 sub euler_phi {
31 if (scalar @_ <= 1) {
32 my($n) = @_;
33 return 0 if defined $n && $n < 0;
34 _validate_num($n) || _validate_positive_integer($n);
35 return Math::Prime::Util::PP::euler_phi($n);
36 }
37 my($lo, $hi) = @_;
38 _validate_num($lo) || _validate_positive_integer($lo);
39 _validate_num($hi) || _validate_positive_integer($hi);
40 return Math::Prime::Util::PP::euler_phi_range($lo, $hi);
41 }
42 sub jordan_totient {
43 my($k, $n) = @_;
44 _validate_positive_integer($k);
45 return 0 if defined $n && $n < 0;
46 _validate_positive_integer($n);
47 return Math::Prime::Util::PP::jordan_totient($k, $n);
48 }
49 sub carmichael_lambda {
50 my($n) = @_;
51 _validate_positive_integer($n);
52 return Math::Prime::Util::PP::carmichael_lambda($n);
53 }
54 sub mertens {
55 my($n) = @_;
56 _validate_positive_integer($n);
57 return Math::Prime::Util::PP::mertens($n);
58 }
59 sub liouville {
60 my($n) = @_;
61 _validate_positive_integer($n);
62 return Math::Prime::Util::PP::liouville($n);
63 }
64 sub exp_mangoldt {
65 my($n) = @_;
66 return 1 if defined $n && $n <= 1;
67 _validate_positive_integer($n);
68 return Math::Prime::Util::PP::exp_mangoldt($n);
69 }
70
71
72 sub nth_prime {
73 my($n) = @_;
74 _validate_positive_integer($n);
75 return Math::Prime::Util::PP::nth_prime($n);
76 }
77 sub nth_prime_lower {
78 my($n) = @_;
79 _validate_positive_integer($n);
80 return Math::Prime::Util::PP::nth_prime_lower($n);
81 }
82 sub nth_prime_upper {
83 my($n) = @_;
84 _validate_positive_integer($n);
85 return Math::Prime::Util::PP::nth_prime_upper($n);
86 }
87 sub nth_prime_approx {
88 my($n) = @_;
89 _validate_positive_integer($n);
90 return Math::Prime::Util::PP::nth_prime_approx($n);
91 }
92 sub prime_count_lower {
93 my($n) = @_;
94 _validate_positive_integer($n);
95 return Math::Prime::Util::PP::prime_count_lower($n);
96 }
97 sub prime_count_upper {
98 my($n) = @_;
99 _validate_positive_integer($n);
100 return Math::Prime::Util::PP::prime_count_upper($n);
101 }
102 sub prime_count_approx {
103 my($n) = @_;
104 _validate_positive_integer($n);
105 return Math::Prime::Util::PP::prime_count_approx($n);
106 }
107
108
109 sub is_prime {
110 my($n) = @_;
111 return 0 if defined $n && int($n) < 0;
112 _validate_positive_integer($n);
113 return Math::Prime::Util::PP::is_prime($n);
114 }
115 sub is_prob_prime {
116 my($n) = @_;
117 return 0 if defined $n && int($n) < 0;
118 _validate_positive_integer($n);
119 return Math::Prime::Util::PP::is_prob_prime($n);
120 }
121 sub is_pseudoprime {
122 my($n, $base) = @_;
123 return 0 if defined $n && int($n) < 0;
124 _validate_positive_integer($n);
125 _validate_positive_integer($base);
126 return Math::Prime::Util::PP::is_pseudoprime($n, $base);
127 }
128 sub is_strong_pseudoprime {
129 my($n, @bases) = @_;
130 return 0 if defined $n && int($n) < 0;
131 _validate_positive_integer($n);
132 croak "No bases given to miller_rabin" unless @bases;
133 return Math::Prime::Util::PP::is_strong_pseudoprime($n, @bases);
134 }
135 sub is_lucas_pseudoprime {
136 my($n) = @_;
137 return 0 if defined $n && int($n) < 0;
138 _validate_positive_integer($n);
139 return Math::Prime::Util::PP::is_lucas_pseudoprime($n);
140 }
141 sub is_strong_lucas_pseudoprime {
142 my($n) = @_;
143 return 0 if defined $n && int($n) < 0;
144 _validate_positive_integer($n);
145 return Math::Prime::Util::PP::is_strong_lucas_pseudoprime($n);
146 }
147 sub is_extra_strong_lucas_pseudoprime {
148 my($n) = @_;
149 return 0 if defined $n && int($n) < 0;
150 _validate_positive_integer($n);
151 return Math::Prime::Util::PP::is_extra_strong_lucas_pseudoprime($n);
152 }
153 sub is_almost_extra_strong_lucas_pseudoprime {
154 my($n, $increment) = @_;
155 return 0 if defined $n && int($n) < 0;
156 _validate_positive_integer($n);
157 if (defined $increment) { _validate_positive_integer($increment, 1, 256);
158 } else { $increment = 1; }
159 return Math::Prime::Util::PP::is_almost_extra_strong_lucas_pseudoprime($n, $increment);
160 }
161 sub is_frobenius_underwood_pseudoprime {
162 my($n) = @_;
163 return 0 if defined $n && int($n) < 0;
164 _validate_positive_integer($n);
165 return Math::Prime::Util::PP::is_frobenius_underwood_pseudoprime($n);
166 }
167 sub is_aks_prime {
168 my($n) = @_;
169 return 0 if defined $n && int($n) < 0;
170 _validate_positive_integer($n);
171 return Math::Prime::Util::PP::is_aks_prime($n);
172 }
173
174
175 sub kronecker {
176 my($a, $b) = @_;
177 my ($va, $vb) = ($a, $b);
178 $va = -$va if defined $va && $va < 0;
179 $vb = -$vb if defined $vb && $vb < 0;
180 _validate_positive_integer($va);
181 _validate_positive_integer($vb);
182 return Math::Prime::Util::PP::kronecker(@_);
183 }
184
185 sub znorder {
186 my($a, $n) = @_;
187 _validate_positive_integer($a);
188 _validate_positive_integer($n);
189 return Math::Prime::Util::PP::znorder($a, $n);
190 }
191
192 sub znlog {
193 my($a, $g, $p) = @_;
194 _validate_positive_integer($a);
195 _validate_positive_integer($g);
196 _validate_positive_integer($p);
197 return Math::Prime::Util::PP::znlog($a, $g, $p);
198 }
199
200 sub znprimroot {
201 my($n) = @_;
202 $n = -$n if defined $n && $n =~ /^-\d+/; # TODO: fix this for string bigints
203 _validate_positive_integer($n);
204 return Math::Prime::Util::PP::znprimroot($n);
205 }
206
207 sub trial_factor {
208 my($n, $maxlim) = @_;
209 _validate_positive_integer($n);
210 if (defined $maxlim) {
211 _validate_positive_integer($maxlim);
212 return Math::Prime::Util::PP::trial_factor($n, $maxlim);
213 }
214 return Math::Prime::Util::PP::trial_factor($n);
215 }
216 sub fermat_factor {
217 my($n, $rounds) = @_;
218 _validate_positive_integer($n);
219 if (defined $rounds) {
220 _validate_positive_integer($rounds);
221 return Math::Prime::Util::PP::fermat_factor($n, $rounds);
222 }
223 return Math::Prime::Util::PP::fermat_factor($n);
224 }
225 sub holf_factor {
226 my($n, $rounds) = @_;
227 _validate_positive_integer($n);
228 if (defined $rounds) {
229 _validate_positive_integer($rounds);
230 return Math::Prime::Util::PP::holf_factor($n, $rounds);
231 }
232 return Math::Prime::Util::PP::holf_factor($n);
233 }
234 sub squfof_factor {
235 my($n, $rounds) = @_;
236 _validate_positive_integer($n);
237 if (defined $rounds) {
238 _validate_positive_integer($rounds);
239 return Math::Prime::Util::PP::squfof_factor($n, $rounds);
240 }
241 return Math::Prime::Util::PP::squfof_factor($n);
242 }
243 sub pbrent_factor {
244 my($n, $rounds, $pa) = @_;
245 _validate_positive_integer($n);
246 if (defined $rounds) { _validate_positive_integer($rounds);
247 } else { $rounds = 4*1024*1024; }
248 if (defined $pa ) { _validate_positive_integer($pa);
249 } else { $pa = 3; }
250 return Math::Prime::Util::PP::pbrent_factor($n, $rounds, $pa);
251 }
252 sub prho_factor {
253 my($n, $rounds, $pa) = @_;
254 _validate_positive_integer($n);
255 if (defined $rounds) { _validate_positive_integer($rounds);
256 } else { $rounds = 4*1024*1024; }
257 if (defined $pa ) { _validate_positive_integer($pa);
258 } else { $pa = 3; }
259 return Math::Prime::Util::PP::prho_factor($n, $rounds, $pa);
260 }
261 sub pminus1_factor {
262 my($n, $B1, $B2) = @_;
263 _validate_positive_integer($n);
264 _validate_positive_integer($B1) if defined $B1;
265 _validate_positive_integer($B2) if defined $B2;
266 Math::Prime::Util::PP::pminus1_factor($n, $B1, $B2);
267 }
268 *pplus1_factor = \&pminus1_factor;
269 sub ecm_factor {
270 my($n, $B1, $B2, $ncurves) = @_;
271 _validate_positive_integer($n);
272 _validate_positive_integer($B1) if defined $B1;
273 _validate_positive_integer($B2) if defined $B2;
274 _validate_positive_integer($ncurves) if defined $ncurves;
275 Math::Prime::Util::PP::ecm_factor($n, $B1, $B2, $ncurves);
276 }
277
278 sub divisors {
279 my($n) = @_;
280 _validate_positive_integer($n);
281 return Math::Prime::Util::PP::divisors($n);
282 }
283
284 sub divisor_sum {
285 my($n, $k) = @_;
286 _validate_positive_integer($n);
287 _validate_positive_integer($k) if defined $k && ref($k) ne 'CODE';
288 return Math::Prime::Util::PP::divisor_sum($n, $k);
289 }
290
291 sub gcd {
292 return Math::Prime::Util::PP::gcd(@_);
293 }
294 sub lcm {
295 return Math::Prime::Util::PP::lcm(@_);
296 }
297
298 sub legendre_phi {
299 my($x, $a) = @_;
300 _validate_positive_integer($x);
301 _validate_positive_integer($a);
302 return Math::Prime::Util::PP::legendre_phi($x, $a);
303 }
304
305 sub chebyshev_theta {
306 my($n) = @_;
307 _validate_positive_integer($n);
308 return Math::Prime::Util::PP::chebyshev_theta($n);
309 }
310 sub chebyshev_psi {
311 my($n) = @_;
312 _validate_positive_integer($n);
313 return Math::Prime::Util::PP::chebyshev_psi($n);
314 }
315
316 #############################################################################
317
318 sub forprimes (&$;$) { ## no critic qw(ProhibitSubroutinePrototypes)
319 my($sub, $beg, $end) = @_;
320 if (!defined $end) { $end = $beg; $beg = 2; }
321 _validate_num($beg) || _validate_positive_integer($beg);
322 _validate_num($end) || _validate_positive_integer($end);
323 $beg = 2 if $beg < 2;
324 {
325 my $pp;
326 local *_ = \$pp;
327 for (my $p = next_prime($beg-1); $p <= $end; $p = next_prime($p)) {
328 $pp = $p;
329 $sub->();
330 }
331 }
332 }
333
334 sub forcomposites(&$;$) { ## no critic qw(ProhibitSubroutinePrototypes)
335 my($sub, $beg, $end) = @_;
336 if (!defined $end) { $end = $beg; $beg = 4; }
337 _validate_num($beg) || _validate_positive_integer($beg);
338 _validate_num($end) || _validate_positive_integer($end);
339 $beg = 4 if $beg < 4;
340 $end = Math::BigInt->new(''.~0) if ref($end) ne 'Math::BigInt' && $end == ~0;
341 {
342 my $pp;
343 local *_ = \$pp;
344 for ( ; $beg <= $end ; $beg++ ) {
345 if (!is_prime($beg)) {
346 $pp = $beg;
347 $sub->();
348 }
349 }
350 }
351 }
352
353 sub fordivisors (&$) { ## no critic qw(ProhibitSubroutinePrototypes)
354 my($sub, $n) = @_;
355 _validate_num($n) || _validate_positive_integer($n);
356 my @divisors = divisors($n);
357 {
358 my $pp;
359 local *_ = \$pp;
360 foreach my $d (@divisors) {
361 $pp = $d;
362 $sub->();
363 }
364 }
365 }
366
367 1;
368
369 __END__
370
371 =pod
372
373 =head1 NAME
374
375 Math::Prime::Util::PPFE - PP front end for Math::Prime::Util
376
377 =head1 SYNOPSIS
378
379 This loads the PP code and adds input validation front ends. It is only
380 meant to be used when XS is not used.
381
382 =head1 DESCRIPTION
383
384 Loads PP module and implements PP front-end functions for all XS code.
385 This is used only if the XS code is not loaded.
386
387 =head1 SEE ALSO
388
389 L<Math::Prime::Util>
390
391 L<Math::Prime::Util::PP>
392
393 =head1 AUTHORS
394
395 Dana Jacobsen E<lt>dana@acm.orgE<gt>
396
397
398 =head1 COPYRIGHT
399
400 Copyright 2014 by Dana Jacobsen E<lt>dana@acm.orgE<gt>
401
402 This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
403
404 =cut
1010
1111 BEGIN {
1212 $Math::Prime::Util::PrimalityProving::AUTHORITY = 'cpan:DANAJ';
13 $Math::Prime::Util::PrimalityProving::VERSION = '0.36';
13 $Math::Prime::Util::PrimalityProving::VERSION = '0.37';
1414 }
1515
1616 BEGIN {
5555 "N $n",
5656 "";
5757 }
58
59 # For stripping off the header on certificates so they can be combined.
60 sub _strip_proof_header {
61 my $proof = shift;
62 $proof =~ s/^\[MPU - Primality Certificate\]\nVersion \S+\n+Proof for:\nN (\d+)\n+//ms;
63 return $proof;
64 }
65
5866
5967 sub primality_proof_lucas {
6068 my ($n) = shift;
95103 carp "could not prove primality of $n.\n";
96104 return (1, '');
97105 }
98 push @fac_proofs, Math::Prime::Util::_strip_proof_header($fproof) if $f > $_smallval;
106 push @fac_proofs, _strip_proof_header($fproof) if $f > $_smallval;
99107 }
100108 $cert .= "A $a\n";
101109 foreach my $proof (@fac_proofs) {
116124 return @composite if ($n & 1) == 0;
117125 return @composite if is_strong_pseudoprime($n,2,15,325) == 0;
118126
127 require Math::Prime::Util::PP;
119128 $n = Math::BigInt->new("$n") unless ref($n) eq 'Math::BigInt';
120129 my $nm1 = $n->copy->bdec;
121130 my $ONE = $nm1->copy->bone;
228237 carp "could not prove primality of $n.\n";
229238 return (1, '');
230239 }
231 push @fac_proofs, Math::Prime::Util::_strip_proof_header($fproof) if $f > $_smallval;
240 push @fac_proofs, _strip_proof_header($fproof) if $f > $_smallval;
232241 }
233242 $cert .= $atext;
234243 $cert .= "----\n";
854863
855864 =head1 VERSION
856865
857 Version 0.36
866 Version 0.37
858867
859868
860869 =head1 SYNOPSIS
33
44 BEGIN {
55 $Math::Prime::Util::PrimeArray::AUTHORITY = 'cpan:DANAJ';
6 $Math::Prime::Util::PrimeArray::VERSION = '0.36';
6 $Math::Prime::Util::PrimeArray::VERSION = '0.37';
77 }
88
99 # parent is cleaner, and in the Perl 5.10.1 / 5.12.0 core, but not earlier.
134134
135135 =head1 VERSION
136136
137 Version 0.36
137 Version 0.37
138138
139139
140140 =head1 SYNOPSIS
33
44 BEGIN {
55 $Math::Prime::Util::PrimeIterator::AUTHORITY = 'cpan:DANAJ';
6 $Math::Prime::Util::PrimeIterator::VERSION = '0.36';
6 $Math::Prime::Util::PrimeIterator::VERSION = '0.37';
77 }
88
99 use base qw( Exporter );
126126
127127 =head1 VERSION
128128
129 Version 0.36
129 Version 0.37
130130
131131
132132 =head1 SYNOPSIS
0 package Math::Prime::Util::RandomPrimes;
1 use strict;
2 use warnings;
3 use Carp qw/carp croak confess/;
4 use Math::Prime::Util qw/ prime_get_config
5 verify_prime
6 is_provable_prime_with_cert
7 primorial prime_count nth_prime
8 is_prob_prime is_strong_pseudoprime
9 next_prime prev_prime
10 /;
11
12 BEGIN {
13 $Math::Prime::Util::RandomPrimes::AUTHORITY = 'cpan:DANAJ';
14 $Math::Prime::Util::RandomPrimes::VERSION = '0.37';
15 }
16
17 BEGIN {
18 do { require Math::BigInt; Math::BigInt->import(try=>"GMP,Pari"); }
19 unless defined $Math::BigInt::VERSION;
20
21 use constant OLD_PERL_VERSION=> $] < 5.008;
22 use constant MPU_MAXBITS => (~0 == 4294967295) ? 32 : 64;
23 use constant MPU_64BIT => MPU_MAXBITS == 64;
24 use constant MPU_32BIT => MPU_MAXBITS == 32;
25 use constant MPU_MAXPARAM => MPU_32BIT ? 4294967295 : 18446744073709551615;
26 use constant MPU_MAXDIGITS => MPU_32BIT ? 10 : 20;
27 use constant MPU_USE_XS => prime_get_config->{'xs'};
28 use constant MPU_USE_GMP => prime_get_config->{'gmp'};
29
30 *_bigint_to_int = \&Math::Prime::Util::_bigint_to_int;
31 }
32
33 ################################################################################
34
35 # These are much faster than straightforward trial division when n is big.
36 # You'll want to first do a test up to and including 23.
37 my @_big_gcd;
38 my $_big_gcd_top = 20046;
39 my $_big_gcd_use = -1;
40 sub _make_big_gcds {
41 return if $_big_gcd_use >= 0;
42 if (prime_get_config->{'gmp'}) {
43 $_big_gcd_use = 0;
44 return;
45 }
46 if (Math::BigInt->config()->{lib} !~ /^Math::BigInt::(GMP|Pari)/) {
47 $_big_gcd_use = 0;
48 return;
49 }
50 $_big_gcd_use = 1;
51 my $p0 = primorial(Math::BigInt->new( 520));
52 my $p1 = primorial(Math::BigInt->new(2052));
53 my $p2 = primorial(Math::BigInt->new(6028));
54 my $p3 = primorial(Math::BigInt->new($_big_gcd_top));
55 $_big_gcd[0] = $p0->bdiv(223092870)->bfloor->as_int;
56 $_big_gcd[1] = $p1->bdiv($p0)->bfloor->as_int;
57 $_big_gcd[2] = $p2->bdiv($p1)->bfloor->as_int;
58 $_big_gcd[3] = $p3->bdiv($p2)->bfloor->as_int;
59 }
60
61 ################################################################################
62
63 # Returns a function that will get a uniform random number
64 # between 0 and $max inclusive. $max can be a bigint.
65 my $_IRANDF;
66 my $_BRS;
67 my $_RANDF;
68 my $_RANDF_NBIT;
69 sub _set_randf {
70 # First define a function $irandf that returns a 32-bit integer. This
71 # corresponds to the irand function of many CPAN modules:
72 # Math::Random::MT
73 # Math::Random::ISAAC
74 # Math::Random::Xorshift
75 # Math::Random::Secure
76 # (but not Math::Random::MT::Auto which will return 64-bits)
77 my $irandf = prime_get_config->{'irand'};
78 if ( ( defined $_IRANDF && !defined $irandf) ||
79 (!defined $_IRANDF && defined $irandf) ||
80 ( defined $_IRANDF && defined $irandf && $_IRANDF != $irandf) ) {
81 undef $_RANDF;
82 undef $_RANDF_NBIT;
83 $_IRANDF = $irandf;
84 }
85 return if defined $_RANDF;
86
87 if (!defined $_IRANDF) { # Default irand: BRS nonblocking
88 require Bytes::Random::Secure;
89 $_BRS = Bytes::Random::Secure->new(NonBlocking=>1) unless defined $_BRS;
90 $_RANDF_NBIT = sub {
91 my($bits) = int("$_[0]");
92 return 0 if $bits <= 0;
93 return ($_BRS->irand() >> (32-$bits))
94 if $bits <= 32;
95 return ( (($_BRS->irand() << 32) + $_BRS->irand()) >> (64-$bits) )
96 if $bits <= 64 && ~0 > 4294967295;
97 my $bytes = int(($bits+7)/8);
98 my $n = Math::BigInt->from_hex('0x' . $_BRS->bytes_hex($bytes));
99 $n->brsft( 8*$bytes - $bits ) unless ($bits % 8) == 0;
100 return $n;
101 };
102 $_RANDF = sub {
103 my($max) = @_;
104 my $range = $max+1;
105 my $U;
106 if (ref($range) eq 'Math::BigInt') {
107 my $bits = length($range->as_bin) - 2; # bits in range
108 my $bytes = 1 + int(($bits+7)/8); # extra byte to reduce ave. loops
109 my $rmax = Math::BigInt->bone->blsft($bytes*8)->bdec();
110 my $overflow = $rmax - ($rmax % $range);
111 do {
112 $U = Math::BigInt->from_hex('0x' . $_BRS->bytes_hex($bytes));
113 } while $U >= $overflow;
114 } elsif ($range <= 4294967295) {
115 my $overflow = (OLD_PERL_VERSION) ? 4294967295-(4294967295.0%$range)
116 : 4294967295-(4294967295 % $range);
117 do {
118 $U = $_BRS->irand();
119 } while $U >= $overflow;
120 } else {
121 croak "randf given max out of bounds: $max" if $range > ~0;
122 my $overflow = 18446744073709551615 - (18446744073709551615 % $range);
123 do {
124 $U = ($_BRS->irand() << 32) + $_BRS->irand();
125 } while $U >= $overflow;
126 }
127 return $U % $range;
128 };
129 } else { # Custom irand
130 $_RANDF_NBIT = sub {
131 my($bits) = int("$_[0]");
132 return 0 if $bits <= 0;
133 return ($_IRANDF->() >> (32-$bits))
134 if $bits <= 32;
135 return ((($_IRANDF->() << 32) + $_IRANDF->()) >> (64-$bits))
136 if $bits <= 64 && MPU_64BIT;
137 my $words = int(($bits+31)/32);
138 my $n = Math::BigInt->from_hex
139 ("0x" . join '', map { sprintf("%08X", $_IRANDF->()) } 1 .. $words );
140 $n->brsft( 32*$words - $bits ) unless ($bits % 32) == 0;
141 return $n;
142 };
143 $_RANDF = sub {
144 my($max) = @_;
145 return 0 if $max <= 0;
146 my $range = $max+1;
147 my $U;
148 if (ref($range) eq 'Math::BigInt') {
149 my $zero = $range->copy->bzero;
150 my $rbits = length($range->as_bin) - 2; # bits in range
151 my $rwords = int($rbits/32) + (($rbits % 32) ? 1 : 0);
152 my $rmax = Math::BigInt->bone->blsft($rwords*32)->bdec();
153 my $overflow = $rmax - ($rmax % $range);
154 do {
155 $U = $range->copy->from_hex
156 ("0x" . join '', map { sprintf("%08X", $_IRANDF->()) } 1 .. $rwords);
157 } while $U >= $overflow;
158 } elsif ($range <= 4294967295) {
159 my $overflow = 4294967295 - (4294967295 % $range);
160 do {
161 $U = $_IRANDF->();
162 } while $U >= $overflow;
163 } else {
164 croak "randf given max out of bounds: $max" if $range > ~0;
165 my $overflow = 18446744073709551615 - (18446744073709551615 % $range);
166 do {
167 $U = ($_IRANDF->() << 32) + $_IRANDF->();
168 } while $U >= $overflow;
169 }
170 return $U % $range;
171 };
172 }
173 }
174
175 sub get_randf {
176 _set_randf();
177 return $_RANDF;
178 }
179 sub get_randf_nbit {
180 _set_randf();
181 return $_RANDF_NBIT;
182 }
183
184 ################################################################################
185
186
187
188 # For random primes, there are two good papers that should be examined:
189 #
190 # "Fast Generation of Prime Numbers and Secure Public-Key
191 # Cryptographic Parameters" by Ueli M. Maurer, 1995
192 # http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.26.2151
193 # related discussions:
194 # http://www.daimi.au.dk/~ivan/provableprimesproject.pdf
195 # Handbook of Applied Cryptography by Menezes, et al.
196 #
197 # "Close to Uniform Prime Number Generation With Fewer Random Bits"
198 # by Pierre-Alain Fouque and Mehdi Tibouchi, 2011
199 # http://eprint.iacr.org/2011/481
200 #
201 # Some things to note:
202 #
203 # 1) Joye and Paillier have patents on their methods. Never use them.
204 #
205 # 2) The easy method of next_prime(random number), known as PRIMEINC, is
206 # fast but gives a terrible distribution. It has a positive bias and
207 # most importantly the probability for a prime is proportional to its
208 # gap, which makes a terrible distribution (some numbers in the range
209 # will be thousands of times more likely than others).
210 #
211 # We use:
212 # TRIVIAL range within native integer size (2^32 or 2^64)
213 # FTA1 random_nbit_prime with 65+ bits
214 # INVA1 other ranges with 65+ bit range
215 # where
216 # TRIVIAL = monte-carlo method or equivalent, perfect uniformity.
217 # FTA1 = Fouque/Tibouchi A1, very close to uniform
218 # INVA1 = inverted FTA1, less uniform but works with arbitrary ranges
219 #
220 # The random_maurer_prime function uses Maurer's FastPrime algorithm.
221 #
222 # If Math::Prime::Util::GMP is installed, these functions will be many times
223 # faster than other methods (e.g. Math::Pari monte-carlo or Crypt::Primes).
224 #
225 # Timings on x86_64, with Math::BigInt::GMP and Math::Random::ISAAC::XS.
226 #
227 # random_nbit_prime random_maurer_prime
228 # n-bits no GMP w/ MPU::GMP no GMP w/ MPU::GMP
229 # ---------- -------- ----------- -------- -----------
230 # 24-bit 22uS same same same
231 # 64-bit 94uS same same same
232 # 128-bit 0.017s 0.0020s 0.098s 0.056s
233 # 256-bit 0.033s 0.0033s 0.25s 0.15s
234 # 512-bit 0.066s 0.0093s 0.65s 0.30s
235 # 1024-bit 0.16s 0.060s 1.3s 0.94s
236 # 2048-bit 0.83s 0.5s 3.2s 3.1s
237 # 4096-bit 6.6s 4.0s 23s 12.0s
238 #
239 # Writing these entirely in GMP has a problem, which is that we want to use
240 # a user-supplied rand function, which means a lot of callbacks. One
241 # possibility is to, if they do not supply a rand function, use the GMP MT
242 # function with an appropriate seed.
243 #
244 # Random timings for 10M calls:
245 # 1.92 system rand
246 # 2.62 Math::Random::MT::Auto
247 # 12.0 Math::Random::Secure w/ISAAC::XS
248 # 12.6 Bytes::Random::Secure OO w/ISAAC::XS <==== our
249 # 31.1 Bytes::Random::Secure OO <==== default
250 # 44.5 Bytes::Random::Secure function w/ISAAC::XS
251 # 44.8 Math::Random::Secure
252 # 71.5 Bytes::Random::Secure function
253 # 1840 Crypt::Random
254 #
255 # time perl -E 'sub irand {int(rand(4294967296));} irand() for 1..10000000;'
256 # time perl -E 'use Math::Random::MT::Auto qw/irand/; irand() for 1..10000000;'
257 # time perl -E 'use Math::Random::Secure qw/irand/; irand() for 1..10000000;'
258 # time perl -E 'use Bytes::Random::Secure qw/random_bytes/; sub irand {return unpack("L",random_bytes(4));} irand() for 1..10000000;'
259 # time perl -E 'use Bytes::Random::Secure; my $rng = Bytes::Random::Secure->new(); sub irand {return $rng->irand;} irand() for 1..10000000;'
260 # time perl -E 'use Crypt::Random qw/makerandom/; sub irand {makerandom(Size=>32, Uniform=>1, Strength=>0)} irand() for 1..100_000;'
261 # > haveged daemon running to stop /dev/random blocking
262 # > Both BRS and CR have more features that this isn't measuring.
263 #
264 # To verify distribution:
265 # perl -Iblib/lib -Iblib/arch -MMath::Prime::Util=:all -E 'my %freq; $n=1000000; $freq{random_nbit_prime(6)}++ for (1..$n); printf("%4d %6.3f%%\n", $_, 100.0*$freq{$_}/$n) for sort {$a<=>$b} keys %freq;'
266 # perl -Iblib/lib -Iblib/arch -MMath::Prime::Util=:all -E 'my %freq; $n=1000000; $freq{random_prime(1260437,1260733)}++ for (1..$n); printf("%4d %6.3f%%\n", $_, 100.0*$freq{$_}/$n) for sort {$a<=>$b} keys %freq;'
267
268 # Sub to call with low and high already primes and verified range.
269 my $_random_prime = sub {
270 my($low,$high) = @_;
271 my $prime;
272
273 _set_randf();
274
275 #{ my $bsize = 100; my @bins; my $counts = 10000000;
276 # for my $c (1..$counts) { $bins[ $_IRANDF->($bsize-1) ]++; }
277 # for my $b (0..$bsize) {printf("%4d %8.5f%%\n", $b, $bins[$b]/$counts);} }
278
279 # low and high are both odds, and low < high.
280
281 # This is fast for small values, low memory, perfectly uniform, and
282 # consumes the minimum amount of randomness needed. But it isn't feasible
283 # with large values. Also note that low must be a prime.
284 if ($high <= 262144 && MPU_USE_XS) {
285 my $li = prime_count(2, $low);
286 my $irange = prime_count($low, $high);
287 my $rand = $_RANDF->($irange-1);
288 return nth_prime($li + $rand);
289 }
290
291 $low-- if $low == 2; # Low of 2 becomes 1 for our program.
292 # Math::BigInt::GMP's RT 71548 will wreak havoc if we don't do this.
293 $low = Math::BigInt->new("$low") if ref($high) eq 'Math::BigInt';
294 confess "Invalid _random_prime parameters: $low, $high" if ($low % 2) == 0 || ($high % 2) == 0;
295
296 # We're going to look at the odd numbers only.
297 my $oddrange = (($high - $low) >> 1) + 1;
298
299 croak "Large random primes not supported on old Perl"
300 if OLD_PERL_VERSION && MPU_64BIT && $oddrange > 4294967295;
301
302 # If $low is large (e.g. >10 digits) and $range is small (say ~10k), it
303 # would be fastest to call primes in the range and randomly pick one. I'm
304 # not implementing it now because it seems like a rare case.
305
306 # If the range is reasonably small, generate using simple Monte Carlo
307 # method (aka the 'trivial' method). Completely uniform.
308 if ($oddrange < MPU_MAXPARAM) {
309 my $loop_limit = 2000 * 1000; # To protect against broken rand
310 if ($low > 11) {
311 while ($loop_limit-- > 0) {
312 $prime = $low + 2 * $_RANDF->($oddrange-1);
313 next if !($prime % 3) || !($prime % 5) || !($prime % 7) || !($prime % 11);
314 return $prime if is_prob_prime($prime);
315 }
316 } else {
317 while ($loop_limit-- > 0) {
318 $prime = $low + 2 * $_RANDF->($oddrange-1);
319 next if $prime > 11 && (!($prime % 3) || !($prime % 5) || !($prime % 7) || !($prime % 11));
320 return 2 if $prime == 1; # Remember the special case for 2.
321 return $prime if is_prob_prime($prime);
322 }
323 }
324 croak "Random function broken?";
325 }
326
327 # We have an ocean of range, and a teaspoon to hold randomness.
328
329 # Since we have an arbitrary range and not a power of two, I don't see how
330 # Fouque's algorithm A1 could be used (where we generate lower bits and
331 # generate random sets of upper). Similarly trying to simply generate
332 # upper bits is full of ways to trip up and get non-uniform results.
333 #
334 # What I'm doing here is:
335 #
336 # 1) divide the range into semi-evenly sized partitions, where each part
337 # is as close to $rand_max_val as we can.
338 # 2) randomly select one of the partitions.
339 # 3) iterate choosing random values within the partition.
340 #
341 # The downside is that we're skewing a _lot_ farther from uniformity than
342 # we'd like. Imagine we started at 0 with 1e18 partitions of size 100k
343 # each.
344 # Probability of '5' being returned =
345 # 1.04e-22 = 1e-18 (chose first partition) * 1/9592 (chose '5')
346 # Probability of '100003' being returned =
347 # 1.19e-22 = 1e-18 (chose second partition) * 1/8392 (chose '100003')
348 # Probability of '99999999999999999999977' being returned =
349 # 5.20e-22 = 1e-18 (chose last partition) * 1/1922 (chose '99...77')
350 # So the primes in the last partition will show up 5x more often.
351 # The partitions are selected uniformly, and the primes within are selected
352 # uniformly, but the number of primes in each bucket is _not_ uniform.
353 # Their individual probability of being selected is the probability of the
354 # partition (uniform) times the probability of being selected inside the
355 # partition (uniform with respect to all other primes in the same
356 # partition, but each partition is different and skewed).
357 #
358 # Partitions are typically much larger than 100k, but with a huge range
359 # we still see this (e.g. ~3x from 0-10^30, ~10x from 0-10^100).
360 #
361 # When selecting n-bit or n-digit primes, this effect is MUCH smaller, as
362 # the skew becomes approx lg(2^n) / lg(2^(n-1)) which is pretty close to 1.
363 #
364 #
365 # Another idea I'd like to try sometime is:
366 # pclo = prime_count_lower(low);
367 # pchi = prime_count_upper(high);
368 # do {
369 # $nth = random selection between pclo and pchi
370 # $prguess = nth_prime_approx($nth);
371 # } while ($prguess >= low) && ($prguess <= high);
372 # monte carlo select a prime in $prguess-2**24 to $prguess+2**24
373 # which accounts for the prime distribution.
374
375 my($binsize, $nparts);
376 my $rand_part_size = 1 << (MPU_64BIT ? 32 : 31);
377 if (ref($oddrange) eq 'Math::BigInt') {
378 # Go to some trouble here because some systems are wonky, such as
379 # giving us +a/+b = -r. Also note the quotes for the bigint argument.
380 # Without that, Math::BigInt::GMP can return garbage.
381 my($nbins, $rem);
382 ($nbins, $rem) = $oddrange->copy->bdiv( "$rand_part_size" );
383 $nbins++ if $rem > 0;
384 $nbins = $nbins->as_int();
385 ($binsize,$rem) = $oddrange->copy->bdiv($nbins);
386 $binsize++ if $rem > 0;
387 $binsize = $binsize->as_int();
388 $nparts = $oddrange->copy->bdiv($binsize)->as_int();
389 $low = $high->copy->bzero->badd($low) if ref($low) ne 'Math::BigInt';
390 } else {
391 my $nbins = int($oddrange / $rand_part_size);
392 $nbins++ if $nbins * $rand_part_size != $oddrange;
393 $binsize = int($oddrange / $nbins);
394 $binsize++ if $binsize * $nbins != $oddrange;
395 $nparts = int($oddrange/$binsize);
396 }
397 $nparts-- if ($nparts * $binsize) == $oddrange;
398
399 my $rpart = $_RANDF->($nparts);
400
401 my $primelow = $low + 2 * $binsize * $rpart;
402 my $partsize = ($rpart < $nparts) ? $binsize
403 : $oddrange - ($nparts * $binsize);
404 $partsize = _bigint_to_int($partsize) if ref($partsize) eq 'Math::BigInt';
405 #warn "range $oddrange = $nparts * $binsize + ", $oddrange - ($nparts * $binsize), "\n";
406 #warn " chose part $rpart size $partsize\n";
407 #warn " primelow is $low + 2 * $binsize * $rpart = $primelow\n";
408 #die "Result could be too large" if ($primelow + 2*($partsize-1)) > $high;
409
410 # Generate random numbers in the interval until one is prime.
411 my $loop_limit = 2000 * 1000; # To protect against broken rand
412
413 # Simply things for non-bigints.
414 if (ref($low) ne 'Math::BigInt') {
415 while ($loop_limit-- > 0) {
416 my $rand = $_RANDF->($partsize-1);
417 $prime = $primelow + $rand + $rand;
418 croak "random prime failure, $prime > $high" if $prime > $high;
419 if ($prime <= 23) {
420 $prime = 2 if $prime == 1; # special case for low = 2
421 next unless (0,0,1,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1)[$prime];
422 return $prime;
423 }
424 next if !($prime % 3) || !($prime % 5) || !($prime % 7) || !($prime % 11);
425 # It looks promising. Check it.
426 next unless is_prob_prime($prime);
427 return $prime;
428 }
429 croak "Random function broken?";
430 }
431
432 # By checking a wheel 30 mod, we can skip anything that would be a multiple
433 # of 2, 3, or 5, without even having to create the bigint prime.
434 my @w30 = (1,0,5,4,3,2,1,0,3,2,1,0,1,0,3,2,1,0,1,0,3,2,1,0,5,4,3,2,1,0);
435 my $primelow30 = $primelow % 30;
436 $primelow30 = _bigint_to_int($primelow30) if ref($primelow30) eq 'Math::BigInt';
437
438 # Big GCD's are hugely fast with GMP or Pari, but super slow with Calc.
439 _make_big_gcds() if $_big_gcd_use < 0;
440
441 while ($loop_limit-- > 0) {
442 my $rand = $_RANDF->($partsize-1);
443 # Check wheel-30 mod
444 my $rand30 = $rand % 30;
445 next if $w30[($primelow30 + 2*$rand30) % 30]
446 && ($rand > 3 || $primelow > 5);
447 # Construct prime
448 $prime = $primelow + $rand + $rand;
449 croak "random prime failure, $prime > $high" if $prime > $high;
450 if ($prime <= 23) {
451 $prime = 2 if $prime == 1; # special case for low = 2
452 next unless (0,0,1,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1)[$prime];
453 return $prime;
454 }
455 # With GMP, the fastest thing to do is check primality.
456 if (MPU_USE_GMP) {
457 next unless Math::Prime::Util::GMP::is_prime($prime);
458 return $prime;
459 }
460 # No MPU:GMP, so primality checking is slow. Skip some composites here.
461 next unless Math::BigInt::bgcd($prime, 7436429) == 1;
462 if ($_big_gcd_use && $prime > $_big_gcd_top) {
463 next unless Math::BigInt::bgcd($prime, $_big_gcd[0]) == 1;
464 next unless Math::BigInt::bgcd($prime, $_big_gcd[1]) == 1;
465 next unless Math::BigInt::bgcd($prime, $_big_gcd[2]) == 1;
466 next unless Math::BigInt::bgcd($prime, $_big_gcd[3]) == 1;
467 }
468 # It looks promising. Check it.
469 next unless is_prob_prime($prime);
470 return $prime;
471 }
472 croak "Random function broken?";
473 };
474
475 # Cache of tight bounds for each digit. Helps performance a lot.
476 my @_random_ndigit_ranges = (undef, [2,7], [11,97] );
477 my @_random_nbit_ranges = (undef, undef, [2,3],[5,7] );
478 my %_random_cache_small;
479
480 # For fixed small ranges with XS, e.g. 6-digit, 18-bit
481 sub _random_xscount_prime {
482 my($low,$high) = @_;
483 my($istart, $irange);
484 my $cachearef = $_random_cache_small{$low,$high};
485 if (defined $cachearef) {
486 ($istart, $irange) = @$cachearef;
487 } else {
488 my $beg = ($low <= 2) ? 2 : next_prime($low-1);
489 my $end = ($high < ~0) ? prev_prime($high + 1) : prev_prime($high);
490 ($istart, $irange) = ( prime_count(2, $beg), prime_count($beg, $end) );
491 $_random_cache_small{$low,$high} = [$istart, $irange];
492 }
493 _set_randf();
494 my $rand = $_RANDF->($irange-1);
495 return nth_prime($istart + $rand);
496 }
497
498 sub random_prime {
499 my($low,$high) = @_;
500
501 # Tighten the range to the nearest prime.
502 $low = ($low <= 2) ? 2 : next_prime($low-1);
503 # TODO: if high is bigint, we should do high++?
504 $high = ($high < ~0) ? prev_prime($high + 1) : prev_prime($high);
505 return $low if ($low == $high) && is_prob_prime($low);
506 return if $low >= $high;
507
508 # At this point low and high are both primes, and low < high.
509 return $_random_prime->($low, $high);
510 }
511
512 sub random_ndigit_prime {
513 my($digits) = @_;
514 croak "random_ndigit_prime, digits must be >= 1" unless $digits >= 1;
515
516 return _random_xscount_prime( int(10 ** ($digits-1)), int(10 ** $digits) )
517 if $digits <= 6 && MPU_USE_XS;
518
519 my $bigdigits = $digits >= MPU_MAXDIGITS;
520 if ($bigdigits && prime_get_config->{'nobigint'}) {
521 croak "random_ndigit_prime with -nobigint, digits out of range"
522 if $digits > MPU_MAXDIGITS;
523 # Special case for nobigint and threshold digits
524 if (!defined $_random_ndigit_ranges[$digits]) {
525 my $low = int(10 ** ($digits-1));
526 my $high = ~0;
527 $_random_ndigit_ranges[$digits] = [next_prime($low),prev_prime($high)];
528 }
529 }
530
531 if (!defined $_random_ndigit_ranges[$digits]) {
532 if ($bigdigits) {
533 my $low = Math::BigInt->new('10')->bpow($digits-1);
534 my $high = Math::BigInt->new('10')->bpow($digits);
535 # Just pull the range in to the nearest odd.
536 $_random_ndigit_ranges[$digits] = [$low+1, $high-1];
537 } else {
538 my $low = int(10 ** ($digits-1));
539 my $high = int(10 ** $digits);
540 # Note: Perl 5.6.2 cannot represent 10**15 as an integer, so things
541 # will crash all over the place if you try. We can stringify it, but
542 # will just fail tests later.
543 $_random_ndigit_ranges[$digits] = [next_prime($low),prev_prime($high)];
544 }
545 }
546 my ($low, $high) = @{$_random_ndigit_ranges[$digits]};
547 return $_random_prime->($low, $high);
548 }
549
550 my @_random_nbit_m;
551 my @_random_nbit_lambda;
552 my @_random_nbit_arange;
553
554 sub random_nbit_prime {
555 my($bits) = @_;
556 croak "random_nbit_prime, bits must be >= 2" unless $bits >= 2;
557 $bits = int("$bits");
558
559 _set_randf();
560
561 # Very small size, use the nth-prime method
562 if ($bits <= 18 && MPU_USE_XS) {
563 if ($bits <= 4) {
564 return (2,3)[$_RANDF_NBIT->(1)] if $bits == 2;
565 return (5,7)[$_RANDF_NBIT->(1)] if $bits == 3;
566 return (11,13)[$_RANDF_NBIT->(1)] if $bits == 4;
567 }
568 return _random_xscount_prime( 1 << ($bits-1), 1 << $bits );
569 }
570
571 croak "Mid-size random primes not supported on broken old Perl"
572 if OLD_PERL_VERSION && MPU_64BIT && $bits > 49 && $bits <= 64;
573
574 # Fouque and Tibouchi (2011) Algorithm 1 (basic)
575 # Modified to make sure the nth bit is always set.
576 #
577 # Example for random_nbit_prime(512) on 64-bit Perl:
578 # p: 1aaaaaaaabbbbbbbbbbbbbbbbbbbb1
579 # ^^ ^ ^--- Trailing 1 so p is odd
580 # || +--- 512-63-2 = 447 lower bits selected before loop
581 # |+--- 63 upper bits selected in loop, repeated until p is prime
582 # +--- upper bit is 1 so we generate an n-bit prime
583 # total: 1 + 63 + 447 + 1 = 512 bits
584 #
585 # Algorithm 2 is implemented in a previous commit on github. The problem
586 # is that it doesn't set the nth bit, and making that change requires a
587 # modification of the algorithm. It was not a lot faster than this A1
588 # with the native int trial division. If the irandf function was very
589 # slow, then A2 would look more promising.
590 #
591 if (1 && $bits > 64) {
592 my $l = (MPU_64BIT && $bits > 79) ? 63 : 31;
593 $l = 49 if $l == 63 && OLD_PERL_VERSION; # Fix for broken Perl 5.6
594 $l = $bits-2 if $bits-2 < $l;
595
596 my $brand = $_RANDF_NBIT->($bits-$l-2);
597 $brand = Math::BigInt->new("$brand") unless ref($brand) eq 'Math::BigInt';
598 my $b = $brand->blsft(1)->binc();
599
600 # Precalculate some modulii so we can do trial division on native int
601 # 9699690 = 2*3*5*7*11*13*17*19, so later operations can be native ints
602 my @premod;
603 my $bpremod = _bigint_to_int($b->copy->bmod(9699690));
604 my $twopremod = _bigint_to_int(Math::BigInt->new(2)->bmodpow($bits-$l-1, 9699690));
605 foreach my $zi (0 .. 19-1) {
606 foreach my $pm (3, 5, 7, 11, 13, 17, 19) {
607 next if $zi >= $pm || defined $premod[$pm];
608 $premod[$pm] = $zi if ( ($twopremod*$zi+$bpremod) % $pm) == 0;
609 }
610 }
611 _make_big_gcds() if $_big_gcd_use < 0;
612 if (!MPU_USE_GMP) { require Math::Prime::Util::PP; }
613
614 my $loop_limit = 1_000_000;
615 while ($loop_limit-- > 0) {
616 my $a = (1 << $l) + $_RANDF_NBIT->($l);
617 # $a % s == $premod[s] => $p % s == 0 => p will be composite
618 next if $a % 3 == $premod[ 3] || $a % 5 == $premod[ 5]
619 || $a % 7 == $premod[ 7] || $a % 11 == $premod[11]
620 || $a % 13 == $premod[13] || $a % 17 == $premod[17]
621 || $a % 19 == $premod[19];
622 my $p = Math::BigInt->new("$a")->blsft($bits-$l-1)->badd($b);
623 #die " $a $b $p" if $a % 11 == $premod[11] && $p % 11 != 0;
624 #die "!$a $b $p" if $a % 11 != $premod[11] && $p % 11 == 0;
625 if (MPU_USE_GMP) {
626 next unless Math::Prime::Util::GMP::is_prime($p);
627 } else {
628 next unless Math::BigInt::bgcd($p, 1348781387) == 1; # 23-43
629 if ($_big_gcd_use && $p > $_big_gcd_top) {
630 next unless Math::BigInt::bgcd($p, $_big_gcd[0]) == 1;
631 next unless Math::BigInt::bgcd($p, $_big_gcd[1]) == 1;
632 next unless Math::BigInt::bgcd($p, $_big_gcd[2]) == 1;
633 next unless Math::BigInt::bgcd($p, $_big_gcd[3]) == 1;
634 }
635 # We know we don't have GMP and are > 2^64, so go directly to this.
636 next unless Math::Prime::Util::PP::is_bpsw_prime($p);
637 }
638 return $p;
639 }
640 croak "Random function broken?";
641 }
642
643 # The Trivial method. Great uniformity, and fine for small sizes. It
644 # gets very slow as the bit size increases, but that is why we have the
645 # method above for bigints.
646 if (1) {
647
648 my $loop_limit = 2_000_000;
649 if ($bits > MPU_MAXBITS) {
650 my $p = Math::BigInt->bone->blsft($bits-1)->binc();
651 while ($loop_limit-- > 0) {
652 my $n = Math::BigInt->new(''.$_RANDF_NBIT->($bits-2))->blsft(1)->badd($p);
653 return $n if is_prob_prime($n);
654 }
655 } else {
656 my $p = (1 << ($bits-1)) + 1;
657 while ($loop_limit-- > 0) {
658 my $n = $p + ($_RANDF_NBIT->($bits-2) << 1);
659 return $n if is_prob_prime($n);
660 }
661 }
662 croak "Random function broken?";
663
664 } else {
665
666 # Send through the generic random_prime function. Decently fast, but
667 # quite a bit slower than the F&T A1 method above.
668 if (!defined $_random_nbit_ranges[$bits]) {
669 if ($bits > MPU_MAXBITS) {
670 my $low = Math::BigInt->new('2')->bpow($bits-1);
671 my $high = Math::BigInt->new('2')->bpow($bits);
672 # Don't pull the range in to primes, just odds
673 $_random_nbit_ranges[$bits] = [$low+1, $high-1];
674 } else {
675 my $low = 1 << ($bits-1);
676 my $high = ($bits == MPU_MAXBITS)
677 ? ~0-1
678 : ~0 >> (MPU_MAXBITS - $bits);
679 $_random_nbit_ranges[$bits] = [next_prime($low-1),prev_prime($high+1)];
680 # Example: bits = 7.
681 # low = 1<<6 = 64. next_prime(64-1) = 67
682 # high = ~0 >> (64-7) = 127. prev_prime(127+1) = 127
683 }
684 }
685 my ($low, $high) = @{$_random_nbit_ranges[$bits]};
686 return $_random_prime->($low, $high);
687
688 }
689 }
690
691
692 # For stripping off the header on certificates so they can be combined.
693 sub _strip_proof_header {
694 my $proof = shift;
695 $proof =~ s/^\[MPU - Primality Certificate\]\nVersion \S+\n+Proof for:\nN (\d+)\n+//ms;
696 return $proof;
697 }
698
699
700 sub random_maurer_prime {
701 my $k = shift;
702 croak "random_maurer_prime, bits must be >= 2" unless $k >= 2;
703 $k = int("$k");
704
705 return random_nbit_prime($k) if $k <= MPU_MAXBITS && !OLD_PERL_VERSION;
706
707 my ($n, $cert) = random_maurer_prime_with_cert($k);
708 croak "maurer prime $n failed certificate verification!"
709 unless verify_prime($cert);
710 return $n;
711 }
712
713 sub random_maurer_prime_with_cert {
714 my $k = shift;
715 croak "random_maurer_prime, bits must be >= 2" unless $k >= 2;
716 $k = int("$k");
717
718 # This should never happen. Trap now to prevent infinite loop.
719 croak "number of bits must not be a bigint" if ref($k) eq 'Math::BigInt';
720
721 # Results for random_nbit_prime are proven for all native bit sizes.
722 my $p0 = MPU_MAXBITS;
723 $p0 = 49 if OLD_PERL_VERSION && MPU_MAXBITS > 49;
724
725 if ($k <= $p0) {
726 my $n = random_nbit_prime($k);
727 my ($isp, $cert) = is_provable_prime_with_cert($n);
728 croak "small nbit prime could not be proven" if $isp != 2;
729 return ($n, $cert);
730 }
731
732 # Set verbose to 3 to get pretty output like Crypt::Primes
733 my $verbose = prime_get_config->{'verbose'};
734 local $| = 1 if $verbose > 2;
735
736 do { require Math::BigFloat; Math::BigFloat->import(); }
737 if !defined $Math::BigFloat::VERSION;
738
739 # Ignore Maurer's g and c that controls how much trial division is done.
740 my $r = Math::BigFloat->new("0.5"); # relative size of the prime q
741 my $m = 20; # makes sure R is big enough
742 _set_randf();
743
744 # Generate a random prime q of size $r*$k, where $r >= 0.5. Try to
745 # cleverly select r to match the size of a typical random factor.
746 if ($k > 2*$m) {
747 do {
748 my $s = Math::BigFloat->new($_RANDF->(2147483647))->bdiv(2147483648);
749 $r = Math::BigFloat->new(2)->bpow($s-1);
750 } while ($k*$r >= $k-$m);
751 }
752
753 # I've seen +0, +1, and +2 here. Maurer uses +0. Menezes uses +1.
754 # We can use +1 because we're using BLS75 theorem 3 later.
755 my $smallk = int(($r * $k)->bfloor->bstr) + 1;
756 my ($q, $qcert) = random_maurer_prime_with_cert($smallk);
757 $q = Math::BigInt->new("$q") unless ref($q) eq 'Math::BigInt';
758 my $I = Math::BigInt->new(2)->bpow($k-2)->bdiv($q)->bfloor->as_int();
759 print "r = $r k = $k q = $q I = $I\n" if $verbose && $verbose != 3;
760 $qcert = ($q < Math::BigInt->new("18446744073709551615"))
761 ? "" : _strip_proof_header($qcert);
762
763 # Big GCD's are hugely fast with GMP or Pari, but super slow with Calc.
764 _make_big_gcds() if $_big_gcd_use < 0;
765 my $ONE = Math::BigInt->bone;
766 my $TWO = $ONE->copy->binc;
767
768 my $loop_limit = 1_000_000 + $k * 1_000;
769 while ($loop_limit-- > 0) {
770 # R is a random number between $I+1 and 2*$I
771 #my $R = $I + 1 + $_RANDF->( $I - 1 );
772 my $R = $I->copy->binc->badd( $_RANDF->($I->copy->bdec) );
773 #my $n = 2 * $R * $q + 1;
774 my $nm1 = $TWO->copy->bmul($R)->bmul($q);
775 my $n = $nm1->copy->binc;
776 # We constructed a promising looking $n. Now test it.
777 print "." if $verbose > 2;
778 if (MPU_USE_GMP) {
779 # MPU::GMP::is_prob_prime has fast tests built in.
780 next unless Math::Prime::Util::GMP::is_prob_prime($n);
781 } else {
782 # No GMP, so first do trial divisions, then a SPSP test.
783 next unless Math::BigInt::bgcd($n, 111546435)->is_one;
784 if ($_big_gcd_use && $n > $_big_gcd_top) {
785 next unless Math::BigInt::bgcd($n, $_big_gcd[0])->is_one;
786 next unless Math::BigInt::bgcd($n, $_big_gcd[1])->is_one;
787 next unless Math::BigInt::bgcd($n, $_big_gcd[2])->is_one;
788 next unless Math::BigInt::bgcd($n, $_big_gcd[3])->is_one;
789 }
790 print "+" if $verbose > 2;
791 next unless is_strong_pseudoprime($n, 3);
792 }
793 print "*" if $verbose > 2;
794
795 # We could pick a random generator by doing:
796 # Step 1: pick a random r
797 # Step 2: compute g = r^((n-1)/q) mod p
798 # Step 3: if g == 1, goto Step 1.
799 # Note that n = 2*R*q+1, hence the exponent is 2*R.
800
801 # We could set r = 0.3333 earlier, then use BLS75 theorem 5 here.
802 # The chain would be shorter, requiring less overall work for
803 # large inputs. Maurer's paper discusses the idea.
804
805 # Use BLS75 theorem 3. This is easier and possibly faster than
806 # BLS75 theorem 4 (Pocklington) used by Maurer's paper.
807
808 # Check conditions -- these should be redundant.
809 my $m = $TWO * $R;
810 if (! ($q->is_odd && $q > 2 && $m > 0 &&
811 $m * $q + $ONE == $n && $TWO*$q+$ONE > $n->copy->bsqrt()) ) {
812 carp "Maurer prime failed BLS75 theorem 3 conditions. Retry.";
813 next;
814 }
815 # Find a suitable a. Move on if one isn't found quickly.
816 foreach my $trya (2, 3, 5, 7, 11, 13) {
817 my $a = Math::BigInt->new($trya);
818 # m/2 = R (n-1)/2 = (2*R*q)/2 = R*q
819 next unless $a->copy->bmodpow($R, $n) != $nm1;
820 next unless $a->copy->bmodpow($R*$q, $n) == $nm1;
821 print "($k)" if $verbose > 2;
822 croak "Maurer prime $n=2*$R*$q+1 failed BPSW" unless is_prob_prime($n);
823 my $cert = "[MPU - Primality Certificate]\nVersion 1.0\n\n" .
824 "Proof for:\nN $n\n\n" .
825 "Type BLS3\nN $n\nQ $q\nA $a\n" .
826 $qcert;
827 return ($n, $cert);
828 }
829 # Didn't pass the selected a values. Try another R.
830 }
831 croak "Failure in random_maurer_prime, could not find a prime\n";
832 } # End of random_maurer_prime
833
834 # Gordon's algorithm for generating a strong prime.
835 sub random_strong_prime {
836 my $t = shift;
837 croak "random_strong_prime, bits must be >= 128" unless $t >= 128;
838 $t = int("$t");
839
840 croak "Random strong primes must be >= 173 bits on old Perl"
841 if OLD_PERL_VERSION && MPU_64BIT && $t < 173;
842
843 _set_randf();
844
845 my $l = (($t+1) >> 1) - 2;
846 my $lp = int($t/2) - 20;
847 my $lpp = $l - 20;
848 while (1) {
849 my $qp = random_nbit_prime($lp);
850 my $qpp = random_nbit_prime($lpp);
851 $qp = Math::BigInt->new("$qp") unless ref($qp) eq 'Math::BigInt';
852 $qpp = Math::BigInt->new("$qpp") unless ref($qpp) eq 'Math::BigInt';
853 my ($il, $rem) = Math::BigInt->new(2)->bpow($l-1)->bdec()->bdiv(2*$qpp);
854 $il++ if $rem > 0;
855 $il = $il->as_int();
856 my $iu = Math::BigInt->new(2)->bpow($l)->bsub(2)->bdiv(2*$qpp)->as_int();
857 my $istart = $il + $_RANDF->($iu - $il);
858 for (my $i = $istart; $i <= $iu; $i++) { # Search for q
859 my $q = 2 * $i * $qpp + 1;
860 next unless is_prob_prime($q);
861 my $pp = $qp->copy->bmodpow($q-2, $q)->bmul(2)->bmul($qp)->bdec();
862 my ($jl, $rem) = Math::BigInt->new(2)->bpow($t-1)->bsub($pp)->bdiv(2*$q*$qp);
863 $jl++ if $rem > 0;
864 $jl = $jl->as_int();
865 my $ju = Math::BigInt->new(2)->bpow($t)->bdec()->bsub($pp)->bdiv(2*$q*$qp)->as_int();
866 my $jstart = $jl + $_RANDF->($ju - $jl);
867 for (my $j = $jstart; $j <= $ju; $j++) { # Search for p
868 my $p = $pp + 2 * $j * $q * $qp;
869 return $p if is_prob_prime($p);
870 }
871 }
872 }
873 }
874
875 sub random_proven_prime {
876 my $k = shift;
877 my ($n, $cert) = random_proven_prime_with_cert($k);
878 croak "random_proven_prime $n failed certificate verification!"
879 unless verify_prime($cert);
880 return $n;
881 }
882
883 sub random_proven_prime_with_cert {
884 my $k = shift;
885
886 if (prime_get_config->{'gmp'} && $k <= 450) {
887 my $n = random_nbit_prime($k);
888 my ($isp, $cert) = is_provable_prime_with_cert($n);
889 croak "small nbit prime could not be proven" if $isp != 2;
890 return ($n, $cert);
891 }
892 return random_maurer_prime_with_cert($k);
893 }
894
895 sub miller_rabin_random {
896 my($n, $k, $seed) = @_;
897
898 # Testing this many bases is silly, but let's pretend they have some
899 # good reason. A composite n > 9 must have at least n/4 witnesses,
900 # hence we need to check only floor(3/4)+1 at most. We could improve
901 # this is $_Config{'assume_rh'} is true, to 1 .. 2(logn)^2.
902 if ($k >= int(3*$n/4)) {
903 return is_strong_pseudoprime($n, 2 .. int(3*$n/4)+1+2 );
904 }
905
906 _set_randf();
907
908 my $brange = $n-3;
909 # Do one first before doing batches
910 return 0 unless is_strong_pseudoprime($n, $_RANDF->($brange)+2 );
911 $k--;
912 while ($k > 0) {
913 my $nbases = ($k >= 20) ? 20 : $k;
914 my @bases = map { $_RANDF->($brange)+2 } 1..$nbases;
915 return 0 unless is_strong_pseudoprime($n, @bases);
916 $k -= $nbases;
917 }
918 1;
919 }
920
921 1;
922
923 __END__
924
925
926 # ABSTRACT: Generate random primes
927
928 =pod
929
930 =encoding utf8
931
932 =head1 NAME
933
934 Math::Prime::Util::RandomPrimes - Generate random primes
935
936
937 =head1 VERSION
938
939 Version 0.37
940
941
942 =head1 SYNOPSIS
943
944 =head1 DESCRIPTION
945
946 Routines to generate random primes, including constructing proven primes.
947
948
949 =head1 RANDOM UTILITY FUNCTIONS
950
951 =head2 get_randf
952
953 Gets a subroutine that will produce random integers between 0 and C<n>,
954 inclusive. The argument C<n> can be a bigint.
955
956 =head2 get_randf_nbit
957
958 Gets a subroutine that will produce random integers between 0 and C<2^n-1>,
959 inclusive.
960
961
962 =head1 RANDOM PRIME FUNCTIONS
963
964 =head2 random_prime
965
966 Generate a random prime between C<low> and C<high>. If given one argument,
967 C<low> will be 2.
968
969 =head2 random_ndigit_prime
970
971 Generate a random prime with C<n> digits. C<n> must be at least 1.
972
973 =head2 random_nbit_prime
974
975 Generate a random prime with C<n> bits. C<n> must be at least 2.
976
977 =head2 random_maurer_prime
978
979 Construct a random provable prime of C<n> bits using Maurer's FastPrime
980 algorithm. C<n> must be at least 2.
981
982 =head2 random_maurer_prime_with_cert
983
984 Construct a random provable prime of C<n> bits using Maurer's FastPrime
985 algorithm. C<n> must be at least 2. Returns a list of two items: the
986 prime and the certificate.
987
988 =head2 random_strong_prime
989
990 Construct a random strong prime of C<n> bits. C<n> must be at least 128.
991
992 =head2 random_proven_prime
993
994 Generate or construct a random provable prime of C<n> bits. C<n> must
995 be at least 2.
996
997 =head2 random_proven_prime_with_cert
998
999 Generate or construct a random provable prime of C<n> bits. C<n> must
1000 be at least 2. Returns a list of two items: the prime and the certificate.
1001
1002
1003 =head1 RANDOM PRIMALITY FUNCTIONS
1004
1005 =head2 miller_rabin_random
1006
1007 Given a number C<n> and a number of tests to perform C<k>, this does C<k>
1008 Miller-Rabin tests on C<n> using randomly selected bases. The return value
1009 is 1 if all bases are a witness to to C<n>, or 0 if any of them fail.
1010
1011 =head1 SEE ALSO
1012
1013 L<Math::Prime::Util>
1014
1015 =head1 AUTHORS
1016
1017 Dana Jacobsen E<lt>dana@acm.orgE<gt>
1018
1019
1020 =head1 COPYRIGHT
1021
1022 Copyright 2012-2013 by Dana Jacobsen E<lt>dana@acm.orgE<gt>
1023
1024 This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
1025
1026 =cut
33
44 BEGIN {
55 $Math::Prime::Util::ZetaBigFloat::AUTHORITY = 'cpan:DANAJ';
6 $Math::Prime::Util::ZetaBigFloat::VERSION = '0.36';
6 $Math::Prime::Util::ZetaBigFloat::VERSION = '0.37';
77 }
88
99 BEGIN {
279279 $sum_n->bmul($d)->badd( $sum_d->copy->bmul($n) );
280280 $sum_d->bmul($d);
281281 $gcd = Math::BigInt::bgcd($sum_n, $sum_d);
282 do { $sum_n /= $gcd; $sum_d /= $gcd; } unless $gcd->is_one;
282 do {
283 $sum_n = int($sum_n / $gcd);
284 $sum_d = int($sum_d / $gcd);
285 } unless $gcd->is_one;
283286 my $dmul = (2*$i+1) * (2*$i+2);
284287 $n->bmul($nterms+$i)->blsft(2);
285288 $d->bdiv($nterms-$i)->bmul($dmul);
468471
469472 =head1 VERSION
470473
471 Version 0.36
474 Version 0.37
472475
473476
474477 =head1 SYNOPSIS
44
55 BEGIN {
66 $Math::Prime::Util::AUTHORITY = 'cpan:DANAJ';
7 $Math::Prime::Util::VERSION = '0.36';
8 }
9
10 BEGIN {
11 # If they have used Math::BigInt already, make sure we don't change the
12 # back end. If they have not, try to get one of the fast ones.
13 do { require Math::BigInt; Math::BigInt->import(try=>"GMP,Pari"); }
14 unless defined $Math::BigInt::VERSION;
15 }
16
7 $Math::Prime::Util::VERSION = '0.37';
8 }
179
1810 # parent is cleaner, and in the Perl 5.10.1 / 5.12.0 core, but not earlier.
1911 # use parent qw( Exporter );
7466 # We could alternately use Config's $Config{uvsize} for MAXBITS
7567 use constant OLD_PERL_VERSION=> $] < 5.008;
7668 use constant MPU_MAXBITS => (~0 == 4294967295) ? 32 : 64;
77 use constant MPU_64BIT => MPU_MAXBITS == 64;
7869 use constant MPU_32BIT => MPU_MAXBITS == 32;
7970 use constant MPU_MAXPARAM => MPU_32BIT ? 4294967295 : 18446744073709551615;
8071 use constant MPU_MAXDIGITS => MPU_32BIT ? 10 : 20;
8172 use constant MPU_MAXPRIME => MPU_32BIT ? 4294967291 : 18446744073709551557;
8273 use constant MPU_MAXPRIMEIDX => MPU_32BIT ? 203280221 : 425656284035217743;
8374 use constant UVPACKLET => MPU_32BIT ? 'L' : 'Q';
84
85 # Load PP code. Nothing exported.
86 require Math::Prime::Util::PP; Math::Prime::Util::PP->import();
8775
8876 eval {
8977 return 0 if defined $ENV{MPU_NO_XS} && $ENV{MPU_NO_XS} == 1;
10088 $_Config{'xs'} = 0;
10189 $_Config{'maxbits'} = MPU_MAXBITS;
10290
103 *_validate_num = \&Math::Prime::Util::PP::_validate_num;
104 *is_prime = \&Math::Prime::Util::PP::is_prime;
105 *is_prob_prime = \&Math::Prime::Util::PP::is_prob_prime;
106 *is_pseudoprime=\&Math::Prime::Util::PP::is_pseudoprime;
107 *is_strong_pseudoprime=\&Math::Prime::Util::PP::is_strong_pseudoprime;
108 *is_lucas_pseudoprime=\&Math::Prime::Util::PP::is_lucas_pseudoprime;
109 *is_strong_lucas_pseudoprime=\&Math::Prime::Util::PP::is_strong_lucas_pseudoprime;
110 *is_extra_strong_lucas_pseudoprime=\&Math::Prime::Util::PP::is_extra_strong_lucas_pseudoprime;
111 *is_almost_extra_strong_lucas_pseudoprime=\&Math::Prime::Util::PP::is_almost_extra_strong_lucas_pseudoprime;
112 *is_frobenius_underwood_pseudoprime=\&Math::Prime::Util::PP::is_frobenius_underwood_pseudoprime;
113 *is_aks_prime =\&Math::Prime::Util::PP::is_aks_prime;
91 # Load PP front end code
92 require Math::Prime::Util::PPFE;
93
11494 *next_prime = \&Math::Prime::Util::_generic_next_prime;
11595 *prev_prime = \&Math::Prime::Util::_generic_prev_prime;
116 *exp_mangoldt = \&Math::Prime::Util::_generic_exp_mangoldt;
117 *euler_phi = \&Math::Prime::Util::_generic_euler_phi;
118 *jordan_totient= \&Math::Prime::Util::PP::jordan_totient;
119 *moebius = \&Math::Prime::Util::_generic_moebius;
120 *mertens = \&Math::Prime::Util::_generic_mertens;
12196 *prime_count = \&Math::Prime::Util::_generic_prime_count;
122 *nth_prime = \&Math::Prime::Util::PP::nth_prime;
123 *carmichael_lambda = \&Math::Prime::Util::_generic_carmichael_lambda;
124 *kronecker = \&Math::Prime::Util::_generic_kronecker;
125 *divisor_sum = \&Math::Prime::Util::_generic_divisor_sum;
126 *znorder = \&Math::Prime::Util::PP::znorder;
127 *znprimroot = \&Math::Prime::Util::_generic_znprimroot;
128 *znlog = \&Math::Prime::Util::PP::znlog;
129 *legendre_phi = \&Math::Prime::Util::PP::legendre_phi;
130 *gcd = \&Math::Prime::Util::PP::gcd;
131 *lcm = \&Math::Prime::Util::PP::lcm;
13297 *factor = \&Math::Prime::Util::_generic_factor;
13398 *factor_exp = \&Math::Prime::Util::_generic_factor_exp;
134 *divisors = \&Math::Prime::Util::_generic_divisors;
135 *forprimes = sub (&$;$) { _generic_forprimes(@_); }; ## no critic qw(ProhibitSubroutinePrototypes)
136 *forcomposites = sub (&$;$) { _generic_forcomposites(@_); }; ## no critic qw(ProhibitSubroutinePrototypes)
137 *fordivisors = sub (&$) { _generic_fordivisors(@_); }; ## no critic qw(ProhibitSubroutinePrototypes)
138
139 *_prime_memfreeall = \&Math::Prime::Util::PP::_prime_memfreeall;
140 *prime_memfree = \&Math::Prime::Util::PP::prime_memfree;
141 *prime_precalc = \&Math::Prime::Util::PP::prime_precalc;
142
143 # These probably shouldn't even be aliased, as they're not public
144 *trial_factor = \&Math::Prime::Util::PP::trial_factor;
145 *fermat_factor = \&Math::Prime::Util::PP::fermat_factor;
146 *holf_factor = \&Math::Prime::Util::PP::holf_factor;
147 *squfof_factor = \&Math::Prime::Util::PP::squfof_factor;
148 *pbrent_factor = \&Math::Prime::Util::PP::pbrent_factor;
149 *prho_factor = \&Math::Prime::Util::PP::prho_factor;
150 *pminus1_factor = \&Math::Prime::Util::PP::pminus1_factor;
151 *pplus1_factor = \&Math::Prime::Util::PP::pminus1_factor; # TODO: implement PP p+1.
15299 };
153100
154101 # aliases for deprecated names. Will eventually be removed.
217164 } elsif ($param eq 'irand') {
218165 croak "irand must supply a sub" unless (!defined $value) || (ref($value) eq 'CODE');
219166 $_Config{'irand'} = $value;
220 _clear_randf(); # Force a new randf to be generated
221167 } elsif ($param =~ /^(assume[_ ]?)?[ge]?rh$/ || $param =~ /riemann\s*h/) {
222168 $_Config{'assume_rh'} = ($value) ? 1 : 0;
223169 } elsif ($param eq 'verbose') {
235181 1;
236182 }
237183
238
239184 sub _bigint_to_int {
240185 return (OLD_PERL_VERSION) ? unpack(UVPACKLET,pack(UVPACKLET,$_[0]->bstr))
241186 : int($_[0]->bstr);
242187 }
243
244 *_validate_positive_integer = \&Math::Prime::Util::PP::_validate_positive_integer;
245
246 sub _upgrade_to_float {
247 do { require Math::BigFloat; Math::BigFloat->import(); }
248 if !defined $Math::BigFloat::VERSION;
249 return Math::BigFloat->new($_[0]);
250 }
251
252 my @_primes_small = (
253 0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,
254 101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,
255 193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,
256 293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,
257 409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509);
258 sub _tiny_prime_count {
259 my($n) = @_;
260 return if $n >= $_primes_small[-1];
261 my $j = $#_primes_small;
262 my $i = 1 + ($n >> 4);
263 while ($i < $j) {
264 my $mid = ($i+$j)>>1;
265 if ($_primes_small[$mid] <= $n) { $i = $mid+1; }
266 else { $j = $mid; }
188 sub _to_bigint {
189 do { require Math::BigInt; Math::BigInt->import(try=>"GMP,Pari"); }
190 unless defined $Math::BigInt::VERSION;
191 return Math::BigInt->new("$_[0]");
192 }
193 sub _reftyped {
194 my $ref0 = ref($_[0]);
195 if ($ref0) {
196 return ($ref0 eq ref($_[1])) ? $_[1] : $ref0->new("$_[1]");
267197 }
268 return $i-1;
269 }
270
271
272
198 my $strn = "$_[1]";
199 return $_[1] if $strn <= ~0;
200 do { require Math::BigInt; Math::BigInt->import(try=>"GMP,Pari"); }
201 unless defined $Math::BigInt::VERSION;
202 return Math::BigInt->new($strn);
203 }
204
205
206 #*_validate_positive_integer = \&Math::Prime::Util::PP::_validate_positive_integer;
207 sub _validate_positive_integer {
208 my($n, $min, $max) = @_;
209 croak "Parameter must be defined" if !defined $n;
210 if (ref($n) eq 'CODE') {
211 $_[0] = $_[0]->();
212 $n = $_[0];
213 }
214 if (ref($n) eq 'Math::BigInt') {
215 croak "Parameter '$n' must be a positive integer"
216 if $n->sign() ne '+' || !$n->is_int();
217 $_[0] = _bigint_to_int($_[0])
218 if $n <= (OLD_PERL_VERSION ? 562949953421312 : ''.~0);
219 } else {
220 my $strn = "$n";
221 croak "Parameter '$strn' must be a positive integer"
222 if $strn =~ tr/0123456789//c && $strn !~ /^\+?\d+$/;
223 if ($n <= (OLD_PERL_VERSION ? 562949953421312 : ''.~0)) {
224 $_[0] = $strn if ref($n);
225 } else {
226 #$_[0] = Math::BigInt->new($strn)
227 $_[0] = _to_bigint($strn);
228 }
229 }
230 $_[0]->upgrade(undef) if ref($_[0]) && $_[0]->upgrade();
231 croak "Parameter '$_[0]' must be >= $min" if defined $min && $_[0] < $min;
232 croak "Parameter '$_[0]' must be <= $max" if defined $max && $_[0] > $max;
233 1;
234 }
273235
274236
275237 #############################################################################
276238
277239 sub primes {
278 my $optref = (ref $_[0] eq 'HASH') ? shift : {};
279 croak "no parameters to primes" unless scalar @_ > 0;
280 croak "too many parameters to primes" unless scalar @_ <= 2;
281 my $low = (@_ == 2) ? shift : 2;
282 my $high = shift;
283
284 _validate_num($low) || _validate_positive_integer($low);
285 _validate_num($high) || _validate_positive_integer($high);
240 my($low,$high) = @_;
241 if (scalar @_ > 1) {
242 _validate_num($low) || _validate_positive_integer($low);
243 _validate_num($high) || _validate_positive_integer($high);
244 } else {
245 ($low,$high) = (2, $low);
246 _validate_num($high) || _validate_positive_integer($high);
247 }
286248
287249 my $sref = [];
288250 return $sref if ($low > $high) || ($high < 2);
298260 }
299261 return $sref;
300262 }
263 require Math::Prime::Util::PP;
301264 return Math::Prime::Util::PP::primes($low,$high);
302265 }
303266
304 my $method = $optref->{'method'};
305 $method = 'Dynamic' unless defined $method;
306
307 if ($method =~ /^(Dyn\w*|Default|Generate)$/i) {
308 # Dynamic -- we should try to do something smart.
309
310 # Tiny range?
311 if (($low+1) >= $high) {
312 $method = 'Trial';
313
314 # Fast for cached sieve?
315 } elsif (($high <= (65536*30)) || ($high <= _get_prime_cache_size())) {
316 $method = 'Sieve';
317
318 # At some point the segmented sieve is faster than the base sieve, not
319 # to mention using much less memory.
320 } elsif ($high > (1024*1024*30)) {
321 $method = 'Segment';
322 # The segment sieve doesn't itself use a segmented sieve for the base,
323 # so it will slow down for very large endpoints (larger than 10^16).
324 # Make a crude predictor of segment and trial and decide.
325 if ($high > 10**14) {
326 my $est_trial = ($high-$low) / 1_000_000; # trial estimate 1s per 1M
327 # segment is exponential on high, plus very fast scan.
328 my $est_segment = 0.2 * 3.3**(log($high / 10**15) / log(10))
329 + ($high-$low) / 1_000_000_000_000;
330 $method = 'Trial' if $est_trial <= $est_segment;
331 }
332
333 # Only want half or less of the range low-high ?
334 } elsif ( int($high / ($high-$low)) >= 2 ) {
335 $method = 'Segment';
336
337 } else {
338 $method = 'Sieve';
339 }
267 # Decide the method to use. We have four to choose from:
268 # 1. Trial No memory, no overhead, but more time per prime.
269 # 2. Sieve Monolithic cached sieve.
270 # 3. Erat Monolithic uncached sieve.
271 # 4. Segment Segment sieve. Never a bad decision.
272
273 if (($low+1) >= $high || # Tiny range, or
274 $high > 10**14 && ($high-$low) < 50000) { # Small relative range
275
276 $sref = trial_primes($low, $high);
277
278 } elsif ($high <= (65536*30) || # Very small, or
279 $high <= _get_prime_cache_size()) { # already in the main cache.
280
281 $sref = sieve_primes($low, $high);
282
283 } else {
284
285 $sref = segment_primes($low, $high);
286
340287 }
341288
342 if ($method =~ /^Simple\w*$/i) {
343 carp "Method 'Simple' is deprecated.";
344 $method = 'Erat';
345 }
346
347 if ($method =~ /^Trial$/i) { $sref = trial_primes($low, $high); }
348 elsif ($method =~ /^Erat\w*$/i) { $sref = erat_primes($low, $high); }
349 elsif ($method =~ /^Seg\w*$/i) { $sref = segment_primes($low, $high); }
350 elsif ($method =~ /^Sieve$/i) { $sref = sieve_primes($low, $high); }
351 else { croak "Unknown prime method: $method"; }
352
353 # Using this line:
289 # We could return an array ref in scalar context, array in list context with:
354290 # return (wantarray) ? @{$sref} : $sref;
355 # would allow us to return an array ref in scalar context, and an array
356 # in array context. Handy for people who might write:
357 # @primes = primes(100);
358 # but I think the dual interface could bite us later.
291 # but I think the dual interface could be confusing, albeit often handy.
359292 return $sref;
360293 }
361294
362
363 # For random primes, there are two good papers that should be examined:
364 #
365 # "Fast Generation of Prime Numbers and Secure Public-Key
366 # Cryptographic Parameters" by Ueli M. Maurer, 1995
367 # http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.26.2151
368 # related discussions:
369 # http://www.daimi.au.dk/~ivan/provableprimesproject.pdf
370 # Handbook of Applied Cryptography by Menezes, et al.
371 #
372 # "Close to Uniform Prime Number Generation With Fewer Random Bits"
373 # by Pierre-Alain Fouque and Mehdi Tibouchi, 2011
374 # http://eprint.iacr.org/2011/481
375 #
376 # Some things to note:
377 #
378 # 1) Joye and Paillier have patents on their methods. Never use them.
379 #
380 # 2) The easy method of next_prime(random number), known as PRIMEINC, is
381 # fast but gives a terrible distribution. It has a positive bias and
382 # most importantly the probability for a prime is proportional to its
383 # gap, which makes a terrible distribution (some numbers in the range
384 # will be thousands of times more likely than others).
385 #
386 # We use:
387 # TRIVIAL range within native integer size (2^32 or 2^64)
388 # FTA1 random_nbit_prime with 65+ bits
389 # INVA1 other ranges with 65+ bit range
390 # where
391 # TRIVIAL = monte-carlo method or equivalent, perfect uniformity.
392 # FTA1 = Fouque/Tibouchi A1, very close to uniform
393 # INVA1 = inverted FTA1, less uniform but works with arbitrary ranges
394 #
395 # The random_maurer_prime function uses Maurer's FastPrime algorithm.
396 #
397 # If Math::Prime::Util::GMP is installed, these functions will be many times
398 # faster than other methods (e.g. Math::Pari monte-carlo or Crypt::Primes).
399 #
400 # Timings on x86_64, with Math::BigInt::GMP and Math::Random::ISAAC::XS.
401 #
402 # random_nbit_prime random_maurer_prime
403 # n-bits no GMP w/ MPU::GMP no GMP w/ MPU::GMP
404 # ---------- -------- ----------- -------- -----------
405 # 24-bit 22uS same same same
406 # 64-bit 94uS same same same
407 # 128-bit 0.017s 0.0020s 0.098s 0.056s
408 # 256-bit 0.033s 0.0033s 0.25s 0.15s
409 # 512-bit 0.066s 0.0093s 0.65s 0.30s
410 # 1024-bit 0.16s 0.060s 1.3s 0.94s
411 # 2048-bit 0.83s 0.5s 3.2s 3.1s
412 # 4096-bit 6.6s 4.0s 23s 12.0s
413 #
414 # Writing these entirely in GMP has a problem, which is that we want to use
415 # a user-supplied rand function, which means a lot of callbacks. One
416 # possibility is to, if they do not supply a rand function, use the GMP MT
417 # function with an appropriate seed.
418 #
419 # Random timings for 10M calls:
420 # 1.92 system rand
421 # 2.62 Math::Random::MT::Auto
422 # 12.0 Math::Random::Secure w/ISAAC::XS
423 # 12.6 Bytes::Random::Secure OO w/ISAAC::XS <==== our
424 # 31.1 Bytes::Random::Secure OO <==== default
425 # 44.5 Bytes::Random::Secure function w/ISAAC::XS
426 # 44.8 Math::Random::Secure
427 # 71.5 Bytes::Random::Secure function
428 # 1840 Crypt::Random
429 #
430 # time perl -E 'sub irand {int(rand(4294967296));} irand() for 1..10000000;'
431 # time perl -E 'use Math::Random::MT::Auto qw/irand/; irand() for 1..10000000;'
432 # time perl -E 'use Math::Random::Secure qw/irand/; irand() for 1..10000000;'
433 # time perl -E 'use Bytes::Random::Secure qw/random_bytes/; sub irand {return unpack("L",random_bytes(4));} irand() for 1..10000000;'
434 # time perl -E 'use Bytes::Random::Secure; my $rng = Bytes::Random::Secure->new(); sub irand {return $rng->irand;} irand() for 1..10000000;'
435 # time perl -E 'use Crypt::Random qw/makerandom/; sub irand {makerandom(Size=>32, Uniform=>1, Strength=>0)} irand() for 1..100_000;'
436 # > haveged daemon running to stop /dev/random blocking
437 # > Both BRS and CR have more features that this isn't measuring.
438 #
439 # To verify distribution:
440 # perl -Iblib/lib -Iblib/arch -MMath::Prime::Util=:all -E 'my %freq; $n=1000000; $freq{random_nbit_prime(6)}++ for (1..$n); printf("%4d %6.3f%%\n", $_, 100.0*$freq{$_}/$n) for sort {$a<=>$b} keys %freq;'
441 # perl -Iblib/lib -Iblib/arch -MMath::Prime::Util=:all -E 'my %freq; $n=1000000; $freq{random_prime(1260437,1260733)}++ for (1..$n); printf("%4d %6.3f%%\n", $_, 100.0*$freq{$_}/$n) for sort {$a<=>$b} keys %freq;'
442
443 {
444 # These are much faster than straightforward trial division when n is big.
445 # You'll want to first do a test up to and including 23.
446 my @_big_gcd;
447 my $_big_gcd_top = 20046;
448 my $_big_gcd_use = -1;
449 sub _make_big_gcds {
450 return if $_big_gcd_use >= 0;
451 if ($_HAVE_GMP) {
452 $_big_gcd_use = 0;
453 return;
454 }
455 if (Math::BigInt->config()->{lib} !~ /^Math::BigInt::(GMP|Pari)/) {
456 $_big_gcd_use = 0;
457 return;
458 }
459 $_big_gcd_use = 1;
460 my $p0 = primorial(Math::BigInt->new( 520));
461 my $p1 = primorial(Math::BigInt->new(2052));
462 my $p2 = primorial(Math::BigInt->new(6028));
463 my $p3 = primorial(Math::BigInt->new($_big_gcd_top));
464 $_big_gcd[0] = $p0->bdiv(223092870)->bfloor->as_int;
465 $_big_gcd[1] = $p1->bdiv($p0)->bfloor->as_int;
466 $_big_gcd[2] = $p2->bdiv($p1)->bfloor->as_int;
467 $_big_gcd[3] = $p3->bdiv($p2)->bfloor->as_int;
468 }
469
470 # Returns a function that will get a uniform random number
471 # between 0 and $max inclusive. $max can be a bigint.
472 my $_BRS;
473 my $_RANDF;
474 my $_RANDF_NBIT;
475 sub _set_randf {
476 # First define a function $irandf that returns a 32-bit integer. This
477 # corresponds to the irand function of many CPAN modules:
478 # Math::Random::MT
479 # Math::Random::ISAAC
480 # Math::Random::Xorshift
481 # Math::Random::Secure
482 # (but not Math::Random::MT::Auto which will return 64-bits)
483 my $irandf = $_Config{'irand'};
484 if (!defined $irandf) { # Default irand: BRS nonblocking
485 require Bytes::Random::Secure;
486 $_BRS = Bytes::Random::Secure->new(NonBlocking=>1) unless defined $_BRS;
487 $_RANDF_NBIT = sub {
488 my($bits) = @_;
489 return 0 if $bits <= 0;
490 return ($_BRS->irand() >> (32-$bits))
491 if $bits <= 32;
492 return ((($_BRS->irand() << 32) + $_BRS->irand()) >> (64-$bits))
493 if $bits <= 64 && ~0 > 4294967295;
494 my $bytes = int(($bits+7)/8);
495 my $n = Math::BigInt->from_hex('0x' . $_BRS->bytes_hex($bytes));
496 $n->brsft( 8*$bytes - $bits ) unless ($bits % 8) == 0;
497 return $n;
498 };
499 $_RANDF = sub {
500 my($max) = @_;
501 my $range = $max+1;
502 my $U;
503 if (ref($range) eq 'Math::BigInt') {
504 my $bits = length($range->as_bin) - 2; # bits in range
505 my $bytes = 1 + int(($bits+7)/8); # extra byte to reduce ave. loops
506 my $rmax = Math::BigInt->bone->blsft($bytes*8)->bdec();
507 my $overflow = $rmax - ($rmax % $range);
508 do {
509 $U = Math::BigInt->from_hex('0x' . $_BRS->bytes_hex($bytes));
510 } while $U >= $overflow;
511 } elsif ($range <= 4294967295) {
512 my $overflow = (OLD_PERL_VERSION) ? 4294967295-(4294967295.0%$range)
513 : 4294967295-(4294967295 % $range);
514 do {
515 $U = $_BRS->irand();
516 } while $U >= $overflow;
517 } else {
518 croak "randf given max out of bounds: $max" if $range > ~0;
519 my $overflow = 18446744073709551615 - (18446744073709551615 % $range);
520 do {
521 $U = ($_BRS->irand() << 32) + $_BRS->irand();
522 } while $U >= $overflow;
523 }
524 return $U % $range;
525 };
526 } else { # Custom irand
527 $_RANDF_NBIT = sub {
528 my($bits) = @_;
529 return 0 if $bits <= 0;
530 return ($irandf->() >> (32-$bits))
531 if $bits <= 32;
532 return ((($irandf->() << 32) + $irandf->()) >> (64-$bits))
533 if $bits <= 64 && MPU_64BIT;
534 my $words = int(($bits+31)/32);
535 my $n = Math::BigInt->from_hex
536 ("0x" . join '', map { sprintf("%08X", $irandf->()) } 1 .. $words );
537 $n->brsft( 32*$words - $bits ) unless ($bits % 32) == 0;
538 return $n;
539 };
540 $_RANDF = sub {
541 my($max) = @_;
542 return 0 if $max <= 0;
543 my $range = $max+1;
544 my $U;
545 if (ref($range) eq 'Math::BigInt') {
546 my $zero = $range->copy->bzero;
547 my $rbits = length($range->as_bin) - 2; # bits in range
548 my $rwords = int($rbits/32) + (($rbits % 32) ? 1 : 0);
549 my $rmax = Math::BigInt->bone->blsft($rwords*32)->bdec();
550 my $overflow = $rmax - ($rmax % $range);
551 do {
552 $U = $range->copy->from_hex
553 ("0x" . join '', map { sprintf("%08X", $irandf->()) } 1 .. $rwords);
554 } while $U >= $overflow;
555 } elsif ($range <= 4294967295) {
556 my $overflow = 4294967295 - (4294967295 % $range);
557 do {
558 $U = $irandf->();
559 } while $U >= $overflow;
560 } else {
561 croak "randf given max out of bounds: $max" if $range > ~0;
562 my $overflow = 18446744073709551615 - (18446744073709551615 % $range);
563 do {
564 $U = ($irandf->() << 32) + $irandf->();
565 } while $U >= $overflow;
566 }
567 return $U % $range;
568 };
569 }
570 }
571 sub _clear_randf {
572 undef $_RANDF;
573 undef $_RANDF_NBIT;
574 undef $_BRS;
575 }
576 sub _get_randf {
577 _set_randf() unless defined $_RANDF;
578 return $_RANDF;
579 }
580 sub _get_randf_nbit {
581 _set_randf() unless defined $_RANDF_NBIT;
582 return $_RANDF_NBIT;
583 }
584
585 # Sub to call with low and high already primes and verified range.
586 my $_random_prime = sub {
587 my($low,$high) = @_;
588 my $prime;
589
590 _set_randf() unless defined $_RANDF;
591
592 #{ my $bsize = 100; my @bins; my $counts = 10000000;
593 # for my $c (1..$counts) { $bins[ $irandf->($bsize-1) ]++; }
594 # for my $b (0..$bsize) {printf("%4d %8.5f%%\n", $b, $bins[$b]/$counts);} }
595
596 # low and high are both odds, and low < high.
597
598 # This is fast for small values, low memory, perfectly uniform, and
599 # consumes the minimum amount of randomness needed. But it isn't feasible
600 # with large values. Also note that low must be a prime.
601 if ($high <= 262144 && $high <= $_XS_MAXVAL) {
602 my $li = prime_count(2, $low);
603 my $irange = prime_count($low, $high);
604 my $rand = $_RANDF->($irange-1);
605 return nth_prime($li + $rand);
606 }
607
608 $low-- if $low == 2; # Low of 2 becomes 1 for our program.
609 # Math::BigInt::GMP's RT 71548 will wreak havoc if we don't do this.
610 $low = Math::BigInt->new("$low") if ref($high) eq 'Math::BigInt';
611 confess "Invalid _random_prime parameters: $low, $high" if ($low % 2) == 0 || ($high % 2) == 0;
612
613 # We're going to look at the odd numbers only.
614 my $oddrange = (($high - $low) >> 1) + 1;
615
616 croak "Large random primes not supported on old Perl"
617 if OLD_PERL_VERSION && MPU_64BIT && $oddrange > 4294967295;
618
619 # If $low is large (e.g. >10 digits) and $range is small (say ~10k), it
620 # would be fastest to call primes in the range and randomly pick one. I'm
621 # not implementing it now because it seems like a rare case.
622
623 # If the range is reasonably small, generate using simple Monte Carlo
624 # method (aka the 'trivial' method). Completely uniform.
625 if ($oddrange < MPU_MAXPARAM) {
626 my $loop_limit = 2000 * 1000; # To protect against broken rand
627 if ($low > 11) {
628 while ($loop_limit-- > 0) {
629 $prime = $low + 2 * $_RANDF->($oddrange-1);
630 next if !($prime % 3) || !($prime % 5) || !($prime % 7) || !($prime % 11);
631 return $prime if is_prob_prime($prime);
632 }
633 } else {
634 while ($loop_limit-- > 0) {
635 $prime = $low + 2 * $_RANDF->($oddrange-1);
636 next if $prime > 11 && (!($prime % 3) || !($prime % 5) || !($prime % 7) || !($prime % 11));
637 return 2 if $prime == 1; # Remember the special case for 2.
638 return $prime if is_prob_prime($prime);
639 }
640 }
641 croak "Random function broken?";
642 }
643
644 # We have an ocean of range, and a teaspoon to hold randomness.
645
646 # Since we have an arbitrary range and not a power of two, I don't see how
647 # Fouque's algorithm A1 could be used (where we generate lower bits and
648 # generate random sets of upper). Similarly trying to simply generate
649 # upper bits is full of ways to trip up and get non-uniform results.
650 #
651 # What I'm doing here is:
652 #
653 # 1) divide the range into semi-evenly sized partitions, where each part
654 # is as close to $rand_max_val as we can.
655 # 2) randomly select one of the partitions.
656 # 3) iterate choosing random values within the partition.
657 #
658 # The downside is that we're skewing a _lot_ farther from uniformity than
659 # we'd like. Imagine we started at 0 with 1e18 partitions of size 100k
660 # each.
661 # Probability of '5' being returned =
662 # 1.04e-22 = 1e-18 (chose first partition) * 1/9592 (chose '5')
663 # Probability of '100003' being returned =
664 # 1.19e-22 = 1e-18 (chose second partition) * 1/8392 (chose '100003')
665 # Probability of '99999999999999999999977' being returned =
666 # 5.20e-22 = 1e-18 (chose last partition) * 1/1922 (chose '99...77')
667 # So the primes in the last partition will show up 5x more often.
668 # The partitions are selected uniformly, and the primes within are selected
669 # uniformly, but the number of primes in each bucket is _not_ uniform.
670 # Their individual probability of being selected is the probability of the
671 # partition (uniform) times the probability of being selected inside the
672 # partition (uniform with respect to all other primes in the same
673 # partition, but each partition is different and skewed).
674 #
675 # Partitions are typically much larger than 100k, but with a huge range
676 # we still see this (e.g. ~3x from 0-10^30, ~10x from 0-10^100).
677 #
678 # When selecting n-bit or n-digit primes, this effect is MUCH smaller, as
679 # the skew becomes approx lg(2^n) / lg(2^(n-1)) which is pretty close to 1.
680 #
681 #
682 # Another idea I'd like to try sometime is:
683 # pclo = prime_count_lower(low);
684 # pchi = prime_count_upper(high);
685 # do {
686 # $nth = random selection between pclo and pchi
687 # $prguess = nth_prime_approx($nth);
688 # } while ($prguess >= low) && ($prguess <= high);
689 # monte carlo select a prime in $prguess-2**24 to $prguess+2**24
690 # which accounts for the prime distribution.
691
692 my($binsize, $nparts);
693 my $rand_part_size = 1 << (MPU_64BIT ? 32 : 31);
694 if (ref($oddrange) eq 'Math::BigInt') {
695 # Go to some trouble here because some systems are wonky, such as
696 # giving us +a/+b = -r. Also note the quotes for the bigint argument.
697 # Without that, Math::BigInt::GMP can return garbage.
698 my($nbins, $rem);
699 ($nbins, $rem) = $oddrange->copy->bdiv( "$rand_part_size" );
700 $nbins++ if $rem > 0;
701 $nbins = $nbins->as_int();
702 ($binsize,$rem) = $oddrange->copy->bdiv($nbins);
703 $binsize++ if $rem > 0;
704 $binsize = $binsize->as_int();
705 $nparts = $oddrange->copy->bdiv($binsize)->as_int();
706 $low = $high->copy->bzero->badd($low) if ref($low) ne 'Math::BigInt';
707 } else {
708 my $nbins = int($oddrange / $rand_part_size);
709 $nbins++ if $nbins * $rand_part_size != $oddrange;
710 $binsize = int($oddrange / $nbins);
711 $binsize++ if $binsize * $nbins != $oddrange;
712 $nparts = int($oddrange/$binsize);
713 }
714 $nparts-- if ($nparts * $binsize) == $oddrange;
715
716 my $rpart = $_RANDF->($nparts);
717
718 my $primelow = $low + 2 * $binsize * $rpart;
719 my $partsize = ($rpart < $nparts) ? $binsize
720 : $oddrange - ($nparts * $binsize);
721 $partsize = _bigint_to_int($partsize) if ref($partsize) eq 'Math::BigInt';
722 #warn "range $oddrange = $nparts * $binsize + ", $oddrange - ($nparts * $binsize), "\n";
723 #warn " chose part $rpart size $partsize\n";
724 #warn " primelow is $low + 2 * $binsize * $rpart = $primelow\n";
725 #die "Result could be too large" if ($primelow + 2*($partsize-1)) > $high;
726
727 # Generate random numbers in the interval until one is prime.
728 my $loop_limit = 2000 * 1000; # To protect against broken rand
729
730 # Simply things for non-bigints.
731 if (ref($low) ne 'Math::BigInt') {
732 while ($loop_limit-- > 0) {
733 my $rand = $_RANDF->($partsize-1);
734 $prime = $primelow + $rand + $rand;
735 croak "random prime failure, $prime > $high" if $prime > $high;
736 if ($prime <= 23) {
737 $prime = 2 if $prime == 1; # special case for low = 2
738 next unless (0,0,1,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1)[$prime];
739 return $prime;
740 }
741 next if !($prime % 3) || !($prime % 5) || !($prime % 7) || !($prime % 11);
742 # It looks promising. Check it.
743 next unless is_prob_prime($prime);
744 return $prime;
745 }
746 croak "Random function broken?";
747 }
748
749 # By checking a wheel 30 mod, we can skip anything that would be a multiple
750 # of 2, 3, or 5, without even having to create the bigint prime.
751 my @w30 = (1,0,5,4,3,2,1,0,3,2,1,0,1,0,3,2,1,0,1,0,3,2,1,0,5,4,3,2,1,0);
752 my $primelow30 = $primelow % 30;
753 $primelow30 = _bigint_to_int($primelow30) if ref($primelow30) eq 'Math::BigInt';
754
755 # Big GCD's are hugely fast with GMP or Pari, but super slow with Calc.
756 _make_big_gcds() if $_big_gcd_use < 0;
757
758 while ($loop_limit-- > 0) {
759 my $rand = $_RANDF->($partsize-1);
760 # Check wheel-30 mod
761 my $rand30 = $rand % 30;
762 next if $w30[($primelow30 + 2*$rand30) % 30]
763 && ($rand > 3 || $primelow > 5);
764 # Construct prime
765 $prime = $primelow + $rand + $rand;
766 croak "random prime failure, $prime > $high" if $prime > $high;
767 if ($prime <= 23) {
768 $prime = 2 if $prime == 1; # special case for low = 2
769 next unless (0,0,1,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1)[$prime];
770 return $prime;
771 }
772 # With GMP, the fastest thing to do is check primality.
773 if ($_HAVE_GMP) {
774 next unless Math::Prime::Util::GMP::is_prime($prime);
775 return $prime;
776 }
777 # No MPU:GMP, so primality checking is slow. Skip some composites here.
778 next unless Math::BigInt::bgcd($prime, 7436429) == 1;
779 if ($_big_gcd_use && $prime > $_big_gcd_top) {
780 next unless Math::BigInt::bgcd($prime, $_big_gcd[0]) == 1;
781 next unless Math::BigInt::bgcd($prime, $_big_gcd[1]) == 1;
782 next unless Math::BigInt::bgcd($prime, $_big_gcd[2]) == 1;
783 next unless Math::BigInt::bgcd($prime, $_big_gcd[3]) == 1;
784 }
785 # It looks promising. Check it.
786 next unless is_prob_prime($prime);
787 return $prime;
788 }
789 croak "Random function broken?";
790 };
791
792 # Cache of tight bounds for each digit. Helps performance a lot.
793 my @_random_ndigit_ranges = (undef, [2,7], [11,97] );
794 my @_random_nbit_ranges = (undef, undef, [2,3],[5,7] );
795 my %_random_cache_small;
796
797 # For fixed small ranges with XS, e.g. 6-digit, 18-bit
798 sub _random_xscount_prime {
799 my($low,$high) = @_;
800 my($istart, $irange);
801 my $cachearef = $_random_cache_small{$low,$high};
802 if (defined $cachearef) {
803 ($istart, $irange) = @$cachearef;
804 } else {
805 my $beg = ($low <= 2) ? 2 : next_prime($low-1);
806 my $end = ($high < ~0) ? prev_prime($high + 1) : prev_prime($high);
807 ($istart, $irange) = ( prime_count(2, $beg), prime_count($beg, $end) );
808 $_random_cache_small{$low,$high} = [$istart, $irange];
809 }
810 _set_randf() unless defined $_RANDF;
811 my $rand = $_RANDF->($irange-1);
812 return nth_prime($istart + $rand);
813 }
814
815 sub random_prime {
816 my $low = (@_ == 2) ? shift : 2;
817 my $high = shift;
295 #############################################################################
296 # Random primes. These are front end functions that do input validation,
297 # load the RandomPrimes module, and call its function.
298
299 sub random_prime {
300 my($low,$high) = @_;
301 if (scalar @_ > 1) {
818302 _validate_num($low) || _validate_positive_integer($low);
819303 _validate_num($high) || _validate_positive_integer($high);
820
821 # Tighten the range to the nearest prime.
822 $low = ($low <= 2) ? 2 : next_prime($low-1);
823 $high = ($high < ~0) ? prev_prime($high + 1) : prev_prime($high);
824 return $low if ($low == $high) && is_prob_prime($low);
825 return if $low >= $high;
826
827 # At this point low and high are both primes, and low < high.
828 return $_random_prime->($low, $high);
304 } else {
305 ($low,$high) = (2, $low);
306 _validate_num($high) || _validate_positive_integer($high);
829307 }
830
831 sub random_ndigit_prime {
832 my($digits) = @_;
833 _validate_num($digits, 1) || _validate_positive_integer($digits, 1);
834
835 return _random_xscount_prime( int(10 ** ($digits-1)), int(10 ** $digits) )
836 if $digits <= 6 && int(10**$digits) <= $_XS_MAXVAL;
837
838 my $bigdigits = $digits >= MPU_MAXDIGITS;
839 if ($bigdigits && $_Config{'nobigint'}) {
840 _validate_positive_integer($digits, 1, MPU_MAXDIGITS);
841 # Special case for nobigint and threshold digits
842 if (!defined $_random_ndigit_ranges[$digits]) {
843 my $low = int(10 ** ($digits-1));
844 my $high = ~0;
845 $_random_ndigit_ranges[$digits] = [next_prime($low),prev_prime($high)];
846 }
847 }
848
849 if (!defined $_random_ndigit_ranges[$digits]) {
850 if ($bigdigits) {
851 my $low = Math::BigInt->new('10')->bpow($digits-1);
852 my $high = Math::BigInt->new('10')->bpow($digits);
853 # Just pull the range in to the nearest odd.
854 $_random_ndigit_ranges[$digits] = [$low+1, $high-1];
855 } else {
856 my $low = int(10 ** ($digits-1));
857 my $high = int(10 ** $digits);
858 # Note: Perl 5.6.2 cannot represent 10**15 as an integer, so things
859 # will crash all over the place if you try. We can stringify it, but
860 # will just fail tests later.
861 $_random_ndigit_ranges[$digits] = [next_prime($low),prev_prime($high)];
862 }
863 }
864 my ($low, $high) = @{$_random_ndigit_ranges[$digits]};
865 return $_random_prime->($low, $high);
866 }
867
868 my @_random_nbit_m;
869 my @_random_nbit_lambda;
870 my @_random_nbit_arange;
871
872 sub random_nbit_prime {
873 my($bits) = @_;
874 _validate_num($bits, 2) || _validate_positive_integer($bits, 2);
875
876 _set_randf() unless defined $_RANDF_NBIT;
877
878 # Very small size, use the nth-prime method
879 if ($bits <= 18 && int(2**$bits) <= $_XS_MAXVAL) {
880 if ($bits <= 4) {
881 return (2,3)[$_RANDF_NBIT->(1)] if $bits == 2;
882 return (5,7)[$_RANDF_NBIT->(1)] if $bits == 3;
883 return (11,13)[$_RANDF_NBIT->(1)] if $bits == 4;
884 }
885 return _random_xscount_prime( 1 << ($bits-1), 1 << $bits );
886 }
887
888 croak "Mid-size random primes not supported on broken old Perl"
889 if OLD_PERL_VERSION && MPU_64BIT && $bits > 49 && $bits <= 64;
890
891 # Fouque and Tibouchi (2011) Algorithm 1 (basic)
892 # Modified to make sure the nth bit is always set.
893 #
894 # Example for random_nbit_prime(512) on 64-bit Perl:
895 # p: 1aaaaaaaabbbbbbbbbbbbbbbbbbbb1
896 # ^^ ^ ^--- Trailing 1 so p is odd
897 # || +--- 512-63-2 = 447 lower bits selected before loop
898 # |+--- 63 upper bits selected in loop, repeated until p is prime
899 # +--- upper bit is 1 so we generate an n-bit prime
900 # total: 1 + 63 + 447 + 1 = 512 bits
901 #
902 # Algorithm 2 is implemented in a previous commit on github. The problem
903 # is that it doesn't set the nth bit, and making that change requires a
904 # modification of the algorithm. It was not a lot faster than this A1
905 # with the native int trial division. If the irandf function was very
906 # slow, then A2 would look more promising.
907 #
908 if (1 && $bits > 64) {
909 my $l = (MPU_64BIT && $bits > 79) ? 63 : 31;
910 $l = 49 if $l == 63 && OLD_PERL_VERSION; # Fix for broken Perl 5.6
911 $l = $bits-2 if $bits-2 < $l;
912
913 my $brand = $_RANDF_NBIT->($bits-$l-2);
914 $brand = Math::BigInt->new("$brand") unless ref($brand) eq 'Math::BigInt';
915 my $b = $brand->blsft(1)->binc();
916
917 # Precalculate some modulii so we can do trial division on native int
918 # 9699690 = 2*3*5*7*11*13*17*19, so later operations can be native ints
919 my @premod;
920 my $bpremod = _bigint_to_int($b->copy->bmod(9699690));
921 my $twopremod = _bigint_to_int(Math::BigInt->new(2)->bmodpow($bits-$l-1, 9699690));
922 foreach my $zi (0 .. 19-1) {
923 foreach my $pm (3, 5, 7, 11, 13, 17, 19) {
924 next if $zi >= $pm || defined $premod[$pm];
925 $premod[$pm] = $zi if ( ($twopremod*$zi+$bpremod) % $pm) == 0;
926 }
927 }
928 _make_big_gcds() if $_big_gcd_use < 0;
929 my $loop_limit = 1_000_000;
930 while ($loop_limit-- > 0) {
931 my $a = (1 << $l) + $_RANDF_NBIT->($l);
932 # $a % s == $premod[s] => $p % s == 0 => p will be composite
933 next if $a % 3 == $premod[ 3] || $a % 5 == $premod[ 5]
934 || $a % 7 == $premod[ 7] || $a % 11 == $premod[11]
935 || $a % 13 == $premod[13] || $a % 17 == $premod[17]
936 || $a % 19 == $premod[19];
937 my $p = Math::BigInt->new("$a")->blsft($bits-$l-1)->badd($b);
938 #die " $a $b $p" if $a % 11 == $premod[11] && $p % 11 != 0;
939 #die "!$a $b $p" if $a % 11 != $premod[11] && $p % 11 == 0;
940 if ($_HAVE_GMP) {
941 next unless Math::Prime::Util::GMP::is_prime($p);
942 } else {
943 next unless Math::BigInt::bgcd($p, 1348781387) == 1; # 23-43
944 if ($_big_gcd_use && $p > $_big_gcd_top) {
945 next unless Math::BigInt::bgcd($p, $_big_gcd[0]) == 1;
946 next unless Math::BigInt::bgcd($p, $_big_gcd[1]) == 1;
947 next unless Math::BigInt::bgcd($p, $_big_gcd[2]) == 1;
948 next unless Math::BigInt::bgcd($p, $_big_gcd[3]) == 1;
949 }
950 # We know we don't have GMP and are > 2^64, so skip all the middle.
951 #next unless is_prob_prime($p);
952 #next unless Math::Prime::Util::PP::is_strong_pseudoprime($p, 2);
953 #next unless Math::Prime::Util::PP::is_extra_strong_lucas_pseudoprime($p);
954 next unless Math::Prime::Util::PP::is_bpsw_prime($p);
955 }
956 return $p;
957 }
958 croak "Random function broken?";
959 }
960
961 # The Trivial method. Great uniformity, and fine for small sizes. It
962 # gets very slow as the bit size increases, but that is why we have the
963 # method above for bigints.
964 if (1) {
965
966 my $loop_limit = 2_000_000;
967 if ($bits > MPU_MAXBITS) {
968 my $p = Math::BigInt->bone->blsft($bits-1)->binc();
969 while ($loop_limit-- > 0) {
970 my $n = Math::BigInt->new(''.$_RANDF_NBIT->($bits-2))->blsft(1)->badd($p);
971 return $n if is_prob_prime($n);
972 }
973 } else {
974 my $p = (1 << ($bits-1)) + 1;
975 while ($loop_limit-- > 0) {
976 my $n = $p + ($_RANDF_NBIT->($bits-2) << 1);
977 return $n if is_prob_prime($n);
978 }
979 }
980 croak "Random function broken?";
981
982 } else {
983
984 # Send through the generic random_prime function. Decently fast, but
985 # quite a bit slower than the F&T A1 method above.
986 if (!defined $_random_nbit_ranges[$bits]) {
987 if ($bits > MPU_MAXBITS) {
988 my $low = Math::BigInt->new('2')->bpow($bits-1);
989 my $high = Math::BigInt->new('2')->bpow($bits);
990 # Don't pull the range in to primes, just odds
991 $_random_nbit_ranges[$bits] = [$low+1, $high-1];
992 } else {
993 my $low = 1 << ($bits-1);
994 my $high = ($bits == MPU_MAXBITS)
995 ? ~0-1
996 : ~0 >> (MPU_MAXBITS - $bits);
997 $_random_nbit_ranges[$bits] = [next_prime($low-1),prev_prime($high+1)];
998 # Example: bits = 7.
999 # low = 1<<6 = 64. next_prime(64-1) = 67
1000 # high = ~0 >> (64-7) = 127. prev_prime(127+1) = 127
1001 }
1002 }
1003 my ($low, $high) = @{$_random_nbit_ranges[$bits]};
1004 return $_random_prime->($low, $high);
1005
1006 }
1007 }
1008
1009 sub random_maurer_prime {
1010 my $k = shift;
1011 _validate_num($k, 2) || _validate_positive_integer($k, 2);
1012 if ($k <= MPU_MAXBITS && !OLD_PERL_VERSION) {
1013 return random_nbit_prime($k);
1014 }
1015 my ($n, $cert) = random_maurer_prime_with_cert($k);
1016 croak "maurer prime $n failed certificate verification!"
1017 unless verify_prime($cert);
1018 return $n;
1019 }
1020
1021 sub random_maurer_prime_with_cert {
1022 my($k) = @_;
1023 _validate_num($k, 2) || _validate_positive_integer($k, 2);
1024 # This should never happen. Trap now to prevent infinite loop.
1025 croak "number of bits must not be a bigint" if ref($k) eq 'Math::BigInt';
1026
1027 # Results for random_nbit_prime are proven for all native bit sizes.
1028 my $p0 = MPU_MAXBITS;
1029 $p0 = 49 if OLD_PERL_VERSION && MPU_MAXBITS > 49;
1030
1031 if ($k <= $p0) {
1032 my $n = random_nbit_prime($k);
1033 my ($isp, $cert) = is_provable_prime_with_cert($n);
1034 croak "small nbit prime could not be proven" if $isp != 2;
1035 return ($n, $cert);
1036 }
1037
1038 # Set verbose to 3 to get pretty output like Crypt::Primes
1039 my $verbose = $_Config{'verbose'};
1040 local $| = 1 if $verbose > 2;
1041
1042 do { require Math::BigFloat; Math::BigFloat->import(); }
1043 if !defined $Math::BigFloat::VERSION;
1044
1045 # Ignore Maurer's g and c that controls how much trial division is done.
1046 my $r = Math::BigFloat->new("0.5"); # relative size of the prime q
1047 my $m = 20; # makes sure R is big enough
1048 _set_randf() unless defined $_RANDF;
1049
1050 # Generate a random prime q of size $r*$k, where $r >= 0.5. Try to
1051 # cleverly select r to match the size of a typical random factor.
1052 if ($k > 2*$m) {
1053 do {
1054 my $s = Math::BigFloat->new($_RANDF->(2147483647))->bdiv(2147483648);
1055 $r = Math::BigFloat->new(2)->bpow($s-1);
1056 } while ($k*$r >= $k-$m);
1057 }
1058
1059 # I've seen +0, +1, and +2 here. Maurer uses +0. Menezes uses +1.
1060 my ($q, $qcert) = random_maurer_prime_with_cert( ($r * $k)->bfloor->binc );
1061 $q = Math::BigInt->new("$q") unless ref($q) eq 'Math::BigInt';
1062 my $I = Math::BigInt->new(2)->bpow($k-2)->bdiv($q)->bfloor->as_int();
1063 print "r = $r k = $k q = $q I = $I\n" if $verbose && $verbose != 3;
1064 $qcert = ($q < Math::BigInt->new("18446744073709551615"))
1065 ? "" : _strip_proof_header($qcert);
1066
1067 # Big GCD's are hugely fast with GMP or Pari, but super slow with Calc.
1068 _make_big_gcds() if $_big_gcd_use < 0;
1069 my $ONE = Math::BigInt->bone;
1070 my $TWO = $ONE->copy->binc;
1071
1072 my $loop_limit = 1_000_000 + $k * 1_000;
1073 while ($loop_limit-- > 0) {
1074 # R is a random number between $I+1 and 2*$I
1075 #my $R = $I + 1 + $_RANDF->( $I - 1 );
1076 my $R = $I->copy->binc->badd( $_RANDF->($I->copy->bdec) );
1077 #my $n = 2 * $R * $q + 1;
1078 my $nm1 = $TWO->copy->bmul($R)->bmul($q);
1079 my $n = $nm1->copy->binc;
1080 # We constructed a promising looking $n. Now test it.
1081 print "." if $verbose > 2;
1082 if ($_HAVE_GMP) {
1083 # MPU::GMP::is_prob_prime has fast tests built in.
1084 next unless Math::Prime::Util::GMP::is_prob_prime($n);
1085 } else {
1086 # No GMP, so first do trial divisions, then a SPSP test.
1087 next unless Math::BigInt::bgcd($n, 111546435)->is_one;
1088 if ($_big_gcd_use && $n > $_big_gcd_top) {
1089 next unless Math::BigInt::bgcd($n, $_big_gcd[0])->is_one;
1090 next unless Math::BigInt::bgcd($n, $_big_gcd[1])->is_one;
1091 next unless Math::BigInt::bgcd($n, $_big_gcd[2])->is_one;
1092 next unless Math::BigInt::bgcd($n, $_big_gcd[3])->is_one;
1093 }
1094 print "+" if $verbose > 2;
1095 next unless is_strong_pseudoprime($n, 3);
1096 }
1097 print "*" if $verbose > 2;
1098
1099 # We could pick a random generator by doing:
1100 # Step 1: pick a random r
1101 # Step 2: compute g = r^((n-1)/q) mod p
1102 # Step 3: if g == 1, goto Step 1.
1103 # Note that n = 2*R*q+1, hence the exponent is 2*R.
1104
1105 # We could set r = 0.3333 earlier, then use BLS75 theorem 5 here.
1106 # The chain would be shorter, requiring less overall work for
1107 # large inputs. Maurer's paper discusses the idea.
1108
1109 # Use BLS75 theorem 3. This is easier and possibly faster than
1110 # BLS75 theorem 4 (Pocklington) used by Maurer's paper.
1111
1112 # Check conditions -- these should be redundant.
1113 my $m = $TWO * $R;
1114 if (! ($q->is_odd && $q > 2 && $m > 0 &&
1115 $m * $q + $ONE == $n && $TWO*$q+$ONE > $n->copy->bsqrt()) ) {
1116 carp "Maurer prime failed BLS75 theorem 3 conditions. Retry.";
1117 next;
1118 }
1119 # Find a suitable a. Move on if one isn't found quickly.
1120 foreach my $trya (2, 3, 5, 7, 11, 13) {
1121 my $a = Math::BigInt->new($trya);
1122 # m/2 = R (n-1)/2 = (2*R*q)/2 = R*q
1123 next unless $a->copy->bmodpow($R, $n) != $nm1;
1124 next unless $a->copy->bmodpow($R*$q, $n) == $nm1;
1125 print "($k)" if $verbose > 2;
1126 croak "Maurer prime $n=2*$R*$q+1 failed BPSW" unless is_prob_prime($n);
1127 my $cert = "[MPU - Primality Certificate]\nVersion 1.0\n\n" .
1128 "Proof for:\nN $n\n\n" .
1129 "Type BLS3\nN $n\nQ $q\nA $a\n" .
1130 $qcert;
1131 return ($n, $cert);
1132 }
1133 # Didn't pass the selected a values. Try another R.
1134 }
1135 croak "Failure in random_maurer_prime, could not find a prime\n";
1136 } # End of random_maurer_prime
1137
1138 # Gordon's algorithm for generating a strong prime.
1139 sub random_strong_prime {
1140 my($t) = @_;
1141 _validate_num($t, 128) || _validate_positive_integer($t, 128);
1142 croak "Random strong primes must be >= 173 bits on old Perl"
1143 if OLD_PERL_VERSION && MPU_64BIT && $t < 173;
1144
1145 _set_randf() unless defined $_RANDF;
1146
1147 my $l = (($t+1) >> 1) - 2;
1148 my $lp = int($t/2) - 20;
1149 my $lpp = $l - 20;
1150 while (1) {
1151 my $qp = random_nbit_prime($lp);
1152 my $qpp = random_nbit_prime($lpp);
1153 $qp = Math::BigInt->new("$qp") unless ref($qp) eq 'Math::BigInt';
1154 $qpp = Math::BigInt->new("$qpp") unless ref($qpp) eq 'Math::BigInt';
1155 my ($il, $rem) = Math::BigInt->new(2)->bpow($l-1)->bdec()->bdiv(2*$qpp);
1156 $il++ if $rem > 0;
1157 $il = $il->as_int();
1158 my $iu = Math::BigInt->new(2)->bpow($l)->bsub(2)->bdiv(2*$qpp)->as_int();
1159 my $istart = $il + $_RANDF->($iu - $il);
1160 for (my $i = $istart; $i <= $iu; $i++) { # Search for q
1161 my $q = 2 * $i * $qpp + 1;
1162 next unless is_prob_prime($q);
1163 my $pp = $qp->copy->bmodpow($q-2, $q)->bmul(2)->bmul($qp)->bdec();
1164 my ($jl, $rem) = Math::BigInt->new(2)->bpow($t-1)->bsub($pp)->bdiv(2*$q*$qp);
1165 $jl++ if $rem > 0;
1166 $jl = $jl->as_int();
1167 my $ju = Math::BigInt->new(2)->bpow($t)->bdec()->bsub($pp)->bdiv(2*$q*$qp)->as_int();
1168 my $jstart = $jl + $_RANDF->($ju - $jl);
1169 for (my $j = $jstart; $j <= $ju; $j++) { # Search for p
1170 my $p = $pp + 2 * $j * $q * $qp;
1171 return $p if is_prob_prime($p);
1172 }
1173 }
1174 }
1175 }
1176
1177 sub random_proven_prime {
1178 my $k = shift;
1179 my ($n, $cert) = random_proven_prime_with_cert($k);
1180 croak "maurer prime $n failed certificate verification!"
1181 unless verify_prime($cert);
1182 return $n;
1183 }
1184
1185 sub random_proven_prime_with_cert {
1186 my $k = shift;
1187 _validate_num($k, 2) || _validate_positive_integer($k, 2);
1188
1189 if ($_HAVE_GMP && $k <= 450) {
1190 my $n = random_nbit_prime($k);
1191 my ($isp, $cert) = is_provable_prime_with_cert($n);
1192 croak "small nbit prime could not be proven" if $isp != 2;
1193 return ($n, $cert);
1194 }
1195 return random_maurer_prime_with_cert($k);
1196 }
1197
1198 } # end of the random prime section
308 require Math::Prime::Util::RandomPrimes;
309 return Math::Prime::Util::RandomPrimes::random_prime($low,$high);
310 }
311
312 sub random_ndigit_prime {
313 my($digits) = @_;
314 _validate_num($digits, 1) || _validate_positive_integer($digits, 1);
315 require Math::Prime::Util::RandomPrimes;
316 return Math::Prime::Util::RandomPrimes::random_ndigit_prime($digits);
317 }
318
319 sub random_nbit_prime {
320 my($bits) = @_;
321 _validate_num($bits, 2) || _validate_positive_integer($bits, 2);
322 require Math::Prime::Util::RandomPrimes;
323 return Math::Prime::Util::RandomPrimes::random_nbit_prime($bits);
324 }
325
326 sub random_maurer_prime {
327 my($bits) = @_;
328 _validate_num($bits, 2) || _validate_positive_integer($bits, 2);
329 require Math::Prime::Util::RandomPrimes;
330 return Math::Prime::Util::RandomPrimes::random_maurer_prime($bits);
331 }
332
333 sub random_maurer_prime_with_cert {
334 my($bits) = @_;
335 _validate_num($bits, 2) || _validate_positive_integer($bits, 2);
336 require Math::Prime::Util::RandomPrimes;
337 return Math::Prime::Util::RandomPrimes::random_maurer_prime_with_cert($bits);
338 }
339
340 sub random_strong_prime {
341 my($bits) = @_;
342 _validate_num($bits, 128) || _validate_positive_integer($bits, 128);
343 require Math::Prime::Util::RandomPrimes;
344 return Math::Prime::Util::RandomPrimes::random_strong_prime($bits);
345 }
346
347 sub random_proven_prime {
348 my($bits) = @_;
349 _validate_num($bits, 2) || _validate_positive_integer($bits, 2);
350 require Math::Prime::Util::RandomPrimes;
351 return Math::Prime::Util::RandomPrimes::random_proven_prime($bits);
352 }
353
354 sub random_proven_prime_with_cert {
355 my($bits) = @_;
356 _validate_num($bits, 2) || _validate_positive_integer($bits, 2);
357 require Math::Prime::Util::RandomPrimes;
358 return Math::Prime::Util::RandomPrimes::random_proven_prime_with_cert($bits);
359 }
360
361 sub miller_rabin_random {
362 my($n, $k, $seed) = @_;
363 _validate_num($n) || _validate_positive_integer($n);
364 _validate_num($k) || _validate_positive_integer($k);
365
366 return 1 if $k <= 0;
367 return (is_prob_prime($n) > 0) if $n < 100;
368 return 0 unless $n & 1;
369
370 return Math::Prime::Util::GMP::miller_rabin_random($n, $k)
371 if $_HAVE_GMP
372 && defined &Math::Prime::Util::GMP::miller_rabin_random;
373
374 require Math::Prime::Util::RandomPrimes;
375 return Math::Prime::Util::RandomPrimes::miller_rabin_random($n, $k, $seed);
376 }
377
378
379 #############################################################################
380 # These functions almost always return bigints, so there is no XS
381 # implementation. Try to run the GMP version, and if it isn't available,
382 # load PP and call it.
1199383
1200384 sub primorial {
1201385 my($n) = @_;
1202386 _validate_num($n) || _validate_positive_integer($n);
1203387
1204 return Math::BigInt->new(''.Math::Prime::Util::GMP::primorial($n))
1205 if $_HAVE_GMP && defined &Math::Prime::Util::GMP::primorial;
1206
1207 my $max = (MPU_32BIT) ? 29 : (OLD_PERL_VERSION) ? 43 : 53;
1208 my $pn = (ref($_[0]) eq 'Math::BigInt') ? $_[0]->copy->bone()
1209 : ($n >= $max) ? Math::BigInt->bone()
1210 : 1;
1211 if (ref($pn) eq 'Math::BigInt') {
1212 my $start = 2;
1213 if ($n >= 97) {
1214 $start = 101;
1215 $pn->bdec->badd(Math::BigInt->new("2305567963945518424753102147331756070"));
1216 }
1217 my @plist = @{primes($start,$n)};
1218 while (@plist > 2 && $plist[2] < 1625) {
1219 $pn->bmul( Math::BigInt->new(shift(@plist)*shift(@plist)*shift(@plist)) );
1220 }
1221 while (@plist > 1 && $plist[1] < 65536) {
1222 $pn->bmul( Math::BigInt->new(shift(@plist)*shift(@plist)) );
1223 }
1224 $pn->bmul($_) for @plist;
1225 } else {
1226 forprimes { $pn *= $_ } $n;
388 if ($_HAVE_GMP && defined &Math::Prime::Util::GMP::primorial) {
389 return _reftyped($_[0], Math::Prime::Util::GMP::primorial($n));
1227390 }
1228 return $pn;
391 require Math::Prime::Util::PP;
392 return Math::Prime::Util::PP::primorial($n);
1229393 }
1230394
1231395 sub pn_primorial {
1232396 my($n) = @_;
397 _validate_num($n) || _validate_positive_integer($n);
1233398
1234399 if ($_HAVE_GMP && defined &Math::Prime::Util::GMP::pn_primorial) {
1235 _validate_num($n) || _validate_positive_integer($n);
1236 return Math::BigInt->new(''.Math::Prime::Util::GMP::pn_primorial($n))
400 return _reftyped($_[0], Math::Prime::Util::GMP::pn_primorial($n));
1237401 }
1238402
1239 return primorial(nth_prime($n));
403 require Math::Prime::Util::PP;
404 return Math::Prime::Util::PP::primorial(nth_prime($n));
1240405 }
1241406
1242407 sub consecutive_integer_lcm {
1244409 _validate_num($n) || _validate_positive_integer($n);
1245410 return 0 if $n < 1;
1246411
1247 my $max = (MPU_32BIT) ? 22 : (OLD_PERL_VERSION) ? 37 : 46;
1248
1249412 if ($_HAVE_GMP && defined &Math::Prime::Util::GMP::consecutive_integer_lcm) {
1250 my $clcm = Math::Prime::Util::GMP::consecutive_integer_lcm($n);
1251 return ($n < $max) ? int($clcm) : Math::BigInt->new("$clcm");
413 return _reftyped($_[0],Math::Prime::Util::GMP::consecutive_integer_lcm($n));
1252414 }
1253
1254 my $pn = (ref($_[0]) eq 'Math::BigInt') ? $_[0]->copy->bone()
1255 : ($n >= $max) ? Math::BigInt->bone()
1256 : 1;
1257 forprimes {
1258 my($p_power, $pmin) = ($_, int($n/$_));
1259 $p_power *= $_ while $p_power <= $pmin;
1260 $pn *= $p_power;
1261 } $n;
1262
1263 return $pn;
1264 }
1265
1266 # A008683 Moebius function mu(n)
1267 # A030059, A013929, A030229, A002321, A005117, A013929 all relate.
1268 sub _generic_moebius {
1269 my($n, $nend) = @_;
1270 return 0 if defined $n && $n < 0;
415 require Math::Prime::Util::PP;
416 return Math::Prime::Util::PP::consecutive_integer_lcm($n);
417 }
418
419 # See 2011+ FLINT and Fredrik Johansson's work for state of the art.
420 # Very crude timing estimates (ignores growth rates).
421 # Perl-comb partitions(10^5) ~ 300 seconds ~200,000x slower than Pari
422 # GMP-comb partitions(10^6) ~ 120 seconds ~1,000x slower than Pari
423 # Pari partitions(10^8) ~ 100 seconds
424 # Bober 0.6 partitions(10^9) ~ 20 seconds ~50x faster than Pari
425 # Johansson partitions(10^12) ~ 10 seconds >1000x faster than Pari
426 sub partitions {
427 my($n) = @_;
428 return 1 if defined $n && $n <= 0;
1271429 _validate_num($n) || _validate_positive_integer($n);
1272 return Math::Prime::Util::PP::moebius($n) if !defined $nend;
1273 _validate_num($nend) || _validate_positive_integer($nend);
1274 return Math::Prime::Util::PP::moebius_range($n, $nend);
1275 }
1276
1277 # A002321 Mertens' function. mertens(n) = sum(moebius(1,n))
1278 sub _generic_mertens {
1279 my($n) = @_;
1280 _validate_num($n) || _validate_positive_integer($n);
1281 # This is the most basic Deléglise and Rivat algorithm. u = n^1/2
1282 # and no segmenting is done. Their algorithm uses u = n^1/3, breaks
1283 # the summation into two parts, and calculates those in segments. Their
1284 # computation time growth is half of this code.
1285 return $n if $n <= 1;
1286 my $u = int(sqrt($n));
1287 my @mu = (0, moebius(1, $u)); # Hold values of mu for 0-u
1288 my $musum = 0;
1289 my @M = map { $musum += $_; } @mu; # Hold values of M for 0-u
1290 my $sum = $M[$u];
1291 foreach my $m (1 .. $u) {
1292 next if $mu[$m] == 0;
1293 my $inner_sum = 0;
1294 my $lower = int($u/$m) + 1;
1295 my $last_nmk = int($n/($m*$lower));
1296 my ($denom, $this_k, $next_k) = ($m, 0, int($n/($m*1)));
1297 for my $nmk (1 .. $last_nmk) {
1298 $denom += $m;
1299 $this_k = int($n/$denom);
1300 next if $this_k == $next_k;
1301 ($this_k, $next_k) = ($next_k, $this_k);
1302 $inner_sum += $M[$nmk] * ($this_k - $next_k);
1303 }
1304 $sum -= $mu[$m] * $inner_sum;
430
431 if ($_HAVE_GMP && defined &Math::Prime::Util::GMP::partitions) {
432 return _reftyped($_[0],Math::Prime::Util::GMP::partitions($n));
1305433 }
1306 return $sum;
1307 }
1308
1309
1310 # A000010 Euler Phi, aka Euler Totient
1311 sub _generic_euler_phi {
1312 my($n, $nend) = @_;
1313 return 0 if defined $n && $n < 0;
1314 _validate_num($n) || _validate_positive_integer($n);
1315 return Math::Prime::Util::PP::euler_phi($n) if !defined $nend;
1316 _validate_num($nend) || _validate_positive_integer($nend);
1317 return Math::Prime::Util::PP::euler_phi_range($n, $nend);
1318 }
1319
1320 sub _generic_divisor_sum {
1321 my($n) = @_;
1322 _validate_num($n) || _validate_positive_integer($n);
1323 return Math::Prime::Util::PP::divisor_sum(@_);
1324 }
1325
1326 # Need proto for the block
1327 sub _generic_forprimes (&$;$) { ## no critic qw(ProhibitSubroutinePrototypes)
434
435 require Math::Prime::Util::PP;
436 return Math::Prime::Util::PP::partitions($n);
437 }
438
439
440 #############################################################################
441 # forprimes, forcomposites, fordivisors.
442 # These are used when the XS code can't handle it.
443
444 sub _generic_forprimes {
1328445 my($sub, $beg, $end) = @_;
1329446 if (!defined $end) { $end = $beg; $beg = 2; }
1330 _validate_num($beg) || _validate_positive_integer($beg);
1331 _validate_num($end) || _validate_positive_integer($end);
447 _validate_positive_integer($beg);
448 _validate_positive_integer($end);
1332449 $beg = 2 if $beg < 2;
1333450 {
1334451 my $pp;
1340457 }
1341458 }
1342459
1343 sub _generic_forcomposites(&$;$) { ## no critic qw(ProhibitSubroutinePrototypes)
460 sub _generic_forcomposites {
1344461 my($sub, $beg, $end) = @_;
1345462 if (!defined $end) { $end = $beg; $beg = 4; }
1346 _validate_num($beg) || _validate_positive_integer($beg);
1347 _validate_num($end) || _validate_positive_integer($end);
463 _validate_positive_integer($beg);
464 _validate_positive_integer($end);
1348465 $beg = 4 if $beg < 4;
1349466 $end = Math::BigInt->new(''.~0) if ref($end) ne 'Math::BigInt' && $end == ~0;
1350467 {
1359476 }
1360477 }
1361478
1362 sub _generic_fordivisors (&$) { ## no critic qw(ProhibitSubroutinePrototypes)
479 sub _generic_fordivisors {
1363480 my($sub, $n) = @_;
1364 _validate_num($n) || _validate_positive_integer($n);
481 _validate_positive_integer($n);
1365482 my @divisors = divisors($n);
1366483 {
1367484 my $pp;
1373490 }
1374491 }
1375492
493 #############################################################################
494 # Iterators
495
1376496 sub prime_iterator {
1377497 my($start) = @_;
1378498 $start = 0 unless defined $start;
1379499 _validate_num($start) || _validate_positive_integer($start);
1380500 my $p = ($start > 0) ? $start-1 : 0;
501 # This works fine:
502 # return sub { $p = next_prime($p); return $p; };
503 # but we can optimize a little
1381504 if (ref($p) ne 'Math::BigInt' && $p <= $_XS_MAXVAL) {
1382505 return sub { $p = next_prime($p); return $p; };
1383506 } elsif ($_HAVE_GMP) {
1384507 return sub { $p = $p-$p+Math::Prime::Util::GMP::next_prime($p); return $p;};
1385508 } else {
509 require Math::Prime::Util::PP;
1386510 return sub { $p = Math::Prime::Util::PP::next_prime($p); return $p; }
1387511 }
1388512 }
1389513
1390514 sub prime_iterator_object {
1391515 my($start) = @_;
1392 eval { require Math::Prime::Util::PrimeIterator; 1; }
1393 or do { croak "Cannot load Math::Prime::Util::PrimeIterator"; };
516 require Math::Prime::Util::PrimeIterator;
1394517 return Math::Prime::Util::PrimeIterator->new($start);
1395518 }
1396
1397 # Exponential of Mangoldt function (A014963).
1398 # Return p if n = p^m [p prime, m >= 1], 1 otherwise.
1399 sub _generic_exp_mangoldt {
1400 my($n) = @_;
1401 return 1 if defined $n && $n <= 1; # n <= 1
1402 _validate_num($n) || _validate_positive_integer($n);
1403
1404 return 2 if ($n & ($n-1)) == 0; # n power of 2
1405 return 1 unless $n & 1; # even n can't be p^m
1406
1407 my @pe = factor_exp($n);
1408 return 1 if scalar @pe > 1;
1409 return $pe[0]->[0];
1410 }
1411
1412 sub liouville {
1413 my($n) = @_;
1414 _validate_num($n) || _validate_positive_integer($n);
1415 my $l = (-1) ** scalar factor($n);
1416 return $l;
1417 }
1418
1419 # See 2011+ FLINT and Fredrik Johansson's work for state of the art.
1420 # Very crude timing estimates (ignores growth rates).
1421 # Perl-comb partitions(10^5) ~ 300 seconds ~200,000x slower than Pari
1422 # GMP-comb partitions(10^6) ~ 120 seconds ~1,000x slower than Pari
1423 # Pari partitions(10^8) ~ 100 seconds
1424 # Bober 0.6 partitions(10^9) ~ 20 seconds ~50x faster than Pari
1425 # Johansson partitions(10^12) ~ 10 seconds >1000x faster than Pari
1426 sub partitions {
1427 my($n) = @_;
1428 return 1 if defined $n && $n <= 0;
1429 _validate_num($n) || _validate_positive_integer($n);
1430
1431 return Math::BigInt->new(''.Math::Prime::Util::GMP::partitions($n))
1432 if $_HAVE_GMP && defined &Math::Prime::Util::GMP::partitions;
1433
1434 my $d = int(sqrt($n+1));
1435 my @pent = (1, map { (($_*(3*$_+1))>>1, (($_+1)*(3*$_+2))>>1) } 1 .. $d);
1436 my @part = (Math::BigInt->bone);
1437 foreach my $j (scalar @part .. $n) {
1438 my ($psum1, $psum2, $k) = (Math::BigInt->bzero, Math::BigInt->bzero, 1);
1439 foreach my $p (@pent) {
1440 last if $p > $j;
1441 if ((++$k) & 2) { $psum1->badd( $part[ $j - $p ] ); }
1442 else { $psum2->badd( $part[ $j - $p ] ); }
1443 }
1444 $part[$j] = $psum1 - $psum2;
1445 }
1446 return $part[$n];
1447 }
1448
1449 sub chebyshev_theta {
1450 my($n) = @_;
1451 _validate_num($n) || _validate_positive_integer($n);
1452 return _XS_chebyshev_theta($n) if $n <= $_XS_MAXVAL;
1453 my $sum = 0.0;
1454 forprimes { $sum += log($_); } $n;
1455 return $sum;
1456 }
1457 sub chebyshev_psi {
1458 my($n) = @_;
1459 _validate_num($n) || _validate_positive_integer($n);
1460 return 0 if $n <= 1;
1461 return _XS_chebyshev_psi($n) if $n <= $_XS_MAXVAL;
1462 my ($sum, $logn, $sqrtn) = (0.0, log($n), int(sqrt($n)));
1463 forprimes {
1464 my $logp = log($_);
1465 $sum += $logp * int($logn/$logp+1e-15);
1466 } $sqrtn;
1467 forprimes {
1468 $sum += log($_);
1469 } $sqrtn+1, $n;
1470 return $sum;
1471 }
1472
1473 sub _generic_carmichael_lambda {
1474 my($n) = @_;
1475 _validate_num($n) || _validate_positive_integer($n);
1476 # lambda(n) = phi(n) for n < 8
1477 return euler_phi($n) if $n < 8;
1478 # lambda(n) = phi(n)/2 for powers of two greater than 4
1479 return euler_phi($n)/2 if ($n & ($n-1)) == 0;
1480
1481 my @pe = factor_exp($n);
1482 $pe[0]->[1]-- if $pe[0]->[0] == 2 && $pe[0]->[1] > 2;
1483
1484 my $lcm = Math::BigInt::blcm(
1485 map { $_->[0]->copy->bpow($_->[1]->copy->bdec)->bmul($_->[0]->copy->bdec) }
1486 map { [ map { Math::BigInt->new("$_") } @$_ ] }
1487 @pe
1488 );
1489 $lcm = _bigint_to_int($lcm) if $lcm->bacmp(''.~0) <= 0;
1490 return $lcm;
1491 }
1492
1493 sub _generic_znprimroot {
1494 my($n) = @_;
1495 $n = -$n if defined $n && $n =~ /^-\d+/; # TODO: fix this for string bigints
1496 _validate_num($n) || _validate_positive_integer($n);
1497 if ($n <= 4) {
1498 return if $n == 0;
1499 return $n-1;
1500 }
1501 return if $n % 4 == 0;
1502 my $a = 1;
1503 my $phi = euler_phi($n);
1504 # Check that a primitive root exists.
1505 return if !is_prob_prime($n) && $phi != carmichael_lambda($n);
1506 my @exp = map { Math::BigInt->new("$_") }
1507 map { int($phi/$_->[0]) }
1508 factor_exp($phi);
1509 #print "phi: $phi factors: ", join(",",factor($phi)), "\n";
1510 #print " exponents: ", join(",", @exp), "\n";
1511 my $bign = (ref($n) eq 'Math::BigInt') ? $n : Math::BigInt->new("$n");
1512 while (1) {
1513 my $fail = 0;
1514 do { $a++ } while kronecker($a,$n) == 0;
1515 return if $a >= $n;
1516 foreach my $f (@exp) {
1517 if ( Math::BigInt->new($a)->bmodpow($f, $bign)->is_one ) {
1518 $fail = 1;
1519 last;
1520 }
1521 }
1522 return $a if !$fail;
1523 }
1524 }
1525
1526
1527
1528
1529519
1530520 #############################################################################
1531521 # Front ends to functions.
1539529 _validate_num($n) || _validate_positive_integer($n);
1540530
1541531 if ($_HAVE_GMP) {
1542 my $r = Math::Prime::Util::GMP::next_prime($n);
1543 return (ref($n) eq 'Math::BigInt' || $n >= MPU_MAXPRIME)
1544 ? Math::BigInt->new("$r") : int($r);
532 return _reftyped($_[0], Math::Prime::Util::GMP::next_prime($n));
1545533 }
1546534
535 require Math::Prime::Util::PP;
1547536 return Math::Prime::Util::PP::next_prime($_[0]);
1548537 }
1549538
1552541 _validate_num($n) || _validate_positive_integer($n);
1553542
1554543 if ($_HAVE_GMP) {
1555 my $r = Math::Prime::Util::GMP::prev_prime($n);
1556 return (ref($n) eq 'Math::BigInt' && $r > MPU_MAXPRIME)
1557 ? Math::BigInt->new("$r") : int($r);
544 return _reftyped($_[0], Math::Prime::Util::GMP::prev_prime($n));
1558545 }
1559546
547 require Math::Prime::Util::PP;
1560548 return Math::Prime::Util::PP::prev_prime($_[0]);
1561 }
1562
1563 sub _generic_kronecker {
1564 my($a, $b) = @_;
1565 croak "Parameter must be defined" if !defined $a;
1566 croak "Parameter must be defined" if !defined $b;
1567 croak "Parameter '$a' must be an integer" unless $a =~ /^[-+]?\d+/;
1568 croak "Parameter '$b' must be an integer" unless $b =~ /^[-+]?\d+/;
1569
1570 return Math::BigInt->new(''.Math::Prime::Util::GMP::kronecker($a,$b))
1571 if $_HAVE_GMP && defined &Math::Prime::Util::GMP::kronecker;
1572
1573 return Math::Prime::Util::PP::kronecker(@_);
1574549 }
1575550
1576551 sub _generic_prime_count {
1590565 && ( (ref($high) eq 'Math::BigInt')
1591566 || (($high-$low) < int($low/1_000_000))
1592567 );
568 require Math::Prime::Util::PP;
1593569 return Math::Prime::Util::PP::prime_count($low,$high);
1594570 }
1595571
1608584 return @factors;
1609585 }
1610586
587 require Math::Prime::Util::PP;
1611588 return Math::Prime::Util::PP::factor($n);
1612589 }
1613590
1619596 my @factors = grep { !$exponents{$_}++ } factor($n);
1620597 return scalar @factors unless wantarray;
1621598 return (map { [$_, $exponents{$_}] } @factors);
1622 }
1623
1624 sub _generic_divisors {
1625 my($n) = @_;
1626 _validate_num($n) || _validate_positive_integer($n);
1627
1628 # In scalar context, returns sigma_0(n). Very fast.
1629 return divisor_sum($n,0) unless wantarray;
1630 return ($n == 0) ? (0,1) : (1) if $n <= 1;
1631
1632 my %all_factors;
1633 my @factors = factor($n);
1634 return (1,$n) if scalar @factors == 1;
1635
1636 if (ref($n) eq 'Math::BigInt') {
1637 foreach my $f1 (@factors) {
1638 my $big_f1 = Math::BigInt->new("$f1");
1639 my @to_add = map { ($_ <= ''.~0) ? _bigint_to_int($_) : $_ }
1640 grep { $_ < $n }
1641 map { $big_f1 * $_ }
1642 keys %all_factors;
1643 undef @all_factors{ $f1, @to_add };
1644 }
1645 } else {
1646 foreach my $f1 (@factors) {
1647 my @to_add = grep { $_ < $n }
1648 map { $f1 * $_ }
1649 keys %all_factors;
1650 undef @all_factors{ $f1, @to_add };
1651 }
1652 }
1653 # Add 1 and n
1654 undef $all_factors{1};
1655 undef $all_factors{$n};
1656 my @divisors = sort {$a<=>$b} keys %all_factors;
1657 return @divisors;
1658599 }
1659600
1660601
1666607 _validate_num($testP) || _validate_positive_integer($testP); }
1667608 { my $testQ = (!defined $Q || $Q >= 0) ? $Q : -$Q;
1668609 _validate_num($testQ) || _validate_positive_integer($testQ); }
610
1669611 return _XS_lucas_sequence($n, $P, $Q, $k)
1670612 if ref($_[0]) ne 'Math::BigInt' && $n <= $_XS_MAXVAL
1671613 && ref($_[3]) ne 'Math::BigInt' && $k <= $_XS_MAXVAL;
614
1672615 if ($_HAVE_GMP && defined &Math::Prime::Util::GMP::lucas_sequence) {
1673616 return map { ($_ > ''.~0) ? Math::BigInt->new(''.$_) : $_ }
1674617 Math::Prime::Util::GMP::lucas_sequence($n, $P, $Q, $k);
1675618 }
619 require Math::Prime::Util::PP;
1676620 return map { ($_ <= ''.~0) ? _bigint_to_int($_) : $_ }
1677621 Math::Prime::Util::PP::lucas_sequence($n, $P, $Q, $k);
1678622 }
1679623
1680 sub miller_rabin_random {
1681 my($n, $k, $seed) = @_;
1682 _validate_num($n) || _validate_positive_integer($n);
1683 _validate_num($k) || _validate_positive_integer($k);
1684
1685 return 1 if $k <= 0;
1686 return (is_prob_prime($n) > 0) if $n < 100;
1687 return 0 unless $n & 1;
1688 return Math::Prime::Util::GMP::miller_rabin_random($n, $k)
1689 if $_HAVE_GMP
1690 && defined &Math::Prime::Util::GMP::miller_rabin_random;
1691
1692 # Testing this many bases is silly, but let's pretend they have some
1693 # good reason. A composite n > 9 must have at least n/4 witnesses,
1694 # hence we need to check only floor(3/4)+1 at most. We could improve
1695 # this is $_Config{'assume_rh'} is true, to 1 .. 2(logn)^2.
1696 if ($k >= int(3*$n/4)) {
1697 return is_strong_pseudoprime($n, 2 .. int(3*$n/4)+1+2 );
1698 }
1699
1700 my $brange = $n-3;
1701 my $irandf = _get_randf();
1702 # Do one first before doing batches
1703 return 0 unless is_strong_pseudoprime($n, $irandf->($brange)+2 );
1704 $k--;
1705 while ($k > 0) {
1706 my $nbases = ($k >= 20) ? 20 : $k;
1707 my @bases = map { $irandf->($brange)+2 } 1..$nbases;
1708 return 0 unless is_strong_pseudoprime($n, @bases);
1709 $k -= $nbases;
1710 }
1711 1;
1712 }
1713
1714624
1715625 #############################################################################
1716
1717 # For stripping off the header on certificates so they can be combined.
1718 sub _strip_proof_header {
1719 my $proof = shift;
1720 $proof =~ s/^\[MPU - Primality Certificate\]\nVersion \S+\n+Proof for:\nN (\d+)\n+//ms;
1721 return $proof;
1722 }
1723626
1724627 # Return just the non-cert portion.
1725628 sub is_provable_prime {
1765668 return ($isp, $cert);
1766669 }
1767670 # Old version. Convert.
1768 if (!defined $Math::Prime::Util::PrimalityProving::VERSION) {
1769 eval { require Math::Prime::Util::PrimalityProving; 1; }
1770 or do { croak "Cannot load Math::Prime::Util::PrimalityProving"; };
1771 }
671 require Math::Prime::Util::PrimalityProving;
1772672 return ($isp, Math::Prime::Util::PrimalityProving::convert_array_cert_to_string($cert));
1773673 }
1774674
1791691 # AKS horribly slow
1792692 # See http://primes.utm.edu/prove/merged.html or other sources.
1793693
1794 if (!defined $Math::Prime::Util::PrimalityProving::VERSION) {
1795 eval { require Math::Prime::Util::PrimalityProving; 1; }
1796 or do { croak "Cannot load Math::Prime::Util::PrimalityProving"; };
1797 }
1798
694 require Math::Prime::Util::PrimalityProving;
1799695 #my ($isp, $pref) = Math::Prime::Util::PrimalityProving::primality_proof_lucas($n);
1800696 my ($isp, $pref) = Math::Prime::Util::PrimalityProving::primality_proof_bls75($n);
1801697 carp "proved $n is not prime\n" if !$isp;
1806702 sub verify_prime {
1807703 my @cdata = @_;
1808704
1809 if (!defined $Math::Prime::Util::PrimalityProving::VERSION) {
1810 eval { require Math::Prime::Util::PrimalityProving; 1; }
1811 or do { croak "Cannot load Math::Prime::Util::PrimalityProving"; };
1812 }
1813
705 require Math::Prime::Util::PrimalityProving;
1814706 my $cert = '';
1815707 if (scalar @cdata == 1 && ref($cdata[0]) eq '') {
1816708 $cert = $cdata[0];
1829721
1830722 #############################################################################
1831723
1832 sub prime_count_approx {
1833 my($x) = @_;
1834 _validate_num($x) || _validate_positive_integer($x);
1835
1836 # With XS using 30k tables, this is super fast.
1837 return prime_count($x) if $x < $_XS_MAXVAL && $x < 3_000_000;
1838 # Give an exact answer for what we have in our little table.
1839 return _tiny_prime_count($x) if $x < $_primes_small[-1];
1840
1841 # Below 2^58th or so, all differences between the high precision and C double
1842 # precision result are less than 0.5.
1843 if ($x <= $_XS_MAXVAL && $x <= 144115188075855872) {
1844 return int(_XS_RiemannR($x) + 0.5);
1845 }
1846
1847 # Turn on high precision FP if they gave us a big number.
1848 $x = _upgrade_to_float($x) if ref($_[0]) eq 'Math::BigInt';
1849
1850 # Method 10^10 %error 10^19 %error
1851 # ----------------- ------------ ------------
1852 # n/(log(n)-1) .22% .06%
1853 # average bounds .01% .0002%
1854 # li(n) .0007% .00000004%
1855 # li(n)-li(n^.5)/2 .0004% .00000001%
1856 # R(n) .0004% .00000001%
1857 #
1858 # Also consider: http://trac.sagemath.org/sage_trac/ticket/8135
1859
1860 # my $result = int( (prime_count_upper($x) + prime_count_lower($x)) / 2);
1861 # my $result = int( LogarithmicIntegral($x) );
1862 # my $result = int(LogarithmicIntegral($x) - LogarithmicIntegral(sqrt($x))/2);
1863 # my $result = RiemannR($x) + 0.5;
1864
1865 # Sadly my Perl RiemannR function is really slow for big values. If MPFR
1866 # is available, then use it -- it rocks. Otherwise, switch to LiCorr for
1867 # very big values. This is hacky and shouldn't be necessary.
1868 my $result;
1869 if ( $x < 1e36 || Math::Prime::Util::PP::_MPFR_available() ) {
1870 if (ref($x) eq 'Math::BigFloat') {
1871 # Make sure we get enough accuracy, and also not too much more than needed
1872 $x->accuracy(length($x->bfloor->bstr())+2);
1873 }
1874 $result = RiemannR($x) + 0.5;
1875 } else {
1876 $result = int(LogarithmicIntegral($x) - LogarithmicIntegral(sqrt($x))/2);
1877 }
1878
1879 return Math::BigInt->new($result->bfloor->bstr()) if ref($result) eq 'Math::BigFloat';
1880 return int($result);
1881 }
1882
1883 sub prime_count_lower {
1884 my($x) = @_;
1885 _validate_num($x) || _validate_positive_integer($x);
1886
1887 # With XS using 30k tables, this is super fast.
1888 return prime_count($x) if $x < $_XS_MAXVAL && $x < 3_000_000;
1889 # Give an exact answer for what we have in our little table.
1890 return _tiny_prime_count($x) if $x < $_primes_small[-1];
1891
1892 $x = _upgrade_to_float($x)
1893 if ref($x) eq 'Math::BigInt' || ref($_[0]) eq 'Math::BigInt';
1894
1895 my $flogx = log($x);
1896
1897 # Chebyshev: 1*x/logx x >= 17
1898 # Rosser & Schoenfeld: x/(logx-1/2) x >= 67
1899 # Dusart 1999: x/logx*(1+1/logx+1.8/logxlogx) x >= 32299
1900 # Dusart 2010: x/logx*(1+1/logx+2.0/logxlogx) x >= 88783
1901 # The Dusart (1999 or 2010) bounds are far, far better than the others.
1902
1903 my $result;
1904 if ($x > 1000_000_000_000 && $_Config{'assume_rh'}) {
1905 my $lix = LogarithmicIntegral($x);
1906 my $sqx = sqrt($x);
1907 # Schoenfeld bound: (constant is 8 * Pi)
1908 $result = $lix - (($sqx*$flogx) / 25.13274122871834590770114707);
1909 } elsif ($x < 599) {
1910 $result = $x / ($flogx - 0.7); # For smaller numbers this works out well.
1911 } else {
1912 my $a;
1913 # Hand tuned for small numbers (< 60_000M)
1914 if ($x < 2700) { $a = 0.30; }
1915 elsif ($x < 5500) { $a = 0.90; }
1916 elsif ($x < 19400) { $a = 1.30; }
1917 elsif ($x < 32299) { $a = 1.60; }
1918 elsif ($x < 176000) { $a = 1.80; }
1919 elsif ($x < 315000) { $a = 2.10; }
1920 elsif ($x < 1100000) { $a = 2.20; }
1921 elsif ($x < 4500000) { $a = 2.31; }
1922 elsif ($x < 233000000) { $a = 2.36; }
1923 elsif ($x < 5433800000) { $a = 2.32; }
1924 elsif ($x <60000000000) { $a = 2.15; }
1925 else { $a = 2.00; } # Dusart 2010, page 2
1926 $result = ($x/$flogx) * (1.0 + 1.0/$flogx + $a/($flogx*$flogx));
1927 }
1928
1929 return Math::BigInt->new($result->bfloor->bstr()) if ref($result) eq 'Math::BigFloat';
1930 return int($result);
1931 }
1932
1933 sub prime_count_upper {
1934 my($x) = @_;
1935 _validate_num($x) || _validate_positive_integer($x);
1936
1937 # With XS using 30k tables, this is super fast.
1938 return prime_count($x) if $x < $_XS_MAXVAL && $x < 3_000_000;
1939 # Give an exact answer for what we have in our little table.
1940 return _tiny_prime_count($x) if $x < $_primes_small[-1];
1941
1942 $x = _upgrade_to_float($x)
1943 if ref($x) eq 'Math::BigInt' || ref($_[0]) eq 'Math::BigInt';
1944
1945 # Chebyshev: 1.25506*x/logx x >= 17
1946 # Rosser & Schoenfeld: x/(logx-3/2) x >= 67
1947 # Dusart 1999: x/logx*(1+1/logx+2.51/logxlogx) x >= 355991
1948 # Dusart 2010: x/logx*(1+1/logx+2.334/logxlogx) x >= 2_953_652_287
1949
1950 # As with the lower bounds, Dusart bounds are best by far.
1951
1952 # Another possibility here for numbers under 3000M is to use Li(x)
1953 # minus a correction.
1954
1955 my $flogx = log($x);
1956
1957 my $result;
1958 if ($x > 10000_000_000_000 && $_Config{'assume_rh'}) {
1959 my $lix = LogarithmicIntegral($x);
1960 my $sqx = sqrt($x);
1961 # Schoenfeld bound: (constant is 8 * Pi)
1962 $result = $lix + (($sqx*$flogx) / 25.13274122871834590770114707);
1963 } elsif ($x < 1621) { $result = ($x / ($flogx - 1.048)) + 1.0; }
1964 elsif ($x < 5000) { $result = ($x / ($flogx - 1.071)) + 1.0; }
1965 elsif ($x < 15900) { $result = ($x / ($flogx - 1.098)) + 1.0; }
1966 else {
1967 my $a;
1968 # Hand tuned for small numbers (< 60_000M)
1969 if ($x < 24000) { $a = 2.30; }
1970 elsif ($x < 59000) { $a = 2.48; }
1971 elsif ($x < 350000) { $a = 2.52; }
1972 elsif ($x < 355991) { $a = 2.54; }
1973 elsif ($x < 356000) { $a = 2.51; }
1974 elsif ($x < 3550000) { $a = 2.50; }
1975 elsif ($x < 3560000) { $a = 2.49; }
1976 elsif ($x < 5000000) { $a = 2.48; }
1977 elsif ($x < 8000000) { $a = 2.47; }
1978 elsif ($x < 13000000) { $a = 2.46; }
1979 elsif ($x < 18000000) { $a = 2.45; }
1980 elsif ($x < 31000000) { $a = 2.44; }
1981 elsif ($x < 41000000) { $a = 2.43; }
1982 elsif ($x < 48000000) { $a = 2.42; }
1983 elsif ($x < 119000000) { $a = 2.41; }
1984 elsif ($x < 182000000) { $a = 2.40; }
1985 elsif ($x < 192000000) { $a = 2.395; }
1986 elsif ($x < 213000000) { $a = 2.390; }
1987 elsif ($x < 271000000) { $a = 2.385; }
1988 elsif ($x < 322000000) { $a = 2.380; }
1989 elsif ($x < 400000000) { $a = 2.375; }
1990 elsif ($x < 510000000) { $a = 2.370; }
1991 elsif ($x < 682000000) { $a = 2.367; }
1992 elsif ($x < 2953652287) { $a = 2.362; }
1993 else { $a = 2.334; } # Dusart 2010, page 2
1994 #elsif ($x <60000000000) { $a = 2.362; }
1995 #else { $a = 2.51; } # Dusart 1999, page 14
1996
1997 # Old versions of Math::BigFloat will do the Wrong Thing with this.
1998 $result = ($x/$flogx) * (1.0 + 1.0/$flogx + $a/($flogx*$flogx)) + 1.0;
1999 }
2000
2001 return Math::BigInt->new($result->bfloor->bstr()) if ref($result) eq 'Math::BigFloat';
2002 return int($result);
2003 }
2004
2005 #############################################################################
2006
2007 sub nth_prime_approx {
2008 my($n) = @_;
2009 _validate_num($n) || _validate_positive_integer($n);
2010
2011 return $_primes_small[$n] if $n <= $#_primes_small;
2012
2013 $n = _upgrade_to_float($n)
2014 if ref($n) eq 'Math::BigInt' || $n >= MPU_MAXPRIMEIDX;
2015
2016 my $flogn = log($n);
2017 my $flog2n = log($flogn);
2018
2019 # Cipolla 1902:
2020 # m=0 fn * ( flogn + flog2n - 1 );
2021 # m=1 + ((flog2n - 2)/flogn) );
2022 # m=2 - (((flog2n*flog2n) - 6*flog2n + 11) / (2*flogn*flogn))
2023 # + O((flog2n/flogn)^3)
2024 #
2025 # Shown in Dusart 1999 page 12, as well as other sources such as:
2026 # http://www.emis.de/journals/JIPAM/images/153_02_JIPAM/153_02.pdf
2027 # where the main issue you run into is that you're doing polynomial
2028 # interpolation, so it oscillates like crazy with many high-order terms.
2029 # Hence I'm leaving it at m=2.
2030 #
2031
2032 my $approx = $n * ( $flogn + $flog2n - 1
2033 + (($flog2n - 2)/$flogn)
2034 - ((($flog2n*$flog2n) - 6*$flog2n + 11) / (2*$flogn*$flogn))
2035 );
2036
2037 # Apply a correction to help keep values close.
2038 my $order = $flog2n/$flogn;
2039 $order = $order*$order*$order * $n;
2040
2041 if ($n < 259) { $approx += 10.4 * $order; }
2042 elsif ($n < 775) { $approx += 7.52* $order; }
2043 elsif ($n < 1271) { $approx += 5.6 * $order; }
2044 elsif ($n < 2000) { $approx += 5.2 * $order; }
2045 elsif ($n < 4000) { $approx += 4.3 * $order; }
2046 elsif ($n < 12000) { $approx += 3.0 * $order; }
2047 elsif ($n < 150000) { $approx += 2.1 * $order; }
2048 elsif ($n < 200000000) { $approx += 0.0 * $order; }
2049 else { $approx += -0.010 * $order; }
2050 # $approx = -0.025 is better for the last, but it gives problems with some
2051 # other code that always wants the asymptotic approximation to be >= actual.
2052
2053 return int($approx + 0.5);
2054 }
2055
2056 # The nth prime will be greater than or equal to this number
2057 sub nth_prime_lower {
2058 my($n) = @_;
2059 _validate_num($n) || _validate_positive_integer($n);
2060
2061 return $_primes_small[$n] if $n <= $#_primes_small;
2062
2063 $n = _upgrade_to_float($n) if $n > MPU_MAXPRIMEIDX || $n > 2**45;
2064
2065 my $flogn = log($n);
2066 my $flog2n = log($flogn); # Note distinction between log_2(n) and log^2(n)
2067
2068 # Dusart 1999 page 14, for all n >= 2
2069 #my $lower = $n * ($flogn + $flog2n - 1.0 + (($flog2n-2.25)/$flogn));
2070 # Dusart 2010 page 2, for all n >= 3
2071 my $lower = $n * ($flogn + $flog2n - 1.0 + (($flog2n-2.10)/$flogn));
2072
2073 return int($lower);
2074 }
2075
2076 # The nth prime will be less or equal to this number
2077 sub nth_prime_upper {
2078 my($n) = @_;
2079 _validate_num($n) || _validate_positive_integer($n);
2080
2081 return $_primes_small[$n] if $n <= $#_primes_small;
2082
2083 $n = _upgrade_to_float($n) if $n > MPU_MAXPRIMEIDX || $n > 2**45;
2084
2085 my $flogn = log($n);
2086 my $flog2n = log($flogn); # Note distinction between log_2(n) and log^2(n)
2087
2088 my $upper;
2089 if ($n >= 688383) { # Dusart 2010 page 2
2090 $upper = $n * ( $flogn + $flog2n - 1.0 + (($flog2n-2.00)/$flogn) );
2091 } elsif ($n >= 178974) { # Dusart 2010 page 7
2092 $upper = $n * ( $flogn + $flog2n - 1.0 + (($flog2n-1.95)/$flogn) );
2093 } elsif ($n >= 39017) { # Dusart 1999 page 14
2094 $upper = $n * ( $flogn + $flog2n - 0.9484 );
2095 } elsif ($n >= 6) { # Modified Robin 1983, for 6-39016 only
2096 $upper = $n * ( $flogn + 0.6000 * $flog2n );
2097 } else {
2098 $upper = $n * ( $flogn + $flog2n );
2099 }
2100
2101 return int($upper + 1.0);
2102 }
2103
2104
2105 #############################################################################
2106
2107
2108724 #############################################################################
2109725
2110726 sub RiemannZeta {
2113729
2114730 return _XS_RiemannZeta($n)
2115731 if !defined $bignum::VERSION && ref($n) ne 'Math::BigFloat' && $n <= $_XS_MAXVAL;
732 require Math::Prime::Util::PP;
2116733 return Math::Prime::Util::PP::RiemannZeta($n);
2117734 }
2118735
2122739
2123740 return _XS_RiemannR($n)
2124741 if !defined $bignum::VERSION && ref($n) ne 'Math::BigFloat' && $n <= $_XS_MAXVAL;
742 require Math::Prime::Util::PP;
2125743 return Math::Prime::Util::PP::RiemannR($n);
2126744 }
2127745
2134752 return _XS_ExponentialIntegral($n)
2135753 if !defined $bignum::VERSION && ref($n) ne 'Math::BigFloat' && $_Config{'xs'};
2136754
755 require Math::Prime::Util::PP;
2137756 return Math::Prime::Util::PP::ExponentialIntegral($n);
2138757 }
2139758
2150769 return _XS_LogarithmicIntegral($n);
2151770 }
2152771
772 require Math::Prime::Util::PP;
2153773 return Math::Prime::Util::PP::LogarithmicIntegral($n);
2154774 }
2155775
2178798
2179799 =head1 VERSION
2180800
2181 Version 0.36
801 Version 0.37
2182802
2183803
2184804 =head1 SYNOPSIS
24171037
24181038 print "$n is prime" if is_prime($n);
24191039
2420 Returns 2 if the number is prime, 0 if not. For numbers larger than C<2^64>
2421 it will return 0 for composite and 1 for probably prime, using an
2422 extra-strong BPSW test. If L<Math::Prime::Util::GMP> is installed, some
2423 additional primality tests are also performed on large inputs, and a
2424 quick attempt is made to perform a primality proof, so it will
2425 return 2 for many other inputs.
1040 Returns 0 is the number is composite, 1 if it is probably prime, and 2 if
1041 it is definitely prime. For numbers smaller than C<2^64> it will only
1042 return 0 (composite) or 2 (definitely prime), as this range has been
1043 exhaustively tested and has no counterexamples. For larger numbers,
1044 an extra-strong BPSW test is used.
1045 If L<Math::Prime::Util::GMP> is installed, some additional primality tests
1046 are also performed, and a quick attempt is made to perform a primality
1047 proof, so it will return 2 for many other inputs.
24261048
24271049 Also see the L</is_prob_prime> function, which will never do additional
24281050 tests, and the L</is_provable_prime> function which will construct a proof
24381060
24391061 For cryptographic key generation, you may want even more testing for probable
24401062 primes (NIST recommends some additional M-R tests). This can be done using
2441 additional random bases with L</is_strong_pseudoprime>, or a different test
2442 such as L</is_frobenius_underwood_pseudoprime>. Even better, make sure
2443 L<Math::Prime::Util::GMP> is installed and use L</is_provable_prime> which
2444 should be reasonably fast for sizes under 2048 bits.
2445 Another possibility is to use L<Math::Prime::Util/random_maurer_prime> which
2446 constructs a random provable prime.
1063 a different test (e.g. L</is_frobenius_underwood_pseudoprime>) or using
1064 additional M-R tests with random bases with L</miller_rabin_random>.
1065 Even better, make sure L<Math::Prime::Util::GMP> is installed and use
1066 L</is_provable_prime> which should be reasonably fast for sizes under
1067 2048 bits. Another possibility is to use
1068 L<Math::Prime::Util/random_maurer_prime> which constructs a random
1069 provable prime.
24471070
24481071
24491072 =head2 primes
24971120 block for each prime in the range. Compared to getting a big array of primes
24981121 and iterating through it, this is more memory efficient and perhaps more
24991122 convenient. This will almost always be the fastest way to loop over a range
2500 of primes. Nesting and using in threads are allowed.
1123 of primes. Nesting and use in threads are allowed.
25011124
25021125 Math::BigInt objects may be used for the range.
25031126
25041127 For some uses an iterator (L</prime_iterator>, L</prime_iterator_object>)
25051128 or a tied array (L<Math::Prime::Util::PrimeArray>) may be more convenient.
2506 Objects can be passed to functions, and allow early loop exits without
2507 exceptions. Here is a clumsy L</forprimes> exception example:
2508
2509 use bigint;
2510 eval { forprimes { die "$_\n" if $_ % 123 == 1 } 2**100, 2**101 };
2511 my $n = 0+$@;
1129 Objects can be passed to functions, and allow early loop exits.
25121130
25131131
25141132 =head2 forcomposites
25171135 forcomposites { say } 2000,2020;
25181136
25191137 Given a block and either an end number or a start and end pair, calls the
2520 block for each composite in the inclusive range. Starting at 2, the
2521 composites are the non-primes (C<0> and C<1> are neither prime nor composite).
1138 block for each composite in the inclusive range. The composites are the
1139 numbers greater than 1 which are not prime:
1140 C<4, 6, 8, 9, 10, 12, 14, 15, ...>
25221141
25231142
25241143 =head2 fordivisors
31321751 Agrawal-Kayal-Saxena (AKS) primality test. This is a deterministic
31331752 unconditional primality test which runs in polynomial time for general input.
31341753
3135 This function is only included for completeness and as an example. The Perl
3136 implementation is fast compared to the only other Perl implementation
3137 available (in L<Math::Primality>), and the implementation in
3138 L<Math::Prime::Util::GMP> compares favorably to others in the literature.
3139 However AKS in general is far too slow to be of practical use. R.P. Brent,
3140 2010: "AKS is not a practical algorithm. ECPP is much faster."
1754 While this is an important theoretical algorithm, and makes an interesting
1755 example, it is hard to overstate just how impractically slow it is in
1756 practice. It is not used for any purpose in non-theoretical work, as it is
1757 literally B<millions> of times slower than other algorithms. From R.P.
1758 Brent, 2010: "AKS is not a practical algorithm. ECPP is much faster."
1759 We have ECPP, and indeed it is much faster.
31411760
31421761
31431762 =head2 lucas_sequence
31471766 Computes C<U_k>, C<V_k>, and C<Q_k> for the Lucas sequence defined by
31481767 C<P>,C<Q>, modulo C<n>. The modular Lucas sequence is used in a
31491768 number of primality tests and proofs.
3150
31511769 The following conditions must hold:
3152 - C<< D = P*P - 4*Q != 0 >>
3153 - C<< P > 0 >>
3154 - C<< P < n >>
3155 - C<< Q < n >>
3156 - C<< k >= 0 >>
3157 - C<< n >= 2 >>
1770 C< D = P*P - 4*Q != 0> ;
1771 C< 0 E<lt> P E<lt> n> ;
1772 C< Q E<lt> n> ;
1773 C< k E<gt>= 0> ;
1774 C< n E<gt>= 2>.
31581775
31591776
31601777 =head2 gcd
31751792 say "$n is square free" if moebius($n) != 0;
31761793 $sum += moebius($_) for (1..200); say "Mertens(200) = $sum";
31771794
3178 Returns μ(n), the Möbius function (also called the Moebius, Mobius, or
1795 Returns μ(n), the Möbius function (also known as the Moebius, Mobius, or
31791796 MoebiusMu function) for an integer input. This function is 1 if
31801797 C<n = 1>, 0 if C<n> is not square free (i.e. C<n> has a repeated factor),
31811798 and C<-1^t> if C<n> is a product of C<t> distinct primes. This is an
31851802 If called with two arguments, they define a range C<low> to C<high>, and the
31861803 function returns an array with the value of the Möbius function for every n
31871804 from low to high inclusive. Large values of high will result in a lot of
3188 memory use. The algorithm used is Deléglise and Rivat (1996) algorithm 4.1,
3189 which is a segmented version of Lioen and van de Lune (1994) algorithm 3.2.
1805 memory use. The algorithm used for ranges is Deléglise and Rivat (1996)
1806 algorithm 4.1, which is a segmented version of Lioen and van de Lune (1994)
1807 algorithm 3.2.
31901808
31911809 The return values are read-only constants. This should almost never come up,
3192 but it does mean trying to modify aliased return values will cause an
1810 but it means trying to modify aliased return values will cause an
31931811 exception (modifying the returned scalar or array is fine).
31941812
31951813
32301848 say "The Euler totient of $n is ", euler_phi($n);
32311849
32321850 Returns φ(n), the Euler totient function (also called Euler's phi or phi
3233 function) for an integer value. This is an arithmetic function that counts
1851 function) for an integer value. This is an arithmetic function which counts
32341852 the number of positive integers less than or equal to C<n> that are relatively
32351853 prime to C<n>. Given the definition used, C<euler_phi> will return 0 for all
3236 C<n E<lt> 1>. This follows the logic used by SAGE. Mathematica
3237 also returns 0 for input 0, but returns C<euler_phi(-n)> for C<n E<lt> 0>.
1854 C<n E<lt> 1>. This follows the logic used by SAGE. Mathematica and Pari
1855 return C<euler_phi(-n)> for C<n E<lt> 0>. Mathematica returns 0 for C<n = 0>
1856 while Pari raises an exception.
32381857
32391858 If called with two arguments, they define a range C<low> to C<high>, and the
32401859 function returns an array with the totient of every n from low to high
32961915 say chebyshev_psi(10000);
32971916
32981917 Returns ψ(n), the second Chebyshev function for a non-negative integer input.
3299 This is the sum of the logarithm of each prime where C<p^k E<lt>= n> for an
3300 integer k. An alternate computation is as the summatory Mangoldt function.
3301 Another alternate computation is as the logarithm of LCM(1,2,...,n).
3302 Hence these functions:
1918 This is the sum of the logarithm of each prime power where C<p^k E<lt>= n>
1919 for an integer k. An alternate computation is as the summatory Mangoldt
1920 function. Another alternate computation is as the logarithm of
1921 LCM(1,2,...,n). Hence these functions:
33031922
33041923 use List::Util qw/sum/; use Math::BigFloat;
33051924
33121931 =head2 divisor_sum
33131932
33141933 say "Sum of divisors of $n:", divisor_sum( $n );
3315
3316 This function takes a positive integer as input and returns the sum of the
3317 k-th powers of the divisors of the input, including 1 and itself. If the
3318 second argument (C<k>) is omitted it is assumed to be 1. This is known as
3319 the sigma function (see Hardy and Wright section 16.7, or OEIS A000203).
3320 The API is identical to Pari/GP's C<sigma> function.
3321
3322 The second argument can be a code reference, which is called for each divisor
3323 and the results are summed. This allows computation of other functions,
3324 but will be less efficient than using the numeric second argument.
3325
3326 An example of the 5th Jordan totient (OEIS A059378):
3327
3328 divisor_sum( $n, sub { my $d=shift; $d**5 * moebius($n/$d); } );
3329
3330 though we have a function L</jordan_totient> which is more efficient.
3331
1934 say "sigma_2($n) = ", divisor_sum($n, 2);
1935 say "Number of divisors: sigma_0($n) = ", divisor_sum($n, 0);
1936
1937 This function takes a positive integer as input and returns the sum of
1938 its divisors, including 1 and itself. An optional second argument C<k>
1939 may be given, which will result in the sum of the C<k-th> powers of the
1940 divisors to be returned.
1941
1942 This is known as the sigma function (see Hardy and Wright section 16.7,
1943 or OEIS A000203). The API is identical to Pari/GP's C<sigma> function.
33321944 This function is useful for calculating things like aliquot sums, abundant
33331945 numbers, perfect numbers, etc.
1946
1947 The second argument may also be a code reference, which is called for each
1948 divisor and the results are summed. This allows computation of other
1949 functions, but will be less efficient than using the numeric second argument.
1950 This corresponds to Pari/GP's C<sumdiv> function.
1951
1952 An example of the 5th Jordan totient (OEIS A059378):
1953
1954 divisor_sum( $n, sub { my $d=shift; $d**5 * moebius($n/$d); } );
1955
1956 though we have a function L</jordan_totient> which is more efficient.
33341957
33351958 For numeric second arguments (sigma computations), the result will be a bigint
33361959 if necessary. For the code reference case, the user must take care to return
34142037
34152038 Returns the Carmichael function (also called the reduced totient function,
34162039 or Carmichael λ(n)) of a positive integer argument. It is the smallest
3417 positive integer m such that a^m = 1 mod n for every integer a coprime to n.
3418 This is L<OEIS series A002322|http://oeis.org/A002322>.
2040 positive integer C<m> such that C<a^m = 1 mod n> for every integer C<a>
2041 coprime to C<n>. This is L<OEIS series A002322|http://oeis.org/A002322>.
34192042
34202043 =head2 kronecker
34212044
34262049 1 a is a quadratic residue modulo n (a = x^2 mod n for some x)
34272050 -1 a is a quadratic non-residue modulo n
34282051
3429 and the return value is congruent to C<a^((n-1)/2)>. The Kronecker
3430 symbol is an extension of the Jacobi symbol to all integer values of
3431 C<n> from its domain of positive odd values of C<n>. The Jacobi
3432 symbol is itself an extension of the Legendre symbol, which is
2052 The Kronecker symbol is an extension of the Jacobi symbol to all integer
2053 values of C<n> from the latter's domain of positive odd values of C<n>.
2054 The Jacobi symbol is itself an extension of the Legendre symbol, which is
34332055 only defined for odd prime values of C<n>. This corresponds to Pari's
34342056 C<kronecker(a,n)> function and Mathematica's C<KroneckerSymbol[n,m]>
34352057 function.
34392061 $order = znorder(2, next_prime(10**19)-6);
34402062
34412063 Given two positive integers C<a> and C<n>, returns the multiplicative order
3442 of C<a> modulo <n>. This is the smallest positive integer C<k> such that
2064 of C<a> modulo C<n>. This is the smallest positive integer C<k> such that
34432065 C<a^k ≡ 1 mod n>. Returns 1 if C<a = 1>. Returns undef if C<a = 0> or if
34442066 C<a> and C<n> are not coprime, since no value will result in 1 mod n.
34452067 This corresponds to Pari's C<znorder(Mod(a,n))> function and Mathematica's
34592081
34602082 =head2 znlog
34612083
3462 $k = znlog($b, $g, $p)
3463
3464 Returns the integer C<k> that solves the equation C<b^k = g mod p>, or
2084 $k = znlog($a, $g, $p)
2085
2086 Returns the integer C<k> that solves the equation C<a = g^k mod p>, or
34652087 undef if no solution is found. This is the discrete logarithm problem.
34662088 The implementation in this version is not very useful, but may be improved.
34672089
34932115 will be seen. This is removes from consideration such algorithms as
34942116 C<PRIMEINC>, which although efficient, gives very non-random output. This
34952117 also implies that the numbers will not be evenly distributed, since the
3496 primes are not evenly distributed. Stated again, the random prime functions
3497 return a uniformly selected prime from the set of primes within the range.
3498 Hence given C<random_prime(1000)>, the numbers 2, 3, 487, 631, and 997 all
3499 have the same probability of being returned.
2118 primes are not evenly distributed. Stated differently, the random prime
2119 functions return a uniformly selected prime from the set of primes within
2120 the range. Hence given C<random_prime(1000)>, the numbers 2, 3, 487, 631,
2121 and 997 all have the same probability of being returned.
35002122
35012123 For small numbers, a random index selection is done, which gives ideal
35022124 uniformity and is very efficient with small inputs. For ranges larger than
35212143
35222144 Examples of various ways to set your own irand function:
35232145
2146 # System rand. You probably don't want to do this.
2147 prime_set_config(irand => sub { int(rand(4294967296)) });
2148
35242149 # Math::Random::Secure. Uses ISAAC and strong seed methods.
35252150 use Math::Random::Secure;
35262151 prime_set_config(irand => \&Math::Random::Secure::irand);
35412166 use Math::Random::MT::Auto;
35422167 prime_set_config(irand=>sub {Math::Random::MT::Auto::irand() & 0xFFFFFFFF});
35432168
2169 # Go back to MPU's default configuration
2170 prime_set_config(irand => undef);
2171
35442172
35452173 =head2 random_ndigit_prime
35462174
35472175 say "My 4-digit prime number is: ", random_ndigit_prime(4);
35482176
35492177 Selects a random n-digit prime, where the input is an integer number of
3550 digits between 1 and the maximum native type (10 for 32-bit, 20 for 64-bit,
3551 10000 if bigint is active). One of the primes within that range
3552 (e.g. 1000 - 9999 for 4-digits) will be uniformly selected using the
3553 C<irand> function as described above.
2178 digits. One of the primes within that range (e.g. 1000 - 9999 for
2179 4-digits) will be uniformly selected using the C<irand> function as
2180 described above.
35542181
35552182 If the number of digits is greater than or equal to the maximum native type,
35562183 then the result will be returned as a BigInt. However, if the C<nobigint>
35642191
35652192 my $bigprime = random_nbit_prime(512);
35662193
3567 Selects a random n-bit prime, where the input is an integer number of bits
3568 between 2 and the maximum representable bits (32, 64, or 100000 for native
3569 32-bit, native 64-bit, and bigint respectively). A prime with the nth bit
3570 set will be uniformly selected, with randomness supplied via calls to the
3571 C<irand> function as described above.
2194 Selects a random n-bit prime, where the input is an integer number of bits.
2195 A prime with the nth bit set will be uniformly selected, with randomness
2196 supplied via calls to the C<irand> function as described above.
35722197
35732198 For bit sizes of 64 and lower, L</random_prime> is used, which gives completely
35742199 uniform results in this range. For sizes larger than 64, Algorithm 1 of
44113036
44123037 =item C<isprime>
44133038
4414 Similar to MPU's L</is_prob_prime> or L</is_prime> functions.
4415 MPU is deterministic for native integers, and uses a strong
4416 BPSW test for bigints (with a quick primality proof tried as well). The
4417 default version of Pari used by L<Math::Pari> (2.1.7) uses 10 random M-R
4418 bases, which is a probable prime test usually considered much weaker than the
4419 BPSW test used by MPU and newer versions of Pari (though better than a fixed
4420 set of bases). Calling as C<isprime($n,1)> performs a Pocklington-Lehmer
4421 C<n-1> proof. This is comparable in performance to MPU:GMP's C<n-1> proof
4422 implementation, and is reasonably fast for about 70 digits, but much slower
4423 than ECPP.
4424
4425 If L<Math::Pari> is compiled with version 2.3.5 of Pari (this is not easy to
4426 do on many platforms), then the algorithms are completely different. The
4427 C<isprime> function now acts like L</is_provable_prime> -- an APRCL proof
4428 is performed, which is quite efficient though requires using a larger stack
4429 for numbers of 300+ digits. It is somewhat comparable in speed to MPU:GMP's
4430 ECPP proof method, but without a certificate. Using the C<ispseudoprime>
4431 function will perform a BPSW test similar to L</is_prob_prime>.
3039 The default L<Math::Pari> is built with Pari 2.1.7. This uses 10 M-R
3040 tests with randomly chosen bases (fixed seed, but doesn't reset each
3041 invocation like GMP's C<is_probab_prime>). This has a greater chance
3042 of false positives compared to the BPSW test. Calling with
3043 C<isprime($n,1)> will perform a Pocklington-Lehmer C<n-1> proof,
3044 but this becomes unreasonably slow past 70 or so digits.
3045
3046 If L<Math::Pari> is built using Pari 2.3.5 (this requires manual
3047 configuration) then the primality tests are completely different. Using
3048 C<ispseudoprime> will perform a BPSW test and is quite a bit faster than
3049 the older test. C<isprime> now does an APR-CL proof (fast, but no
3050 certificate).
3051
3052 L<Math::Primality> uses a strong BPSW test, which is the standard BPSW
3053 test based on the 1980 paper. It has no known counterexamples (though
3054 like all these tests, we know some exist). Pari 2.3.5 (and through at
3055 least 2.6.2) uses an almost-extra-strong BPSW test for its
3056 C<ispseudoprime> function. This is deterministic for native integers,
3057 and should be excellent for bigints, with a slightly lower chance of
3058 counterexamples than the traditional strong test.
3059 L<Math::Prime::Util> uses the
3060 full extra-strong BPSW test, which has an even lower chance of
3061 counterexample.
3062 With L<Math::Prime::Util::GMP>, C<is_prime> adds 1 to 5 extra M-R tests
3063 using random bases, which further reduces the probability of a composite
3064 being allowed to pass.
44323065
44333066 =item C<primepi>
44343067
44673100
44683101 =item C<forprime>, C<forcomposite>, C<fordiv>, C<sumdiv>
44693102
4470 Similar to MPU's L</forprimes>, L</forcomposites>, L<fordivisors>, and
4471 L<divisor_sum>.
3103 Similar to MPU's L</forprimes>, L</forcomposites>, L</fordivisors>, and
3104 L</divisor_sum>.
44723105
44733106 =item C<eulerphi>, C<moebius>
44743107
45043137
45053138 =item C<zeta>
45063139
4507 A more feature-rich version MPU's L</RiemannZeta> function (supports negative
4508 and complex inputs).
3140 MPU has L</RiemannZeta> which takes non-negative real inputs, while Pari's
3141 function supports negative and complex inputs.
45093142
45103143 =back
45113144
45583191
45593192 =item Primes
45603193
4561 L<primesieve|http://code.google.com/p/primesieve/> is the fastest publically
4562 available code I am aware of. It is much faster than any of the alternatives,
4563 and even more so when run multi-threaded. Tomás Oliveira e Silva's private
4564 code may be faster for very large values, but isn't available for testing.
3194 L<primesieve|http://code.google.com/p/primesieve/> and
3195 L<yafu|http://sourceforge.net/projects/yafu/>
3196 are the fastest publically available code I am aware of. Primesieve
3197 will additionally take advantage of multiple cores with excellent
3198 efficiency.
3199 Tomás Oliveira e Silva's private code may be faster for very large
3200 values, but isn't available for testing.
45653201
45663202 Note that the Sieve of Atkin is I<not> faster than the Sieve of Eratosthenes
45673203 when both are well implemented. The only Sieve of Atkin that is even
4568 competitive is Bernstein's super optimized I<primegen>, which runs slightly
4569 slower than the SoE in this module. The SoE's in Pari, yafu, and primesieve
3204 competitive is Bernstein's super optimized I<primegen>, which runs on par
3205 with the SoE in this module. The SoE's in Pari, yafu, and primesieve
45703206 are all faster.
45713207
45723208 =item Prime Counts and Nth Prime
46113247
46123248 =head2 PRIMALITY TESTING
46133249
4614 C<is_prime>: my impressions for various sized inputs:
4615
4616 Module 1-10 digits 10-20 digits BigInts
4617 ----------------------- ----------- ------------ --------------
4618 Math::Prime::Util Very fast Very fast Slow / Very Fast (1)
4619 Math::Prime::XS Very fast Very slow (2) --
4620 Math::Prime::FastSieve Very fast N/A (3) --
4621 Math::Primality Very slow Very slow Fast
4622 Math::Pari Slow OK OK / Fast (4)
4623
4624 (1) Without / With L<Math::Prime::Util::GMP> installed.
4625 (2) Trial division only. Very fast if every factor is tiny.
4626 (3) Too much memory to hold the sieve (11dig = 6GB, 12dig = ~50GB)
4627 (4) By default L<Math::Pari> installs Pari 2.1.7, which uses 10 M-R tests
4628 for isprime and is not fast. See notes below for 2.3.5.
4629
4630
4631 The differences are in the implementations:
4632
46333250 =over 4
46343251
4635 =item L<Math::Prime::Util>
4636
4637 first does simple divisibility tests to quickly recognize composites, then
4638 looks in the sieve for a fast bit lookup if possible (default up to 30,000
4639 but can be expanded via C<prime_precalc>). Next, for relatively small inputs,
4640 a deterministic set of Miller-Rabin tests are used, while for larger inputs
4641 a strong BPSW test is performed. For native integers, this is faster than
4642 any of the other modules. With Bigints, you need the L<Math::Prime::Util::GMP>
4643 module installed to get good performance. With that installed, it is about
4644 2x faster than Math::Primality and 10x faster than Math::Pari (default 2.1.7).
4645
4646 =item L<Math::Prime::XS>
4647
4648 does trial divisions, which is wonderful if the input has a small factor
4649 (or is small itself). If given a large prime it can be tens of thousands of
4650 times slower than MPU. It does not support bigints.
4651
4652 =item L<Math::Prime::FastSieve>
4653
4654 only works in a sieved range, which is really fast if you can do it
4655 (M::P::U will do the same if you call C<prime_precalc>). Larger inputs
4656 just need too much time and memory for the sieve.
4657
4658 =item L<Math::Primality>
4659
4660 uses GMP (in Perl) for all work. Under ~32-bits it uses 2 or 3 MR tests,
4661 while above 4759123141 it performs a BPSW test. This is great for
4662 bigints over 2^64, but it is significantly slower than native precision
4663 tests. With 64-bit numbers it is generally an order of magnitude or more
4664 slower than any of the others. Once bigints are being used, its relative
4665 performance is quite good. It is faster than this module unless
4666 L<Math::Prime::Util::GMP> has been installed, in which case Math::Prime::Util
4667 is faster.
4668
4669 =item L<Math::Pari>
4670
4671 has some very effective code, but it has some overhead to get to it from
4672 Perl. That means for small numbers it is relatively slow: an order of
4673 magnitude slower than M::P::XS and M::P::Util (arguably this is
4674 only important for benchmarking since "slow" is ~2 microseconds). With
4675 the default Pari version, C<isprime> will do M-R tests for 10 randomly
4676 chosen bases, but can perform a Pocklington-Lehmer proof if requested using
4677 C<isprime(x,1)>. Both could fail to identify a composite. If pari 2.3.5
4678 is used instead (this requires hand-building the Math::Pari module) then
4679 the options are quite different. C<ispseudoprime(x,0)> performs a strong
4680 BPSW test, while C<isprime> now performs a primality proof using a fast
4681 implementation of the APRCL method. While the APRCL method is very fast
4682 it is still much, much slower than a BPSW probable prime test for large inputs.
3252 =item Small inputs: is_prime from 1 to 20M
3253
3254 2.6s Math::Prime::Util (sieve lookup if prime_precalc used)
3255 3.4s Math::Prime::FastSieve (sieve lookup)
3256 4.4s Math::Prime::Util (trial + deterministic M-R)
3257 10.9s Math::Prime::XS (trial)
3258 36.5s Math::Pari w/2.3.5 (BPSW)
3259 78.2s Math::Pari (10 random M-R)
3260 501.3s Math::Primality (deterministic M-R)
3261
3262 =item Large native inputs: is_prime from 10^16 to 10^16 + 20M
3263
3264 7.0s Math::Prime::Util (BPSW)
3265 42.6s Math::Pari w/2.3.5 (BPSW)
3266 144.3s Math::Pari (10 random M-R)
3267 664.0s Math::Primality (BPSW)
3268 30 HRS Math::Prime::XS (trial)
3269
3270 These inputs are too large for Math::Prime::FastSieve.
3271
3272 =item bigints: is_prime from 10^100 to 10^100 + 0.2M
3273
3274 2.5s Math::Prime::Util (BPSW + 1 random M-R)
3275 3.0s Math::Pari w/2.3.5 (BPSW)
3276 12.9s Math::Primality (BPSW)
3277 35.3s Math::Pari (10 random M-R)
3278 53.5s Math::Prime::Util w/o GMP (BPSW)
3279 94.4s Math::Prime::Util (n-1 or ECPP proof)
3280 102.7s Math::Pari w/2.3.5 (APR-CL proof)
3281
3282 =back
3283
3284 =over 4
3285
3286 =item *
3287
3288 MPU is consistently the fastest solution, and performs the most
3289 stringent probable prime tests on bigints.
3290
3291 =item *
3292
3293 Math::Primality has a lot of overhead that makes it quite slow for
3294 native size integers. With bigints we finally see it work well.
3295
3296 =item *
3297
3298 Math::Pari build with 2.3.5 not only has a better primality test, but
3299 runs faster. It still has quite a bit of overhead with native size
3300 integers. Pari/gp 2.5.0's takes 11.3s, 16.9s, and 2.9s respectively
3301 for the tests above. MPU is still faster, but clearly the time for
3302 native integers is dominated by the calling overhead.
46833303
46843304 =back
46853305
292292 UV i, c = (a > PHIC) ? PHIC : a;
293293 UV sum = tablephi(x, c);
294294 if (a > c) {
295 UV p = _XS_nth_prime(c);
296 UV pa = _XS_nth_prime(a);
295 UV p = nth_prime(c);
296 UV pa = nth_prime(a);
297297 for (i = c+1; i <= a; i++) {
298298 UV xp;
299299 p = next_prime(p);
343343 uint32_t lastidx;
344344 UV res, max_cache_a = (a >= PHICACHEA) ? PHICACHEA : a+1;
345345 Newz(0, cache, PHICACHEX * max_cache_a, uint16_t);
346 primes = make_primelist(_XS_nth_prime(a+1), &lastidx);
346 primes = make_primelist(nth_prime(a+1), &lastidx);
347347 res = (UV) _phi(x, a, 1, primes, lastidx, cache);
348348 Safefree(primes);
349349 Safefree(cache);
3131 /* Add this to a number and you'll ensure you're on a wheel location */
3232 static const unsigned char distancewheel30[30] =
3333 {1,0,5,4,3,2,1,0,3,2,1,0,1,0,3,2,1,0,1,0,3,2,1,0,5,4,3,2,1,0};
34 /* Once on the wheel, add this to get to next spot. In p space, not m. */
34 /* add this to n to get to the next wheel location */
3535 static const unsigned char wheeladvance30[30] =
36 {0,6,0,0,0,0,0,4,0,0,0,2,0,4,0,0,0,2,0,4,0,0,0,6,0,0,0,0,0,2};
36 {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};
37 /* subtract this from n to get to the previous wheel location */
38 static const unsigned char wheelretreat[30] =
39 {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};
40
3741
3842 #ifdef FUNC_is_prime_in_sieve
3943 static int is_prime_in_sieve(const unsigned char* sieve, UV p) {
66
77 my $use64 = Math::Prime::Util::prime_get_config->{'maxbits'} > 32;
88 $use64 = 0 if 18446744073709550592 == ~0;
9 my $usexs = Math::Prime::Util::prime_get_config->{'xs'};
910
10 plan tests => 12+3 + 12 + 1 + 19 + ($use64 ? 1 : 0) + 1 + 13*5;
11 my %primesubs = (
12 trial => \&Math::Prime::Util::trial_primes,
13 erat => \&Math::Prime::Util::erat_primes,
14 segment => \&Math::Prime::Util::segment_primes,
15 sieve => \&Math::Prime::Util::sieve_primes,
16 primes => \&Math::Prime::Util::primes,
17 );
18 # Don't test the private XS methods if we're not using XS.
19 delete @primesubs{qw/trial erat segment sieve/} unless $usexs;
20
21 plan tests => 12+3 + 12 + 1 + 19 + ($use64 ? 1 : 0) + 1 + 13*scalar(keys(%primesubs));
1122
1223 ok(!eval { primes(undef); }, "primes(undef)");
1324 ok(!eval { primes("a"); }, "primes(a)");
111122
112123 is( scalar @{primes(474973,838390)}, prime_count(838390) - prime_count(474973), "count primes within a range" );
113124
114
115 foreach my $method (qw/trial erat segment sieve dynamic/) {
116 is_deeply( primes({method=>$method}, 0, 3572), \@small_primes, "Primes between 0 and 3572" );
117 is_deeply( primes({method=>$method}, 2, 20), [2,3,5,7,11,13,17,19], "Primes between 2 and 20" );
118 is_deeply( primes({method=>$method}, 30, 70), [31,37,41,43,47,53,59,61,67], "Primes between 30 and 70" );
119 is_deeply( primes({method=>$method}, 30, 70), [31,37,41,43,47,53,59,61,67], "Primes between 30 and 70" );
120 is_deeply( primes({method=>$method}, 20, 2), [], "Primes between 20 and 2" );
121 is_deeply( primes({method=>$method}, 1, 1), [], "Primes ($method) between 1 and 1" );
122 is_deeply( primes({method=>$method}, 2, 2), [2], "Primes ($method) between 2 and 2" );
123 is_deeply( primes({method=>$method}, 3, 3), [3], "Primes ($method) between 3 and 3" );
124 is_deeply( primes({method=>$method}, 2010733, 2010733+148), [2010733,2010733+148], "Primegap 21 inclusive" );
125 is_deeply( primes({method=>$method}, 2010733+1, 2010733+148-2), [], "Primegap 21 exclusive" );
126 is_deeply( primes({method=>$method}, 3088, 3164), [3089,3109,3119,3121,3137,3163], "Primes between 3088 and 3164" );
127 is_deeply( primes({method=>$method}, 3089, 3163), [3089,3109,3119,3121,3137,3163], "Primes between 3089 and 3163" );
128 is_deeply( primes({method=>$method}, 3090, 3162), [3109,3119,3121,3137], "Primes between 3090 and 3162" );
125 # Test individual methods
126 while (my($method, $sub) = each (%primesubs)) {
127 is_deeply( $sub->(0, 3572), \@small_primes, "$method(0, 3572)" );
128 is_deeply( $sub->(2, 20), [2,3,5,7,11,13,17,19], "$method(2, 20)" );
129 is_deeply( $sub->(30, 70), [31,37,41,43,47,53,59,61,67], "$method(30, 70)" );
130 is_deeply( $sub->(30, 70), [31,37,41,43,47,53,59,61,67], "$method(30, 70)" );
131 is_deeply( $sub->(20, 2), [], "$method(20, 2)" );
132 is_deeply( $sub->(1, 1), [], "$method(1, 1)" );
133 is_deeply( $sub->(2, 2), [2], "$method(2, 2)" );
134 is_deeply( $sub->(3, 3), [3], "$method(3, 3)" );
135 is_deeply( $sub->(2010733, 2010733+148), [2010733,2010733+148], "$method Primegap 21 inclusive" );
136 is_deeply( $sub->(2010733+1, 2010733+148-2), [], "$method Primegap 21 exclusive" );
137 is_deeply( $sub->(3088, 3164), [3089,3109,3119,3121,3137,3163], "$method(3088, 3164)" );
138 is_deeply( $sub->(3089, 3163), [3089,3109,3119,3121,3137,3163], "$method(3089, 3163)" );
139 is_deeply( $sub->(3090, 3162), [3109,3119,3121,3137], "$method(3090, 3162)" );
129140 }
8686 + $use64 * 3 * scalar(keys %pivals64)
8787 + scalar(keys %intervals)
8888 + 1
89 + 4 + 2*$extra; # prime count specific methods
89 + 5 + 2*$extra; # prime count specific methods
9090
9191 ok( eval { prime_count(13); 1; }, "prime_count in void context");
9292
164164 is(Math::Prime::Util::_XS_LMO_pi (66123456), 3903023,"XS LMO count");
165165 is(Math::Prime::Util::_XS_segment_pi (66123456), 3903023,"XS segment count");
166166 }
167
168 require_ok 'Math::Prime::Util::PP';
167169 is(Math::Prime::Util::PP::_lehmer_pi (1456789), 111119, "PP Lehmer count");
168170 is(Math::Prime::Util::PP::_sieve_prime_count(145678), 13478, "PP sieve count");
169171 if ($extra) {
1919 # Do some tests only if:
2020 # EXTENDED_TESTING is on OR we have the GMP backend
2121 # Note that with Calc, these things are incredibly slow.
22 use Math::BigInt try=>"GMP,Pari";
2223 my $doexpensive = 0 + ($extra || ( (!$use64 || !$broken64) && Math::BigInt->config()->{lib} eq 'Math::BigInt::GMP' ));
2324
2425 my @plist = qw/20907001 809120722675364249/;
99 # The second method in theory is all that is needed.
1010
1111 use Math::Prime::Util qw/:all/;
12 use Math::Prime::Util::PP;
1213 use bignum;
1314
1415 use Test::More tests => 2;
297297
298298 *factor = \&Math::Prime::Util::PP::factor;
299299
300 *moebius = \&Math::Prime::Util::_generic_moebius;
301 *euler_phi = \&Math::Prime::Util::_generic_euler_phi;
302 *mertens = \&Math::Prime::Util::_generic_mertens;
303 *exp_mangoldt = \&Math::Prime::Util::_generic_exp_mangoldt;
300 *moebius = \&Math::Prime::Util::PP::moebius;
301 *euler_phi = \&Math::Prime::Util::PP::euler_phi;
302 *mertens = \&Math::Prime::Util::PP::mertens;
303 *exp_mangoldt = \&Math::Prime::Util::PP::exp_mangoldt;
304304
305305 *RiemannR = \&Math::Prime::Util::PP::RiemannR;
306306 *RiemannZeta = \&Math::Prime::Util::PP::RiemannZeta;
7575 + 6*2*$extra # more PC tests
7676 + 2*scalar(keys %factors)
7777 + scalar(keys %allfactors)
78 + 13+3*$extra # moebius, euler_phi, jordan totient, divsum, etc.
78 + 14+3*$extra # moebius, euler_phi, jordan totient, divsum, etc.
7979 + 2 # liouville
8080 + 3 # gcd
8181 + 3 # lcm
107107 divisor_sum
108108 znorder
109109 znprimroot
110 znlog
110111 liouville
111112 gcd
112113 lcm
144145 diag "BigInt $bignumver/$bigintver, lib: $bigintlib. MPU::GMP $mpugmpver\n";
145146
146147 # Turn off use of BRS - ECM tries to use this.
147 prime_set_config( irand => sub { int(rand(4294967296.0)) } );
148 prime_set_config( irand => sub { int(rand(4294967296)) } );
148149
149150
150151 ###############################################################################
227228 ###############################################################################
228229
229230 SKIP: {
230 skip "Your 64-bit Perl is broken, skipping moebius, totient, etc.", 13+3*$extra if $broken64;
231 skip "Your 64-bit Perl is broken, skipping moebius, totient, etc.", 14+3*$extra if $broken64;
231232 my $n;
232233 $n = 618970019642690137449562110;
233234 is( moebius($n), -1, "moebius($n)" );
266267
267268 is( znprimroot(333822190384002421914469856494764513809), 3, "znprimroot(333822190384002421914469856494764513809)" );
268269
270 is( znlog(232752345212475230211680, 23847293847923847239847098123812075234, 804842536444911030681947), 13, "znlog(b,g,p): find k where b^k = g mod p" );
271
269272 }
270273
271274 ###############################################################################
1616 plan skip_all => "Test::Pod::Coverage 1.08 required for testing POD coverage"
1717 if $@;
1818
19 my @modules = Test::Pod::Coverage::all_modules();
19 my @modules = grep { $_ ne 'Math::Prime::Util::PPFE' }
20 Test::Pod::Coverage::all_modules();
21
2022 plan tests => scalar @modules;
2123
2224 #my $ppsubclass = { trustme => [mpu_public_regex()] };
+204
-63
util.c less more
2828 extern long double logl(long double);
2929 extern long double fabsl(long double);
3030 extern long double floorl(long double);
31 extern long double ceill(long double);
3132 #else
3233 #define powl(x, y) (long double) pow( (double) (x), (double) (y) )
3334 #define expl(x) (long double) exp( (double) (x) )
3435 #define logl(x) (long double) log( (double) (x) )
3536 #define fabsl(x) (long double) fabs( (double) (x) )
3637 #define floorl(x) (long double) floor( (double) (x) )
38 #define ceill(x) (long double) ceil( (double) (x) )
3739 #endif
3840
3941 #ifdef LDBL_INFINITY
100102 return (b * 0x0101010101010101) >> 56;
101103 }
102104 #endif
103 #else
104 static UV popcnt(UV b) {
105 b -= (b >> 1) & 0x55555555;
106 b = (b & 0x33333333) + ((b >> 2) & 0x33333333);
107 b = (b + (b >> 4)) & 0x0f0f0f0f;
108 return (b * 0x01010101) >> 24;
109 }
110105 #endif
111106
112107 #if defined(__GNUC__)
219214
220215 UV next_prime(UV n)
221216 {
222 UV d, m, sieve_size, next;
217 UV m, sieve_size, next;
223218 const unsigned char* sieve;
224219
225220 if (n < 30*NPRIME_SIEVE30) {
234229 release_prime_cache(sieve);
235230 if (next != 0) return next;
236231
237 d = n/30;
238 m = n - d*30;
239 /* Move forward one, knowing we may not be on the wheel */
240 if (m == 29) { d++; m = 1; } else { m = nextwheel30[m]; }
241 n = d*30+m;
242 while (!is_prob_prime(n)) {
243 /* Move forward one, knowing we are on the wheel */
232 m = n % 30;
233 do { /* Move forward one. */
244234 n += wheeladvance30[m];
245235 m = nextwheel30[m];
246 }
247 return(n);
236 } while (!is_prob_prime(n));
237 return n;
248238 }
249239
250240
251241 UV prev_prime(UV n)
252242 {
253243 const unsigned char* sieve;
254 UV d, m, prev;
244 UV m, prev;
255245
256246 if (n < 30*NPRIME_SIEVE30)
257247 return prev_prime_in_sieve(prime_sieve30, n);
263253 }
264254 release_prime_cache(sieve);
265255
266 d = n/30;
267 m = n - d*30;
268 do {
256 m = n % 30;
257 do { /* Move back one. */
258 n -= wheelretreat[m];
269259 m = prevwheel30[m];
270 if (m==29) d--;
271 n = d*30+m;
272260 } while (!is_prob_prime(n));
273261 return n;
274262 }
576564 return count;
577565 }
578566
579
567 UV prime_count_approx(UV n)
568 {
569 if (n < 3000000) return _XS_prime_count(2, n);
570 return (UV) (_XS_RiemannR( (long double) n ) + 0.5 );
571 }
572
573 UV prime_count_lower(UV n)
574 {
575 long double fn, flogn, lower, a;
576
577 if (n < 33000) return _XS_prime_count(2, n);
578
579 fn = (long double) n;
580 flogn = logl(n);
581
582 if (n < 176000) a = 1.80;
583 else if (n < 315000) a = 2.10;
584 else if (n < 1100000) a = 2.20;
585 else if (n < 4500000) a = 2.31;
586 else if (n <233000000) a = 2.36;
587 #if BITS_PER_WORD == 32
588 else a = 2.32;
589 #else
590 else if (n < UVCONST( 5433800000)) a = 2.32;
591 else if (n < UVCONST(60000000000)) a = 2.15;
592 else a = 2.00;
593 #endif
594
595 lower = fn/flogn * (1.0 + 1.0/flogn + a/(flogn*flogn));
596 return (UV) floorl(lower);
597 }
598
599 typedef struct {
600 UV thresh;
601 float aval;
602 } thresh_t;
603
604 static const thresh_t _upper_thresh[] = {
605 { 59000, 2.48 },
606 { 350000, 2.52 },
607 { 355991, 2.54 },
608 { 356000, 2.51 },
609 { 3550000, 2.50 },
610 { 3560000, 2.49 },
611 { 5000000, 2.48 },
612 { 8000000, 2.47 },
613 { 13000000, 2.46 },
614 { 18000000, 2.45 },
615 { 31000000, 2.44 },
616 { 41000000, 2.43 },
617 { 48000000, 2.42 },
618 { 119000000, 2.41 },
619 { 182000000, 2.40 },
620 { 192000000, 2.395 },
621 { 213000000, 2.390 },
622 { 271000000, 2.385 },
623 { 322000000, 2.380 },
624 { 400000000, 2.375 },
625 { 510000000, 2.370 },
626 { 682000000, 2.367 },
627 { UVCONST(2953652287), 2.362 }
628 };
629 #define NUPPER_THRESH (sizeof(_upper_thresh)/sizeof(_upper_thresh[0]))
630
631 UV prime_count_upper(UV n)
632 {
633 int i;
634 long double fn, flogn, upper, a;
635
636 if (n < 33000) return _XS_prime_count(2, n);
637
638 fn = (long double) n;
639 flogn = logl(n);
640
641 for (i = 0; i < (int)NUPPER_THRESH; i++)
642 if (n < _upper_thresh[i].thresh)
643 break;
644
645 if (i < (int)NUPPER_THRESH) a = _upper_thresh[i].aval;
646 else a = 2.334; /* Dusart 2010, page 2 */
647
648 upper = fn/flogn * (1.0 + 1.0/flogn + a/(flogn*flogn));
649 return (UV) ceill(upper);
650 }
580651
581652 static const unsigned short primes_small[] =
582653 {0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,
586657 409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499};
587658 #define NPRIMES_SMALL (sizeof(primes_small)/sizeof(primes_small[0]))
588659
589 /* Note: We're keeping this here because we use it for nth_prime */
590660 /* The nth prime will be less or equal to this number */
591 static UV _XS_nth_prime_upper(UV n)
661 UV nth_prime_upper(UV n)
592662 {
593 double fn, flogn, flog2n, upper;
663 long double fn, flogn, flog2n, upper;
594664
595665 if (n < NPRIMES_SMALL)
596666 return primes_small[n];
597667
598 fn = (double) n;
599 flogn = log(n);
600 flog2n = log(flogn); /* Note distinction between log_2(n) and log^2(n) */
668 fn = (long double) n;
669 flogn = logl(n);
670 flog2n = logl(flogn); /* Note distinction between log_2(n) and log^2(n) */
601671
602672 if (n >= 688383) /* Dusart 2010 page 2 */
603673 upper = fn * (flogn + flog2n - 1.0 + ((flog2n-2.00)/flogn));
621691 * nth_prime_lower(n) <= nth_prime(n) <= nth_prime_upper(n)
622692 */
623693 /* Watch out for overflow */
624 if (upper >= (double)UV_MAX) {
694 if (upper >= (long double)UV_MAX) {
625695 if (n <= MPU_MAX_PRIME_IDX) return MPU_MAX_PRIME;
626696 croak("nth_prime_upper(%"UVuf") overflow", n);
627697 }
628698
629 return (UV) ceil(upper);
630 }
631
632
633 UV _XS_nth_prime(UV n)
699 return (UV) ceill(upper);
700 }
701
702 /* The nth prime will be greater than or equal to this number */
703 UV nth_prime_lower(UV n)
704 {
705 long double fn, flogn, flog2n, lower;
706
707 if (n < NPRIMES_SMALL)
708 return primes_small[n];
709
710 fn = (long double) n;
711 flogn = logl(n);
712 flog2n = logl(flogn); /* Note distinction between log_2(n) and log^2(n) */
713
714 /* Dusart 2010 page 2, for all n >= 3 */
715 lower = fn * (flogn + flog2n - 1.0 + ((flog2n-2.10)/flogn));
716
717 return (UV) floorl(lower);
718 }
719
720 UV nth_prime_approx(UV n)
721 {
722 long double fn, flogn, flog2n, approx, order;
723
724 if (n < NPRIMES_SMALL)
725 return primes_small[n];
726
727 fn = (long double) n;
728 flogn = logl(n);
729 flog2n = logl(flogn); /* Note distinction between log_2(n) and log^2(n) */
730
731 /* Cipolla 1902:
732 * m=0 fn * ( flogn + flog2n - 1 );
733 * m=1 + ((flog2n - 2)/flogn) );
734 * m=2 - (((flog2n*flog2n) - 6*flog2n + 11) / (2*flogn*flogn))
735 * + O((flog2n/flogn)^3)
736 */
737
738 approx = fn * ( flogn + flog2n - 1.0
739 + ((flog2n - 2.0) / flogn)
740 - (((flog2n*flog2n) - 6.0*flog2n + 11.0) / (2*flogn*flogn))
741 );
742
743 /* Apply a correction */
744 order = flog2n / flogn;
745 order = order * order * order * fn;
746 if (n < 259) { approx += 10.4 * order; }
747 else if (n < 775) { approx += 7.52 * order; }
748 else if (n < 1271) { approx += 5.6 * order; }
749 else if (n < 2000) { approx += 5.2 * order; }
750 else if (n < 4000) { approx += 4.3 * order; }
751 else if (n < 12000) { approx += 3.0 * order; }
752 else if (n < 150000) { approx += 2.1 * order; }
753 else if (n <200000000) { }
754 else { approx += -0.01 * order; } /* -0.25 is closer */
755
756 return (UV) floorl(approx + 0.5);
757 }
758
759
760 UV nth_prime(UV n)
634761 {
635762 const unsigned char* cache_sieve;
636763 unsigned char* segment;
644771 return primes_small[n];
645772
646773 /* Determine a bound on the nth prime. We know it comes before this. */
647 upper_limit = _XS_nth_prime_upper(n);
774 upper_limit = nth_prime_upper(n);
648775 MPUassert(upper_limit > 0, "nth_prime got an upper limit of 0");
649776
650777 /* For relatively small values, generate a sieve and count the results.
769896 unsigned char* segment;
770897 void* ctx;
771898
772 if (hi < lo) croak("_totient_range error hi %lu < lo %lu\n", hi, lo);
899 if (hi < lo) croak("_totient_range error hi %"UVuf" < lo %"UVuf"\n", hi, lo);
773900 New(0, totients, hi-lo+1, UV);
774901
775902 /* Do via factoring if very small or if we have a small range */
10851212 return mulmod(a, binv, n);
10861213 }
10871214
1088 /* Find smallest n where a = g^n mod p
1215 /* Find smallest k where a = g^k mod p
10891216 * This implementation is just a stupid placeholder.
1090 * When prho or bsgs gets working well, lower the trial limit
1217 * When prho or bsgs starts working well, lower the trial limit
10911218 */
10921219 #define DLP_TRIAL_NUM 1000000
10931220 UV znlog(UV a, UV g, UV p) {
11241251 UV seg_base, seg_low, seg_high;
11251252 unsigned char* segment;
11261253 void* ctx;
1254 long double logl2 = logl(2);
1255 long double logl3 = logl(3);
1256 long double logl5 = logl(5);
11271257 if (!which) {
1128 KAHAN_SUM(sum,logl(2)); KAHAN_SUM(sum,logl(3)); KAHAN_SUM(sum,logl(5));
1258 KAHAN_SUM(sum,logl2); KAHAN_SUM(sum,logl3); KAHAN_SUM(sum,logl5);
11291259 } else {
1130 KAHAN_SUM(sum, logl(2) * floorl(logn/logl(2) + 1e-15));
1131 KAHAN_SUM(sum, logl(3) * floorl(logn/logl(3) + 1e-15));
1132 KAHAN_SUM(sum, logl(5) * floorl(logn/logl(5) + 1e-15));
1260 KAHAN_SUM(sum, logl2 * floorl(logn/logl2 + 1e-15));
1261 KAHAN_SUM(sum, logl3 * floorl(logn/logl3 + 1e-15));
1262 KAHAN_SUM(sum, logl5 * floorl(logn/logl5 + 1e-15));
11331263 }
11341264 ctx = start_segment_primes(7, n, &segment);
11351265 while (next_segment_primes(ctx, &seg_base, &seg_low, &seg_high)) {
12611391
12621392 /* Thanks to Kim Walisch for this idea */
12631393 UV _XS_Inverse_Li(UV x) {
1264 double n = x;
1265 double logn = log(n);
1266 UV lo = (UV) (n*logn);
1267 UV hi = (UV) (n*logn * 2 + 2);
1394 double nlogn = (double)x * log((double)x);
1395 UV lo = (UV) (nlogn);
1396 UV hi = (UV) (nlogn * 2 + 2);
12681397
12691398 if (x == 0) return 0;
12701399 if (hi <= lo) hi = UV_MAX;
13221451 0.0000000000036379795473786511902372363L,
13231452 0.0000000000018189896503070659475848321L,
13241453 0.0000000000009094947840263889282533118L,
1454 0.0000000000004547473783042154026799112L,
1455 0.0000000000002273736845824652515226821L,
1456 0.0000000000001136868407680227849349105L,
1457 0.0000000000000568434198762758560927718L,
1458 0.0000000000000284217097688930185545507L,
1459 0.0000000000000142108548280316067698343L,
1460 0.00000000000000710542739521085271287735L,
1461 0.00000000000000355271369133711367329847L,
1462 0.00000000000000177635684357912032747335L,
1463 0.000000000000000888178421093081590309609L,
1464 0.000000000000000444089210314381336419777L,
1465 0.000000000000000222044605079804198399932L,
1466 0.000000000000000111022302514106613372055L,
1467 0.0000000000000000555111512484548124372374L,
1468 0.0000000000000000277555756213612417258163L,
1469 0.0000000000000000138777878097252327628391L,
13251470 };
13261471 #define NPRECALC_ZETA (sizeof(riemann_zeta_table)/sizeof(riemann_zeta_table[0]))
13271472
13311476 * The Cephes zeta function uses a series (2k)!/B_2k which converges rapidly
13321477 * and has a very wide range of values. We use it here for some values.
13331478 *
1334 * Note: Calculations here are done on long doubles and we try to generate ~17
1335 * digits of accuracy. When these are returned to Perl they get put in
1336 * a standard 64-bit double, so don't expect more than 15 digits.
1479 * Note: Calculations here are done on long doubles and we try to generate as
1480 * much accuracy as possible. They will get returned to Perl as an NV,
1481 * which is typically a 64-bit double with 15 digits.
13371482 *
13381483 * For values 0.5 to 5, this code uses the rational Chebyshev approximation
13391484 * from Cody and Thacher. This method is extraordinarily fast and very
13781523 return sum;
13791524 }
13801525
1381 if (x > 2000.0) {
1382 /* 1) zeta(2000)-1 is about 8.7E-603, which is far less than a IEEE-754
1383 * 64-bit double can represent. A 128-bit quad could go to ~16000.
1384 * 2) pow / powl start getting obnoxiously slow with values like -7500. */
1526 if (x > 17000.0)
13851527 return 0.0;
1386 }
13871528
13881529 #if 0
13891530 {
14261567 for (i = 2; i < 11; i++) {
14271568 b = powl( i, -x );
14281569 s += b;
1429 if (fabsl(b/s) < LDBL_EPSILON)
1430 return s;
1570 if (fabsl(b) < fabsl(LDBL_EPSILON * s))
1571 return s;
14311572 }
14321573 s = s + b*w/(x-1.0) - 0.5 * b;
14331574 a = 1.0;
14371578 b /= w;
14381579 t = a*b/A[i];
14391580 s = s + t;
1440 t = fabsl(t/s);
1441 if (t < LDBL_EPSILON)
1581 if (fabsl(t) < fabsl(LDBL_EPSILON * s))
14421582 break;
14431583 a *= x + k + 1.0;
14441584 b /= w;
14611601
14621602 for (k = 1; k <= 10000; k++) {
14631603 part_term *= flogx / k;
1464 term = part_term / (k + k * ld_riemann_zeta(k+1));
1604 if (k-1 < NPRECALC_ZETA) term = part_term / (k+k*riemann_zeta_table[k-1]);
1605 else term = part_term / (k+k*ld_riemann_zeta(k+1));
14651606 KAHAN_SUM(sum, term);
1466 /* printf("R after adding %.15lg, sum = %.15lg\n", term, sum); */
1467 if (fabsl(term/sum) < LDBL_EPSILON) break;
1607 /* printf("R %5d after adding %.18Lg, sum = %.19Lg\n", k, term, sum); */
1608 if (fabsl(term) < fabsl(LDBL_EPSILON*sum)) break;
14681609 }
14691610
14701611 return sum;
1212 extern UV prev_prime(UV x);
1313
1414 extern UV _XS_prime_count(UV low, UV high);
15 extern UV _XS_nth_prime(UV x);
15 extern UV nth_prime(UV x);
16 extern UV nth_prime_upper(UV x);
17 extern UV nth_prime_lower(UV x);
18 extern UV nth_prime_approx(UV x);
19 extern UV prime_count_lower(UV x);
20 extern UV prime_count_upper(UV x);
21 extern UV prime_count_approx(UV x);
1622
1723 extern signed char* _moebius_range(UV low, UV high);
1824 extern UV* _totient_range(UV low, UV high);
7171 is_deeply( gen_forprimes($b,$e), \@p, "forprimes {} $b,$e");
7272 }
7373 }
74 diag "\nChecking numbers near end with segment primes(). Very slow.\n";
74 diag "\nChecking numbers near end with segment primes().\n";
7575 {
7676 my $b = $lprimes[-1] - 1;
7777 my $e = ~0;
7878 my @p = ($lprimes[-1]);
7979 diag "\n Window around $lprimes[-1]\n";
80 is_deeply( gen_primes({method => 'Segment'}, $b, $b), [], "primes($b,$b)");
81 is_deeply( gen_primes({method => 'Segment'}, $b, $b+1), \@p, "primes($b,$b+1)");
82 is_deeply( gen_primes({method => 'Segment'}, $b, $b+2), \@p, "primes($b,$b+2)");
83 is_deeply( gen_primes({method => 'Segment'}, $b+1, $b+1), \@p, "primes($b+1,$b+1)");
84 is_deeply( gen_primes({method => 'Segment'}, $b+1, $b+2), \@p, "primes($b+1,$b+2)");
85 is_deeply( gen_primes({method => 'Segment'}, $b+2, $b+2), [], "primes($b+2,$b+2)");
80 is_deeply( gen_segment_primes($b, $b), [], "primes($b,$b)");
81 is_deeply( gen_segment_primes($b, $b+1), \@p, "primes($b,$b+1)");
82 is_deeply( gen_segment_primes($b, $b+2), \@p, "primes($b,$b+2)");
83 is_deeply( gen_segment_primes($b+1, $b+1), \@p, "primes($b+1,$b+1)");
84 is_deeply( gen_segment_primes($b+1, $b+2), \@p, "primes($b+1,$b+2)");
85 is_deeply( gen_segment_primes($b+2, $b+2), [], "primes($b+2,$b+2)");
8686 diag "\n Window around $e\n";
87 is_deeply( gen_primes({method => 'Segment'}, $e-2, $e-2), [], "primes($e-2,$e-2)");
88 is_deeply( gen_primes({method => 'Segment'}, $e-2, $e), [], "primes($e-2,$e)");
89 is_deeply( gen_primes({method => 'Segment'}, $e-1, $e), [], "primes($e-1,$e)");
90 is_deeply( gen_primes({method => 'Segment'}, $e, $e), [], "primes($e,$e)");
87 is_deeply( gen_segment_primes($e-2, $e-2), [], "primes($e-2,$e-2)");
88 is_deeply( gen_segment_primes($e-2, $e), [], "primes($e-2,$e)");
89 is_deeply( gen_segment_primes($e-1, $e), [], "primes($e-1,$e)");
90 is_deeply( gen_segment_primes($e, $e), [], "primes($e,$e)");
9191 }
9292
93 #diag "\nChecking numbers near end with forprimes. This will take a *very* long time.\n";
94 #foreach my $bdelta (reverse 0 .. 9) {
95 # foreach my $edelta (reverse 0 .. $bdelta) {
96 # my ($b, $e) = (~0 - $bdelta, ~0 - $edelta);
97 # my @p = grep { $_ >= $b && $_ <= $e } @lprimes;
98 # is_deeply( gen_forprimes($b,$e), \@p, "forprimes {} $b,$e");
99 # }
100 #}
10193
10294 sub gen_primes {
10395 return primes(@_);
96 }
97 sub gen_segment_primes {
98 my($low, $high) = @_;
99 return Math::Prime::Util::segment_primes($low,$high); # Private function
104100 }
105101 sub gen_forprimes {
106102 my($b, $e) = @_;
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 use Math::Prime::Util qw/factor/;
4 use File::Temp qw/tempfile/;
5 use Math::BigInt try => 'GMP,Pari';
6 use Config;
7 use autodie;
8 use Text::Diff;
9 my $maxdigits = 50;
10 $| = 1; # fast pipes
11 my $num = 10000;
12 my $yafu_fname = "yafu_batchfile_$$.txt";
13 $SIG{'INT'} = \&gotsig;
14
15 my $rgen = sub {
16 my $range = shift;
17 return 0 if $range <= 0;
18 my $rbits = 0; { my $t = $range; while ($t) { $rbits++; $t >>= 1; } }
19 while (1) {
20 my $rbitsleft = $rbits;
21 my $U = $range - $range; # 0 or bigint 0
22 while ($rbitsleft > 0) {
23 my $usebits = ($rbitsleft > $Config{randbits}) ? $Config{randbits} : $rbitsleft;
24 $U = ($U << $usebits) + int(rand(1 << $usebits));
25 $rbitsleft -= $usebits;
26 }
27 return $U if $U <= $range;
28 }
29 };
30
31 { # Test from 2 to 10000
32 print " 2 - 1000"; test_array( 2 .. 1000);
33 print " 1001 - 5000"; test_array( 1001 .. 5000);
34 print " 5001 - 10000"; test_array( 5001 .. 10000);
35 }
36
37 foreach my $digits (5 .. $maxdigits) {
38 printf "%5d %2d-digit numbers", $num, $digits;
39 my @narray = gendigits($digits, $num);
40 test_array(@narray);
41 $num = int($num * 0.9) + 1; # reduce as we go
42 }
43
44 sub test_array {
45 my @narray = @_;
46 print ".";
47 my @mpuarray = mpu_factors(@narray);
48 print ".";
49 my @yafuarray = yafu_factors(@narray);
50 print ".";
51 if ($#mpuarray != $#yafuarray) {
52 die "MPU got $#mpuarray factors, YAFU got $#yafuarray\n";
53 }
54 foreach my $n (@narray) {
55 my @mpu = @{shift @mpuarray};
56 my @yafu = @{shift @yafuarray};
57 die "mpu array is for the wrong n?" unless $n == shift @mpu;
58 die "yafu array is for the wrong n?" unless $n == shift @yafu;
59 my $diff = diff \@mpu, \@yafu, { STYLE => 'Table' };
60 die "factor($n):\n$diff\n" if length($diff) > 0;
61 }
62 print ".";
63 print "OK\n";
64 }
65
66 sub gendigits {
67 my $digits = shift;
68 die "Digits must be > 0" unless $digits > 0;
69 my $howmany = shift;
70 my ($base, $max);
71
72 if ( 10**$digits < ~0) {
73 $base = ($digits == 1) ? 0 : int(10 ** ($digits-1));
74 $max = int(10 ** $digits);
75 $max = ~0 if $max > ~0;
76 } else {
77 $base = Math::BigInt->new(10)->bpow($digits-1);
78 $max = Math::BigInt->new(10)->bpow($digits) - 1;
79 }
80 my @nums = map { $base + $rgen->($max-$base) } (1 .. $howmany);
81 return @nums;
82 }
83
84 sub mpu_factors {
85 my @piarray;
86 push @piarray, [$_, factor($_)] for @_;
87 @piarray;
88 }
89
90 sub yafu_factors {
91 my @ns = @_;
92 my @piarray;
93
94 #my $fh = File::Temp->new; # .... autodie
95 #print $fh, "$_\n" for @_;
96 #$fh->flush;
97
98 # Shudder. Yafu must have a file in the current directory.
99 open(my $fh, '>', $yafu_fname);
100 print $fh "$_\n" for @ns;
101 close $fh;
102
103 open my $yafu, "yafu \"factor(\@)\" -batchfile $yafu_fname |";
104 my @curfactors;
105 while (<$yafu>) {
106 chomp;
107 if (/^P(RP)?\d+ = (\d+)/) {
108 push @curfactors, $2;
109 } elsif (/^C\d+ = (\d+)/) {
110 # Yafu didn't factor this one completely. Sneakily do it ourselves.
111 push @curfactors, factor( Math::BigInt->new("$1") );
112 } elsif (/ans = (\d+)/ || /^1$/) {
113 push @piarray, [shift @ns, sort {$a<=>$b} @curfactors];
114 @curfactors = ();
115 }
116 }
117 close($yafu);
118 @piarray;
119 }
120 sub gotsig { my $sig = shift; die "Die because SIG$sig\n"; }
121 END {
122 unlink $yafu_fname if -e $yafu_fname;
123 # YAFU leaves stuff around
124 unlink "__tmpbatchfile" if -e "__tmpbatchfile";
125 unlink "session.log" if -e "session.log";
126 unlink "factor.log" if -e "factor.log";
127 }
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 use Math::Prime::Util qw/next_prime/;
4 use File::Temp qw/tempfile/;
5 use autodie;
6 my $maxdigits = (~0 <= 4294967295) ? 10 : 20;
7 $| = 1; # fast pipes
8 my $num = shift || 10000;
9 my $yafu_fname = "yafu_batchfile_$$.txt";
10 $SIG{'INT'} = \&gotsig;
11
12 foreach my $digits (4 .. $maxdigits) {
13 printf "%2d-digit numbers", $digits;
14 my @narray = gendigits($digits, $num);
15 print ".";
16 my @mpuarray = mpu_next_primes(@narray);
17 print ".";
18 die "mpu_next_primes didn't get enough numbers" unless $#mpuarray == $#narray;
19 my @yafuarray = yafu_next_primes(@narray);
20 die "yafunext_primes didn't get enough numbers" unless $#yafuarray == $#narray;
21 print ".";
22 foreach my $n (@narray) {
23 my $mpu = shift @mpuarray;
24 my $yafu = shift @yafuarray;
25 die "next_prime($n): MPU: $mpu YAFU: $yafu\n" unless $mpu == $yafu;
26 }
27 print ".";
28 print "OK\n";
29 }
30
31 sub gendigits {
32 my $digits = shift;
33 die "Digits must be > 0" unless $digits > 0;
34 my $howmany = shift;
35
36 my $base = ($digits == 1) ? 0 : int(10 ** ($digits-1));
37 my $max = int(10 ** $digits);
38 $max = ~0 if $max > ~0;
39 my @nums = map { $base+int(rand($max-$base)) } (1 .. $howmany);
40 return @nums;
41 }
42
43 sub mpu_next_primes {
44 my @nparray;
45 push @nparray, next_prime($_) for @_;
46 @nparray;
47 }
48
49 sub yafu_next_primes {
50 my @nparray;
51 # Yafu 1.31 seems to go out of its way to make it hard to process more than
52 # one number at a time. The batchfile system will infinite loop if the data
53 # file isn't in the current directory.
54 # It does its darndest to see if you're on a terminal or not, and if not it
55 # just cuts you off after one number. So any sort of tempfile or pipe stuff
56 # just plain doesn't work. Faking it using IO::*tty* would probably work.
57
58 #my $fh = File::Temp->new; # .... autodie
59 #print $fh, "$_\n" for @_;
60 #$fh->flush;
61
62 # Shudder. Read comments above about why I have to do this.
63 open(my $fh, '>', $yafu_fname);
64 print $fh "$_\n" for @_;
65 close $fh;
66
67 open my $yafu, "yafu \"nextprime(\@)\" -batchfile $yafu_fname |";
68 while (<$yafu>) {
69 if (/^(ans = )?(\d+)\s*$/) {
70 push @nparray, $2;
71 }
72 }
73 close($yafu);
74 @nparray;
75 }
76 sub gotsig { my $sig = shift; die "Die because SIG$sig\n"; }
77 END {
78 unlink $yafu_fname if -e $yafu_fname;
79 # YAFU leaves stuff around
80 unlink "__tmpbatchfile" if -e "__tmpbatchfile";
81 unlink "session.log" if -e "session.log";
82 }