[libmath-prime-util-perl] 08/11: tests for forprimes and iterator

Partha P. Mukherjee ppm-guest at moszumanska.debian.org
Thu May 21 18:48:32 UTC 2015


This is an automated email from the git hooks/post-receive script.

ppm-guest pushed a commit to annotated tag v0.28
in repository libmath-prime-util-perl.

commit b1a7215698bdcec89ced51b3013599828e3baf9d
Author: Dana Jacobsen <dana at acm.org>
Date:   Thu May 23 01:45:47 2013 -0700

    tests for forprimes and iterator
---
 Changes                           |  3 ++
 TODO                              |  9 ------
 XS.xs                             |  9 +++---
 factor.c                          | 35 +++++++++++++--------
 lib/Math/Prime/Util.pm            | 17 ++++++-----
 lib/Math/Prime/Util/PP.pm         |  7 +++--
 lib/Math/Prime/Util/PrimeArray.pm |  2 +-
 t/32-iterators.t                  | 64 +++++++++++++++++++++++++++++++++++++++
 8 files changed, 109 insertions(+), 37 deletions(-)

diff --git a/Changes b/Changes
index e97dbdb..52e67ed 100644
--- a/Changes
+++ b/Changes
@@ -12,6 +12,9 @@ Revision history for Perl extension Math::Prime::Util.
         $sum = 0;  forprimes { $sum += $_ } 1000,50000;  say $sum;
         forprimes { say if is_prime($_+2) } 10000;  # print twin primes
 
+    - my $it = prime_iterator(10000); say $it->(); 
+      This is experimental (that is, the interface may change).
+
 0.27 20 May 2013
 
     - is_prime, is_prob_prime, next_prime, and prev_prime now all go straight
diff --git a/TODO b/TODO
index bc275d1..aaa6311 100644
--- a/TODO
+++ b/TODO
@@ -41,15 +41,6 @@
    - LMO prime count
    - QS factoring
 
-- forprimes { say } 1000,2000
-  - Tests
-  - Examples
-
-- prime_iterator
-  - Documentation
-  - Tests
-  - Examples
-
 - Make forprimes use a segment sieve
 
 - Figure out a way to make the internal FOR_EACH_PRIME macros use a segmented
diff --git a/XS.xs b/XS.xs
index f395c63..86066d9 100644
--- a/XS.xs
+++ b/XS.xs
@@ -5,7 +5,6 @@
 #include "perl.h"
 #include "XSUB.h"
 #include "multicall.h"  /* only works in 5.6 and newer */
-#include <ctype.h>
 /* We're not using anything for which we need ppport.h */
 #ifndef XSRETURN_UV   /* Er, almost.  Fix 21086 from Sep 2003 */
   #define XST_mUV(i,v)  (ST(i) = sv_2mortal(newSVuv(v))  )
@@ -23,7 +22,7 @@
 #if PERL_REVISION <= 5 && PERL_VERSION <= 6 && BITS_PER_WORD == 64
  /* This could be blown up with a wacky string, but it's just for 5.6 */
  #define set_val_from_sv(val, sv) \
-   { char*ptr = SvPV_nolen(sv); val = strtoul(ptr, NULL, 10); }
+   { char*ptr = SvPV_nolen(sv); val = Strtoul(ptr, NULL, 10); }
 #else
  #define set_val_from_sv(val, sv) \
    val = SvUV(sv)
@@ -72,10 +71,12 @@ static int _validate_int(SV* n, int negok)
   ptr = SvPV(n, len);
   if (len == 0)  croak("Parameter '' must be a positive integer");
   for (i = 0; i < len; i++) {
-    if (!isdigit(ptr[i])) {
+    if (!isDIGIT(ptr[i])) {
       if (i == 0 && ptr[i] == '-' && negok)
         isneg = 1;
-      else if (i == 0 && ptr[i] != '+')
+      else if (i == 0 && ptr[i] == '+')
+        /* Allowed */ ;
+      else
         croak("Parameter '%s' must be a positive integer", ptr); /* TODO NULL */
     }
   }
diff --git a/factor.c b/factor.c
index 5a3a3b0..2eb88d6 100644
--- a/factor.c
+++ b/factor.c
@@ -354,13 +354,14 @@ int _XS_is_prob_prime(UV n)
   if (n < 2809) /* 53*53 */                 return 2;
 
 #if BITS_PER_WORD == 32
+  /* These aren't ideal.  Could use 1 when n < 49191, 2 when n < 360018361 */
   if (n < UVCONST(9080191)) {
     bases[0] = 31; bases[1] = 73; nbases = 2;
   } else  {
     bases[0] = 2; bases[1] = 7; bases[2] = 61; nbases = 3;
   }
 #else
-  /* Better bases from http://miller-rabin.appspot.com/, 18 May 2013 */
+  /* Better bases from http://miller-rabin.appspot.com/, 23 May 2013 */
   if (n < UVCONST(341531)) {
     bases[0] = UVCONST(9345883071009581737);
     nbases = 1;
@@ -368,24 +369,32 @@ int _XS_is_prob_prime(UV n)
     bases[0] = 15;
     bases[1] = UVCONST( 13393019396194701 );
     nbases = 2;
-  } else if (n < UVCONST(242175507817)) {
+  } else if (n < UVCONST(273919523041)) {
     bases[0] = 15;
-    bases[1] = UVCONST(      7363882082 );
-    bases[2] = UVCONST( 211573017068182 );
+    bases[1] = UVCONST(        7363882082 );
+    bases[2] = UVCONST(   992620450144556 );
     nbases = 3;
-  } else if (n < UVCONST(47636622961201)) {
+  } else if (n < UVCONST(55245642489451)) {
     bases[0] = 2;
-    bases[1] = UVCONST( 2570940    );
-    bases[2] = UVCONST( 211991001  );
-    bases[3] = UVCONST( 3749873356 );
+    bases[1] = UVCONST(      141889084524735 );
+    bases[2] = UVCONST(  1199124725622454117 );
+    bases[3] = UVCONST( 11096072698276303650 );
     nbases = 4;
-  } else if (n < UVCONST(3770579582154547)) {
+  } else if (n < UVCONST(7999252175582851)) {
     bases[0] = 2;
-    bases[1] = UVCONST( 2570940    );
-    bases[2] = UVCONST( 880937     );
-    bases[3] = UVCONST( 610386380  );
-    bases[4] = UVCONST( 4130785767 );
+    bases[1] = UVCONST(        4130806001517 );
+    bases[2] = UVCONST(   149795463772692060 );
+    bases[3] = UVCONST(   186635894390467037 );
+    bases[4] = UVCONST(  3967304179347715805 );
     nbases = 5;
+  } else if (n < UVCONST(585226005592931977)) {
+    bases[0] = 2;
+    bases[1] = UVCONST(      123635709730000 );
+    bases[2] = UVCONST(     9233062284813009 );
+    bases[3] = UVCONST(    43835965440333360 );
+    bases[4] = UVCONST(   761179012939631437 );
+    bases[5] = UVCONST(  1263739024124850375 );
+    nbases = 6;
   } else {
     bases[0] = 2;
     bases[1] = UVCONST( 325        );
diff --git a/lib/Math/Prime/Util.pm b/lib/Math/Prime/Util.pm
index 3af8fa8..b0a5c79 100644
--- a/lib/Math/Prime/Util.pm
+++ b/lib/Math/Prime/Util.pm
@@ -1352,7 +1352,8 @@ sub divisor_sum {
   return $sum;
 }
 
-sub _generic_forprimes (&$;$) {
+                                   # Need proto for the block
+sub _generic_forprimes (&$;$) {    ## no critic qw(ProhibitSubroutinePrototypes)
   my($sub, $beg, $end) = @_;
   if (!defined $end) { $end = $beg; $beg = 2; }
   _validate_num($beg) || _validate_positive_integer($beg);
@@ -1367,7 +1368,9 @@ sub _generic_forprimes (&$;$) {
 
 sub prime_iterator {
   my($start) = @_;
-  my $p = (defined $start && $start > 0) ? $start-1 : 0;
+  $start = 0 unless defined $start;
+  _validate_num($start) || _validate_positive_integer($start);
+  my $p = ($start > 0) ? $start-1 : 0;
   if (ref($p) ne 'Math::BigInt' && $p <= $_XS_MAXVAL) {
     return sub { $p = _XS_next_prime($p); return $p; };
   } elsif ($_HAVE_GMP) {
@@ -2368,7 +2371,7 @@ __END__
 
 =encoding utf8
 
-=for stopwords Möbius Deléglise totient moebius mertens irand primesieve uniqued k-tuples von SoE pari yafu fonction qui compte le nombre nombres voor PhD
+=for stopwords forprimes Möbius Deléglise totient moebius mertens irand primesieve uniqued k-tuples von SoE pari yafu fonction qui compte le nombre nombres voor PhD
 
 
 =head1 NAME
@@ -2688,10 +2691,8 @@ input is C<2> or lower.
 Given a block and either an end count or a start and end pair, calls the
 block for each prime in the range.  Compared to getting a big array of primes
 and iterating through it, this is more memory efficient and perhaps more
-convenient.
-
-Inside the block, you may use C<last> to exit early, or C<return> to skip to
-the next entry.
+convenient.  There is no way to exit the loop early, so the iterator may
+be more appropriate for those uses.
 
 
 =head2 prime_iterator
@@ -2711,7 +2712,7 @@ On each call, the iterator returns the current value and increments to
 the next prime.
 
 In general, L</forprimes> will be more efficient, but the generic iterator has
-a little more flexibility.
+more flexibility (e.g. exiting a loop early, or passing the iterator around).
 
 
 =head2 prime_count
diff --git a/lib/Math/Prime/Util/PP.pm b/lib/Math/Prime/Util/PP.pm
index aa5d818..e413d0b 100644
--- a/lib/Math/Prime/Util/PP.pm
+++ b/lib/Math/Prime/Util/PP.pm
@@ -1070,8 +1070,11 @@ sub is_aks_prime {
   return 0 if _is_perfect_power($n);
 
   # limit = floor( log2(n) * log2(n) ).  o_r(n) must be larger than this
-  my $sqrtn = int(Math::BigFloat->new($n)->bsqrt->bfloor->bstr);
-  my $log2n = Math::BigFloat->new("$n")->blog(2);
+  my $floatn = Math::BigFloat->new($n);
+  my $sqrtn = int($floatn->copy->bsqrt->bfloor->bstr);
+  # The following line seems to trigger a memory leak in Math::BigFloat::blog
+  # (the part where $MBI is copied to $int) if $n is a Math::BigInt::GMP.
+  my $log2n = $floatn->copy->blog(2);
   my $log2_squared_n = $log2n * $log2n;
   my $limit = int($log2_squared_n->bfloor->bstr);
 
diff --git a/lib/Math/Prime/Util/PrimeArray.pm b/lib/Math/Prime/Util/PrimeArray.pm
index 377b418..0d0f08b 100644
--- a/lib/Math/Prime/Util/PrimeArray.pm
+++ b/lib/Math/Prime/Util/PrimeArray.pm
@@ -180,7 +180,7 @@ An array that acts like the infinite set of primes.  This may be more
 convenient than using L<Math::Prime::Util> directly, and in some cases it can
 be faster than calling C<next_prime> and C<prev_prime>.
 
-If the access pattern is ascending or decending, then a window is sieved and
+If the access pattern is ascending or descending, then a window is sieved and
 results returned from the window as needed.  If the access pattern is random,
 then C<nth_prime> is used.
 
diff --git a/t/32-iterators.t b/t/32-iterators.t
new file mode 100644
index 0000000..202ad66
--- /dev/null
+++ b/t/32-iterators.t
@@ -0,0 +1,64 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+
+use Test::More;
+use Math::Prime::Util qw/primes forprimes prime_iterator/;
+
+my $use64 = Math::Prime::Util::prime_get_config->{'maxbits'} > 32;
+
+plan tests => 8 + 5
+            + 3 + 7;
+
+ok(!eval { forprimes { 1 } undef; },   "forprimes undef");
+ok(!eval { forprimes { 1 } 2, undef; },   "forprimes 2,undef");
+ok(!eval { forprimes { 1 } undef, 2; },   "forprimes 2,undef");
+# This is caught at compile type because of the prototype
+#ok(!eval { forprimes { 1 } 2, 3, 4; },   "forprimes 2,3,4");
+ok(!eval { forprimes { 1 } -2, 3; },   "forprimes -2,3");
+ok(!eval { forprimes { 1 } 2, -3; },   "forprimes 2,-3");
+ok(!eval { forprimes { 1 } "abc"; },   "forprimes abc");
+ok(!eval { forprimes { 1 } 2, "abc"; },   "forprimes 2, abc");
+ok(!eval { forprimes { 1 } 5.6; },   "forprimes abc");
+
+{ my @t; forprimes { push @t, $_ } 50;
+  is_deeply( [@t], [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47], "forprimes 50" );
+}
+{ my @t; forprimes { push @t, $_ } 2,20;
+  is_deeply( [@t], [2,3,5,7,11,13,17,19], "forprimes 2,20" );
+}
+{ my @t; forprimes { push @t, $_ } 20,30;
+  is_deeply( [@t], [23,29], "forprimes 20,30" );
+}
+{ my @t; forprimes { push @t, $_ } 199, 223;
+  is_deeply( [@t], [199,211,223], "forprimes 199,223" );
+}
+{ my @t; forprimes { push @t, $_ } 31398, 31468;
+  is_deeply( [@t], [], "forprimes 31398,31468 (empty region)" );
+}
+
+ok(!eval { prime_iterator(-2); }, "iterator -2");
+ok(!eval { prime_iterator("abc"); }, "iterator abc");
+ok(!eval { prime_iterator(4.5); }, "iterator 4.5");
+
+{ my $it = prime_iterator();
+  is_deeply( [map { $it->() } 1..10], [2,3,5,7,11,13,17,19,23,29], "iterator first 10 primes" );
+}
+{my $it = prime_iterator(47);
+  is_deeply( [map { $it->() } 1..5], [47,53,59,61,67], "iterator 5 primes starting at 47" );
+}
+{my $it = prime_iterator(199);
+  is_deeply( [map { $it->() } 1..3], [199,211,223], "iterator 3 primes starting at 199" );
+}
+{my $it = prime_iterator(200);
+  is_deeply( [map { $it->() } 1..3], [211,223,227], "iterator 3 primes starting at 200" );
+}
+{my $it = prime_iterator(31397);
+  is_deeply( [map { $it->() } 1..3], [31397,31469,31477], "iterator 3 primes starting at 31397" );
+}
+{my $it = prime_iterator(31396);
+  is_deeply( [map { $it->() } 1..3], [31397,31469,31477], "iterator 3 primes starting at 31396" );
+}
+{my $it = prime_iterator(31398);
+  is_deeply( [map { $it->() } 1..3], [31469,31477,31481], "iterator 3 primes starting at 31398" );
+}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-perl/packages/libmath-prime-util-perl.git



More information about the Pkg-perl-cvs-commits mailing list