File Coverage

blib/lib/Math/NumSeq/Primorials.pm
Criterion Covered Total %
statement 93 96 96.8
branch 19 22 86.3
condition 4 6 66.6
subroutine 18 18 100.0
pod 5 5 100.0
total 139 147 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   13 use 5.004;
  1         2  
20 1     1   4 use strict;
  1         1  
  1         15  
21 1     1   3 use Math::Prime::XS;
  1         1  
  1         56  
22              
23 1     1   4 use vars '$VERSION', '@ISA';
  1         5  
  1         41  
24             $VERSION = 72;
25 1     1   4 use Math::NumSeq;
  1         1  
  1         60  
26             @ISA = ('Math::NumSeq');
27             *_is_infinite = \&Math::NumSeq::_is_infinite;
28              
29             # use constant name => Math::NumSeq::__('Primorials');
30 1     1   7 use constant description => Math::NumSeq::__('The primorials 1, 2, 6, 30, 210, etc, 2*3*5*7*...Prime(n).');
  1         3  
  1         17  
31 1     1   6 use constant i_start => 0;
  1         1  
  1         59  
32 1     1   6 use constant characteristic_increasing => 1;
  1         3  
  1         53  
33 1     1   6 use constant characteristic_integer => 1;
  1         1  
  1         59  
34 1     1   5 use constant values_min => 1;
  1         2  
  1         35  
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   3 use constant oeis_anum => 'A002110'; # starting at 1
  1         1  
  1         43  
40              
41             # uncomment this to run the ### lines
42             #use Devel::Comments;
43              
44 1     1   3 use constant 1.02; # for leading underscore
  1         11  
  1         83  
45 1         2 use constant _UV_LIMIT => do {
46 1         1 my $u = ~0 >> 1;
47 1         1 my $limit = 1;
48 1         4 for my $p (Math::Prime::XS::sieve_primes(100)) {
49             ### $p
50 16 100       82 if ($u < $p) {
51             ### _UV_LIMIT stop before prime: "p=$p"
52 1         2 last;
53             }
54 15         9 $u -= ($u % $p);
55 15         13 $u /= $p;
56 15         8 $limit *= $p;
57             }
58             $limit
59 1     1   3 };
  1         1  
  1         410  
60             ### _UV_LIMIT: _UV_LIMIT()
61              
62             sub rewind {
63 3     3 1 333 my ($self) = @_;
64             ### Primorials rewind()
65 3         8 $self->{'prime'} = 1;
66 3         14 $self->{'i'} = $self->i_start;
67 3         6 $self->{'f'} = 1;
68             }
69             sub next {
70 10     10 1 301 my ($self) = @_;
71             ### Primorials next() ...
72              
73 10 100       18 if (my $i = $self->{'i'}++) {
74 8         7 my $f = $self->{'f'};
75 8 50 33     17 if ($f >= _UV_LIMIT && ! ref $f) {
76 0         0 $self->{'f'} = Math::NumSeq::_to_bigint($f);
77             }
78 8         12 my $prime;
79 8         10 do {
80 14         33 $prime = $self->{'prime'}++;
81             } until (Math::Prime::XS::is_prime($prime));
82 8         10 return ($i, $self->{'f'} *= $prime);
83              
84             } else {
85 2         5 return (0, 1);
86             }
87             }
88              
89             sub ith {
90 18     18 1 40 my ($self, $i) = @_;
91             ### Primorials ith(): $i
92 18 50       45 if (_is_infinite($i)) {
93 0         0 return $i;
94             }
95 18         13 my $f = 1;
96 18         17 my $prime = 1;
97 18         24 while ($i-- > 0) {
98 128 100 100     7180 if ($f >= _UV_LIMIT && ! ref $f) {
99 1         4 $f = Math::NumSeq::_to_bigint($f);
100             }
101 128         5592 until (Math::Prime::XS::is_prime(++$prime)) {}
102 128         198 $f *= $prime;
103             }
104 18         141 return $f;
105             }
106              
107             sub pred {
108 424     424 1 887 my ($self, $value) = @_;
109             ### Primorials pred()
110 424         255 my $prime = 2;
111 424         224 for (;;) {
112 566 100       593 if ($value <= 1) {
113 10         13 return ($value == 1);
114             }
115 556 100       597 if ($value % $prime) {
116 296         245 return 0; # not divisible by this prime
117             }
118              
119 260         146 $value /= $prime;
120 260 100       315 if (($value % $prime) == 0) {
121 118         93 return 0; # doubled prime factor
122             }
123              
124 142         240 until (Math::Prime::XS::is_prime(++$prime)) {} # next $prime
125             }
126             }
127              
128             sub value_to_i_floor {
129 43     43 1 296 my ($self, $value) = @_;
130 43 50       58 if (_is_infinite($value)) {
131 0         0 return $value;
132             }
133 43 100       1338 if ($value < 2) {
134 17         81 return $self->i_start;
135             }
136              
137 26         267 my $i = 0;
138 26         18 my $prime = 2;
139 26         20 for (;;) {
140             ### $value
141             ### $i
142              
143 87 100       108 if ($value < $prime) {
144 26         291 return $i;
145             }
146 61         812 $value = int($value/$prime);
147              
148 61         1421 $i++;
149 61         155 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__