File Coverage

blib/lib/Math/NumSeq/FibonacciRepresentations.pm
Criterion Covered Total %
statement 73 74 98.6
branch 13 14 92.8
condition 1 3 33.3
subroutine 16 16 100.0
pod 3 3 100.0
total 106 110 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              
40             package Math::NumSeq::FibonacciRepresentations;
41 2     2   18892 use 5.004;
  2         7  
  2         158  
42 2     2   11 use strict;
  2         5  
  2         76  
43              
44 2     2   12 use vars '$VERSION', '@ISA';
  2         5  
  2         364  
45             $VERSION = 71;
46              
47 2     2   1238 use Math::NumSeq;
  2         5  
  2         73  
48 2     2   1838 use Math::NumSeq::Base::IterateIth;
  2         6  
  2         137  
49             @ISA = ('Math::NumSeq::Base::IterateIth', 'Math::NumSeq');
50             *_is_infinite = \&Math::NumSeq::_is_infinite;
51              
52             # uncomment this to run the ### lines
53             # use Smart::Comments;
54              
55             # use constant name => Math::NumSeq::__('Fibonacci Representations');
56 2     2   11 use constant description => Math::NumSeq::__('Fibonacci representations sequence, the number of ways i can be formed as a sum of distinct Fibonacci numbers.');
  2         4  
  2         9  
57 2     2   11 use constant default_i_start => 0;
  2         3  
  2         85  
58 2     2   10 use constant characteristic_count => 1;
  2         5  
  2         110  
59 2     2   14 use constant characteristic_smaller => 1;
  2         4  
  2         82  
60 2     2   10 use constant characteristic_integer => 1;
  2         3  
  2         79  
61 2     2   9 use constant characteristic_increasing => 0;
  2         5  
  2         103  
62 2     2   51 use constant values_min => 1;
  2         5  
  2         97  
63              
64             #------------------------------------------------------------------------------
65             #
66 2     2   10 use constant oeis_anum => 'A000119';
  2         9  
  2         839  
67              
68             #------------------------------------------------------------------------------
69              
70             sub ith {
71 1126     1126 1 1512 my ($self, $i) = @_;
72 1126         2161 return ($self->ith_pair($i))[0];
73             }
74              
75             sub ith_pair {
76 1145     1145 1 1341 my ($self, $i) = @_;
77             ### ith_pair(): $i
78              
79 1145 100       2219 if ($i < 0) {
80 3         8 return (undef,undef);
81             }
82 1142 50       2794 if (_is_infinite($i)) {
83 0         0 return ($i,$i); # +inf or nan
84             }
85              
86             # seeking f2 >= i+1
87             # but stop at f1 >= i so not go past UV_MAX if i=UV_MAX
88             #
89 1142         1548 my @fibs; # all Fibonacci numbers <= $i
90             {
91             # find biggest fibonacci f1 <= i
92             # if f1+f0 > i then stop loop
93             # f1+f0 might overflow UV_MAX so do the loop
94             # condition as stop when f1 > i-f0, continue while f1 <= i-f0
95             #
96 1142         1302 my $f0 = ($i*0) + 1; # $f0=1, inherit bignum from $i
  1142         1807  
97 1142         1376 my $f1 = $f0 + 1; # $f1=2, inherit bignum from $i
98 1142         2441 while ($f0 <= $i-$f1) {
99 9520         11037 push @fibs, $f0;
100 9520         21021 ($f1,$f0) = ($f1+$f0,$f1);
101             }
102             ### @fibs
103             ### $f0
104             ### $f1
105              
106             # here have f1 <= i < f0+f1
107             # subtract i+1 - f1
108 1142         1167 $i -= $f1;
109 1142         1257 $i += 1;
110             ### i+1 - f1: $i
111              
112             # If i+1-f1 >= f0 then high fib is not the f1 just subtracted but
113             # instead f2=f1+f0. Subtract also f0 so i+1 - (f1+f0). Now skip f1
114             # since the Zeck form has no consecutive fibs. Push f0 onto @fibs to be
115             # the next fib tested in the loop.
116             #
117             # Actually i+1-(f1+f0) = 0 here, since f1 <= i and f0+f1 <= i+1 means
118             # i+1==f0+f1 exactly. Could return r += $#fibs/2 which is the effect of
119             # every second 0-bit step, but i+1=fibonacci will be fairly rare.
120             #
121             # If i+1-f1 < f0 then high fib is f1 just subtracted. Now skip f0 since
122             # the Zeck form has no consecutive fibs.
123             #
124 1142 100       2311 if ($i >= $f0) {
125 57         264 return (1, int(scalar(@fibs)/2) + 2);
126              
127             # $i -= $f0;
128             # ### subtract f0, so i+1 sub f2=f1+f0: $i
129             # push @fibs, $f0;
130             }
131             }
132              
133 1085         3235 my $r = 1; # R(0) = 1
134 1085         1895 my $rplus1 = 1; # R(1) = 1
135 1085         1002 my $odd_zeros = 1; # high zeck "10..." initial zero
136              
137 1085         2361 while (my $f = pop @fibs) {
138             ### at: "f=$f i=$i r=$r rplus1=$rplus1 odd_zeros=$odd_zeros"
139              
140 7045 100       11253 if ($i < $f) {
141             ### 0-bit ...
142              
143 4286 100       7131 if ($odd_zeros) {
144             ### odd zeros on i+1, add to rplus1 ...
145 2776         3270 $rplus1 += $r;
146             }
147 4286         10144 $odd_zeros ^= 1;
148              
149             } else {
150 2759         3843 $i -= $f;
151             ### 1-bit sub: "$f to i=$i"
152              
153 2759 100       3993 if ($odd_zeros) {
154             ### odd zeros on i+1, add to r ...
155 1723         1915 $r += $rplus1;
156             } else {
157             ### even zeros on i+1, r same as rplus1 ...
158 1036         1139 $r = $rplus1;
159             }
160              
161             ### never consecutive fibs, so pop without comparing to i ...
162 2759 100       6164 pop @fibs || last;
163 2325         5454 $odd_zeros = 1; # one trailing 0-bit is odd
164             }
165             }
166              
167             ### final: "r=$r rplus1=$rplus1"
168 1085         4961 return ($r, $rplus1);
169             }
170              
171             sub pred {
172 20     20 1 98 my ($self, $value) = @_;
173             ### FibonacciRepresentations pred(): $value
174 20   33     89 return ($value >= 1 && $value == int($value));
175             }
176              
177             1;
178             __END__