File Coverage

blib/lib/Math/NumSeq/RepdigitAny.pm
Criterion Covered Total %
statement 80 80 100.0
branch 22 22 100.0
condition 2 3 66.6
subroutine 13 13 100.0
pod 3 3 100.0
total 120 121 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   385010 use 5.004;
  2         9  
  2         83  
20 2     2   12 use strict;
  2         3  
  2         89  
21              
22 2     2   9 use vars '$VERSION', '@ISA';
  2         5  
  2         145  
23             $VERSION = 71;
24 2     2   695 use Math::NumSeq 7; # v.7 for _is_infinite()
  2         38  
  2         125  
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   13 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         4  
  2         11  
34 2     2   12 use constant i_start => 1;
  2         3  
  2         83  
35 2     2   8 use constant values_min => 0;
  2         4  
  2         80  
36 2     2   9 use constant characteristic_increasing => 1;
  2         3  
  2         75  
37 2     2   8 use constant characteristic_integer => 1;
  2         6  
  2         74  
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   9 use constant oeis_anum => 'A167782'; # length >=3, 1 or more bases
  2         4  
  2         6832  
48              
49             sub rewind {
50 4     4 1 309 my ($self) = @_;
51 4         35 $self->{'i'} = $self->i_start;
52 4         9 $self->{'done'} = 0;
53 4         16 $self->{'ones'} = [ undef, undef, 7 ];
54 4         23 $self->{'digits'} = [ undef, undef, 1 ];
55             }
56              
57             sub next {
58 25     25 1 326 my ($self) = @_;
59             ### RepdigitAny next(): $self->{'i'}
60              
61 25         29 my $done;
62 25 100       58 if ($done = $self->{'done'}) {
63 22         33 my $min = $done*$done + 7;
64 22         34 my $ones = $self->{'ones'};
65 22         64 my $digits = $self->{'digits'};
66              
67 22         34 for (my $radix = 2; ; $radix++) {
68             ### $radix
69              
70 86         87 my $one;
71 86 100       161 if ($radix > $#$ones) {
72             ### maybe extend array: $radix
73 33         43 $one = ($radix + 1) * $radix + 1;
74 33 100       64 if ($one > $min) {
75             ### stop at big one: $one
76 22         32 last;
77             }
78 11         21 $ones->[$radix] = $one;
79 11         22 $digits->[$radix] = 1;
80             } else {
81 53         65 $one = $ones->[$radix];
82             }
83              
84 64         75 my $repdigit;
85 64         151 while (($repdigit = $one * $digits->[$radix]) <= $done) {
86             ### increase past done: $repdigit
87 20 100       51 if (++$digits->[$radix] >= $radix) {
88 10         13 $digits->[$radix] = 1;
89 10         32 $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       126 if ($repdigit < $min) {
98             ### min now: "$repdigit at $radix"
99 40         63 $min = $repdigit;
100             }
101             }
102             ### result: $min
103 22         38 $self->{'done'} = $min;
104 22         67 return ($self->{'i'}++, $min);
105              
106             } else {
107             # special case value 0
108 3         6 $self->{'done'} = 1;
109 3         15 return ($self->{'i'}++, 0);
110             }
111             }
112              
113             sub pred {
114 70     70 1 415 my ($self, $value) = @_;
115             ### RepdigitAny pred(): $value
116              
117 70 100       152 if ($value == 0) {
118 2         6 return 1;
119             }
120 68 100 66     160 if (_is_infinite($value) || $value != int($value)) {
121 31         72 return 0;
122             }
123              
124 37         64 RADIX: for (my $radix = 2; ; $radix++) {
125 86         140 my $ones = ($radix + 1) * $radix + 1;
126 86 100       203 if ($ones > $value) {
127 25         64 return 0;
128             }
129              
130 61         78 do {
131 84 100       163 if ($ones == $value) {
132 10         27 return 1;
133             }
134 74         131 foreach my $digit (2 .. $radix-1) {
135 26         34 my $repdigit = $digit * $ones;
136 26 100       51 if ($repdigit == $value) {
137 2         6 return 1;
138             }
139 24 100       55 if ($repdigit > $value) {
140 20         42 next RADIX;
141             }
142             }
143 52         135 $ones = $ones * $radix + 1;
144             } while ($ones <= $value);
145             }
146             }
147              
148             1;
149             __END__