File Coverage

blib/lib/Math/NumSeq/Multiples.pm
Criterion Covered Total %
statement 78 86 90.7
branch 10 16 62.5
condition n/a
subroutine 25 26 96.1
pod 13 16 81.2
total 126 144 87.5


line stmt bran cond sub pod time code
1             # Copyright 2010, 2011, 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::Multiples;
19 2     2   6852 use 5.004;
  2         5  
20 2     2   11 use strict;
  2         2  
  2         54  
21 2     2   396 use POSIX 'ceil';
  2         4614  
  2         11  
22              
23 2     2   2213 use vars '$VERSION', '@ISA';
  2         4  
  2         129  
24             $VERSION = 72;
25 2     2   358 use Math::NumSeq;
  2         3  
  2         104  
26             @ISA = ('Math::NumSeq');
27              
28             # uncomment this to run the ### lines
29             #use Devel::Comments;
30              
31              
32             # use constant name => Math::NumSeq::__('Multiples of a given K');
33 2     2   10 use constant description => Math::NumSeq::__('The multiples K, 2*K, 3*K, 4*K, etc of a given number.');
  2         2  
  2         6  
34 2     2   8 use constant default_i_start => 0;
  2         3  
  2         516  
35              
36             sub values_min {
37 2     2 1 10 my ($self) = @_;
38 2 50       6 if ((my $multiples = $self->{'multiples'}) >= 0) {
39 2         5 return $multiples * $self->i_start;
40             } else {
41 0         0 return undef;
42             }
43             }
44             sub values_max {
45 0     0 1 0 my ($self) = @_;
46 0 0       0 if ((my $multiples = $self->{'multiples'}) <= 0) {
47 0         0 return $multiples * $self->i_start;
48             } else {
49 0         0 return undef;
50             }
51             }
52             sub characteristic_non_decreasing {
53 2     2 0 2 my ($self) = @_;
54 2         7 return ($self->{'multiples'} >= 0);
55             }
56             sub characteristic_increasing {
57 4     4 0 6 my ($self) = @_;
58 4         12 return ($self->{'multiples'} > 0);
59             }
60             sub characteristic_integer {
61 3     3 0 2 my ($self) = @_;
62 3         12 return (int($self->{'multiples'}) == $self->{'multiples'});
63             }
64              
65 2         5 use constant parameter_info_array =>
66             [ { name => 'multiples',
67             type => 'float',
68             width => 10,
69             decimals => 4,
70             page_increment => 10,
71             step_increment => 1,
72             minimum => 0,
73             default => 29,
74             description => Math::NumSeq::__('Display multiples of this number. For example 6 means show 6,12,18,24,30,etc.'),
75             },
76 2     2   10 ];
  2         4  
77              
78             #------------------------------------------------------------------------------
79              
80             # cf A017173 9n+1
81             my %oeis_anum =
82             (0 => { 0 => 'A000004', # 0, all zeros
83             # OEIS-Catalogue: A000004 multiples=0
84              
85             1 => 'A001477', # 1, integers 0,1,2,...
86             2 => 'A005843', # 2 even 0,2,4,...
87             # OEIS-Other: A001477 multiples=1
88             # OEIS-Other: A005843 multiples=2
89              
90             3 => 'A008585', # 3 starting from i=0
91             4 => 'A008586', # 4 starting from i=0
92             5 => 'A008587', # 5 starting from i=0
93             6 => 'A008588', # 6 starting from i=0
94             7 => 'A008589', # 7 starting from i=0
95             8 => 'A008590', # 8 starting from i=0
96             9 => 'A008591', # 9 starting from i=0
97             10 => 'A008592', # 10 starting from i=0
98             # OEIS-Catalogue: A008585 multiples=3
99             # OEIS-Catalogue: A008586 multiples=4
100             # OEIS-Catalogue: A008587 multiples=5
101             # OEIS-Catalogue: A008588 multiples=6
102             # OEIS-Catalogue: A008589 multiples=7
103             # OEIS-Catalogue: A008590 multiples=8
104             # OEIS-Catalogue: A008591 multiples=9
105             # OEIS-Catalogue: A008592 multiples=10
106             },
107             1 => {
108             3018 => 'A086746', # multiples of 3018, start OFFSET=1 value=3018
109             # OEIS-Catalogue: A086746 multiples=3018 i_start=1
110             },
111             );
112             sub oeis_anum {
113 2     2 1 8 my ($self) = @_;
114 2         5 my $i_start = $self->i_start;
115 2 50       6 if ($i_start < 0) { return undef; }
  0         0  
116 2         7 return $oeis_anum{$i_start}->{$self->{'multiples'}};
117             }
118              
119             #------------------------------------------------------------------------------
120              
121             sub rewind {
122 12     12 1 813 my ($self) = @_;
123 12         35 $self->{'i'} = $self->i_start;
124             }
125             sub seek_to_i {
126 14     14 1 137 my ($self, $i) = @_;
127             # if ($i >= $self->{'uv_i_limit'}) {
128             # $i = Math::NumSeq::_to_bigint($i);
129             # }
130 14         17 $self->{'i'} = $i;
131             }
132             sub seek_to_value {
133 14     14 1 66 my ($self, $value) = @_;
134 14         18 $self->{'i'} = $self->value_to_i_ceil($value);
135             }
136             sub next {
137 98     98 1 1211 my ($self) = @_;
138 98         70 my $i = $self->{'i'}++;
139 98         108 return ($i, $i * $self->{'multiples'});
140             }
141             sub ith {
142 218     218 1 244 my ($self, $i) = @_;
143 218         344 return $i * $self->{'multiples'};
144             }
145             sub pred {
146 484     484 1 1029 my ($self, $value) = @_;
147 484         329 my $multiples = $self->{'multiples'};
148 484 50       495 if ($multiples == 0) {
149 0         0 return ($value == 0);
150             }
151 484         342 my $i = int($value / $multiples);
152 484         459 return ($value == $i*$multiples);
153             }
154              
155             use constant::defer _INFINITY => sub {
156 1         20 require POSIX;
157 1         3 return 2 * POSIX::DBL_MAX();
158 2     2   11 };
  2         2  
  2         15  
159              
160             sub value_to_i_estimate {
161 34     34 1 646 my ($self, $value) = @_;
162 34         20 my $multiples = $self->{'multiples'};
163 34 100       43 if ($multiples == 0) {
164 1         4 return _INFINITY;
165             }
166 33         37 return int($value / $multiples);
167             }
168              
169 2     2   1604 use Math::NumSeq::All;
  2         3  
  2         355  
170             *_floor = \&Math::NumSeq::All::_floor;
171              
172             sub value_to_i {
173 76     76 1 188 my ($self, $value) = @_;
174 76         91 my $i = $self->value_to_i_floor($value);
175 76 100       93 if ($value == $self->ith($i)) {
176 29         1477 return $i;
177             }
178 47         50 return undef;
179             }
180             sub value_to_i_floor {
181 277     277 1 344 my ($self, $value) = @_;
182 277         475 return _floor($value/$self->{'multiples'});
183             }
184             sub value_to_i_ceil {
185 94     94 1 206 my ($self, $value) = @_;
186 94 50       127 if ($value < 0) { return 0; }
  0         0  
187 94         1322 my $i = $self->value_to_i_floor($value);
188 94 100       112 if ($value > $self->ith($i)) {
189 24         21 $i += 1;
190             }
191 94         1490 return $i;
192             }
193              
194              
195             1;
196             __END__