Merge tag 'upstream/0.37'
Upstream version 0.37
gregor herrmann
10 years ago
0 | 0 | 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 | ||
1 | 32 | |
2 | 33 | 0.36 2014-01-13 |
3 | 34 |
4 | 4 | lib/Math/Prime/Util/PrimeArray.pm |
5 | 5 | lib/Math/Prime/Util/PrimeIterator.pm |
6 | 6 | lib/Math/Prime/Util/PP.pm |
7 | lib/Math/Prime/Util/PPFE.pm | |
7 | 8 | lib/Math/Prime/Util/ZetaBigFloat.pm |
8 | 9 | lib/Math/Prime/Util/ECAffinePoint.pm |
9 | 10 | lib/Math/Prime/Util/ECProjectivePoint.pm |
10 | 11 | lib/Math/Prime/Util/PrimalityProving.pm |
12 | lib/Math/Prime/Util/RandomPrimes.pm | |
11 | 13 | LICENSE |
12 | 14 | Makefile.PL |
13 | 15 | MANIFEST |
35 | 37 | sieve.c |
36 | 38 | util.h |
37 | 39 | 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 | |
38 | 59 | 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 | |
60 | 60 | examples/sophie_germain.pl |
61 | 61 | examples/twin_primes.pl |
62 | 62 | examples/abundant.pl |
63 | 63 | examples/find_mr_bases.pl |
64 | 64 | examples/parallel_fibprime.pl |
65 | examples/test-factor-gnufactor.pl | |
65 | examples/porter.pl | |
66 | 66 | examples/verify-gmp-ecpp-cert.pl |
67 | 67 | examples/verify-sage-ecpp-cert.pl |
68 | 68 | examples/verify-cert.pl |
124 | 124 | xt/test-pcapprox.pl |
125 | 125 | xt/test-primes-script.pl |
126 | 126 | xt/test-primes-script2.pl |
127 | xt/test-factor-yafu.pl | |
128 | xt/test-nextprime-yafu.pl | |
127 | 129 | .travis.yml |
128 | 130 | META.yml Module YAML meta-data (added by MakeMaker) |
129 | 131 | META.json Module JSON meta-data (added by MakeMaker) |
3 | 3 | "Dana A Jacobsen <dana@acm.org>" |
4 | 4 | ], |
5 | 5 | "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", | |
7 | 7 | "license" : [ |
8 | 8 | "perl_5" |
9 | 9 | ], |
20 | 20 | }, |
21 | 21 | "prereqs" : { |
22 | 22 | "build" : { |
23 | "requires" : { | |
24 | "ExtUtils::MakeMaker" : "0" | |
25 | } | |
26 | }, | |
27 | "configure" : { | |
23 | 28 | "requires" : { |
24 | 29 | "ExtUtils::MakeMaker" : "0" |
25 | 30 | } |
64 | 69 | "url" : "https://github.com/danaj/Math-Prime-Util" |
65 | 70 | } |
66 | 71 | }, |
67 | "version" : "0.36" | |
72 | "version" : "0.37" | |
68 | 73 | } |
5 | 5 | ExtUtils::MakeMaker: 0 |
6 | 6 | Test::More: 0.45 |
7 | 7 | bignum: 0.22 |
8 | configure_requires: | |
9 | ExtUtils::MakeMaker: 0 | |
8 | 10 | 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' | |
10 | 12 | license: perl |
11 | 13 | meta-spec: |
12 | 14 | url: http://module-build.sourceforge.net/META-spec-v1.4.html |
36 | 38 | homepage: https://github.com/danaj/Math-Prime-Util |
37 | 39 | license: http://dev.perl.org/licenses/ |
38 | 40 | 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 | |
1 | 1 | |
2 | 2 | A set of utilities related to prime numbers. These include multiple sieving |
3 | 3 | methods, is_prime, prime_count, nth_prime, approximations and bounds for |
4 | 4 | * use: -O2 -g -Wall -Wextra -Wdeclaration-after-statement -fsigned-char |
5 | 5 | * Test on 32-bit Perl. Test on Win32. |
6 | 6 | |
7 | ||
8 | - Add test to check maxbits in compiled library vs. Perl | |
9 | 7 | |
10 | 8 | - Figure out documentation solution for PP.pm |
11 | 9 | |
28 | 26 | - Big features: |
29 | 27 | - QS factoring |
30 | 28 | |
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 | ||
34 | 29 | - Figure out a way to make the internal FOR_EACH_PRIME macros use a segmented |
35 | 30 | sieve. |
36 | 31 | |
37 | 32 | - Rewrite 23-primality-proofs.t for new format (keep some of the old tests?). |
38 | 33 | |
39 | 34 | - 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. | |
45 | 35 | |
46 | 36 | - Factoring in PP code is really wasteful -- we're calling _isprime7 before |
47 | 37 | we've done enough trial division, and later we're calling it on known |
69 | 59 | - Perhaps have main segment know the filled in range. That would allow |
70 | 60 | a sieved next_prime, and might speed up some counts and the like. |
71 | 61 | |
72 | - Consider exporting is_bpsw_prime | |
73 | ||
74 | - Add Inverse Li to API? | |
62 | - Consider exporting is_bpsw_prime and inverse Li | |
75 | 63 | |
76 | 64 | - Benchmark simple SoEs, SoA. Include Sisyphus SoE hidden in Math::GMPz. |
77 | ||
78 | - Redo trial vs. segment test in Util.pm primes(). | |
79 | 65 | |
80 | 66 | - commit Porter example |
81 | 67 | |
84 | 70 | - Investigate optree constant folding in PP compilation for performance. |
85 | 71 | Use B::Deparse to check. |
86 | 72 | |
87 | - Move more functions from _generic_... to PP:: | |
88 | ||
89 | 73 | - Ensure a fast path for Math::GMP from MPU -> MPU:GMP -> GMP, and back. |
90 | 74 | |
91 | - znlog bignum tests, znlog better implementation | |
75 | - znlog better implementation |
175 | 175 | GV ** gvp = (GV**)hv_fetch(MY_CXT.MPUGMP,name,namelen,0); |
176 | 176 | if (gvp) gv = *gvp; |
177 | 177 | } |
178 | if (!gv && (stashflags & VCALL_PP)) | |
179 | perl_require_pv("Math/Prime/Util/PP.pm"); | |
178 | 180 | if (!gv) { |
179 | 181 | GV ** gvp = (GV**)hv_fetch(stashflags & VCALL_PP? MY_CXT.MPUPP : MY_CXT.MPUroot, name,namelen,0); |
180 | 182 | if (gvp) gv = *gvp; |
586 | 588 | ALIAS: |
587 | 589 | prev_prime = 1 |
588 | 590 | 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 | |
589 | 597 | PPCODE: |
590 | 598 | if (_validate_int(aTHX_ svn, 0)) { |
591 | 599 | 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)) ) { | |
594 | 602 | /* Out of range. Fall through to Perl. */ |
595 | 603 | } else { |
596 | 604 | UV ret; |
597 | 605 | switch (ix) { |
598 | 606 | case 0: ret = next_prime(n); break; |
599 | 607 | 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; | |
602 | 616 | } |
603 | 617 | XSRETURN_UV(ret); |
604 | 618 | } |
605 | 619 | } |
606 | 620 | 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; | |
610 | 631 | } |
611 | 632 | return; /* skip implicit PUTBACK */ |
612 | 633 | |
664 | 685 | switch (ix) { |
665 | 686 | case 0: _vcallsubn(aTHX_ gimme_v, VCALL_ROOT, "_generic_factor", 1); break; |
666 | 687 | 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; | |
668 | 689 | } |
669 | 690 | return; /* skip implicit PUTBACK */ |
670 | 691 | } |
684 | 705 | UV sigma = divisor_sum(n, k); |
685 | 706 | if (sigma != 0) XSRETURN_UV(sigma); /* sigma 0 means overflow */ |
686 | 707 | } |
687 | _vcallsub("_generic_divisor_sum"); | |
708 | _vcallsub_with_gmp("divisor_sum"); | |
688 | 709 | return; /* skip implicit PUTBACK */ |
689 | 710 | |
690 | 711 | void |
717 | 738 | } |
718 | 739 | overflow: |
719 | 740 | switch (ix) { |
720 | case 0: _vcallsub_with_pp("znorder"); break; | |
741 | case 0: _vcallsub_with_gmp("znorder"); break; | |
721 | 742 | case 1: _vcallsub_with_pp("jordan_totient"); break; |
722 | 743 | case 2: |
723 | 744 | default: _vcallsub_with_pp("legendre_phi"); break; |
738 | 759 | if (ret == 0 && a > 1) XSRETURN_UNDEF; |
739 | 760 | XSRETURN_UV(ret); |
740 | 761 | } |
741 | _vcallsub_with_pp("znlog"); | |
762 | _vcallsub_with_gmp("znlog"); | |
742 | 763 | return; /* skip implicit PUTBACK */ |
743 | 764 | |
744 | 765 | void |
760 | 781 | int k = (abpositive) ? kronecker_uu(a,b) : kronecker_ss(a,b); |
761 | 782 | RETURN_NPARITY(k); |
762 | 783 | } |
763 | _vcallsub("_generic_kronecker"); | |
784 | _vcallsub_with_gmp("kronecker"); | |
764 | 785 | return; /* skip implicit PUTBACK */ |
765 | 786 | |
766 | double | |
787 | NV | |
767 | 788 | _XS_ExponentialIntegral(IN SV* x) |
768 | 789 | ALIAS: |
769 | 790 | _XS_LogarithmicIntegral = 1 |
770 | 791 | _XS_RiemannZeta = 2 |
771 | 792 | _XS_RiemannR = 3 |
772 | _XS_chebyshev_theta = 4 | |
773 | _XS_chebyshev_psi = 5 | |
774 | PREINIT: | |
775 | double ret; | |
793 | PREINIT: | |
794 | NV nv, ret; | |
776 | 795 | 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; | |
789 | 803 | } |
790 | 804 | RETVAL = ret; |
791 | 805 | OUTPUT: |
833 | 847 | /* Whatever we didn't handle above */ |
834 | 848 | U32 gimme_v = GIMME_V; |
835 | 849 | 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; | |
837 | 851 | 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; | |
839 | 853 | } |
840 | 854 | return; |
841 | 855 | } |
844 | 858 | carmichael_lambda(IN SV* svn) |
845 | 859 | ALIAS: |
846 | 860 | 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 | |
849 | 866 | PREINIT: |
850 | 867 | int status; |
851 | 868 | PPCODE: |
852 | status = _validate_int(aTHX_ svn, (ix > 1) ? 1 : 0); | |
869 | status = _validate_int(aTHX_ svn, (ix >= 5) ? 1 : 0); | |
853 | 870 | switch (ix) { |
854 | 871 | case 0: if (status == 1) XSRETURN_UV(carmichael_lambda(my_svuv(svn))); |
855 | _vcallsub("_generic_carmichael_lambda"); | |
872 | _vcallsub_with_gmp("carmichael_lambda"); | |
856 | 873 | break; |
857 | 874 | case 1: if (status == 1) XSRETURN_IV(mertens(my_svuv(svn))); |
858 | _vcallsub("_generic_mertens"); | |
875 | _vcallsub_with_pp("mertens"); | |
859 | 876 | 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"); | |
863 | 883 | 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: | |
865 | 895 | default:if (status != 0) { |
866 | 896 | UV r, n = my_svuv(svn); |
867 | 897 | if (status == -1) n = -(IV)n; |
871 | 901 | else |
872 | 902 | XSRETURN_UV(r); |
873 | 903 | } |
874 | _vcallsub("_generic_znprimroot"); | |
904 | _vcallsub_with_gmp("znprimroot"); | |
875 | 905 | break; |
876 | 906 | } |
877 | 907 | 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 | } |
1 | 1 | use strict; |
2 | 2 | use warnings; |
3 | 3 | use Getopt::Long; |
4 | use bigint try => 'GMP'; | |
5 | 4 | use Math::Prime::Util qw/factor nth_prime prime_set_config/; |
6 | 5 | $| = 1; |
7 | no bigint; | |
8 | 6 | |
9 | 7 | # Allow execution of any of these functions in the command line |
10 | 8 | my @mpu_funcs = (qw/next_prime prev_prime prime_count nth_prime random_prime |
22 | 20 | ) || die_usage(); |
23 | 21 | if (exists $opts{'version'}) { |
24 | 22 | 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"; | |
26 | 24 | $version_str .= " and MPU::GMP $Math::Prime::Util::GMP::VERSION" |
27 | 25 | if Math::Prime::Util::prime_get_config->{'gmp'}; |
28 | 26 | $version_str .= "\nWritten by Dana Jacobsen.\n"; |
68 | 66 | $expr =~ s/:$mpu_func_map{$func}\(/Math::Prime::Util::$func(/g; |
69 | 67 | } |
70 | 68 | $expr =~ s/(\d+)/ Math::BigInt->new("$1") /g; |
69 | $expr = 'use Math::BigInt try=>"GMP"; ' . $expr; | |
71 | 70 | my $res = eval $expr; ## no critic |
72 | 71 | die "Cannot eval: $expr\n" if !defined $res; |
73 | 72 | $res = int($res->bstr) if ref($res) eq 'Math::BigInt' && $res <= ~0; |
157 | 157 | #endif |
158 | 158 | } |
159 | 159 | |
160 | #ifdef USE_ITHREADS | |
160 | 161 | void release_prime_cache(const unsigned char* mem) { |
161 | 162 | (void)mem; /* We don't currently care about the pointer */ |
162 | 163 | READ_LOCK_END; |
163 | 164 | } |
165 | #endif | |
164 | 166 | |
165 | 167 | |
166 | 168 |
29 | 29 | */ |
30 | 30 | extern UV get_prime_cache(UV n, const unsigned char** sieve); |
31 | 31 | /* Inform the system we're done using the primary cache if we got a ptr. */ |
32 | #ifdef USE_ITHREADS | |
32 | 33 | extern void release_prime_cache(const unsigned char* sieve); |
34 | #else | |
35 | #define release_prime_cache(mem) | |
36 | #endif | |
33 | 37 | |
34 | 38 | /* Get the segment cache. Set size to its size. */ |
35 | 39 | extern unsigned char* get_prime_segment(UV* size); |
0 | 0 | |
1 | There are two main types of scripts here: benchmarks and correctness tests. | |
1 | abundant.pl | |
2 | 2 | |
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 | |
8 | 8 | |
9 | 9 | |
10 | test-factor-yafu.pl | |
10 | sophie_germain.pl | |
11 | 11 | |
12 | Tests factorization compared with YAFU (v1.31.1). No arguments. | |
12 | Prints the first N Sophie-Germain primes. E.g.: | |
13 | 13 | |
14 | test-factor-mpxs.pl | |
14 | perl sophia_germain.pl 100000 | |
15 | 15 | |
16 | Tests factorization compared with Math::Factor::XS (v0.26). | |
17 | One argument gives the number of random tests to perform. | |
18 | 16 | |
19 | test-nextprime-yafu.pl | |
17 | twin_primes.pl | |
20 | 18 | |
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.: | |
22 | 20 | |
23 | test-primes-yafu.pl | |
21 | perl twin_primes.pl 100000 | |
24 | 22 | |
25 | Tests primes($a,$b+$interval) compared with YAFU (v1.31.1). No arguments. | |
26 | The interval is currently 8000. | |
27 | 23 | |
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. | |
29 | 31 | |
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. | |
33 | 32 | |
34 | test-nthapprox.pl | |
33 | parallel_fibprime.pl | |
35 | 34 | |
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. | |
38 | 37 | |
39 | test-pcapprox.pl | |
40 | 38 | |
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 | |
44 | 40 | |
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. | |
46 | 44 | |
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). | |
51 | 45 | |
52 | bench-factor.pl | |
53 | 46 | |
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 | |
59 | 48 | |
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. | |
61 | 51 | |
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 | |
65 | 53 | |
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. | |
67 | 56 | |
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 | |
80 | 58 | |
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. |
4 | 4 | # Find the first N abundant, deficient, or perfect numbers. |
5 | 5 | |
6 | 6 | use Math::Prime::Util qw/divisor_sum next_prime is_prime/; |
7 | use Math::BigInt try => "GMP,Pari"; | |
8 | 7 | |
9 | 8 | my $count = shift || 20; |
10 | 9 | my $type = lc(shift || 'abundant'); |
25 | 24 | # We just look for 2^(p-1)*(2^p-1) where 2^p-1 is prime. |
26 | 25 | # Basically we're just finding Mersenne primes. |
27 | 26 | # It's possible there are odd perfect numbers larger than 10^1500. |
27 | do { require Math::BigInt; Math::BigInt->import(try=>"GMP,Pari"); }; | |
28 | 28 | while ($count-- > 0) { |
29 | 29 | while (1) { |
30 | 30 | $p = next_prime($p); |
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 | } |
2 | 2 | use strict; |
3 | 3 | use threads; |
4 | 4 | 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; | |
7 | 7 | |
8 | 8 | # Single base. |
9 | 9 | |
10 | 10 | 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; | |
14 | 12 | |
15 | 13 | # Serial: |
16 | 14 | # my $base = 2; |
30 | 28 | |
31 | 29 | # Parallel: |
32 | 30 | 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 | |
34 | 32 | $maxn = 2047; |
35 | my $nextn = 2049; | |
36 | 33 | 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; | |
38 | 35 | # We should sit here doing cond_waits on a results array. |
39 | 36 | $_->join() for (@threads); |
40 | 37 | |
41 | 38 | sub search_bases { |
42 | 39 | 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); | |
46 | 42 | for my $n (@composites) { |
47 | 43 | if (is_strong_pseudoprime($n,$base)) { |
48 | 44 | if ($n > $maxn) { |
49 | 45 | lock($maxn); |
50 | print "base $base good up to $n\n"; | |
46 | print "base $base good up to $n\n" if $n > $maxn; | |
51 | 47 | $maxn = $n; |
52 | $nextn = $n+2; $nextn++ while is_prime($nextn); | |
53 | 48 | } |
54 | 49 | last; |
55 | 50 | } |
56 | 51 | } |
57 | $base += $t; | |
58 | 52 | } |
59 | 53 | } |
60 | 54 | |
61 | 55 | __END__ |
62 | 56 | |
63 | 57 | 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 | |
73 | 66 | 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 | |
76 | 68 | 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 | |
79 | 70 | |
80 | 71 | (best results known, not found with this program) |
81 | 72 | 2011-02-12 base 814494960528 good up to 132239 |
83 | 74 | 2012-10-15 base 1769236083487960 good up to 192001 |
84 | 75 | 2012-10-17 base 1948244569546278 good up to 212321 |
85 | 76 | 2013-01-14 base 34933608779780163 good up to 218245 |
77 | 2013-03-03 base 9345883071009581737 good up to 341531 |
2 | 2 | use warnings; |
3 | 3 | use threads; |
4 | 4 | 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 | ||
6 | 18 | use Math::Prime::Util ':all'; |
7 | 19 | use Time::HiRes qw(gettimeofday tv_interval); |
8 | 20 | $| = 1; |
50 | 62 | my @karray : shared; # array of min k for each thread |
51 | 63 | |
52 | 64 | my @threads; |
53 | push @threads, threads->create('fibprime', $_) for (1..$nthreads); | |
65 | push @threads, threads->create('fibprime', $_) for 1 .. $nthreads; | |
54 | 66 | |
55 | 67 | # Let the threads work for a little before starting the display loop |
56 | 68 | sleep 2; |
79 | 91 | |
80 | 92 | sub fib_n { |
81 | 93 | 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)) | |
83 | 95 | unless defined $fibstate->[0]; |
84 | 96 | my ($curn, $a, $b) = @$fibstate; |
85 | 97 | 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); |
5 | 5 | next_prime nth_prime_upper prime_precalc forprimes/; |
6 | 6 | |
7 | 7 | 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 | |
8 | 10 | |
9 | 11 | # Find Sophie Germain primes (numbers where p and 2p+1 are both prime). |
10 | 12 | |
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: | |
15 | 16 | # |
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 | } | |
29 | 31 | |
30 | 32 | |
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 | ||
38 | 78 | } |
39 | my $sgit = get_sophie_germain_iterator(); | |
40 | print $sgit->(), "\n" for 1 .. $count; | |
41 | 79 | |
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 ); | |
53 | 94 | |
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 | #!/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 | #!/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 | #!/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 | #!/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 | } |
1 | 1 | use strict; |
2 | 2 | use warnings; |
3 | 3 | |
4 | use Math::Prime::Util qw/-nobigint | |
5 | prime_iterator prime_iterator_object | |
4 | use Math::Prime::Util qw/prime_iterator prime_iterator_object | |
6 | 5 | next_prime is_prime |
7 | 6 | nth_prime_upper prime_precalc/; |
8 | 7 | |
11 | 10 | # Find twin primes (numbers where p and p+2 are prime) |
12 | 11 | |
13 | 12 | # Time for the first 300k: |
13 | # | |
14 | # Not iterators: | |
15 | # 0.6s forprimes { say $l if $l+2==$_; $l=$_; } 64764841 | |
14 | 16 | # 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) | |
24 | 32 | |
25 | 33 | # This speeds things up, but isn't necessary. |
26 | 34 | my $estimate = 5000 + int( nth_prime_upper($count) * 1.4 * log($count) ); |
366 | 366 | fail "BLS15: $n failed 2Q-1 > sqrt(N)" unless 2*$q-1 > $n->copy->bsqrt(); |
367 | 367 | my $D = $lp*$lp - 4*$lq; |
368 | 368 | 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; | |
370 | 370 | fail "BLS15: $n failed V_{m/2} mod N != 0" |
371 | 371 | unless (lucas_sequence($n, $lp, $lq, $m/2))[1] != 0; |
372 | 372 | fail "BLS15: $n failed V_{(N+1)/2} mod N == 0" |
562 | 562 | } |
563 | 563 | 0; |
564 | 564 | } |
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 | } |
89 | 89 | |
90 | 90 | /* loop over each remaining factor, until ntofac == 0 */ |
91 | 91 | 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)) ) { | |
93 | 94 | int split_success = 0; |
94 | 95 | /* 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; | |
96 | 97 | UV const sq_rounds =100000; /* 20k 91%, 40k 98%, 80k 99.9%, 120k 99.99% */ |
97 | 98 | |
98 | 99 | /* 99.7% of 32-bit, 94% of 64-bit random inputs factored here */ |
106 | 107 | if (verbose) printf("squfof %d\n", split_success); |
107 | 108 | } |
108 | 109 | /* 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 */ | |
110 | 110 | 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; | |
112 | 112 | 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 | } | |
124 | 122 | } |
125 | 123 | |
126 | 124 | if (split_success) { |
130 | 128 | croak("bad factor\n"); |
131 | 129 | n = tofac_stack[ntofac]; /* Set n to the other one */ |
132 | 130 | } else { |
133 | /* Factor via trial division. Nothing should make it here. */ | |
131 | /* Factor via trial division. Nothing should ever get here. */ | |
134 | 132 | UV m = f % 30; |
135 | 133 | UV limit = isqrt(n); |
136 | 134 | if (verbose) printf("doing trial on %"UVuf"\n", n); |
660 | 658 | } |
661 | 659 | |
662 | 660 | /* 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) | |
664 | 662 | { |
665 | 663 | UV X0 = *cX; |
666 | 664 | UV X = *cX; |
667 | 665 | UV Y = mulsubmod(X, X, 2, n); |
668 | unsigned long bit = 1UL << (clz(exp)-1); | |
666 | UV bit = UVCONST(1) << (clz(exp)-1); | |
669 | 667 | while (bit) { |
670 | 668 | UV T = mulsubmod(X, Y, X0, n); |
671 | 669 | if ( exp & bit ) { |
909 | 907 | } |
910 | 908 | |
911 | 909 | UV dlp_trial(UV a, UV g, UV p, UV maxrounds) { |
912 | UV t, n = 1; | |
910 | UV t, k = 1; | |
913 | 911 | 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); | |
916 | 914 | if (t == a) |
917 | return n; | |
915 | return k; | |
918 | 916 | } |
919 | 917 | return 0; |
920 | 918 | } |
939 | 937 | pollard_rho_cycle(u,v,w,p,n,a,g); /* xi, ai, bi */ |
940 | 938 | pollard_rho_cycle(U,V,W,p,n,a,g); |
941 | 939 | 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 ); | |
943 | 941 | if (u == U) { |
944 | 942 | UV r1, r2, k; |
945 | 943 | r1 = submod(v, V, n); |
950 | 948 | r2 = submod(W, w, n); |
951 | 949 | k = divmod(r2, r1, n); |
952 | 950 | 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); | |
955 | 953 | return 0; |
956 | 954 | } |
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); | |
958 | 956 | return k; |
959 | 957 | } |
960 | 958 | } |
4 | 4 | |
5 | 5 | BEGIN { |
6 | 6 | $Math::Prime::Util::ECAffinePoint::AUTHORITY = 'cpan:DANAJ'; |
7 | $Math::Prime::Util::ECAffinePoint::VERSION = '0.36'; | |
7 | $Math::Prime::Util::ECAffinePoint::VERSION = '0.37'; | |
8 | 8 | } |
9 | 9 | |
10 | 10 | BEGIN { |
198 | 198 | |
199 | 199 | =head1 VERSION |
200 | 200 | |
201 | Version 0.36 | |
201 | Version 0.37 | |
202 | 202 | |
203 | 203 | |
204 | 204 | =head1 SYNOPSIS |
4 | 4 | |
5 | 5 | BEGIN { |
6 | 6 | $Math::Prime::Util::ECProjectivePoint::AUTHORITY = 'cpan:DANAJ'; |
7 | $Math::Prime::Util::ECProjectivePoint::VERSION = '0.36'; | |
7 | $Math::Prime::Util::ECProjectivePoint::VERSION = '0.37'; | |
8 | 8 | } |
9 | 9 | |
10 | 10 | BEGIN { |
206 | 206 | |
207 | 207 | =head1 VERSION |
208 | 208 | |
209 | Version 0.36 | |
209 | Version 0.37 | |
210 | 210 | |
211 | 211 | |
212 | 212 | =head1 SYNOPSIS |
3 | 3 | |
4 | 4 | BEGIN { |
5 | 5 | $Math::Prime::Util::MemFree::AUTHORITY = 'cpan:DANAJ'; |
6 | $Math::Prime::Util::MemFree::VERSION = '0.36'; | |
6 | $Math::Prime::Util::MemFree::VERSION = '0.37'; | |
7 | 7 | } |
8 | 8 | |
9 | 9 | use base qw( Exporter ); |
43 | 43 | |
44 | 44 | =head1 VERSION |
45 | 45 | |
46 | Version 0.36 | |
46 | Version 0.37 | |
47 | 47 | |
48 | 48 | |
49 | 49 | =head1 SYNOPSIS |
4 | 4 | |
5 | 5 | BEGIN { |
6 | 6 | $Math::Prime::Util::PP::AUTHORITY = 'cpan:DANAJ'; |
7 | $Math::Prime::Util::PP::VERSION = '0.36'; | |
7 | $Math::Prime::Util::PP::VERSION = '0.37'; | |
8 | 8 | } |
9 | 9 | |
10 | 10 | BEGIN { |
39 | 39 | use constant BTWO => Math::BigInt->new(2); |
40 | 40 | use constant B_PRIM759 => Math::BigInt->new("64092011671807087969"); |
41 | 41 | use constant B_PRIM235 => Math::BigInt->new("30"); |
42 | use constant PI_TIMES_8 => 25.13274122871834590770114707; | |
42 | 43 | } |
43 | 44 | |
44 | 45 | { |
71 | 72 | } |
72 | 73 | |
73 | 74 | 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 | ||
77 | 107 | |
78 | 108 | sub _validate_num { |
79 | 109 | my($n, $min, $max) = @_; |
123 | 153 | 101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191, |
124 | 154 | 193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283, |
125 | 155 | 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); | |
131 | 157 | my @_prime_next_small = ( |
132 | 158 | 2,2,3,5,5,7,7,11,11,11,11,13,13,17,17,17,17,19,19,23,23,23,23, |
133 | 159 | 29,29,29,29,29,29,31,31,37,37,37,37,37,37,41,41,41,41,43,43,47, |
137 | 163 | my @_prime_indices = (1, 7, 11, 13, 17, 19, 23, 29); |
138 | 164 | 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); |
139 | 165 | 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 | } | |
140 | 179 | |
141 | 180 | sub _is_prime7 { # n must not be divisible by 2, 3, or 5 |
142 | 181 | my($n) = @_; |
211 | 250 | |
212 | 251 | sub is_prime { |
213 | 252 | my($n) = @_; |
214 | return 0 if defined $n && int($n) < 0; | |
253 | return 0 if int($n) < 0; | |
215 | 254 | _validate_positive_integer($n); |
216 | 255 | |
217 | 256 | if (ref($n) eq 'Math::BigInt') { |
370 | 409 | } |
371 | 410 | |
372 | 411 | 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 | } | |
378 | 420 | my $sref = []; |
379 | ||
380 | _validate_positive_integer($low); | |
381 | _validate_positive_integer($high); | |
382 | ||
383 | 421 | return $sref if ($low > $high) || ($high < 2); |
384 | ||
385 | # Ignore method options in this code | |
386 | 422 | |
387 | 423 | # At some point even the pretty-fast pure perl sieve is going to be a |
388 | 424 | # dog, and we should move to trials. This is typical with a small range |
493 | 529 | #$d*30+$m; |
494 | 530 | } |
495 | 531 | |
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 | ||
496 | 591 | sub jordan_totient { |
497 | 592 | my($k, $n) = @_; |
498 | _validate_num($k) || _validate_positive_integer($k); | |
499 | 593 | return ($n == 1) ? 1 : 0 if $k == 0; |
500 | 594 | 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; | |
503 | 596 | return ($n == 1) ? 1 : 0 if $n <= 1; |
504 | 597 | |
505 | 598 | my @pe = Math::Prime::Util::factor_exp($n); |
517 | 610 | } |
518 | 611 | |
519 | 612 | sub euler_phi { |
613 | return euler_phi_range(@_) if scalar @_ > 1; | |
520 | 614 | my($n) = @_; |
521 | 615 | return 0 if $n < 0; |
522 | 616 | return $n if $n <= 1; |
566 | 660 | } |
567 | 661 | |
568 | 662 | sub moebius { |
663 | return moebius_range(@_) if scalar @_ > 1; | |
569 | 664 | my($n) = @_; |
570 | 665 | return ($n == 1) ? 1 : 0 if $n <= 1; |
571 | 666 | return 0 if ($n >= 49) && (!($n % 4) || !($n % 9) || !($n % 25) || !($n%49) ); |
613 | 708 | return @mu; |
614 | 709 | } |
615 | 710 | |
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 | ||
616 | 778 | my @_ds_overflow = # We'll use BigInt math if the input is larger than this. |
617 | 779 | (~0 > 4294967295) |
618 | 780 | ? (124, 3000000000000000000, 3000000000, 2487240, 64260, 7026) |
619 | 781 | : ( 50, 845404560, 52560, 1548, 252, 84); |
620 | 782 | sub divisor_sum { |
621 | 783 | my($n, $k) = @_; |
622 | return 1 if defined $n && $n == 1; | |
784 | return 1 if $n == 1; | |
623 | 785 | |
624 | 786 | if (defined $k && ref($k) eq 'CODE') { |
625 | 787 | 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 ); | |
635 | 791 | } |
636 | 792 | return $sum; |
637 | 793 | } |
909 | 1065 | $prime; |
910 | 1066 | } |
911 | 1067 | |
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 | ||
912 | 1335 | sub _mulmod { |
913 | 1336 | my($x, $y, $n) = @_; |
914 | 1337 | return (($x * $y) % $n) if ($x|$y) < MPU_HALFWORD; |
1020 | 1443 | |
1021 | 1444 | sub is_pseudoprime { |
1022 | 1445 | my($n, $base) = @_; |
1023 | return 0 if defined $n && int($n) < 0; | |
1446 | return 0 if int($n) < 0; | |
1024 | 1447 | _validate_positive_integer($n); |
1025 | _validate_positive_integer($base); | |
1026 | 1448 | |
1027 | 1449 | if ($n < 5) { return ($n == 2) || ($n == 3) ? 1 : 0; } |
1028 | 1450 | croak "Base $base is invalid" if $base < 2; |
1093 | 1515 | |
1094 | 1516 | sub is_strong_pseudoprime { |
1095 | 1517 | my($n, @bases) = @_; |
1096 | return 0 if defined $n && int($n) < 0; | |
1518 | return 0 if int($n) < 0; | |
1097 | 1519 | _validate_positive_integer($n); |
1098 | croak "No bases given to miller_rabin" unless @bases; | |
1099 | 1520 | |
1100 | 1521 | return 0+($n >= 2) if $n < 4; |
1101 | 1522 | return 0 if ($n % 2) == 0; |
1233 | 1654 | |
1234 | 1655 | sub znorder { |
1235 | 1656 | my($a, $n) = @_; |
1236 | _validate_num($a) || _validate_positive_integer($a); | |
1237 | _validate_num($n) || _validate_positive_integer($n); | |
1238 | 1657 | return if $n <= 0; |
1239 | 1658 | return (undef,1)[$a] if $a <= 1; |
1240 | 1659 | return 1 if $n == 1; |
1275 | 1694 | sub znlog { |
1276 | 1695 | my ($a,$g,$p) = |
1277 | 1696 | 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); | |
1280 | 1699 | 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; | |
1283 | 1702 | } |
1284 | 1703 | } |
1285 | 1704 | return; |
1286 | 1705 | } |
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 | ||
1287 | 1739 | |
1288 | 1740 | # Find first D in sequence (5,-7,9,-11,13,-15,...) where (D|N) == -1 |
1289 | 1741 | sub _lucas_selfridge_params { |
1416 | 1868 | |
1417 | 1869 | sub is_lucas_pseudoprime { |
1418 | 1870 | my($n) = @_; |
1419 | return 0 if defined $n && int($n) < 0; | |
1420 | _validate_positive_integer($n); | |
1421 | 1871 | |
1422 | 1872 | return 0+($n >= 2) if $n < 4; |
1423 | 1873 | return 0 if ($n % 2) == 0 || _is_perfect_square($n); |
1432 | 1882 | |
1433 | 1883 | sub is_strong_lucas_pseudoprime { |
1434 | 1884 | my($n) = @_; |
1435 | return 0 if defined $n && int($n) < 0; | |
1436 | _validate_positive_integer($n); | |
1437 | 1885 | |
1438 | 1886 | return 0+($n >= 2) if $n < 4; |
1439 | 1887 | return 0 if ($n % 2) == 0 || _is_perfect_square($n); |
1463 | 1911 | |
1464 | 1912 | sub is_extra_strong_lucas_pseudoprime { |
1465 | 1913 | my($n) = @_; |
1466 | return 0 if defined $n && int($n) < 0; | |
1467 | _validate_positive_integer($n); | |
1468 | 1914 | |
1469 | 1915 | return 0+($n >= 2) if $n < 4; |
1470 | 1916 | return 0 if ($n % 2) == 0 || _is_perfect_square($n); |
1495 | 1941 | |
1496 | 1942 | sub is_almost_extra_strong_lucas_pseudoprime { |
1497 | 1943 | 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; | |
1505 | 1945 | |
1506 | 1946 | return 0+($n >= 2) if $n < 4; |
1507 | 1947 | return 0 if ($n % 2) == 0 || _is_perfect_square($n); |
1540 | 1980 | |
1541 | 1981 | sub is_frobenius_underwood_pseudoprime { |
1542 | 1982 | my($n) = @_; |
1543 | return 0 if defined $n && int($n) < 0; | |
1544 | _validate_positive_integer($n); | |
1545 | 1983 | return 0+($n >= 2) if $n < 4; |
1546 | 1984 | return 0 if ($n % 2) == 0 || _is_perfect_square($n); |
1547 | 1985 | |
1658 | 2096 | |
1659 | 2097 | sub is_aks_prime { |
1660 | 2098 | 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); | |
1666 | 2100 | |
1667 | 2101 | my($log2n, $limit); |
1668 | 2102 | if ($n > 2**48) { |
1727 | 2161 | while ( !($_[0] % 3) ) { push @factors, 3; $_[0] = int($_[0] / 3); } |
1728 | 2162 | while ( !($_[0] % 5) ) { push @factors, 5; $_[0] = int($_[0] / 5); } |
1729 | 2163 | } 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(); | |
1730 | 2167 | if (!Math::BigInt::bgcd($_[0], B_PRIM235)->is_one) { |
1731 | 2168 | while ( $_[0]->is_even) { push @factors, 2; $_[0]->brsft(BONE); } |
1732 | 2169 | foreach my $div (3, 5) { |
1921 | 2358 | |
1922 | 2359 | sub prho_factor { |
1923 | 2360 | my($n, $rounds, $pa) = @_; |
1924 | _validate_positive_integer($n); | |
1925 | 2361 | $rounds = 4*1024*1024 unless defined $rounds; |
1926 | 2362 | $pa = 3 unless defined $pa; |
1927 | 2363 | |
1991 | 2427 | |
1992 | 2428 | sub pbrent_factor { |
1993 | 2429 | my($n, $rounds, $pa) = @_; |
1994 | _validate_positive_integer($n); | |
1995 | 2430 | $rounds = 4*1024*1024 unless defined $rounds; |
1996 | 2431 | $pa = 3 unless defined $pa; |
1997 | 2432 | |
2072 | 2507 | |
2073 | 2508 | sub pminus1_factor { |
2074 | 2509 | my($n, $B1, $B2) = @_; |
2075 | _validate_positive_integer($n); | |
2076 | 2510 | |
2077 | 2511 | my @factors = _basic_factor($n); |
2078 | 2512 | return @factors if $n < 4; |
2221 | 2655 | |
2222 | 2656 | sub holf_factor { |
2223 | 2657 | my($n, $rounds, $startrounds) = @_; |
2224 | _validate_positive_integer($n); | |
2225 | 2658 | $rounds = 64*1024*1024 unless defined $rounds; |
2226 | 2659 | $startrounds = 1 unless defined $startrounds; |
2227 | 2660 | $startrounds = 1 if $startrounds < 1; |
2268 | 2701 | |
2269 | 2702 | sub fermat_factor { |
2270 | 2703 | my($n, $rounds) = @_; |
2271 | _validate_positive_integer($n); | |
2272 | 2704 | $rounds = 64*1024*1024 unless defined $rounds; |
2273 | 2705 | |
2274 | 2706 | my @factors = _basic_factor($n); |
2318 | 2750 | |
2319 | 2751 | sub ecm_factor { |
2320 | 2752 | my($n, $B1, $B2, $ncurves) = @_; |
2321 | _validate_positive_integer($n); | |
2322 | 2753 | |
2323 | 2754 | my @factors = _basic_factor($n); |
2324 | 2755 | return @factors if $n < 4; |
2372 | 2803 | # } |
2373 | 2804 | #} |
2374 | 2805 | |
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; | |
2379 | 2808 | |
2380 | 2809 | # With multiple curves, it's better to get all the primes at once. |
2381 | 2810 | # The downside is this can kill memory with a very large B1. |
2387 | 2816 | $q = $k; |
2388 | 2817 | } |
2389 | 2818 | 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(); | |
2391 | 2820 | |
2392 | 2821 | foreach my $curve (1 .. $ncurves) { |
2393 | 2822 | my $sigma = $irandf->($n-1-6) + 6; |
2498 | 2927 | @factors; |
2499 | 2928 | } |
2500 | 2929 | |
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 | } | |
2502 | 2993 | |
2503 | 2994 | sub ExponentialIntegral { |
2504 | 2995 | my($x) = @_; |
2514 | 3005 | do { require Math::BigFloat; Math::BigFloat->import(); } |
2515 | 3006 | if !defined $Math::BigFloat::VERSION; |
2516 | 3007 | $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; | |
2519 | 3010 | } |
2520 | 3011 | my $rnd = 0; # MPFR_RNDN; |
2521 | 3012 | my $bit_precision = int($xdigits * 3.322) + 4; |
2526 | 3017 | Math::MPFR::Rmpfr_set_prec($eix, $bit_precision); |
2527 | 3018 | Math::MPFR::Rmpfr_eint($eix, $rx, $rnd); |
2528 | 3019 | 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; | |
2530 | 3021 | } |
2531 | 3022 | |
2532 | 3023 | $x = Math::BigFloat->new("$x") if defined $bignum::VERSION && ref($x) ne 'Math::BigFloat'; |
2613 | 3104 | my $wantbf = 0; |
2614 | 3105 | my $xdigits = 18; |
2615 | 3106 | 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; | |
2618 | 3109 | } |
2619 | 3110 | $xdigits += length(int(log(0.0+"$x"))) + 1; |
2620 | 3111 | my $rnd = 0; # MPFR_RNDN; |
2627 | 3118 | Math::MPFR::Rmpfr_set_prec($lix, $bit_precision); |
2628 | 3119 | Math::MPFR::Rmpfr_eint($lix, $rx, $rnd); |
2629 | 3120 | 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; | |
2633 | 3122 | } |
2634 | 3123 | |
2635 | 3124 | if ($x == 2) { |
2648 | 3137 | my $xdigits = 0; |
2649 | 3138 | my $finalacc = 0; |
2650 | 3139 | if (ref($x) =~ /^Math::Big/) { |
2651 | $xdigits = $x->accuracy || Math::BigFloat->accuracy() || Math::BigFloat->div_scale(); | |
3140 | $xdigits = _find_big_acc($x); | |
2652 | 3141 | my $xlen = length($x->bfloor->bstr()); |
2653 | 3142 | $xdigits = $xlen if $xdigits < $xlen; |
2654 | 3143 | $finalacc = $xdigits; |
2761 | 3250 | $x->accuracy($xacc) if $xacc; |
2762 | 3251 | } |
2763 | 3252 | $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; | |
2766 | 3255 | } |
2767 | 3256 | my $rnd = 0; # MPFR_RNDN; |
2768 | 3257 | my $bit_precision = int($xdigits * 3.322) + 7; |
2776 | 3265 | Math::MPFR::Rmpfr_zeta($zetax, $rx, $rnd); |
2777 | 3266 | Math::MPFR::Rmpfr_sub_ui($zetax, $zetax, 1, $rnd); |
2778 | 3267 | 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; | |
2780 | 3269 | } |
2781 | 3270 | |
2782 | 3271 | if (defined $bignum::VERSION || ref($x) =~ /^Math::Big/) { |
2850 | 3339 | $x->accuracy($xacc) if $xacc; |
2851 | 3340 | } |
2852 | 3341 | $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; | |
2855 | 3344 | } |
2856 | 3345 | my $rnd = 0; # MPFR_RNDN; |
2857 | 3346 | my $bit_precision = int($xdigits * 3.322) + 8; # Add some extra |
2892 | 3381 | Math::MPFR::Rmpfr_add($rsum, $rsum, $rterm, $rnd); |
2893 | 3382 | } |
2894 | 3383 | 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; | |
2896 | 3385 | } |
2897 | 3386 | |
2898 | 3387 | if (defined $bignum::VERSION || ref($x) =~ /^Math::Big/) { |
2941 | 3430 | |
2942 | 3431 | =head1 VERSION |
2943 | 3432 | |
2944 | Version 0.36 | |
3433 | Version 0.37 | |
2945 | 3434 | |
2946 | 3435 | |
2947 | 3436 | =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 |
10 | 10 | |
11 | 11 | BEGIN { |
12 | 12 | $Math::Prime::Util::PrimalityProving::AUTHORITY = 'cpan:DANAJ'; |
13 | $Math::Prime::Util::PrimalityProving::VERSION = '0.36'; | |
13 | $Math::Prime::Util::PrimalityProving::VERSION = '0.37'; | |
14 | 14 | } |
15 | 15 | |
16 | 16 | BEGIN { |
55 | 55 | "N $n", |
56 | 56 | ""; |
57 | 57 | } |
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 | ||
58 | 66 | |
59 | 67 | sub primality_proof_lucas { |
60 | 68 | my ($n) = shift; |
95 | 103 | carp "could not prove primality of $n.\n"; |
96 | 104 | return (1, ''); |
97 | 105 | } |
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; | |
99 | 107 | } |
100 | 108 | $cert .= "A $a\n"; |
101 | 109 | foreach my $proof (@fac_proofs) { |
116 | 124 | return @composite if ($n & 1) == 0; |
117 | 125 | return @composite if is_strong_pseudoprime($n,2,15,325) == 0; |
118 | 126 | |
127 | require Math::Prime::Util::PP; | |
119 | 128 | $n = Math::BigInt->new("$n") unless ref($n) eq 'Math::BigInt'; |
120 | 129 | my $nm1 = $n->copy->bdec; |
121 | 130 | my $ONE = $nm1->copy->bone; |
228 | 237 | carp "could not prove primality of $n.\n"; |
229 | 238 | return (1, ''); |
230 | 239 | } |
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; | |
232 | 241 | } |
233 | 242 | $cert .= $atext; |
234 | 243 | $cert .= "----\n"; |
854 | 863 | |
855 | 864 | =head1 VERSION |
856 | 865 | |
857 | Version 0.36 | |
866 | Version 0.37 | |
858 | 867 | |
859 | 868 | |
860 | 869 | =head1 SYNOPSIS |
3 | 3 | |
4 | 4 | BEGIN { |
5 | 5 | $Math::Prime::Util::PrimeArray::AUTHORITY = 'cpan:DANAJ'; |
6 | $Math::Prime::Util::PrimeArray::VERSION = '0.36'; | |
6 | $Math::Prime::Util::PrimeArray::VERSION = '0.37'; | |
7 | 7 | } |
8 | 8 | |
9 | 9 | # parent is cleaner, and in the Perl 5.10.1 / 5.12.0 core, but not earlier. |
134 | 134 | |
135 | 135 | =head1 VERSION |
136 | 136 | |
137 | Version 0.36 | |
137 | Version 0.37 | |
138 | 138 | |
139 | 139 | |
140 | 140 | =head1 SYNOPSIS |
3 | 3 | |
4 | 4 | BEGIN { |
5 | 5 | $Math::Prime::Util::PrimeIterator::AUTHORITY = 'cpan:DANAJ'; |
6 | $Math::Prime::Util::PrimeIterator::VERSION = '0.36'; | |
6 | $Math::Prime::Util::PrimeIterator::VERSION = '0.37'; | |
7 | 7 | } |
8 | 8 | |
9 | 9 | use base qw( Exporter ); |
126 | 126 | |
127 | 127 | =head1 VERSION |
128 | 128 | |
129 | Version 0.36 | |
129 | Version 0.37 | |
130 | 130 | |
131 | 131 | |
132 | 132 | =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 |
3 | 3 | |
4 | 4 | BEGIN { |
5 | 5 | $Math::Prime::Util::ZetaBigFloat::AUTHORITY = 'cpan:DANAJ'; |
6 | $Math::Prime::Util::ZetaBigFloat::VERSION = '0.36'; | |
6 | $Math::Prime::Util::ZetaBigFloat::VERSION = '0.37'; | |
7 | 7 | } |
8 | 8 | |
9 | 9 | BEGIN { |
279 | 279 | $sum_n->bmul($d)->badd( $sum_d->copy->bmul($n) ); |
280 | 280 | $sum_d->bmul($d); |
281 | 281 | $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; | |
283 | 286 | my $dmul = (2*$i+1) * (2*$i+2); |
284 | 287 | $n->bmul($nterms+$i)->blsft(2); |
285 | 288 | $d->bdiv($nterms-$i)->bmul($dmul); |
468 | 471 | |
469 | 472 | =head1 VERSION |
470 | 473 | |
471 | Version 0.36 | |
474 | Version 0.37 | |
472 | 475 | |
473 | 476 | |
474 | 477 | =head1 SYNOPSIS |
4 | 4 | |
5 | 5 | BEGIN { |
6 | 6 | $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 | } | |
17 | 9 | |
18 | 10 | # parent is cleaner, and in the Perl 5.10.1 / 5.12.0 core, but not earlier. |
19 | 11 | # use parent qw( Exporter ); |
74 | 66 | # We could alternately use Config's $Config{uvsize} for MAXBITS |
75 | 67 | use constant OLD_PERL_VERSION=> $] < 5.008; |
76 | 68 | use constant MPU_MAXBITS => (~0 == 4294967295) ? 32 : 64; |
77 | use constant MPU_64BIT => MPU_MAXBITS == 64; | |
78 | 69 | use constant MPU_32BIT => MPU_MAXBITS == 32; |
79 | 70 | use constant MPU_MAXPARAM => MPU_32BIT ? 4294967295 : 18446744073709551615; |
80 | 71 | use constant MPU_MAXDIGITS => MPU_32BIT ? 10 : 20; |
81 | 72 | use constant MPU_MAXPRIME => MPU_32BIT ? 4294967291 : 18446744073709551557; |
82 | 73 | use constant MPU_MAXPRIMEIDX => MPU_32BIT ? 203280221 : 425656284035217743; |
83 | 74 | 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(); | |
87 | 75 | |
88 | 76 | eval { |
89 | 77 | return 0 if defined $ENV{MPU_NO_XS} && $ENV{MPU_NO_XS} == 1; |
100 | 88 | $_Config{'xs'} = 0; |
101 | 89 | $_Config{'maxbits'} = MPU_MAXBITS; |
102 | 90 | |
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 | ||
114 | 94 | *next_prime = \&Math::Prime::Util::_generic_next_prime; |
115 | 95 | *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; | |
121 | 96 | *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; | |
132 | 97 | *factor = \&Math::Prime::Util::_generic_factor; |
133 | 98 | *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. | |
152 | 99 | }; |
153 | 100 | |
154 | 101 | # aliases for deprecated names. Will eventually be removed. |
217 | 164 | } elsif ($param eq 'irand') { |
218 | 165 | croak "irand must supply a sub" unless (!defined $value) || (ref($value) eq 'CODE'); |
219 | 166 | $_Config{'irand'} = $value; |
220 | _clear_randf(); # Force a new randf to be generated | |
221 | 167 | } elsif ($param =~ /^(assume[_ ]?)?[ge]?rh$/ || $param =~ /riemann\s*h/) { |
222 | 168 | $_Config{'assume_rh'} = ($value) ? 1 : 0; |
223 | 169 | } elsif ($param eq 'verbose') { |
235 | 181 | 1; |
236 | 182 | } |
237 | 183 | |
238 | ||
239 | 184 | sub _bigint_to_int { |
240 | 185 | return (OLD_PERL_VERSION) ? unpack(UVPACKLET,pack(UVPACKLET,$_[0]->bstr)) |
241 | 186 | : int($_[0]->bstr); |
242 | 187 | } |
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]"); | |
267 | 197 | } |
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 | } | |
273 | 235 | |
274 | 236 | |
275 | 237 | ############################################################################# |
276 | 238 | |
277 | 239 | 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 | } | |
286 | 248 | |
287 | 249 | my $sref = []; |
288 | 250 | return $sref if ($low > $high) || ($high < 2); |
298 | 260 | } |
299 | 261 | return $sref; |
300 | 262 | } |
263 | require Math::Prime::Util::PP; | |
301 | 264 | return Math::Prime::Util::PP::primes($low,$high); |
302 | 265 | } |
303 | 266 | |
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 | ||
340 | 287 | } |
341 | 288 | |
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: | |
354 | 290 | # 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. | |
359 | 292 | return $sref; |
360 | 293 | } |
361 | 294 | |
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) { | |
818 | 302 | _validate_num($low) || _validate_positive_integer($low); |
819 | 303 | _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); | |
829 | 307 | } |
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. | |
1199 | 383 | |
1200 | 384 | sub primorial { |
1201 | 385 | my($n) = @_; |
1202 | 386 | _validate_num($n) || _validate_positive_integer($n); |
1203 | 387 | |
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)); | |
1227 | 390 | } |
1228 | return $pn; | |
391 | require Math::Prime::Util::PP; | |
392 | return Math::Prime::Util::PP::primorial($n); | |
1229 | 393 | } |
1230 | 394 | |
1231 | 395 | sub pn_primorial { |
1232 | 396 | my($n) = @_; |
397 | _validate_num($n) || _validate_positive_integer($n); | |
1233 | 398 | |
1234 | 399 | 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)); | |
1237 | 401 | } |
1238 | 402 | |
1239 | return primorial(nth_prime($n)); | |
403 | require Math::Prime::Util::PP; | |
404 | return Math::Prime::Util::PP::primorial(nth_prime($n)); | |
1240 | 405 | } |
1241 | 406 | |
1242 | 407 | sub consecutive_integer_lcm { |
1244 | 409 | _validate_num($n) || _validate_positive_integer($n); |
1245 | 410 | return 0 if $n < 1; |
1246 | 411 | |
1247 | my $max = (MPU_32BIT) ? 22 : (OLD_PERL_VERSION) ? 37 : 46; | |
1248 | ||
1249 | 412 | 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)); | |
1252 | 414 | } |
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; | |
1271 | 429 | _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)); | |
1305 | 433 | } |
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 { | |
1328 | 445 | my($sub, $beg, $end) = @_; |
1329 | 446 | 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); | |
1332 | 449 | $beg = 2 if $beg < 2; |
1333 | 450 | { |
1334 | 451 | my $pp; |
1340 | 457 | } |
1341 | 458 | } |
1342 | 459 | |
1343 | sub _generic_forcomposites(&$;$) { ## no critic qw(ProhibitSubroutinePrototypes) | |
460 | sub _generic_forcomposites { | |
1344 | 461 | my($sub, $beg, $end) = @_; |
1345 | 462 | 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); | |
1348 | 465 | $beg = 4 if $beg < 4; |
1349 | 466 | $end = Math::BigInt->new(''.~0) if ref($end) ne 'Math::BigInt' && $end == ~0; |
1350 | 467 | { |
1359 | 476 | } |
1360 | 477 | } |
1361 | 478 | |
1362 | sub _generic_fordivisors (&$) { ## no critic qw(ProhibitSubroutinePrototypes) | |
479 | sub _generic_fordivisors { | |
1363 | 480 | my($sub, $n) = @_; |
1364 | _validate_num($n) || _validate_positive_integer($n); | |
481 | _validate_positive_integer($n); | |
1365 | 482 | my @divisors = divisors($n); |
1366 | 483 | { |
1367 | 484 | my $pp; |
1373 | 490 | } |
1374 | 491 | } |
1375 | 492 | |
493 | ############################################################################# | |
494 | # Iterators | |
495 | ||
1376 | 496 | sub prime_iterator { |
1377 | 497 | my($start) = @_; |
1378 | 498 | $start = 0 unless defined $start; |
1379 | 499 | _validate_num($start) || _validate_positive_integer($start); |
1380 | 500 | 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 | |
1381 | 504 | if (ref($p) ne 'Math::BigInt' && $p <= $_XS_MAXVAL) { |
1382 | 505 | return sub { $p = next_prime($p); return $p; }; |
1383 | 506 | } elsif ($_HAVE_GMP) { |
1384 | 507 | return sub { $p = $p-$p+Math::Prime::Util::GMP::next_prime($p); return $p;}; |
1385 | 508 | } else { |
509 | require Math::Prime::Util::PP; | |
1386 | 510 | return sub { $p = Math::Prime::Util::PP::next_prime($p); return $p; } |
1387 | 511 | } |
1388 | 512 | } |
1389 | 513 | |
1390 | 514 | sub prime_iterator_object { |
1391 | 515 | 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; | |
1394 | 517 | return Math::Prime::Util::PrimeIterator->new($start); |
1395 | 518 | } |
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 | ||
1529 | 519 | |
1530 | 520 | ############################################################################# |
1531 | 521 | # Front ends to functions. |
1539 | 529 | _validate_num($n) || _validate_positive_integer($n); |
1540 | 530 | |
1541 | 531 | 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)); | |
1545 | 533 | } |
1546 | 534 | |
535 | require Math::Prime::Util::PP; | |
1547 | 536 | return Math::Prime::Util::PP::next_prime($_[0]); |
1548 | 537 | } |
1549 | 538 | |
1552 | 541 | _validate_num($n) || _validate_positive_integer($n); |
1553 | 542 | |
1554 | 543 | 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)); | |
1558 | 545 | } |
1559 | 546 | |
547 | require Math::Prime::Util::PP; | |
1560 | 548 | 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(@_); | |
1574 | 549 | } |
1575 | 550 | |
1576 | 551 | sub _generic_prime_count { |
1590 | 565 | && ( (ref($high) eq 'Math::BigInt') |
1591 | 566 | || (($high-$low) < int($low/1_000_000)) |
1592 | 567 | ); |
568 | require Math::Prime::Util::PP; | |
1593 | 569 | return Math::Prime::Util::PP::prime_count($low,$high); |
1594 | 570 | } |
1595 | 571 | |
1608 | 584 | return @factors; |
1609 | 585 | } |
1610 | 586 | |
587 | require Math::Prime::Util::PP; | |
1611 | 588 | return Math::Prime::Util::PP::factor($n); |
1612 | 589 | } |
1613 | 590 | |
1619 | 596 | my @factors = grep { !$exponents{$_}++ } factor($n); |
1620 | 597 | return scalar @factors unless wantarray; |
1621 | 598 | 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; | |
1658 | 599 | } |
1659 | 600 | |
1660 | 601 | |
1666 | 607 | _validate_num($testP) || _validate_positive_integer($testP); } |
1667 | 608 | { my $testQ = (!defined $Q || $Q >= 0) ? $Q : -$Q; |
1668 | 609 | _validate_num($testQ) || _validate_positive_integer($testQ); } |
610 | ||
1669 | 611 | return _XS_lucas_sequence($n, $P, $Q, $k) |
1670 | 612 | if ref($_[0]) ne 'Math::BigInt' && $n <= $_XS_MAXVAL |
1671 | 613 | && ref($_[3]) ne 'Math::BigInt' && $k <= $_XS_MAXVAL; |
614 | ||
1672 | 615 | if ($_HAVE_GMP && defined &Math::Prime::Util::GMP::lucas_sequence) { |
1673 | 616 | return map { ($_ > ''.~0) ? Math::BigInt->new(''.$_) : $_ } |
1674 | 617 | Math::Prime::Util::GMP::lucas_sequence($n, $P, $Q, $k); |
1675 | 618 | } |
619 | require Math::Prime::Util::PP; | |
1676 | 620 | return map { ($_ <= ''.~0) ? _bigint_to_int($_) : $_ } |
1677 | 621 | Math::Prime::Util::PP::lucas_sequence($n, $P, $Q, $k); |
1678 | 622 | } |
1679 | 623 | |
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 | ||
1714 | 624 | |
1715 | 625 | ############################################################################# |
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 | } | |
1723 | 626 | |
1724 | 627 | # Return just the non-cert portion. |
1725 | 628 | sub is_provable_prime { |
1765 | 668 | return ($isp, $cert); |
1766 | 669 | } |
1767 | 670 | # 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; | |
1772 | 672 | return ($isp, Math::Prime::Util::PrimalityProving::convert_array_cert_to_string($cert)); |
1773 | 673 | } |
1774 | 674 | |
1791 | 691 | # AKS horribly slow |
1792 | 692 | # See http://primes.utm.edu/prove/merged.html or other sources. |
1793 | 693 | |
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; | |
1799 | 695 | #my ($isp, $pref) = Math::Prime::Util::PrimalityProving::primality_proof_lucas($n); |
1800 | 696 | my ($isp, $pref) = Math::Prime::Util::PrimalityProving::primality_proof_bls75($n); |
1801 | 697 | carp "proved $n is not prime\n" if !$isp; |
1806 | 702 | sub verify_prime { |
1807 | 703 | my @cdata = @_; |
1808 | 704 | |
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; | |
1814 | 706 | my $cert = ''; |
1815 | 707 | if (scalar @cdata == 1 && ref($cdata[0]) eq '') { |
1816 | 708 | $cert = $cdata[0]; |
1829 | 721 | |
1830 | 722 | ############################################################################# |
1831 | 723 | |
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 | ||
2108 | 724 | ############################################################################# |
2109 | 725 | |
2110 | 726 | sub RiemannZeta { |
2113 | 729 | |
2114 | 730 | return _XS_RiemannZeta($n) |
2115 | 731 | if !defined $bignum::VERSION && ref($n) ne 'Math::BigFloat' && $n <= $_XS_MAXVAL; |
732 | require Math::Prime::Util::PP; | |
2116 | 733 | return Math::Prime::Util::PP::RiemannZeta($n); |
2117 | 734 | } |
2118 | 735 | |
2122 | 739 | |
2123 | 740 | return _XS_RiemannR($n) |
2124 | 741 | if !defined $bignum::VERSION && ref($n) ne 'Math::BigFloat' && $n <= $_XS_MAXVAL; |
742 | require Math::Prime::Util::PP; | |
2125 | 743 | return Math::Prime::Util::PP::RiemannR($n); |
2126 | 744 | } |
2127 | 745 | |
2134 | 752 | return _XS_ExponentialIntegral($n) |
2135 | 753 | if !defined $bignum::VERSION && ref($n) ne 'Math::BigFloat' && $_Config{'xs'}; |
2136 | 754 | |
755 | require Math::Prime::Util::PP; | |
2137 | 756 | return Math::Prime::Util::PP::ExponentialIntegral($n); |
2138 | 757 | } |
2139 | 758 | |
2150 | 769 | return _XS_LogarithmicIntegral($n); |
2151 | 770 | } |
2152 | 771 | |
772 | require Math::Prime::Util::PP; | |
2153 | 773 | return Math::Prime::Util::PP::LogarithmicIntegral($n); |
2154 | 774 | } |
2155 | 775 | |
2178 | 798 | |
2179 | 799 | =head1 VERSION |
2180 | 800 | |
2181 | Version 0.36 | |
801 | Version 0.37 | |
2182 | 802 | |
2183 | 803 | |
2184 | 804 | =head1 SYNOPSIS |
2417 | 1037 | |
2418 | 1038 | print "$n is prime" if is_prime($n); |
2419 | 1039 | |
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. | |
2426 | 1048 | |
2427 | 1049 | Also see the L</is_prob_prime> function, which will never do additional |
2428 | 1050 | tests, and the L</is_provable_prime> function which will construct a proof |
2438 | 1060 | |
2439 | 1061 | For cryptographic key generation, you may want even more testing for probable |
2440 | 1062 | 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. | |
2447 | 1070 | |
2448 | 1071 | |
2449 | 1072 | =head2 primes |
2497 | 1120 | block for each prime in the range. Compared to getting a big array of primes |
2498 | 1121 | and iterating through it, this is more memory efficient and perhaps more |
2499 | 1122 | 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. | |
2501 | 1124 | |
2502 | 1125 | Math::BigInt objects may be used for the range. |
2503 | 1126 | |
2504 | 1127 | For some uses an iterator (L</prime_iterator>, L</prime_iterator_object>) |
2505 | 1128 | 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. | |
2512 | 1130 | |
2513 | 1131 | |
2514 | 1132 | =head2 forcomposites |
2517 | 1135 | forcomposites { say } 2000,2020; |
2518 | 1136 | |
2519 | 1137 | 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, ...> | |
2522 | 1141 | |
2523 | 1142 | |
2524 | 1143 | =head2 fordivisors |
3132 | 1751 | Agrawal-Kayal-Saxena (AKS) primality test. This is a deterministic |
3133 | 1752 | unconditional primality test which runs in polynomial time for general input. |
3134 | 1753 | |
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. | |
3141 | 1760 | |
3142 | 1761 | |
3143 | 1762 | =head2 lucas_sequence |
3147 | 1766 | Computes C<U_k>, C<V_k>, and C<Q_k> for the Lucas sequence defined by |
3148 | 1767 | C<P>,C<Q>, modulo C<n>. The modular Lucas sequence is used in a |
3149 | 1768 | number of primality tests and proofs. |
3150 | ||
3151 | 1769 | 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>. | |
3158 | 1775 | |
3159 | 1776 | |
3160 | 1777 | =head2 gcd |
3175 | 1792 | say "$n is square free" if moebius($n) != 0; |
3176 | 1793 | $sum += moebius($_) for (1..200); say "Mertens(200) = $sum"; |
3177 | 1794 | |
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 | |
3179 | 1796 | MoebiusMu function) for an integer input. This function is 1 if |
3180 | 1797 | C<n = 1>, 0 if C<n> is not square free (i.e. C<n> has a repeated factor), |
3181 | 1798 | and C<-1^t> if C<n> is a product of C<t> distinct primes. This is an |
3185 | 1802 | If called with two arguments, they define a range C<low> to C<high>, and the |
3186 | 1803 | function returns an array with the value of the Möbius function for every n |
3187 | 1804 | 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. | |
3190 | 1808 | |
3191 | 1809 | 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 | |
3193 | 1811 | exception (modifying the returned scalar or array is fine). |
3194 | 1812 | |
3195 | 1813 | |
3230 | 1848 | say "The Euler totient of $n is ", euler_phi($n); |
3231 | 1849 | |
3232 | 1850 | 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 | |
3234 | 1852 | the number of positive integers less than or equal to C<n> that are relatively |
3235 | 1853 | 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. | |
3238 | 1857 | |
3239 | 1858 | If called with two arguments, they define a range C<low> to C<high>, and the |
3240 | 1859 | function returns an array with the totient of every n from low to high |
3296 | 1915 | say chebyshev_psi(10000); |
3297 | 1916 | |
3298 | 1917 | 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: | |
3303 | 1922 | |
3304 | 1923 | use List::Util qw/sum/; use Math::BigFloat; |
3305 | 1924 | |
3312 | 1931 | =head2 divisor_sum |
3313 | 1932 | |
3314 | 1933 | 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. | |
3332 | 1944 | This function is useful for calculating things like aliquot sums, abundant |
3333 | 1945 | 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. | |
3334 | 1957 | |
3335 | 1958 | For numeric second arguments (sigma computations), the result will be a bigint |
3336 | 1959 | if necessary. For the code reference case, the user must take care to return |
3414 | 2037 | |
3415 | 2038 | Returns the Carmichael function (also called the reduced totient function, |
3416 | 2039 | 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>. | |
3419 | 2042 | |
3420 | 2043 | =head2 kronecker |
3421 | 2044 | |
3426 | 2049 | 1 a is a quadratic residue modulo n (a = x^2 mod n for some x) |
3427 | 2050 | -1 a is a quadratic non-residue modulo n |
3428 | 2051 | |
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 | |
3433 | 2055 | only defined for odd prime values of C<n>. This corresponds to Pari's |
3434 | 2056 | C<kronecker(a,n)> function and Mathematica's C<KroneckerSymbol[n,m]> |
3435 | 2057 | function. |
3439 | 2061 | $order = znorder(2, next_prime(10**19)-6); |
3440 | 2062 | |
3441 | 2063 | 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 | |
3443 | 2065 | C<a^k ≡ 1 mod n>. Returns 1 if C<a = 1>. Returns undef if C<a = 0> or if |
3444 | 2066 | C<a> and C<n> are not coprime, since no value will result in 1 mod n. |
3445 | 2067 | This corresponds to Pari's C<znorder(Mod(a,n))> function and Mathematica's |
3459 | 2081 | |
3460 | 2082 | =head2 znlog |
3461 | 2083 | |
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 | |
3465 | 2087 | undef if no solution is found. This is the discrete logarithm problem. |
3466 | 2088 | The implementation in this version is not very useful, but may be improved. |
3467 | 2089 | |
3493 | 2115 | will be seen. This is removes from consideration such algorithms as |
3494 | 2116 | C<PRIMEINC>, which although efficient, gives very non-random output. This |
3495 | 2117 | 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. | |
3500 | 2122 | |
3501 | 2123 | For small numbers, a random index selection is done, which gives ideal |
3502 | 2124 | uniformity and is very efficient with small inputs. For ranges larger than |
3521 | 2143 | |
3522 | 2144 | Examples of various ways to set your own irand function: |
3523 | 2145 | |
2146 | # System rand. You probably don't want to do this. | |
2147 | prime_set_config(irand => sub { int(rand(4294967296)) }); | |
2148 | ||
3524 | 2149 | # Math::Random::Secure. Uses ISAAC and strong seed methods. |
3525 | 2150 | use Math::Random::Secure; |
3526 | 2151 | prime_set_config(irand => \&Math::Random::Secure::irand); |
3541 | 2166 | use Math::Random::MT::Auto; |
3542 | 2167 | prime_set_config(irand=>sub {Math::Random::MT::Auto::irand() & 0xFFFFFFFF}); |
3543 | 2168 | |
2169 | # Go back to MPU's default configuration | |
2170 | prime_set_config(irand => undef); | |
2171 | ||
3544 | 2172 | |
3545 | 2173 | =head2 random_ndigit_prime |
3546 | 2174 | |
3547 | 2175 | say "My 4-digit prime number is: ", random_ndigit_prime(4); |
3548 | 2176 | |
3549 | 2177 | 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. | |
3554 | 2181 | |
3555 | 2182 | If the number of digits is greater than or equal to the maximum native type, |
3556 | 2183 | then the result will be returned as a BigInt. However, if the C<nobigint> |
3564 | 2191 | |
3565 | 2192 | my $bigprime = random_nbit_prime(512); |
3566 | 2193 | |
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. | |
3572 | 2197 | |
3573 | 2198 | For bit sizes of 64 and lower, L</random_prime> is used, which gives completely |
3574 | 2199 | uniform results in this range. For sizes larger than 64, Algorithm 1 of |
4411 | 3036 | |
4412 | 3037 | =item C<isprime> |
4413 | 3038 | |
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. | |
4432 | 3065 | |
4433 | 3066 | =item C<primepi> |
4434 | 3067 | |
4467 | 3100 | |
4468 | 3101 | =item C<forprime>, C<forcomposite>, C<fordiv>, C<sumdiv> |
4469 | 3102 | |
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>. | |
4472 | 3105 | |
4473 | 3106 | =item C<eulerphi>, C<moebius> |
4474 | 3107 | |
4504 | 3137 | |
4505 | 3138 | =item C<zeta> |
4506 | 3139 | |
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. | |
4509 | 3142 | |
4510 | 3143 | =back |
4511 | 3144 | |
4558 | 3191 | |
4559 | 3192 | =item Primes |
4560 | 3193 | |
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. | |
4565 | 3201 | |
4566 | 3202 | Note that the Sieve of Atkin is I<not> faster than the Sieve of Eratosthenes |
4567 | 3203 | 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 | |
4570 | 3206 | are all faster. |
4571 | 3207 | |
4572 | 3208 | =item Prime Counts and Nth Prime |
4611 | 3247 | |
4612 | 3248 | =head2 PRIMALITY TESTING |
4613 | 3249 | |
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 | ||
4633 | 3250 | =over 4 |
4634 | 3251 | |
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. | |
4683 | 3303 | |
4684 | 3304 | =back |
4685 | 3305 |
292 | 292 | UV i, c = (a > PHIC) ? PHIC : a; |
293 | 293 | UV sum = tablephi(x, c); |
294 | 294 | 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); | |
297 | 297 | for (i = c+1; i <= a; i++) { |
298 | 298 | UV xp; |
299 | 299 | p = next_prime(p); |
343 | 343 | uint32_t lastidx; |
344 | 344 | UV res, max_cache_a = (a >= PHICACHEA) ? PHICACHEA : a+1; |
345 | 345 | 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); | |
347 | 347 | res = (UV) _phi(x, a, 1, primes, lastidx, cache); |
348 | 348 | Safefree(primes); |
349 | 349 | Safefree(cache); |
31 | 31 | /* Add this to a number and you'll ensure you're on a wheel location */ |
32 | 32 | static const unsigned char distancewheel30[30] = |
33 | 33 | {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 */ | |
35 | 35 | 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 | ||
37 | 41 | |
38 | 42 | #ifdef FUNC_is_prime_in_sieve |
39 | 43 | static int is_prime_in_sieve(const unsigned char* sieve, UV p) { |
6 | 6 | |
7 | 7 | my $use64 = Math::Prime::Util::prime_get_config->{'maxbits'} > 32; |
8 | 8 | $use64 = 0 if 18446744073709550592 == ~0; |
9 | my $usexs = Math::Prime::Util::prime_get_config->{'xs'}; | |
9 | 10 | |
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)); | |
11 | 22 | |
12 | 23 | ok(!eval { primes(undef); }, "primes(undef)"); |
13 | 24 | ok(!eval { primes("a"); }, "primes(a)"); |
111 | 122 | |
112 | 123 | is( scalar @{primes(474973,838390)}, prime_count(838390) - prime_count(474973), "count primes within a range" ); |
113 | 124 | |
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)" ); | |
129 | 140 | } |
86 | 86 | + $use64 * 3 * scalar(keys %pivals64) |
87 | 87 | + scalar(keys %intervals) |
88 | 88 | + 1 |
89 | + 4 + 2*$extra; # prime count specific methods | |
89 | + 5 + 2*$extra; # prime count specific methods | |
90 | 90 | |
91 | 91 | ok( eval { prime_count(13); 1; }, "prime_count in void context"); |
92 | 92 | |
164 | 164 | is(Math::Prime::Util::_XS_LMO_pi (66123456), 3903023,"XS LMO count"); |
165 | 165 | is(Math::Prime::Util::_XS_segment_pi (66123456), 3903023,"XS segment count"); |
166 | 166 | } |
167 | ||
168 | require_ok 'Math::Prime::Util::PP'; | |
167 | 169 | is(Math::Prime::Util::PP::_lehmer_pi (1456789), 111119, "PP Lehmer count"); |
168 | 170 | is(Math::Prime::Util::PP::_sieve_prime_count(145678), 13478, "PP sieve count"); |
169 | 171 | if ($extra) { |
19 | 19 | # Do some tests only if: |
20 | 20 | # EXTENDED_TESTING is on OR we have the GMP backend |
21 | 21 | # Note that with Calc, these things are incredibly slow. |
22 | use Math::BigInt try=>"GMP,Pari"; | |
22 | 23 | my $doexpensive = 0 + ($extra || ( (!$use64 || !$broken64) && Math::BigInt->config()->{lib} eq 'Math::BigInt::GMP' )); |
23 | 24 | |
24 | 25 | my @plist = qw/20907001 809120722675364249/; |
9 | 9 | # The second method in theory is all that is needed. |
10 | 10 | |
11 | 11 | use Math::Prime::Util qw/:all/; |
12 | use Math::Prime::Util::PP; | |
12 | 13 | use bignum; |
13 | 14 | |
14 | 15 | use Test::More tests => 2; |
297 | 297 | |
298 | 298 | *factor = \&Math::Prime::Util::PP::factor; |
299 | 299 | |
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; | |
304 | 304 | |
305 | 305 | *RiemannR = \&Math::Prime::Util::PP::RiemannR; |
306 | 306 | *RiemannZeta = \&Math::Prime::Util::PP::RiemannZeta; |
75 | 75 | + 6*2*$extra # more PC tests |
76 | 76 | + 2*scalar(keys %factors) |
77 | 77 | + 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. | |
79 | 79 | + 2 # liouville |
80 | 80 | + 3 # gcd |
81 | 81 | + 3 # lcm |
107 | 107 | divisor_sum |
108 | 108 | znorder |
109 | 109 | znprimroot |
110 | znlog | |
110 | 111 | liouville |
111 | 112 | gcd |
112 | 113 | lcm |
144 | 145 | diag "BigInt $bignumver/$bigintver, lib: $bigintlib. MPU::GMP $mpugmpver\n"; |
145 | 146 | |
146 | 147 | # 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)) } ); | |
148 | 149 | |
149 | 150 | |
150 | 151 | ############################################################################### |
227 | 228 | ############################################################################### |
228 | 229 | |
229 | 230 | 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; | |
231 | 232 | my $n; |
232 | 233 | $n = 618970019642690137449562110; |
233 | 234 | is( moebius($n), -1, "moebius($n)" ); |
266 | 267 | |
267 | 268 | is( znprimroot(333822190384002421914469856494764513809), 3, "znprimroot(333822190384002421914469856494764513809)" ); |
268 | 269 | |
270 | is( znlog(232752345212475230211680, 23847293847923847239847098123812075234, 804842536444911030681947), 13, "znlog(b,g,p): find k where b^k = g mod p" ); | |
271 | ||
269 | 272 | } |
270 | 273 | |
271 | 274 | ############################################################################### |
16 | 16 | plan skip_all => "Test::Pod::Coverage 1.08 required for testing POD coverage" |
17 | 17 | if $@; |
18 | 18 | |
19 | my @modules = Test::Pod::Coverage::all_modules(); | |
19 | my @modules = grep { $_ ne 'Math::Prime::Util::PPFE' } | |
20 | Test::Pod::Coverage::all_modules(); | |
21 | ||
20 | 22 | plan tests => scalar @modules; |
21 | 23 | |
22 | 24 | #my $ppsubclass = { trustme => [mpu_public_regex()] }; |
28 | 28 | extern long double logl(long double); |
29 | 29 | extern long double fabsl(long double); |
30 | 30 | extern long double floorl(long double); |
31 | extern long double ceill(long double); | |
31 | 32 | #else |
32 | 33 | #define powl(x, y) (long double) pow( (double) (x), (double) (y) ) |
33 | 34 | #define expl(x) (long double) exp( (double) (x) ) |
34 | 35 | #define logl(x) (long double) log( (double) (x) ) |
35 | 36 | #define fabsl(x) (long double) fabs( (double) (x) ) |
36 | 37 | #define floorl(x) (long double) floor( (double) (x) ) |
38 | #define ceill(x) (long double) ceil( (double) (x) ) | |
37 | 39 | #endif |
38 | 40 | |
39 | 41 | #ifdef LDBL_INFINITY |
100 | 102 | return (b * 0x0101010101010101) >> 56; |
101 | 103 | } |
102 | 104 | #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 | } | |
110 | 105 | #endif |
111 | 106 | |
112 | 107 | #if defined(__GNUC__) |
219 | 214 | |
220 | 215 | UV next_prime(UV n) |
221 | 216 | { |
222 | UV d, m, sieve_size, next; | |
217 | UV m, sieve_size, next; | |
223 | 218 | const unsigned char* sieve; |
224 | 219 | |
225 | 220 | if (n < 30*NPRIME_SIEVE30) { |
234 | 229 | release_prime_cache(sieve); |
235 | 230 | if (next != 0) return next; |
236 | 231 | |
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. */ | |
244 | 234 | n += wheeladvance30[m]; |
245 | 235 | m = nextwheel30[m]; |
246 | } | |
247 | return(n); | |
236 | } while (!is_prob_prime(n)); | |
237 | return n; | |
248 | 238 | } |
249 | 239 | |
250 | 240 | |
251 | 241 | UV prev_prime(UV n) |
252 | 242 | { |
253 | 243 | const unsigned char* sieve; |
254 | UV d, m, prev; | |
244 | UV m, prev; | |
255 | 245 | |
256 | 246 | if (n < 30*NPRIME_SIEVE30) |
257 | 247 | return prev_prime_in_sieve(prime_sieve30, n); |
263 | 253 | } |
264 | 254 | release_prime_cache(sieve); |
265 | 255 | |
266 | d = n/30; | |
267 | m = n - d*30; | |
268 | do { | |
256 | m = n % 30; | |
257 | do { /* Move back one. */ | |
258 | n -= wheelretreat[m]; | |
269 | 259 | m = prevwheel30[m]; |
270 | if (m==29) d--; | |
271 | n = d*30+m; | |
272 | 260 | } while (!is_prob_prime(n)); |
273 | 261 | return n; |
274 | 262 | } |
576 | 564 | return count; |
577 | 565 | } |
578 | 566 | |
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 | } | |
580 | 651 | |
581 | 652 | static const unsigned short primes_small[] = |
582 | 653 | {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, |
586 | 657 | 409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499}; |
587 | 658 | #define NPRIMES_SMALL (sizeof(primes_small)/sizeof(primes_small[0])) |
588 | 659 | |
589 | /* Note: We're keeping this here because we use it for nth_prime */ | |
590 | 660 | /* 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) | |
592 | 662 | { |
593 | double fn, flogn, flog2n, upper; | |
663 | long double fn, flogn, flog2n, upper; | |
594 | 664 | |
595 | 665 | if (n < NPRIMES_SMALL) |
596 | 666 | return primes_small[n]; |
597 | 667 | |
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) */ | |
601 | 671 | |
602 | 672 | if (n >= 688383) /* Dusart 2010 page 2 */ |
603 | 673 | upper = fn * (flogn + flog2n - 1.0 + ((flog2n-2.00)/flogn)); |
621 | 691 | * nth_prime_lower(n) <= nth_prime(n) <= nth_prime_upper(n) |
622 | 692 | */ |
623 | 693 | /* Watch out for overflow */ |
624 | if (upper >= (double)UV_MAX) { | |
694 | if (upper >= (long double)UV_MAX) { | |
625 | 695 | if (n <= MPU_MAX_PRIME_IDX) return MPU_MAX_PRIME; |
626 | 696 | croak("nth_prime_upper(%"UVuf") overflow", n); |
627 | 697 | } |
628 | 698 | |
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) | |
634 | 761 | { |
635 | 762 | const unsigned char* cache_sieve; |
636 | 763 | unsigned char* segment; |
644 | 771 | return primes_small[n]; |
645 | 772 | |
646 | 773 | /* 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); | |
648 | 775 | MPUassert(upper_limit > 0, "nth_prime got an upper limit of 0"); |
649 | 776 | |
650 | 777 | /* For relatively small values, generate a sieve and count the results. |
769 | 896 | unsigned char* segment; |
770 | 897 | void* ctx; |
771 | 898 | |
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); | |
773 | 900 | New(0, totients, hi-lo+1, UV); |
774 | 901 | |
775 | 902 | /* Do via factoring if very small or if we have a small range */ |
1085 | 1212 | return mulmod(a, binv, n); |
1086 | 1213 | } |
1087 | 1214 | |
1088 | /* Find smallest n where a = g^n mod p | |
1215 | /* Find smallest k where a = g^k mod p | |
1089 | 1216 | * 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 | |
1091 | 1218 | */ |
1092 | 1219 | #define DLP_TRIAL_NUM 1000000 |
1093 | 1220 | UV znlog(UV a, UV g, UV p) { |
1124 | 1251 | UV seg_base, seg_low, seg_high; |
1125 | 1252 | unsigned char* segment; |
1126 | 1253 | void* ctx; |
1254 | long double logl2 = logl(2); | |
1255 | long double logl3 = logl(3); | |
1256 | long double logl5 = logl(5); | |
1127 | 1257 | 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); | |
1129 | 1259 | } 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)); | |
1133 | 1263 | } |
1134 | 1264 | ctx = start_segment_primes(7, n, &segment); |
1135 | 1265 | while (next_segment_primes(ctx, &seg_base, &seg_low, &seg_high)) { |
1261 | 1391 | |
1262 | 1392 | /* Thanks to Kim Walisch for this idea */ |
1263 | 1393 | 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); | |
1268 | 1397 | |
1269 | 1398 | if (x == 0) return 0; |
1270 | 1399 | if (hi <= lo) hi = UV_MAX; |
1322 | 1451 | 0.0000000000036379795473786511902372363L, |
1323 | 1452 | 0.0000000000018189896503070659475848321L, |
1324 | 1453 | 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, | |
1325 | 1470 | }; |
1326 | 1471 | #define NPRECALC_ZETA (sizeof(riemann_zeta_table)/sizeof(riemann_zeta_table[0])) |
1327 | 1472 | |
1331 | 1476 | * The Cephes zeta function uses a series (2k)!/B_2k which converges rapidly |
1332 | 1477 | * and has a very wide range of values. We use it here for some values. |
1333 | 1478 | * |
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. | |
1337 | 1482 | * |
1338 | 1483 | * For values 0.5 to 5, this code uses the rational Chebyshev approximation |
1339 | 1484 | * from Cody and Thacher. This method is extraordinarily fast and very |
1378 | 1523 | return sum; |
1379 | 1524 | } |
1380 | 1525 | |
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) | |
1385 | 1527 | return 0.0; |
1386 | } | |
1387 | 1528 | |
1388 | 1529 | #if 0 |
1389 | 1530 | { |
1426 | 1567 | for (i = 2; i < 11; i++) { |
1427 | 1568 | b = powl( i, -x ); |
1428 | 1569 | s += b; |
1429 | if (fabsl(b/s) < LDBL_EPSILON) | |
1430 | return s; | |
1570 | if (fabsl(b) < fabsl(LDBL_EPSILON * s)) | |
1571 | return s; | |
1431 | 1572 | } |
1432 | 1573 | s = s + b*w/(x-1.0) - 0.5 * b; |
1433 | 1574 | a = 1.0; |
1437 | 1578 | b /= w; |
1438 | 1579 | t = a*b/A[i]; |
1439 | 1580 | s = s + t; |
1440 | t = fabsl(t/s); | |
1441 | if (t < LDBL_EPSILON) | |
1581 | if (fabsl(t) < fabsl(LDBL_EPSILON * s)) | |
1442 | 1582 | break; |
1443 | 1583 | a *= x + k + 1.0; |
1444 | 1584 | b /= w; |
1461 | 1601 | |
1462 | 1602 | for (k = 1; k <= 10000; k++) { |
1463 | 1603 | 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)); | |
1465 | 1606 | 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; | |
1468 | 1609 | } |
1469 | 1610 | |
1470 | 1611 | return sum; |
12 | 12 | extern UV prev_prime(UV x); |
13 | 13 | |
14 | 14 | 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); | |
16 | 22 | |
17 | 23 | extern signed char* _moebius_range(UV low, UV high); |
18 | 24 | extern UV* _totient_range(UV low, UV high); |
71 | 71 | is_deeply( gen_forprimes($b,$e), \@p, "forprimes {} $b,$e"); |
72 | 72 | } |
73 | 73 | } |
74 | diag "\nChecking numbers near end with segment primes(). Very slow.\n"; | |
74 | diag "\nChecking numbers near end with segment primes().\n"; | |
75 | 75 | { |
76 | 76 | my $b = $lprimes[-1] - 1; |
77 | 77 | my $e = ~0; |
78 | 78 | my @p = ($lprimes[-1]); |
79 | 79 | 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)"); | |
86 | 86 | 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)"); | |
91 | 91 | } |
92 | 92 | |
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 | #} | |
101 | 93 | |
102 | 94 | sub gen_primes { |
103 | 95 | return primes(@_); |
96 | } | |
97 | sub gen_segment_primes { | |
98 | my($low, $high) = @_; | |
99 | return Math::Prime::Util::segment_primes($low,$high); # Private function | |
104 | 100 | } |
105 | 101 | sub gen_forprimes { |
106 | 102 | 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 | } |