File Coverage

blib/lib/Math/NumSeq/RepdigitAny.pm
Criterion Covered Total %
statement 79 79 100.0
branch 22 22 100.0
condition 2 3 66.6
subroutine 13 13 100.0
pod 3 3 100.0
total 119 120 99.1


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::RepdigitAny;
19 2     2   6854 use 5.004;
  2         4  
20 2     2   6 use strict;
  2         2  
  2         39  
21              
22 2     2   6 use vars '$VERSION', '@ISA';
  2         2  
  2         94  
23             $VERSION = 72;
24 2     2   347 use Math::NumSeq 7; # v.7 for _is_infinite()
  2         21  
  2         77  
25             @ISA = ('Math::NumSeq');
26             *_is_infinite = \&Math::NumSeq::_is_infinite;
27              
28             # uncomment this to run the ### lines
29             #use Smart::Comments;
30              
31              
32             # use constant name => Math::NumSeq::__('Repdigit Any Radix');
33 2     2   7 use constant description => Math::NumSeq::__('Numbers which are a "repdigit" like 1111, 222, 999 etc of 3 or more digits in some number base.');
  2         3  
  2         5  
34 2     2   7 use constant i_start => 1;
  2         3  
  2         72  
35 2     2   9 use constant values_min => 0;
  2         2  
  2         89  
36 2     2   7 use constant characteristic_increasing => 1;
  2         3  
  2         66  
37 2     2   6 use constant characteristic_integer => 1;
  2         2  
  2         67  
38              
39             # cf A167783 - length >=2, 2 or more bases
40             # A053696 - length >=3, 1 or more bases repunit
41             #
42             # A158235 - square is a repdigit in some base < i
43             # A158236 - the radix for those squares
44             # A158237 - those squares, ie. squares which are repdigits some base
45             # A158245 - "primitives" in squares seq, meaning square-free
46             #
47 2     2   5 use constant oeis_anum => 'A167782'; # length >=3, 1 or more bases
  2         2  
  2         678  
48              
49             sub rewind {
50 4     4 1 364 my ($self) = @_;
51 4         19 $self->{'i'} = $self->i_start;
52 4         4 $self->{'done'} = 0;
53 4         9 $self->{'ones'} = [ undef, undef, 7 ];
54 4         12 $self->{'digits'} = [ undef, undef, 1 ];
55             }
56              
57             sub next {
58 25     25 1 431 my ($self) = @_;
59             ### RepdigitAny next(): $self->{'i'}
60              
61 25         18 my $done;
62 25 100       33 if ($done = $self->{'done'}) {
63 22         21 my $min = $done*$done + 7;
64 22         14 my $ones = $self->{'ones'};
65 22         17 my $digits = $self->{'digits'};
66              
67 22         18 for (my $radix = 2; ; $radix++) {
68             ### $radix
69              
70 86         47 my $one;
71 86 100       77 if ($radix > $#$ones) {
72             ### maybe extend array: $radix
73 33         24 $one = ($radix + 1) * $radix + 1;
74 33 100       43 if ($one > $min) {
75             ### stop at big one: $one
76 22         17 last;
77             }
78 11         16 $ones->[$radix] = $one;
79 11         10 $digits->[$radix] = 1;
80             } else {
81 53         37 $one = $ones->[$radix];
82             }
83              
84 64         38 my $repdigit;
85 64         83 while (($repdigit = $one * $digits->[$radix]) <= $done) {
86             ### increase past done: $repdigit
87 20 100       32 if (++$digits->[$radix] >= $radix) {
88 10         8 $digits->[$radix] = 1;
89 10         19 $one = $ones->[$radix] = $ones->[$radix] * $radix + 1;
90             ### digit wrap new ones: $ones->[$radix]
91             } else {
92             ### digit step: $digits->[$radix]
93             }
94             }
95              
96             ### consider repdigit: $repdigit
97 64 100       75 if ($repdigit < $min) {
98             ### min now: "$repdigit at $radix"
99 40         27 $min = $repdigit;
100             }
101             }
102             ### result: $min
103 22         16 $self->{'done'} = $min;
104 22         33 return ($self->{'i'}++, $min);
105              
106             } else {
107             # special case value 0
108 3         3 $self->{'done'} = 1;
109 3         8 return ($self->{'i'}++, 0);
110             }
111             }
112              
113             sub pred {
114 70     70 1 221 my ($self, $value) = @_;
115             ### RepdigitAny pred(): $value
116              
117 70 100       81 if ($value == 0) {
118 2         3 return 1;
119             }
120 68 100 66     97 if (_is_infinite($value) || $value != int($value)) {
121 31         31 return 0;
122             }
123              
124 37         27 RADIX: for (my $radix = 2; ; $radix++) {
125 86         64 my $ones = ($radix + 1) * $radix + 1;
126 86 100       93 if ($ones > $value) {
127 25         25 return 0;
128             }
129              
130 61         37 do {
131 84 100       89 if ($ones == $value) {
132 10         10 return 1;
133             }
134 74         69 foreach my $digit (2 .. $radix-1) {
135 26         16 my $repdigit = $digit * $ones;
136 26 100       30 if ($repdigit == $value) {
137 2         5 return 1;
138             }
139 24 100       30 if ($repdigit > $value) {
140 20         19 next RADIX;
141             }
142             }
143 52         75 $ones = $ones * $radix + 1;
144             } while ($ones <= $value);
145             }
146             }
147              
148             1;
149             __END__