File Coverage

blib/lib/Math/NumSeq/FibonacciRepresentations.pm
Criterion Covered Total %
statement 72 73 98.6
branch 13 14 92.8
condition 1 3 33.3
subroutine 16 16 100.0
pod 3 3 100.0
total 105 109 96.3


line stmt bran cond sub pod time code
1             # Copyright 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             # https://eudml.org/doc/92679
20             # J. Berstel, An Exercise on Fibonacci Representations, RAIRO/
21             # Informatique Theorique, Vol. 35, No 6, 2001, pp. 491-498, in
22             # the issue dedicated to Aldo De Luca on the occasion of his
23             # 60-th anniversary.
24              
25             # Paul K. Stockmeyer, "A Smooth Tight Upper Bound for the Fibonacci
26             # Representation Function R(N)", Fibonacci Quarterly, Volume 46/47, Number
27             # 2, May 2009.
28             # Free access only post 2003
29             # http://www.fq.math.ca/46_47-2.html
30             # http://www.fq.math.ca/Papers/46_47-2/Stockmeyer.pdf
31              
32             # Klarner 1966
33             # Product (1+x^fib(i)) gives coefficients R(N)
34             # R(F[n]) = floor((n+2)/2) n > 1
35             # R(F[n]-1) = floor((n+1)/2) n > 0
36             # R(F[n]-2) = n-2 n > 2
37             # R(F[n]-3) = n-3 n > 4
38              
39             # http://www.math.tugraz.at/~edson/Publications/Representations%20in%20Fibonacci%20Base.pdf
40              
41              
42             package Math::NumSeq::FibonacciRepresentations;
43 2     2   7484 use 5.004;
  2         5  
44 2     2   6 use strict;
  2         1  
  2         41  
45              
46 2     2   5 use vars '$VERSION', '@ISA';
  2         1  
  2         97  
47             $VERSION = 72;
48              
49 2     2   347 use Math::NumSeq;
  2         2  
  2         33  
50 2     2   904 use Math::NumSeq::Base::IterateIth;
  2         3  
  2         89  
51             @ISA = ('Math::NumSeq::Base::IterateIth', 'Math::NumSeq');
52             *_is_infinite = \&Math::NumSeq::_is_infinite;
53              
54             # uncomment this to run the ### lines
55             # use Smart::Comments;
56              
57             # use constant name => Math::NumSeq::__('Fibonacci Representations');
58 2     2   7 use constant description => Math::NumSeq::__('Fibonacci representations sequence, the number of ways i can be formed as a sum of distinct Fibonacci numbers.');
  2         2  
  2         4  
59 2     2   6 use constant default_i_start => 0;
  2         2  
  2         62  
60 2     2   6 use constant characteristic_count => 1;
  2         2  
  2         61  
61 2     2   6 use constant characteristic_smaller => 1;
  2         2  
  2         64  
62 2     2   6 use constant characteristic_integer => 1;
  2         2  
  2         58  
63 2     2   6 use constant characteristic_increasing => 0;
  2         1  
  2         69  
64 2     2   6 use constant values_min => 1;
  2         2  
  2         59  
65              
66             #------------------------------------------------------------------------------
67             #
68 2     2   5 use constant oeis_anum => 'A000119';
  2         2  
  2         521  
69              
70             #------------------------------------------------------------------------------
71              
72             sub ith {
73 1126     1126 1 859 my ($self, $i) = @_;
74 1126         1053 return ($self->ith_pair($i))[0];
75             }
76              
77             sub ith_pair {
78 1145     1145 1 824 my ($self, $i) = @_;
79             ### ith_pair(): $i
80              
81 1145 100       1344 if ($i < 0) {
82 3         5 return (undef,undef);
83             }
84 1142 50       1401 if (_is_infinite($i)) {
85 0         0 return ($i,$i); # +inf or nan
86             }
87              
88             # seeking f2 >= i+1
89             # but stop at f1 >= i so not go past UV_MAX if i=UV_MAX
90             #
91 1142         847 my @fibs; # all Fibonacci numbers <= $i
92             {
93             # find biggest fibonacci f1 <= i
94             # if f1+f0 > i then stop loop
95             # f1+f0 might overflow UV_MAX so do the loop
96             # condition as stop when f1 > i-f0, continue while f1 <= i-f0
97             #
98 1142         706 my $f0 = ($i*0) + 1; # $f0=1, inherit bignum from $i
  1142         844  
99 1142         689 my $f1 = $f0 + 1; # $f1=2, inherit bignum from $i
100 1142         1351 while ($f0 <= $i-$f1) {
101 9520         5435 push @fibs, $f0;
102 9520         11718 ($f1,$f0) = ($f1+$f0,$f1);
103             }
104             ### @fibs
105             ### $f0
106             ### $f1
107              
108             # here have f1 <= i < f0+f1
109             # subtract i+1 - f1
110 1142         703 $i -= $f1;
111 1142         680 $i += 1;
112             ### i+1 - f1: $i
113              
114             # If i+1-f1 >= f0 then high fib is not the f1 just subtracted but
115             # instead f2=f1+f0. Subtract also f0 so i+1 - (f1+f0). Now skip f1
116             # since the Zeck form has no consecutive fibs. Push f0 onto @fibs to be
117             # the next fib tested in the loop.
118             #
119             # Actually i+1-(f1+f0) = 0 here, since f1 <= i and f0+f1 <= i+1 means
120             # i+1==f0+f1 exactly. Could return r += $#fibs/2 which is the effect of
121             # every second 0-bit step, but i+1=fibonacci will be fairly rare.
122             #
123             # If i+1-f1 < f0 then high fib is f1 just subtracted. Now skip f0 since
124             # the Zeck form has no consecutive fibs.
125             #
126 1142 100       1336 if ($i >= $f0) {
127 57         190 return (1, int(scalar(@fibs)/2) + 2);
128              
129             # $i -= $f0;
130             # ### subtract f0, so i+1 sub f2=f1+f0: $i
131             # push @fibs, $f0;
132             }
133             }
134              
135 1085         680 my $r = 1; # R(0) = 1
136 1085         603 my $rplus1 = 1; # R(1) = 1
137 1085         631 my $odd_zeros = 1; # high zeck "10..." initial zero
138              
139 1085         1307 while (my $f = pop @fibs) {
140             ### at: "f=$f i=$i r=$r rplus1=$rplus1 odd_zeros=$odd_zeros"
141              
142 7045 100       6325 if ($i < $f) {
143             ### 0-bit ...
144              
145 4286 100       4291 if ($odd_zeros) {
146             ### odd zeros on i+1, add to rplus1 ...
147 2776         1743 $rplus1 += $r;
148             }
149 4286         5299 $odd_zeros ^= 1;
150              
151             } else {
152 2759         1605 $i -= $f;
153             ### 1-bit sub: "$f to i=$i"
154              
155 2759 100       2281 if ($odd_zeros) {
156             ### odd zeros on i+1, add to r ...
157 1723         1069 $r += $rplus1;
158             } else {
159             ### even zeros on i+1, r same as rplus1 ...
160 1036         646 $r = $rplus1;
161             }
162              
163             ### never consecutive fibs, so pop without comparing to i ...
164 2759 100       3005 pop @fibs || last;
165 2325         3053 $odd_zeros = 1; # one trailing 0-bit is odd
166             }
167             }
168              
169             ### final: "r=$r rplus1=$rplus1"
170 1085         2003 return ($r, $rplus1);
171             }
172              
173             sub pred {
174 20     20 1 49 my ($self, $value) = @_;
175             ### FibonacciRepresentations pred(): $value
176 20   33     53 return ($value >= 1 && $value == int($value));
177             }
178              
179             1;
180             __END__