File Coverage

blib/lib/Math/NumSeq/DigitProductSteps.pm
Criterion Covered Total %
statement 64 65 98.4
branch 5 6 83.3
condition 1 3 33.3
subroutine 20 20 100.0
pod 3 3 100.0
total 93 97 95.8


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              
19             # http://www.inwap.com/pdp10/hbaker/hakmem/number.html#item56
20             # /so/hakmem/number.html
21              
22              
23             package Math::NumSeq::DigitProductSteps;
24 1     1   1631 use 5.004;
  1         4  
25 1     1   7 use strict;
  1         2  
  1         41  
26 1     1   6 use List::Util 'reduce';
  1         2  
  1         93  
27              
28 1     1   6 use vars '$VERSION', '@ISA';
  1         2  
  1         84  
29             $VERSION = 72;
30              
31 1     1   7 use Math::NumSeq;
  1         1  
  1         33  
32 1     1   8 use Math::NumSeq::Base::IterateIth;
  1         2  
  1         65  
33             @ISA = ('Math::NumSeq::Base::IterateIth',
34             'Math::NumSeq');
35             *_is_infinite = \&Math::NumSeq::_is_infinite;
36              
37 1     1   6 use Math::NumSeq::Repdigits;
  1         3  
  1         47  
38             *_digit_split_lowtohigh = \&Math::NumSeq::Repdigits::_digit_split_lowtohigh;
39              
40 1     1   1029 use Math::NumSeq::DigitProduct;
  1         4  
  1         43  
41              
42             # uncomment this to run the ### lines
43             #use Smart::Comments;
44              
45              
46             # use constant name => Math::NumSeq::__('...');
47 1     1   5 use constant description => Math::NumSeq::__('Number of steps of digit product until reaching a single digit.');
  1         2  
  1         5  
48 1     1   6 use constant i_start => 0;
  1         2  
  1         60  
49 1     1   5 use constant characteristic_count => 1;
  1         4  
  1         60  
50 1     1   6 use constant characteristic_smaller => 1;
  1         3  
  1         66  
51 1     1   7 use constant characteristic_integer => 1;
  1         2  
  1         59  
52              
53 1     1   6 use Math::NumSeq::Base::Digits; # radix
  1         2  
  1         139  
54 1         7 use constant parameter_info_array =>
55             [
56             Math::NumSeq::Base::Digits::parameter_common_radix(),
57             {
58             name => 'values_type',
59             type => 'enum',
60             share_key => 'values_type_countroot',
61             default => 'count',
62             choices => ['count',
63             'root',
64             ],
65             choices_display => [Math::NumSeq::__('Count'),
66             Math::NumSeq::__('Root'),
67             ],
68             description => Math::NumSeq::__('The values, either steps count or the final value after the steps.'),
69 1     1   8 } ];
  1         1  
70 1     1   6 use constant values_min => 0;
  1         2  
  1         407  
71              
72             #------------------------------------------------------------------------------
73             # cf A046511 - numbers with persistence 2
74             #
75             # A031348 - iterate product of squares of digits until 0,1
76             # A031349 - iterate product of cubes of digits
77             # A031350 -
78             # A031351
79             # A031352
80             # A031353
81             # A031354
82             # A031355 -
83             # A031356 - 10th powers of digits
84             #
85             # A087471 - iterate product of alternate digits, final digit
86             # A087472 - num steps
87             # A087473 - first of n iterations
88             # A087474 - triangle of values of those first taking n iterations
89             #
90             # A031286 - additive persistence to single digit
91             # A010888 - additive root single digit
92              
93             my %oeis_anum;
94              
95             $oeis_anum{'count'}->[10] = 'A031346';
96             $oeis_anum{'root'}->[10] = 'A031347';
97             # OEIS-Catalogue: A031346
98             # OEIS-Catalogue: A031347 values_type=root
99              
100             sub oeis_anum {
101 2     2 1 10 my ($self) = @_;
102 2         6 return $oeis_anum{$self->{'values_type'}}->[$self->{'radix'}];
103             }
104              
105             #------------------------------------------------------------------------------
106              
107             sub ith {
108 1146     1146 1 1047 my ($self, $i) = @_;
109             ### ith(): $i
110              
111 1146 50       1558 if (_is_infinite($i)) {
112 0         0 return $i; # don't loop forever if $i is +infinity
113             }
114              
115 1146         1197 my $radix = $self->{'radix'};
116 1146         703 my $count = 0;
117 1146         718 for (;;) {
118 2336         3285 my @digits = _digit_split_lowtohigh($i, $radix);
119 2336 100       3203 if (@digits <= 1) {
120 1146 100       1480 if ($self->{'values_type'} eq 'count') {
121 573         1273 return $count;
122             } else {
123 573         1195 return $i; # final root
124             }
125             }
126 1190     1194   3859 $i = reduce {$a*$b} @digits;
  1194         1204  
127 1190         1801 $count++;
128             }
129             }
130              
131             sub pred {
132 60     60 1 145 my ($self, $value) = @_;
133             return ($value == int($value)
134             && $value >= 0
135             && ($self->{'values_type'} eq 'count' # anything for count
136 60   33     243 || $value < $self->{'radix'})); # 0 to R-1 for root
137             }
138              
139             1;
140             __END__