File Coverage

blib/lib/Math/NumSeq/SelfLengthCumulative.pm
Criterion Covered Total %
statement 76 77 98.7
branch 13 14 92.8
condition 2 3 66.6
subroutine 17 17 100.0
pod 5 5 100.0
total 113 116 97.4


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   337004 use 5.004;
  1         8  
  1         86  
20 1     1   17 use strict;
  1         3  
  1         74  
21              
22 1     1   23 use vars '$VERSION', '@ISA';
  1         2  
  1         133  
23             $VERSION = 71;
24              
25 1     1   10 use Math::NumSeq;
  1         2  
  1         198  
26             @ISA = ('Math::NumSeq');
27             *_is_infinite = \&Math::NumSeq::_is_infinite;
28              
29 1     1   34 use Math::NumSeq::Fibonacci;
  1         4  
  1         104  
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   10 use constant name => Math::NumSeq::__('Self Length Cumulative');
  1         5  
  1         10  
37 1     1   8 use constant description => Math::NumSeq::__('Cumulative digit length of own values.');
  1         3  
  1         7  
38 1     1   7 use constant default_i_start => 1;
  1         3  
  1         67  
39 1     1   9 use constant characteristic_increasing => 1;
  1         15  
  1         66  
40 1     1   9 use constant characteristic_integer => 1;
  1         2  
  1         69  
41 1     1   10 use constant values_min => 1;
  1         3  
  1         98  
42              
43             use Math::NumSeq::Base::Digits
44 1     1   10 'parameter_info_array'; # radix parameter
  1         3  
  1         930  
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 21 my ($self) = @_;
55 4         17 return $oeis_anum[$self->{'radix'}];
56             }
57              
58              
59             #------------------------------------------------------------------------------
60              
61             sub rewind {
62 12     12 1 9391 my ($self) = @_;
63 12         65 $self->{'i'} = $self->i_start;
64 12         44 $self->{'value'} = 1;
65 12         33 $self->{'power'} = $self->{'radix'};
66 12         85 $self->{'length'} = 1;
67             }
68             sub next {
69 112     112 1 3623 my ($self) = @_;
70              
71 112         192 my $value = $self->{'value'};
72 112 100       285 if ($value >= $self->{'power'}) {
73 24         42 $self->{'power'} *= $self->{'radix'};
74 24         36 $self->{'length'}++;
75             }
76 112         208 $self->{'value'} += $self->{'length'};
77 112         336 return ($self->{'i'}++, $value);
78             }
79              
80             sub pred {
81 328     328 1 1777 my ($self, $value) = @_;
82              
83 328 100 66     1369 if ($value < 1 || $value != int($value)) {
84 134         271 return 0;
85             }
86 194 50       434 if (_is_infinite($value)) {
87 0         0 return undef;
88             }
89              
90 194         294 my $length = 1;
91 194         333 my $radix = $self->{'radix'};
92 194         261 my $power = ($value * 0) + $radix; # inherit bignum $value
93 194         219 my $upto = 1;
94 194         209 for (;;) {
95 678 100       1397 if ($value < $power) {
96 194         564 return (($value - $upto) % $length) == 0;
97             }
98 484         579 $upto = $power + ($upto-$power)%$length;
99              
100 484         502 $power *= $radix;
101 484         499 $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 1805 my ($self, $value) = @_;
124              
125 92 100       189 if ($value <= 1) {
126 36         75 return 0;
127             }
128              
129 56         608 my $t;
130 56 100       155 if (defined (my $blog2 = _blog2_estimate($value))) {
131 4         1428 $t = $blog2 * log(2);
132             } else {
133 52         88 $t = log($value);
134             }
135              
136 56         134 $self->{'logR'} = log($self->{'radix'});
137              
138             # integer divisor to help Math::BigInt
139 56         96 my $div = int($t/$self->{'logR'});
140 56 100       118 if ($div > 1) {
141 27         49 $value /= $div;
142             }
143 56         758 return int($value);
144             }
145              
146             1;
147             __END__