File Coverage

blib/lib/Math/NumSeq/SelfLengthCumulative.pm
Criterion Covered Total %
statement 75 76 98.6
branch 13 14 92.8
condition 2 3 66.6
subroutine 17 17 100.0
pod 5 5 100.0
total 112 115 97.3


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::SelfLengthCumulative;
19 1     1   1087 use 5.004;
  1         4  
20 1     1   6 use strict;
  1         3  
  1         43  
21              
22 1     1   5 use vars '$VERSION', '@ISA';
  1         2  
  1         77  
23             $VERSION = 72;
24              
25 1     1   5 use Math::NumSeq;
  1         1  
  1         50  
26             @ISA = ('Math::NumSeq');
27             *_is_infinite = \&Math::NumSeq::_is_infinite;
28              
29 1     1   6 use Math::NumSeq::Fibonacci;
  1         2  
  1         57  
30             *_blog2_estimate = \&Math::NumSeq::Fibonacci::_blog2_estimate;
31              
32             # uncomment this to run the ### lines
33             #use Smart::Comments;
34              
35              
36 1     1   6 use constant name => Math::NumSeq::__('Self Length Cumulative');
  1         3  
  1         4  
37 1     1   6 use constant description => Math::NumSeq::__('Cumulative digit length of own values.');
  1         3  
  1         4  
38 1     1   7 use constant default_i_start => 1;
  1         2  
  1         47  
39 1     1   4 use constant characteristic_increasing => 1;
  1         1  
  1         31  
40 1     1   3 use constant characteristic_integer => 1;
  1         2  
  1         32  
41 1     1   3 use constant values_min => 1;
  1         2  
  1         35  
42              
43             use Math::NumSeq::Base::Digits
44 1     1   4 'parameter_info_array'; # radix parameter
  1         0  
  1         358  
45              
46              
47             #------------------------------------------------------------------------------
48              
49             my @oeis_anum;
50             $oeis_anum[10] = 'A064223';
51             # OEIS-Catalogue: A064223
52              
53             sub oeis_anum {
54 4     4 1 12 my ($self) = @_;
55 4         7 return $oeis_anum[$self->{'radix'}];
56             }
57              
58              
59             #------------------------------------------------------------------------------
60              
61             sub rewind {
62 12     12 1 1558 my ($self) = @_;
63 12         30 $self->{'i'} = $self->i_start;
64 12         15 $self->{'value'} = 1;
65 12         14 $self->{'power'} = $self->{'radix'};
66 12         30 $self->{'length'} = 1;
67             }
68             sub next {
69 112     112 1 1414 my ($self) = @_;
70              
71 112         80 my $value = $self->{'value'};
72 112 100       137 if ($value >= $self->{'power'}) {
73 24         19 $self->{'power'} *= $self->{'radix'};
74 24         20 $self->{'length'}++;
75             }
76 112         59 $self->{'value'} += $self->{'length'};
77 112         103 return ($self->{'i'}++, $value);
78             }
79              
80             sub pred {
81 328     328 1 881 my ($self, $value) = @_;
82              
83 328 100 66     813 if ($value < 1 || $value != int($value)) {
84 134         125 return 0;
85             }
86 194 50       228 if (_is_infinite($value)) {
87 0         0 return undef;
88             }
89              
90 194         182 my $length = 1;
91 194         140 my $radix = $self->{'radix'};
92 194         141 my $power = ($value * 0) + $radix; # inherit bignum $value
93 194         108 my $upto = 1;
94 194         102 for (;;) {
95 678 100       712 if ($value < $power) {
96 194         253 return (($value - $upto) % $length) == 0;
97             }
98 484         307 $upto = $power + ($upto-$power)%$length;
99              
100 484         268 $power *= $radix;
101 484         264 $length++;
102             }
103             }
104              
105             # value = 10 i=10
106             # value = 100 i=10+90/2
107             # value = 1000 i=10+90/2+900/3
108             #
109             # value = R^k
110             # i = R + R^2/2 + R^3/3 + ... + R^k/k
111             # i = R + R^2/2 + R^3/3 + ... + R^k/k
112             # <= (R + R^2 + R^3 + ... + R^k)/k
113             # = (R^(k+1)-1)/(R-1) /k
114             # ~= R^k/k
115             # i ~= value/logR(value)
116             # logR(value) = log(value)/log(R)
117             #
118             # est(R^k) = R^k/k
119             # log(est(R^k)) = log(R^k/k)
120             # = log(value) - log(k)
121             #
122             sub value_to_i_estimate {
123 92     92 1 1027 my ($self, $value) = @_;
124              
125 92 100       113 if ($value <= 1) {
126 36         37 return 0;
127             }
128              
129 56         260 my $t;
130 56 100       83 if (defined (my $blog2 = _blog2_estimate($value))) {
131 4         860 $t = $blog2 * log(2);
132             } else {
133 52         50 $t = log($value);
134             }
135              
136 56         63 $self->{'logR'} = log($self->{'radix'});
137              
138             # integer divisor to help Math::BigInt
139 56         45 my $div = int($t/$self->{'logR'});
140 56 100       71 if ($div > 1) {
141 27         30 $value /= $div;
142             }
143 56         425 return int($value);
144             }
145              
146             1;
147             __END__