| 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 |  | 1040 | use 5.004; | 
|  | 1 |  |  |  |  | 2 |  | 
| 20 | 1 |  |  | 1 |  | 4 | use strict; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 21 |  | 
| 21 | 1 |  |  | 1 |  | 3 | use List::Util 'max'; | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 58 |  | 
| 22 |  |  |  |  |  |  |  | 
| 23 | 1 |  |  | 1 |  | 3 | use vars '$VERSION', '@ISA'; | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 53 |  | 
| 24 |  |  |  |  |  |  | $VERSION = 72; | 
| 25 |  |  |  |  |  |  |  | 
| 26 | 1 |  |  | 1 |  | 3 | use Math::NumSeq; | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 14 |  | 
| 27 | 1 |  |  | 1 |  | 3 | use Math::NumSeq::Base::IterateIth; | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 47 |  | 
| 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 |  | 4 | use constant description => Math::NumSeq::__('Maximum count of a given digit in any radix.'); | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 4 |  | 
| 38 | 1 |  |  | 1 |  | 3 | use constant default_i_start => 1; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 88 |  | 
| 39 | 1 |  |  |  |  | 3 | 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 |  | 3 | ]; | 
|  | 1 |  |  |  |  | 2 |  | 
| 62 |  |  |  |  |  |  |  | 
| 63 |  |  |  |  |  |  | sub characteristic_count { | 
| 64 | 4 |  |  | 4 | 0 | 5 | my ($self) = @_; | 
| 65 | 4 |  |  |  |  | 11 | 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 |  | 4 | use constant characteristic_smaller => 1; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 40 |  | 
| 72 | 1 |  |  | 1 |  | 3 | use constant characteristic_integer => 1; | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 350 |  | 
| 73 |  |  |  |  |  |  |  | 
| 74 |  |  |  |  |  |  | sub values_min { | 
| 75 | 4 |  |  | 4 | 1 | 21 | my ($self) = @_; | 
| 76 | 4 | 100 |  |  |  | 13 | if ($self->{'values_type'} eq 'count') { | 
| 77 | 2 | 100 |  |  |  | 6 | if ($self->{'digit'} == 1) { | 
| 78 | 1 |  |  |  |  | 3 | return 1; | 
| 79 |  |  |  |  |  |  | } | 
| 80 |  |  |  |  |  |  | } else { # values_type=='radix' | 
| 81 | 2 |  |  |  |  | 5 | 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 | 12 | my ($self) = @_; | 
| 96 | 4 |  |  |  |  | 10 | return $oeis_anum{$self->{'values_type'}}->[$self->{'digit'}]; | 
| 97 |  |  |  |  |  |  | } | 
| 98 |  |  |  |  |  |  |  | 
| 99 |  |  |  |  |  |  | #------------------------------------------------------------------------------ | 
| 100 |  |  |  |  |  |  |  | 
| 101 |  |  |  |  |  |  | sub ith { | 
| 102 | 432 |  |  | 432 | 1 | 492 | my ($self, $i) = @_; | 
| 103 |  |  |  |  |  |  | ### MaxDigitCount ith(): $i | 
| 104 |  |  |  |  |  |  |  | 
| 105 | 432 | 50 |  |  |  | 555 | if (_is_infinite($i)) { | 
| 106 | 0 |  |  |  |  | 0 | return $i; | 
| 107 |  |  |  |  |  |  | } | 
| 108 | 432 |  |  |  |  | 335 | $i = abs($i); | 
| 109 |  |  |  |  |  |  |  | 
| 110 | 432 |  |  |  |  | 315 | my $digit = $self->{'digit'}; | 
| 111 | 432 |  |  |  |  | 259 | my $found_count = 0; | 
| 112 | 432 |  |  |  |  | 270 | my $found_radix = 2; | 
| 113 | 432 |  |  |  |  | 634 | foreach my $radix (2 .. max($i,2)) { | 
| 114 | 1900 |  |  |  |  | 1684 | my $digits = _digit_split($i,$radix); # low to high | 
| 115 |  |  |  |  |  |  |  | 
| 116 |  |  |  |  |  |  | ### $radix | 
| 117 |  |  |  |  |  |  | ### $digits | 
| 118 |  |  |  |  |  |  |  | 
| 119 | 1900 | 100 |  |  |  | 2160 | if (@$digits < $found_count) { | 
| 120 | 8 |  |  |  |  | 10 | last;  # fewer digits now than already found | 
| 121 |  |  |  |  |  |  | } | 
| 122 | 1892 |  |  |  |  | 1300 | my $count = grep {$_ == $digit} @$digits; | 
|  | 4464 |  |  |  |  | 3928 |  | 
| 123 | 1892 | 100 |  |  |  | 2391 | if ($count > $found_count) { | 
| 124 | 460 |  |  |  |  | 283 | $found_count = $count; | 
| 125 | 460 |  |  |  |  | 292 | $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 |  |  |  | 693 | if ($count == scalar(@$digits) - ($digit==0)) { | 
| 130 | 194 |  |  |  |  | 181 | last; | 
| 131 |  |  |  |  |  |  | } | 
| 132 |  |  |  |  |  |  | } | 
| 133 |  |  |  |  |  |  | } | 
| 134 | 432 | 100 |  |  |  | 943 | return ($self->{'values_type'} eq 'radix' ? $found_radix : $found_count); | 
| 135 |  |  |  |  |  |  | } | 
| 136 |  |  |  |  |  |  |  | 
| 137 |  |  |  |  |  |  | sub _digit_split { | 
| 138 | 1900 |  |  | 1900 |  | 1360 | my ($n, $radix) = @_; | 
| 139 |  |  |  |  |  |  | #  ### _digit_split(): $n | 
| 140 | 1900 |  |  |  |  | 1035 | my @ret; | 
| 141 | 1900 |  |  |  |  | 2068 | while ($n) { | 
| 142 | 4484 |  |  |  |  | 3129 | push @ret, $n % $radix; | 
| 143 | 4484 |  |  |  |  | 5192 | $n = int($n/$radix); | 
| 144 |  |  |  |  |  |  | } | 
| 145 | 1900 |  |  |  |  | 1612 | return \@ret;   # array[0] low digit | 
| 146 |  |  |  |  |  |  | } | 
| 147 |  |  |  |  |  |  |  | 
| 148 |  |  |  |  |  |  | sub pred { | 
| 149 | 40 |  |  | 40 | 1 | 118 | my ($self, $value) = @_; | 
| 150 | 40 | 50 |  |  |  | 50 | unless ($value == int($value)) { | 
| 151 | 0 |  |  |  |  | 0 | return 0; | 
| 152 |  |  |  |  |  |  | } | 
| 153 | 40 | 100 |  |  |  | 42 | if ($self->{'values_type'} eq 'count') { | 
| 154 | 20 | 100 |  |  |  | 23 | if ($self->{'digit'} == 1) { | 
| 155 | 10 |  |  |  |  | 11 | return ($value >= 1); | 
| 156 |  |  |  |  |  |  | } | 
| 157 |  |  |  |  |  |  | } else { # values_type=='radix' | 
| 158 | 20 | 50 |  |  |  | 29 | if ($value == 1) { | 
| 159 | 0 |  |  |  |  | 0 | return 0; | 
| 160 |  |  |  |  |  |  | } | 
| 161 |  |  |  |  |  |  | } | 
| 162 | 30 |  |  |  |  | 28 | return ($value >= 0); | 
| 163 |  |  |  |  |  |  | } | 
| 164 |  |  |  |  |  |  |  | 
| 165 |  |  |  |  |  |  | 1; | 
| 166 |  |  |  |  |  |  | __END__ |