File Coverage

blib/lib/Math/NumSeq/Primorials.pm
Criterion Covered Total %
statement 94 97 96.9
branch 19 22 86.3
condition 4 6 66.6
subroutine 18 18 100.0
pod 5 5 100.0
total 140 148 94.5


line stmt bran cond sub pod time code
1             # Copyright2011, 2012, 2013, 2014 Kevin Ryde
2              
3             # This file is part of Math-NumSeq.
4             #
5             # Math-NumSeq is free software; you can redistribute it and/or modify
6             # it under the terms of the GNU General Public License as published by the
7             # Free Software Foundation; either version 3, or (at your option) any later
8             # version.
9             #
10             # Math-NumSeq is distributed in the hope that it will be useful, but
11             # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12             # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13             # for more details.
14             #
15             # You should have received a copy of the GNU General Public License along
16             # with Math-NumSeq. If not, see .
17              
18             package Math::NumSeq::Primorials;
19 1     1   20 use 5.004;
  1         3  
  1         36  
20 1     1   5 use strict;
  1         2  
  1         28  
21 1     1   4 use Math::Prime::XS;
  1         4  
  1         52  
22              
23 1     1   4 use vars '$VERSION', '@ISA';
  1         2  
  1         56  
24             $VERSION = 71;
25 1     1   5 use Math::NumSeq;
  1         4  
  1         59  
26             @ISA = ('Math::NumSeq');
27             *_is_infinite = \&Math::NumSeq::_is_infinite;
28              
29             # use constant name => Math::NumSeq::__('Primorials');
30 1     1   5 use constant description => Math::NumSeq::__('The primorials 1, 2, 6, 30, 210, etc, 2*3*5*7*...Prime(n).');
  1         2  
  1         6  
31 1     1   5 use constant i_start => 0;
  1         2  
  1         41  
32 1     1   5 use constant characteristic_increasing => 1;
  1         2  
  1         31  
33 1     1   12 use constant characteristic_integer => 1;
  1         2  
  1         38  
34 1     1   4 use constant values_min => 1;
  1         2  
  1         39  
35              
36             # cf A034386 product of primes p <= i, so repeating 1, 2, 6, 6, 30, 30,
37             # A143293 partial sums of primorials
38             #
39 1     1   6 use constant oeis_anum => 'A002110'; # starting at 1
  1         2  
  1         43  
40              
41             # uncomment this to run the ### lines
42             #use Devel::Comments;
43              
44 1     1   6 use constant 1.02; # for leading underscore
  1         16  
  1         120  
45 1         2 use constant _UV_LIMIT => do {
46 1         2 my $u = ~0 >> 1;
47 1         2 my $limit = 1;
48 1         6 for my $p (Math::Prime::XS::sieve_primes(100)) {
49             ### $p
50 16 100       131 if ($u < $p) {
51             ### _UV_LIMIT stop before prime: "p=$p"
52 1         5 last;
53             }
54 15         16 $u -= ($u % $p);
55 15         16 $u /= $p;
56 15         18 $limit *= $p;
57             }
58             $limit
59 1     1   6 };
  1         3  
  1         628  
60             ### _UV_LIMIT: _UV_LIMIT()
61              
62             sub rewind {
63 3     3 1 252 my ($self) = @_;
64             ### Primorials rewind()
65 3         10 $self->{'prime'} = 1;
66 3         21 $self->{'i'} = $self->i_start;
67 3         13 $self->{'f'} = 1;
68             }
69             sub next {
70 10     10 1 138 my ($self) = @_;
71             ### Primorials next() ...
72              
73 10 100       27 if (my $i = $self->{'i'}++) {
74 8         12 my $f = $self->{'f'};
75 8 50 33     21 if ($f >= _UV_LIMIT && ! ref $f) {
76 0         0 $self->{'f'} = Math::NumSeq::_to_bigint($f);
77             }
78 8         11 my $prime;
79 8         10 do {
80 14         47 $prime = $self->{'prime'}++;
81             } until (Math::Prime::XS::is_prime($prime));
82 8         26 return ($i, $self->{'f'} *= $prime);
83              
84             } else {
85 2         9 return (0, 1);
86             }
87             }
88              
89             sub ith {
90 18     18 1 66 my ($self, $i) = @_;
91             ### Primorials ith(): $i
92 18 50       47 if (_is_infinite($i)) {
93 0         0 return $i;
94             }
95 18         28 my $f = 1;
96 18         25 my $prime = 1;
97 18         48 while ($i-- > 0) {
98 128 100 100     11286 if ($f >= _UV_LIMIT && ! ref $f) {
99 1         7 $f = Math::NumSeq::_to_bigint($f);
100             }
101 128         8876 until (Math::Prime::XS::is_prime(++$prime)) {}
102 128         336 $f *= $prime;
103             }
104 18         199 return $f;
105             }
106              
107             sub pred {
108 424     424 1 2046 my ($self, $value) = @_;
109             ### Primorials pred()
110 424         472 my $prime = 2;
111 424         459 for (;;) {
112 566 100       1013 if ($value <= 1) {
113 10         31 return ($value == 1);
114             }
115 556 100       1306 if ($value % $prime) {
116 296         622 return 0; # not divisible by this prime
117             }
118              
119 260         379 $value /= $prime;
120 260 100       527 if (($value % $prime) == 0) {
121 118         264 return 0; # doubled prime factor
122             }
123              
124 142         444 until (Math::Prime::XS::is_prime(++$prime)) {} # next $prime
125             }
126             }
127              
128             sub value_to_i_floor {
129 43     43 1 524 my ($self, $value) = @_;
130 43 50       98 if (_is_infinite($value)) {
131 0         0 return $value;
132             }
133 43 100       2013 if ($value < 2) {
134 17         129 return $self->i_start;
135             }
136              
137 26         436 my $i = 0;
138 26         35 my $prime = 2;
139 26         31 for (;;) {
140             ### $value
141             ### $i
142              
143 87 100       184 if ($value < $prime) {
144 26         478 return $i;
145             }
146 61         1291 $value = int($value/$prime);
147              
148 61         2461 $i++;
149 61         273 until (Math::Prime::XS::is_prime(++$prime)) {} # next $prime
150             }
151             }
152              
153             # ENHANCE-ME: maybe a slightly squashed down log() would be close enough
154             #
155             *value_to_i_estimate = \&value_to_i_floor;
156              
157             1;
158             __END__