File Coverage

blib/lib/Math/NumSeq/MaxDigitCount.pm
Criterion Covered Total %
statement 74 79 93.6
branch 19 22 86.3
condition n/a
subroutine 17 18 94.4
pod 4 6 66.6
total 114 125 91.2


line stmt bran cond sub pod time code
1             # Copyright 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::MaxDigitCount;
19 1     1   14470 use 5.004;
  1         5  
  1         41  
20 1     1   10 use strict;
  1         3  
  1         105  
21 1     1   6 use List::Util 'max';
  1         4  
  1         84  
22              
23 1     1   6 use vars '$VERSION', '@ISA';
  1         2  
  1         70  
24             $VERSION = 71;
25              
26 1     1   6 use Math::NumSeq;
  1         3  
  1         26  
27 1     1   7 use Math::NumSeq::Base::IterateIth;
  1         2  
  1         62  
28             @ISA = ('Math::NumSeq::Base::IterateIth',
29             'Math::NumSeq');
30             *_is_infinite = \&Math::NumSeq::_is_infinite;
31              
32             # uncomment this to run the ### lines
33             #use Smart::Comments;
34              
35              
36             # use constant name => Math::NumSeq::__('...');
37 1     1   6 use constant description => Math::NumSeq::__('Maximum count of a given digit in any radix.');
  1         2  
  1         7  
38 1     1   6 use constant default_i_start => 1;
  1         3  
  1         133  
39 1         5 use constant parameter_info_array =>
40             [
41             {
42             name => 'digit',
43             share_key => 'digit_0',
44             type => 'integer',
45             display => Math::NumSeq::__('Digit'),
46             default => 0,
47             minimum => 0,
48             width => 2,
49             description => Math::NumSeq::__('Digit to count.'),
50             },
51             {
52             name => 'values_type',
53             share_key => 'values_type_cr',
54             type => 'enum',
55             default => 'count',
56             choices => ['count','radix'],
57             choices_display => [Math::NumSeq::__('Count'),
58             Math::NumSeq::__('Radix')],
59             description => Math::NumSeq::__('Whether to give the digit count or the radix the count occurs in.'),
60             },
61 1     1   4 ];
  1         4  
62              
63             sub characteristic_count {
64 4     4 0 10 my ($self) = @_;
65 4         18 return $self->{'values_type'} eq 'count';
66             }
67             sub characteristic_value_is_radix {
68 0     0 0 0 my ($self) = @_;
69 0         0 return $self->{'values_type'} eq 'radix';
70             }
71 1     1   7 use constant characteristic_smaller => 1;
  1         2  
  1         44  
72 1     1   5 use constant characteristic_integer => 1;
  1         3  
  1         518  
73              
74             sub values_min {
75 4     4 1 42 my ($self) = @_;
76 4 100       21 if ($self->{'values_type'} eq 'count') {
77 2 100       10 if ($self->{'digit'} == 1) {
78 1         5 return 1;
79             }
80             } else { # values_type=='radix'
81 2         6 return 2;
82             }
83 1         3 return 0;
84             }
85              
86             #------------------------------------------------------------------------------
87             # cf A033093 number of zeros in triangle of base 2 to n+1
88              
89             my %oeis_anum;
90             $oeis_anum{'count'}->[0] = 'A062842'; # max 0s count
91             $oeis_anum{'count'}->[1] = 'A062843'; # max 1s count
92             # OEIS-Catalogue: A062842
93             # OEIS-Catalogue: A062843 digit=1
94             sub oeis_anum {
95 4     4 1 21 my ($self) = @_;
96 4         18 return $oeis_anum{$self->{'values_type'}}->[$self->{'digit'}];
97             }
98              
99             #------------------------------------------------------------------------------
100              
101             sub ith {
102 432     432 1 804 my ($self, $i) = @_;
103             ### MaxDigitCount ith(): $i
104              
105 432 50       981 if (_is_infinite($i)) {
106 0         0 return $i;
107             }
108 432         636 $i = abs($i);
109              
110 432         650 my $digit = $self->{'digit'};
111 432         472 my $found_count = 0;
112 432         468 my $found_radix = 2;
113 432         1047 foreach my $radix (2 .. max($i,2)) {
114 1900         3630 my $digits = _digit_split($i,$radix); # low to high
115              
116             ### $radix
117             ### $digits
118              
119 1900 100       5074 if (@$digits < $found_count) {
120 8         20 last; # fewer digits now than already found
121             }
122 1892         2839 my $count = grep {$_ == $digit} @$digits;
  4464         7545  
123 1892 100       4374 if ($count > $found_count) {
124 460         766 $found_count = $count;
125 460         878 $found_radix = $radix;
126              
127             # all "ddddd" digits, is the maximum possible
128             # or "X0000" when digit=0 is the maximum possible
129 460 100       1136 if ($count == scalar(@$digits) - ($digit==0)) {
130 194         340 last;
131             }
132             }
133             }
134 432 100       1863 return ($self->{'values_type'} eq 'radix' ? $found_radix : $found_count);
135             }
136              
137             sub _digit_split {
138 1900     1900   2449 my ($n, $radix) = @_;
139             # ### _digit_split(): $n
140 1900         1899 my @ret;
141 1900         3274 while ($n) {
142 4484         5613 push @ret, $n % $radix;
143 4484         8991 $n = int($n/$radix);
144             }
145 1900         3370 return \@ret; # array[0] low digit
146             }
147              
148             sub pred {
149 40     40 1 199 my ($self, $value) = @_;
150 40 50       80 unless ($value == int($value)) {
151 0         0 return 0;
152             }
153 40 100       76 if ($self->{'values_type'} eq 'count') {
154 20 100       50 if ($self->{'digit'} == 1) {
155 10         29 return ($value >= 1);
156             }
157             } else { # values_type=='radix'
158 20 50       37 if ($value == 1) {
159 0         0 return 0;
160             }
161             }
162 30         60 return ($value >= 0);
163             }
164              
165             1;
166             __END__