File Coverage

blib/lib/Math/Primality.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Math::Primality;
2 8     8   138737 use warnings;
  8         14  
  8         272  
3 8     8   32 use strict;
  8         13  
  8         165  
4 8     8   4659 use Data::Dumper;
  8         69654  
  8         899  
5 8     8   7334 use Math::GMPz qw/:mpz/;
  0            
  0            
6             use base 'Exporter';
7             use Carp qw/croak/;
8             my %small_primes = (
9             2 => 2,
10             3 => 2,
11             5 => 2,
12             7 => 2,
13             11 => 2,
14             13 => 2,
15             17 => 2,
16             19 => 2,
17             23 => 2,
18             29 => 2,
19             31 => 2,
20             37 => 2,
21             41 => 2,
22             43 => 2,
23             47 => 2,
24             53 => 2,
25             59 => 2,
26             61 => 2,
27             67 => 2,
28             71 => 2,
29             73 => 2,
30             79 => 2,
31             83 => 2,
32             89 => 2,
33             97 => 2,
34             101 => 2,
35             103 => 2,
36             107 => 2,
37             109 => 2,
38             113 => 2,
39             127 => 2,
40             131 => 2,
41             137 => 2,
42             139 => 2,
43             149 => 2,
44             151 => 2,
45             157 => 2,
46             163 => 2,
47             167 => 2,
48             173 => 2,
49             179 => 2,
50             181 => 2,
51             191 => 2,
52             193 => 2,
53             197 => 2,
54             199 => 2,
55             211 => 2,
56             223 => 2,
57             227 => 2,
58             229 => 2,
59             233 => 2,
60             239 => 2,
61             241 => 2,
62             251 => 2,
63             257 => 2,
64             );
65              
66             use constant
67             DEBUG => 0
68             ;
69              
70             use constant GMP => 'Math::GMPz';
71              
72             =head1 NAME
73              
74             Math::Primality - Advanced Primality Algorithms using GMP
75              
76             =head1 VERSION
77              
78             Version 0.03_03
79              
80             =cut
81              
82             our $VERSION = '0.03_03';
83             $VERSION = eval $VERSION;
84              
85              
86             our @EXPORT_OK = qw/is_pseudoprime is_strong_pseudoprime is_strong_lucas_pseudoprime is_prime next_prime prev_prime prime_count/;
87              
88             our %EXPORT_TAGS = ( all => \@EXPORT_OK );
89              
90             =head1 SYNOPSIS
91              
92             use Math::Primality qw/:all/;
93              
94             my $t1 = is_pseudoprime($x,$base);
95             my $t2 = is_strong_pseudoprime($x);
96              
97             print "Prime!" if is_prime($outrageously_large_prime);
98              
99             my $t3 = next_prime($x);
100              
101             =head1 DESCRIPTION
102              
103             Math::Primality implements is_prime() and next_prime() as a replacement for Math::PARI::is_prime(). It uses the GMP library through Math::GMPz. The is_prime() method is actually a Baillie-PSW primality test which consists of two steps:
104              
105             =over 4
106              
107             =item * Perform a strong Miller-Rabin probable prime test (base 2) on N
108              
109             =item * Perform a strong Lucas-Selfridge test on N (using the parameters suggested by Selfridge)
110              
111             =back
112              
113             At any point the function may return 2 which means N is definitely composite. If not, N has passed the strong Baillie-PSW test and is either prime or a strong Baillie-PSW pseudoprime. To date no counterexample (Baillie-PSW strong pseudoprime) is known to exist for N < 10^15. Baillie-PSW requires O((log n)^3) bit operations. See L for a more thorough introduction to the Baillie-PSW test. Also see L for a more theoretical introduction to the Baillie-PSW test.
114              
115             =head1 EXPORT
116              
117             =head1 FUNCTIONS
118              
119             =head2 is_pseudoprime($n,$b)
120              
121             Returns true if $n is a base $b pseudoprime, otherwise false. The variable $n
122             should be a Perl integer or Math::GMPz object.
123              
124             The default base of 2 is used if no base is given. Base 2 pseudoprimes are often called Fermat pseudoprimes.
125              
126             if ( is_pseudoprime($n,$b) ) {
127             # it's a pseudoprime
128             } else {
129             # not a psuedoprime
130             }
131              
132             =head3 Details
133              
134             A pseudoprime is a number that satisfies Fermat's Little Theorm, that is, $b^ ($n - 1) = 1 mod $n.
135              
136             =cut
137              
138             sub is_pseudoprime($;$)
139             {
140             my ($n, $base) = @_;
141             return 0 unless $n;
142             $base ||= 2;
143             # we should check if we are passed a GMPz object
144             $base = GMP->new($base);
145             $n = GMP->new($n);
146              
147             my $m = GMP->new();
148             Rmpz_sub_ui($m, $n, 1); # $m = $n - 1
149              
150             my $mod = GMP->new();
151             Rmpz_powm($mod, $base, $m, $n ); # $mod = ($base ^ $m) mod $n
152             return ! Rmpz_cmp_ui($mod, 1); # pseudoprime if $mod = 1
153             }
154              
155             # checks if $n is in %small_primes
156             # private functions expect a Math::GMPz object
157             sub _is_small_prime
158             {
159             my $n = shift;
160             $n = Rmpz_get_ui($n);
161             return $small_primes{$n} ? 2 : 0;
162              
163             }
164              
165             sub debug {
166             if ( DEBUG ) {
167             warn $_[0];
168             }
169             }
170              
171             =head2 is_strong_pseudoprime($n,$b)
172              
173             Returns true if $n is a base $b strong pseudoprime, false otherwise. The variable $n should be a Perl integer
174             or a Math::GMPz object. Strong psuedoprimes are often called Miller-Rabin pseudoprimes.
175              
176             The default base of 2 is used if no base is given.
177              
178             if ( is_strong_pseudoprime($n,$b) ) {
179             # it's a strong pseudoprime
180             } else {
181             # not a strong psuedoprime
182             }
183              
184             =head3 Details
185              
186             A strong pseudoprime to $base is an odd number $n with ($n - 1) = $d * 2^$s that either satisfies
187              
188             =over 4
189              
190             =item * $base^$d = 1 mod $n
191              
192             =item * $base^($d * 2^$r) = -1 mod $n, for $r = 0, 1, ..., $s-1
193              
194             =back
195              
196             =head3 Notes
197              
198             The second condition is checked by sucessive squaring $base^$d and reducing that mod $n.
199              
200             =cut
201              
202             sub is_strong_pseudoprime($;$)
203             {
204             my ($n, $base) = @_;
205              
206             $base ||= 2;
207             # we should check if we are passed a GMPz object
208             $base = GMP->new($base);
209             $n = GMP->new($n);
210              
211             # unnecessary but faster if $n is even
212             my $cmp = _check_two_and_even($n);
213             return $cmp if $cmp != 2;
214              
215             my $m = GMP->new();
216             Rmpz_sub_ui($m,$n,1); # $m = $n - 1
217              
218             my ($s,$d) = _find_s_d($m);
219             debug "m=$m, s=$s, d=$d" if DEBUG;
220              
221             my $residue = GMP->new();
222             Rmpz_powm($residue, $base,$d, $n); # $residue = ($base ^ $d) mod $n
223             debug "$base^$d % $n = $residue" if DEBUG;
224              
225             # if $base^$d = +-1 (mod $n) , $n is a strong pseudoprime
226              
227             if ( Rmpz_cmp_ui($residue,1) == 0 ) {
228             debug "found $n as spsp since $base^$d % $n == $residue == 1\n" if DEBUG;
229             return 1;
230             }
231              
232             if ( Rmpz_cmp($residue,$m) == 0 ) {
233             debug "found $n as spsp since $base^$d % $n == $residue == $m\n" if DEBUG;
234             return 1;
235             }
236              
237             map {
238             # successively square $residue, $n is a strong psuedoprime
239             # if any of these are congruent to -1 (mod $n)
240             Rmpz_mul($residue,$residue,$residue); # $residue = $residue * $residue
241             debug "$_: r=$residue" if DEBUG;
242              
243             my $mod = GMP->new();
244             Rmpz_mod($mod, $residue, $n); # $mod = $residue mod $n
245             debug "$_:$residue % $n = $mod " if DEBUG;
246             $mod = Rmpz_cmp($mod, $m);
247              
248             if ($mod == 0) {
249             debug "$_:$mod == $m => spsp!" if DEBUG;
250             return 1;
251             }
252             } ( 1 .. $s-1 );
253              
254             return 0;
255             }
256              
257             # given an odd number N find (s, d) such that N = d * 2^s + 1
258             # private functions expect a Math::GMPz object
259             sub _find_s_d($)
260             {
261             my $m = $_[0];
262             my $s = Rmpz_scan1($m,1);
263             my $d = GMP->new();
264             Rmpz_tdiv_q_2exp($d,$m,$s);
265             return ($s,$d);
266             }
267              
268             =head2 is_strong_lucas_pseudoprime($n)
269              
270             Returns true if $n is a strong Lucas-Selfridge pseudoprime, false otherwise. The variable $n should be a Perl
271             integer or a Math::GMPz object.
272              
273             if ( is_strong_lucas_pseudoprime($n) ) {
274             # it's a strong Lucas-Selfridge pseudoprime
275             } else {
276             # not a strong Lucas-Selfridge psuedoprime
277             # i.e. definitely composite
278             }
279              
280             =head3 Details
281              
282             If we let
283              
284             =over 4
285              
286             =item * $D be the first element of the sequence 5, -7, 9, -11, 13, ... for which ($D/$n) = -1. Let $P = 1 and $Q = (1 - $D) /4
287              
288             =item * U($P, $Q) and V($P, $Q) be Lucas sequences
289              
290             =item * $n + 1 = $d * 2^$s + 1
291              
292             =back
293              
294             Then a strong Lucas-Selfridge pseudoprime is an odd, non-perfect square number $n with that satisfies either
295              
296             =over 4
297              
298             =item * U_$d = 0 mod $n
299              
300             =item * V_($d * 2^$r) = 0 mod $n, for $r = 0, 1, ..., $s-1
301              
302             =back
303              
304             =head3 Notes
305              
306             ($d/$n) refers to the Legendre symbol.
307              
308             =cut
309              
310             sub is_strong_lucas_pseudoprime($)
311             {
312             my ($n) = @_;
313             $n = GMP->new($n);
314             # we also need to handle all N < 3 and all even N
315             my $cmp = _check_two_and_even($n);
316             return $cmp if $cmp != 2;
317             # handle all perfect squares
318             if ( Rmpz_perfect_square_p($n) ) {
319             return 0;
320             }
321             # determine Selfridge parameters D, P and Q
322             my ($D, $P, $Q) = _find_dpq_selfridge($n);
323             if ($D == 0) { #_find_dpq_selfridge found a factor of N
324             return 0;
325             }
326             my $m = GMP->new();
327             Rmpz_add_ui($m, $n, 1); # $m = $n + 1
328              
329             # determine $s and $d such that $m = $d * 2^$s + 1
330             my ($s,$d) = _find_s_d($m);
331             # compute U_d and V_d
332             # initalize $U, $V, $U_2m, $V_2m
333             my $U = GMP->new(1); # $U = U_1 = 1
334             my $V = GMP->new($P); # $V = V_1 = P
335             my $U_2m = GMP->new(1); # $U_2m = U_1
336             my $V_2m = GMP->new($P); # $V_2m = P
337             # initalize Q values (eventually need to calculate Q^d, which will be used in later stages of test)
338             my $Q_m = GMP->new($Q);
339             my $Q2_m = GMP->new(2 * $Q); # Really 2Q_m, but perl will barf with a variable named like that
340             my $Qkd = GMP->new($Q);
341             # start doubling the indicies!
342             my $dbits = Rmpz_sizeinbase($d,2);
343             for (my $i = 1; $i < $dbits; $i++) { #since d is odd, the zeroth bit is on so we skip it
344             # U_2m = U_m * V_m (mod N)
345             Rmpz_mul($U_2m, $U_2m, $V_2m); # U_2m = U_m * V_m
346             Rmpz_mod($U_2m, $U_2m, $n); # U_2m = U_2m mod N
347             # V_2m = V_m * V_m - 2 * Q^m (mod N)
348             Rmpz_mul($V_2m, $V_2m, $V_2m); # V_2m = V_2m * V_2m
349             Rmpz_sub($V_2m, $V_2m, $Q2_m); # V_2m = V_2m - 2Q_m
350             Rmpz_mod($V_2m, $V_2m, $n); # V_2m = V_2m mod N
351             # calculate powers of Q for V_2m and Q^d (used later)
352             # 2Q_m = 2 * Q_m * Q_m (mod N)
353             Rmpz_mul($Q_m, $Q_m, $Q_m); # Q_m = Q_m * Q_m
354             Rmpz_mod($Q_m, $Q_m, $n); # Q_m = Q_m mod N
355             Rmpz_mul_2exp($Q2_m, $Q_m, 1); # 2Q_m = Q_m * 2
356             if (Rmpz_tstbit($d, $i)) { # if bit i of d is set
357             # add some indicies
358             # initalize some temporary variables
359             my $T1 = GMP->new();
360             my $T2 = GMP->new();
361             my $T3 = GMP->new();
362             my $T4 = GMP->new();
363             # this is how we do it
364             # U_(m+n) = (U_m * V_n + U_n * V_m) / 2
365             # V_(m+n) = (V_m * V_n + D * U_m * U_n) / 2
366             Rmpz_mul($T1, $U_2m, $V); # T1 = U_2m * V
367             Rmpz_mul($T2, $U, $V_2m); # T2 = U * V_2m
368             Rmpz_mul($T3, $V_2m, $V); # T3 = V_2m * V
369             Rmpz_mul($T4, $U_2m, $U); # T4 = U_2m * U
370             Rmpz_mul_si($T4, $T4, $D); # T4 = T4 * D = U_2m * U * D
371             Rmpz_add($U, $T1, $T2); # U = T1 + T2 = U_2m * V - U * V_2m
372             if (Rmpz_odd_p($U)) { # if U is odd
373             Rmpz_add($U, $U, $n); # U = U + n
374             }
375             Rmpz_fdiv_q_2exp($U, $U, 1); # U = floor(U / 2)
376             Rmpz_add($V, $T3, $T4); # V = T3 + T4 = V_2m * V + U_2m * U * D
377             if (Rmpz_odd_p($V)) { # if V is odd
378             Rmpz_add($V, $V, $n); # V = V + n
379             }
380             Rmpz_fdiv_q_2exp($V, $V, 1); # V = floor(V / 2)
381             Rmpz_mod($U, $U, $n); # U = U mod N
382             Rmpz_mod($V, $V, $n); # V = V mod N
383             # Get our Q^d calculating on (to be used later)
384             Rmpz_mul($Qkd, $Qkd, $Q_m); # Qkd = Qkd * Q_m
385             Rmpz_mod($Qkd, $Qkd, $n); # Qkd = Qkd mod N
386             }
387             }
388             # if U_d or V_d = 0 mod N, then N is prime or a strong Lucas pseudoprime
389             if(Rmpz_sgn($U) == 0 || Rmpz_sgn($V) == 0) {
390             return 1;
391             }
392             # ok, if we're still here, we have to compute V_2d, V_4d, V_8d, ..., V_{2^(s-1)*d}
393             # initalize 2Qkd
394             my $Q2kd = GMP->new;
395             Rmpz_mul_2exp($Q2kd, $Qkd, 1); # 2Qkd = 2 * Qkd
396             # V_2m = V_m * V_m - 2 * Q^m (mod N)
397             for (my $r = 1; $r < $s; $r++) {
398             Rmpz_mul($V, $V, $V); # V = V * V;
399             Rmpz_sub($V, $V, $Q2kd); # V = V - 2Qkd
400             Rmpz_mod($V, $V, $n); # V = V mod N
401             # if V = 0 mod N then N is a prime or a strong Lucas pseudoprime
402             if(Rmpz_sgn($V) == 0) {
403             return 1;
404             }
405             # calculate Q ^(d * 2^r) for next r (unless on final iteration)
406             if ($r < ($s - 1)) {
407             Rmpz_mul($Qkd, $Qkd, $Qkd); # Qkd = Qkd * Qkd
408             Rmpz_mod($Qkd, $Qkd, $n); # Qkd = Qkd mod N
409             Rmpz_mul_2exp($Q2kd, $Qkd, 1); # 2Qkd = 2 * Qkd
410             }
411             }
412             # otherwise N is definitely composite
413             return 0;
414             }
415              
416             # selfridge's method for finding the tuple (D,P,Q) for is_strong_lucas_pseudoprime
417             # private functions expect a Math::GMPz object
418             sub _find_dpq_selfridge($) {
419             my $n = $_[0];
420             my ($d,$sign,$wd) = (5,1,0);
421             my $gcd = GMP->new;
422              
423             # determine D
424             while (1) {
425             $wd = $d * $sign;
426              
427             Rmpz_gcd_ui($gcd, $n, abs $wd);
428             if ($gcd > 1 && Rmpz_cmp($n, $gcd) > 0) {
429             debug "1 < $gcd < $n => $n is composite with factor $wd" if DEBUG;
430             return 0;
431             }
432             my $j = Rmpz_jacobi(GMP->new($wd), $n);
433             if ($j == -1) {
434             debug "Rmpz_jacobi($wd, $n) == -1 => found D" if DEBUG;
435             last;
436             }
437             # didn't find D, increment and swap sign
438             $d += 2;
439             $sign = -$sign;
440             }
441             # P = 1
442             my ($p,$q) = (1,0);
443             {
444             use integer;
445             # Q = (1 - D) / 4
446             $q = (1 - $wd) / 4;
447             }
448             debug "found P and Q: ($p, $q)" if DEBUG;
449             return ($wd, $p, $q);
450             }
451              
452             # method returns 0 if N < two or even, returns 1 if N == 2
453             # returns 2 if N > 2 and odd
454             # private functions expect a Math::GMPz object
455             sub _check_two_and_even($) {
456             my $n = $_[0];
457              
458             my $cmp = Rmpz_cmp_ui($n, 2);
459             return 1 if $cmp == 0;
460             return 0 if $cmp < 0;
461             return 0 if Rmpz_even_p($n);
462             return 2;
463             }
464              
465             =head2 is_prime($n)
466              
467             Returns 2 if $n is definitely prime, 1 is $n is a probable prime, 0 if $n is composite.
468              
469             if ( is_prime($n) ) {
470             # it's a prime
471             } else {
472             # definitely composite
473             }
474              
475             =head3 Details
476              
477             is_prime() is implemented using the BPSW algorithim which is a combination of two probable-prime
478             algorithims, the strong Miller-Rabin test and the strong Lucas-Selfridge test. While no
479             psuedoprime has been found for N < 10^15, this does not mean there is not a pseudoprime. A
480             possible improvement would be to instead implement the AKS test which runs in quadratic time and
481             is deterministic with no false-positives.
482              
483             =head3 Notes
484              
485             The strong Miller-Rabin test is implemented by is_strong_pseudoprime(). The strong Lucas-Selfridge test is implemented
486             by is_strong_lucas_pseudoprime().
487              
488             We have implemented some optimizations. We have an array of small primes to check all $n <= 257. According to
489             L if $n < 9,080,191 is a both a base-31 and a base-73 strong pseudoprime,
490             then $n is prime. If $n < 4,759,123,141 is a base-2, base-7 and base-61 strong pseudoprime, then $n is prime.
491              
492             =cut
493              
494             sub is_prime($) {
495             my $n = shift;
496             $n = GMP->new($n);
497              
498             if (Rmpz_cmp_ui($n, 2) == -1) {
499             return 0;
500             }
501             if (Rmpz_cmp_ui($n, 257) == -1) {
502             return _is_small_prime($n);
503             } elsif ( Rmpz_cmp_ui($n, 9_080_191) == -1 ) {
504             return 0 unless is_strong_pseudoprime($n,31);
505             return 0 unless is_strong_pseudoprime($n,73);
506             return 2;
507             } elsif ( Rmpz_cmp_ui($n, 4_759_123_141) == -1 ) {
508             return 0 unless is_strong_pseudoprime($n,2);
509             return 0 unless is_strong_pseudoprime($n,7);
510             return 0 unless is_strong_pseudoprime($n,61);
511             return 2;
512             }
513             # the strong_pseudoprime test is quicker, do it first
514             return is_strong_pseudoprime($n,2) && is_strong_lucas_pseudoprime($n);
515             }
516              
517             =head2 next_prime($n)
518              
519             Given a number, produces the next prime number.
520              
521             my $q = next_prime($n);
522              
523             =head3 Details
524              
525             Each next greatest odd number is checked until one is found to be prime
526              
527             =head3 Notes
528              
529             Checking of primality is implemented by is_prime()
530              
531             =cut
532              
533             sub next_prime($) {
534             my $n = GMP->new($_[0]);
535             my $cmp = Rmpz_cmp_ui($n, 2 ); #check if $n < 2
536             if ($cmp < 0) {
537             return GMP->new(2);
538             }
539             if (Rmpz_odd_p($n)) { # if N is odd
540             Rmpz_add_ui($n, $n, 2); # N = N + 2
541             } else {
542             Rmpz_add_ui($n, $n, 1); # N = N + 1
543             }
544             # N is now the next odd number
545             while (1) {
546             return $n if is_prime($n); # check primality of that number, return if prime
547             Rmpz_add_ui($n, $n, 2); # N = N + 2
548             }
549             }
550              
551             =head2 prev_prime($n)
552              
553             Given a number, produces the previous prime number.
554              
555             my $q = prev_prime($n);
556              
557             =head3 Details
558              
559             Each previous odd number is checked until one is found to be prime. prev_prime(2) or for any number less than 2 returns undef
560              
561             =head3 Notes
562              
563             Checking of primality is implemented by is_prime()
564              
565             =cut
566              
567             sub prev_prime($) {
568             my $n = GMP->new($_[0]);
569             my $cmp = Rmpz_cmp_ui($n, 3); # compare N with 3
570             if ($cmp == 0) { # N = 3
571             return GMP->new(2);
572             } elsif ($cmp < 0) { # N < 3
573             return undef;
574             } else {
575             if (Rmpz_odd_p($n)) { # if N is odd
576             Rmpz_sub_ui($n, $n, 2); # N = N - 2
577             } else {
578             Rmpz_sub_ui($n, $n, 1); # N = N - 1
579             }
580             # N is now the previous odd number
581             while (1) {
582             return $n if is_prime($n); # check primality of that number, return if prime
583             Rmpz_sub_ui($n, $n, 2); # N = N - 2
584             }
585             }
586             }
587              
588             =head2 prime_count($n)
589              
590             Returns the number of primes less than or equal to $n.
591              
592             my $count = prime_count(1000); # $count = 168
593             my $bigger_count = prime_count(10000); # $bigger_count = 1229
594              
595             =head3 Details
596              
597             This is implemented with a simple for loop. The Meissel, Lehmer, Lagarias, Miller,
598             Odlyzko method is considerably faster. A paper can be found at
599             L
600             that describes this method in rigorous detail.
601              
602             =head3 Notes
603              
604             Checking of primality is implemented by is_prime()
605              
606             =cut
607              
608             sub prime_count($) {
609             my $n = GMP->new($_[0]); # check if $n needs to be a Math::GMPz object
610             my $primes = 0;
611             return 0 if $n <= 1;
612              
613             for (my $i = GMP->new(0); Rmpz_cmp($i, $n) <= 0; Rmpz_add_ui($i, $i, 1)) {
614             $primes++ if is_prime($i);
615             }
616             return $primes;
617             }
618              
619              
620             =head1 AUTHORS
621              
622             Jonathan Leto, C<< >>
623             Bob Kuo, C<< >>
624              
625             =head1 BUGS
626              
627             Please report any bugs or feature requests to C
628             rt.cpan.org>, or through the web interface at
629             L. I will be
630             notified, and then you'll automatically be notified of progress on your bug as I
631             make changes.
632              
633              
634             =head1 THANKS
635              
636             The algorithms in this module have been ported from the C source code in
637             bpsw1.zip by Thomas R. Nicely, available at http://www.trnicely.net/misc/bpsw.html
638             or in the spec/bpsw directory of the Math::Primality source code. Without his
639             research this module would not exist.
640              
641             The Math::GMPz module that interfaces with the GMP C-library was written and is
642             maintained by Sysiphus. Without his work, our work would be impossible.
643              
644             =head1 SUPPORT
645              
646             You can find documentation for this module with the perldoc command.
647              
648             perldoc Math::Primality
649              
650              
651             You can also look for information at:
652              
653             =over 4
654              
655             =item * Math::Primality on Github
656              
657             L
658              
659             =item * RT: CPAN's request tracker
660              
661             L
662              
663             =item * AnnoCPAN: Annotated CPAN documentation
664              
665             L
666              
667             =item * CPAN Ratings
668              
669             L
670              
671             =item * Search CPAN
672              
673             L
674              
675             =back
676              
677              
678             =head1 ACKNOWLEDGEMENTS
679              
680              
681             =head1 COPYRIGHT & LICENSE
682              
683             Copyright 2009 Jonathan Leto, all rights reserved.
684              
685             This program is free software; you can redistribute it and/or modify it
686             under the same terms as Perl itself.
687              
688              
689             =cut
690              
691             exp(0); # End of Math::Primality