[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