line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Math::ContinuedFraction;
|
2
|
|
|
|
|
|
|
|
3
|
4
|
|
|
4
|
|
261047
|
use warnings;
|
|
4
|
|
|
|
|
12
|
|
|
4
|
|
|
|
|
149
|
|
4
|
4
|
|
|
4
|
|
23
|
use strict;
|
|
4
|
|
|
|
|
10
|
|
|
4
|
|
|
|
|
138
|
|
5
|
4
|
|
|
4
|
|
23
|
use Carp;
|
|
4
|
|
|
|
|
12
|
|
|
4
|
|
|
|
|
362
|
|
6
|
4
|
|
|
4
|
|
4095
|
use Math::BigInt;
|
|
4
|
|
|
|
|
61300
|
|
|
4
|
|
|
|
|
25
|
|
7
|
4
|
|
|
4
|
|
39222
|
use Math::BigRat;
|
|
4
|
|
|
|
|
79383
|
|
|
4
|
|
|
|
|
24
|
|
8
|
|
|
|
|
|
|
#use Smart::Comments;
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
our $VERSION = '0.11';
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
#
|
13
|
|
|
|
|
|
|
# $cf = Math::ContinuedFraction->new([1, 1, 1, 1, [3, 2, 3, 2]]);
|
14
|
|
|
|
|
|
|
#
|
15
|
|
|
|
|
|
|
#
|
16
|
|
|
|
|
|
|
sub new
|
17
|
|
|
|
|
|
|
{
|
18
|
3
|
|
|
3
|
1
|
49
|
my $class = shift;
|
19
|
3
|
|
|
|
|
8
|
my $self = {};
|
20
|
3
|
|
|
|
|
8
|
my(@seq);
|
21
|
|
|
|
|
|
|
|
22
|
3
|
50
|
|
|
|
12
|
if (ref $class)
|
23
|
|
|
|
|
|
|
{
|
24
|
0
|
0
|
|
|
|
0
|
if ($class->isa(__PACKAGE__))
|
25
|
|
|
|
|
|
|
{
|
26
|
0
|
|
|
|
|
0
|
$class->_copy($self);
|
27
|
0
|
|
|
|
|
0
|
return bless($self, ref $class);
|
28
|
|
|
|
|
|
|
}
|
29
|
|
|
|
|
|
|
|
30
|
0
|
|
|
|
|
0
|
warn "Attempts to create a Continued Fraction object from a '",
|
31
|
|
|
|
|
|
|
ref $class, "' object fail.\n";
|
32
|
0
|
|
|
|
|
0
|
return undef;
|
33
|
|
|
|
|
|
|
}
|
34
|
|
|
|
|
|
|
|
35
|
3
|
|
|
|
|
11
|
bless($self, $class);
|
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
#
|
38
|
|
|
|
|
|
|
# We're not creating a copy of an existing CF, so start from
|
39
|
|
|
|
|
|
|
# first principles.
|
40
|
|
|
|
|
|
|
#
|
41
|
3
|
|
|
|
|
20
|
$self->{simple} = [0];
|
42
|
3
|
|
|
|
|
11
|
$self->{repeat} = undef;
|
43
|
|
|
|
|
|
|
|
44
|
3
|
50
|
|
|
|
13
|
if (scalar @_)
|
45
|
|
|
|
|
|
|
{
|
46
|
|
|
|
|
|
|
#
|
47
|
|
|
|
|
|
|
# Get the a's and b's.
|
48
|
|
|
|
|
|
|
# SHHH! Don't tell anyone about the b's yet, but
|
49
|
|
|
|
|
|
|
# they'll get accessed in a later version.
|
50
|
|
|
|
|
|
|
#
|
51
|
3
|
|
|
|
|
7
|
my($a_ref, $b_ref) = @_;
|
52
|
|
|
|
|
|
|
|
53
|
3
|
50
|
|
|
|
15
|
if (ref $a_ref eq "ARRAY")
|
|
|
0
|
|
|
|
|
|
54
|
|
|
|
|
|
|
{
|
55
|
3
|
|
|
|
|
9
|
my(@seq) = @$a_ref;
|
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
#
|
58
|
|
|
|
|
|
|
# See if there's a repeating component. If there is, check for
|
59
|
|
|
|
|
|
|
# one of those "Why are you doing that" empty array cases.
|
60
|
|
|
|
|
|
|
#
|
61
|
3
|
100
|
|
|
|
18
|
if (ref $seq[$#seq] eq "ARRAY")
|
62
|
|
|
|
|
|
|
{
|
63
|
1
|
|
|
|
|
2
|
my @r = @{ pop @seq };
|
|
1
|
|
|
|
|
2
|
|
64
|
1
|
50
|
|
|
|
13
|
$self->{repeat} = [@r] if (scalar @r > 0);
|
65
|
|
|
|
|
|
|
}
|
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
#
|
68
|
|
|
|
|
|
|
# Another empty array case check, this one slightly legitimate.
|
69
|
|
|
|
|
|
|
#
|
70
|
3
|
50
|
|
|
|
17
|
$self->{simple} = (scalar @seq)? [@seq]: [0];
|
71
|
|
|
|
|
|
|
}
|
72
|
|
|
|
|
|
|
elsif (ref $a_ref eq "Math::BigRat")
|
73
|
|
|
|
|
|
|
{
|
74
|
0
|
|
|
|
|
0
|
my($n, $d) = $a_ref->parts();
|
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
#
|
77
|
|
|
|
|
|
|
# Do from_ratio stuff.
|
78
|
|
|
|
|
|
|
#
|
79
|
0
|
|
|
|
|
0
|
$self->from_ratio($n, $d);
|
80
|
|
|
|
|
|
|
}
|
81
|
|
|
|
|
|
|
else
|
82
|
|
|
|
|
|
|
{
|
83
|
|
|
|
|
|
|
#
|
84
|
|
|
|
|
|
|
# Complain bitterly if we weren't passed an ARRAY or
|
85
|
|
|
|
|
|
|
# BigRat reference.
|
86
|
|
|
|
|
|
|
#
|
87
|
0
|
|
|
|
|
0
|
carp __PACKAGE__ .
|
88
|
|
|
|
|
|
|
"->new() takes either an array reference or a Math::BigRat object or another " .
|
89
|
|
|
|
|
|
|
__PACKAGE__ . " object";
|
90
|
0
|
|
|
|
|
0
|
return undef;
|
91
|
|
|
|
|
|
|
}
|
92
|
|
|
|
|
|
|
}
|
93
|
|
|
|
|
|
|
|
94
|
3
|
|
|
|
|
12
|
return $self;
|
95
|
|
|
|
|
|
|
}
|
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
#
|
98
|
|
|
|
|
|
|
# my $cf67_29 = Math::ContinuedFraction->from_ratio(67, 29);
|
99
|
|
|
|
|
|
|
#
|
100
|
|
|
|
|
|
|
# Create a continued fraction from a simple ratio.
|
101
|
|
|
|
|
|
|
# These CFs will always be the simple types.
|
102
|
|
|
|
|
|
|
#
|
103
|
|
|
|
|
|
|
sub from_ratio
|
104
|
|
|
|
|
|
|
{
|
105
|
1
|
|
|
1
|
1
|
14
|
my $class = shift;
|
106
|
1
|
|
|
|
|
1
|
my($n, $d) = @_;
|
107
|
1
|
|
|
|
|
4
|
my $self = {};
|
108
|
1
|
|
|
|
|
2
|
my @cf;
|
109
|
|
|
|
|
|
|
|
110
|
4
|
|
|
4
|
|
6247
|
use integer;
|
|
4
|
|
|
|
|
10
|
|
|
4
|
|
|
|
|
35
|
|
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
LOOP:
|
113
|
1
|
|
|
|
|
2
|
for (;;)
|
114
|
|
|
|
|
|
|
{
|
115
|
3
|
|
|
|
|
6
|
my $q = $n / $d;
|
116
|
3
|
|
|
|
|
17
|
my $r = $n % $d;
|
117
|
|
|
|
|
|
|
|
118
|
3
|
|
|
|
|
4
|
push @cf, $q;
|
119
|
3
|
50
|
|
|
|
8
|
last LOOP if ($r == 0);
|
120
|
3
|
100
|
|
|
|
9
|
if ($r == 1)
|
121
|
|
|
|
|
|
|
{
|
122
|
1
|
|
|
|
|
1
|
push @cf, $d;
|
123
|
1
|
|
|
|
|
6
|
last LOOP;
|
124
|
|
|
|
|
|
|
}
|
125
|
2
|
|
|
|
|
3
|
$n = $d;
|
126
|
2
|
|
|
|
|
3
|
$d = $r;
|
127
|
|
|
|
|
|
|
}
|
128
|
|
|
|
|
|
|
|
129
|
1
|
|
|
|
|
5
|
$self->{simple} = [@cf];
|
130
|
1
|
|
|
|
|
3
|
$self->{repeat} = undef;
|
131
|
1
|
|
|
|
|
6
|
return bless($self, $class);
|
132
|
|
|
|
|
|
|
}
|
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
#
|
135
|
|
|
|
|
|
|
# $qs = Math::ContinuedFraction->from_quadratic($a, $b, $c);
|
136
|
|
|
|
|
|
|
#
|
137
|
|
|
|
|
|
|
sub from_root
|
138
|
|
|
|
|
|
|
{
|
139
|
0
|
|
|
0
|
0
|
0
|
my $class = shift;
|
140
|
0
|
|
|
|
|
0
|
my($dis) = @_;
|
141
|
0
|
|
|
|
|
0
|
my $self = {};
|
142
|
0
|
|
|
|
|
0
|
my(@repeat);
|
143
|
|
|
|
|
|
|
|
144
|
0
|
|
|
|
|
0
|
my($p, $q) = (0, 1);
|
145
|
0
|
|
|
|
|
0
|
my($a0, $a, $last);
|
146
|
0
|
|
|
|
|
0
|
$last = 2 * ($a0 = $a = int(sqrt($dis)));
|
147
|
|
|
|
|
|
|
|
148
|
0
|
|
|
|
|
0
|
for (;;)
|
149
|
|
|
|
|
|
|
{
|
150
|
0
|
|
|
|
|
0
|
$p = $a * $q - $p;
|
151
|
0
|
|
|
|
|
0
|
$q = ($dis - $p**2)/$q;
|
152
|
0
|
|
|
|
|
0
|
$a = int(($a0 + $p)/$q);
|
153
|
0
|
|
|
|
|
0
|
push @repeat, $a;
|
154
|
0
|
0
|
|
|
|
0
|
last if ($last == $a);
|
155
|
|
|
|
|
|
|
}
|
156
|
|
|
|
|
|
|
|
157
|
0
|
|
|
|
|
0
|
$self->{simple} = [$a0];
|
158
|
0
|
|
|
|
|
0
|
$self->{repeat} = [@repeat];
|
159
|
0
|
|
|
|
|
0
|
return bless($self, $class);
|
160
|
|
|
|
|
|
|
}
|
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
#
|
163
|
|
|
|
|
|
|
# $qs = Math::ContinuedFraction->from_quadratic($a, $b, $c);
|
164
|
|
|
|
|
|
|
#
|
165
|
|
|
|
|
|
|
sub from_quadratic
|
166
|
|
|
|
|
|
|
{
|
167
|
0
|
|
|
0
|
0
|
0
|
my $self = shift;
|
168
|
0
|
|
|
|
|
0
|
my(@coefficients) = @_;
|
169
|
|
|
|
|
|
|
|
170
|
0
|
|
|
|
|
0
|
while (@coefficients)
|
171
|
|
|
|
|
|
|
{
|
172
|
|
|
|
|
|
|
}
|
173
|
|
|
|
|
|
|
}
|
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
#
|
176
|
|
|
|
|
|
|
# if ($cf->is_finite()) { ...
|
177
|
|
|
|
|
|
|
#
|
178
|
|
|
|
|
|
|
#
|
179
|
|
|
|
|
|
|
#
|
180
|
|
|
|
|
|
|
sub is_finite
|
181
|
|
|
|
|
|
|
{
|
182
|
0
|
|
|
0
|
0
|
0
|
my $self = shift;
|
183
|
0
|
0
|
|
|
|
0
|
return ($self->{repeat})? 1: 0;
|
184
|
|
|
|
|
|
|
}
|
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
#
|
187
|
|
|
|
|
|
|
# my($slength, $rlength) = $cf->sequence_length();
|
188
|
|
|
|
|
|
|
#
|
189
|
|
|
|
|
|
|
#
|
190
|
|
|
|
|
|
|
sub sequence_length
|
191
|
|
|
|
|
|
|
{
|
192
|
9
|
|
|
9
|
0
|
14
|
my $self = shift;
|
193
|
9
|
|
|
|
|
12
|
my $sl = scalar @{ $self->{simple} };
|
|
9
|
|
|
|
|
22
|
|
194
|
9
|
100
|
|
|
|
27
|
my $rl = ($self->{repeat})? scalar @{ $self->{repeat} }: 0;
|
|
4
|
|
|
|
|
8
|
|
195
|
|
|
|
|
|
|
|
196
|
9
|
|
|
|
|
22
|
return ($sl, $rl);
|
197
|
|
|
|
|
|
|
}
|
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
#
|
200
|
|
|
|
|
|
|
# $bigratio = $cf->brconvergent($nth);
|
201
|
|
|
|
|
|
|
#
|
202
|
|
|
|
|
|
|
# Exactly like the convergent() method, except returning a BigRat
|
203
|
|
|
|
|
|
|
# type instead of separate BigInt numerator and denominator.
|
204
|
|
|
|
|
|
|
#
|
205
|
|
|
|
|
|
|
sub brconvergent
|
206
|
|
|
|
|
|
|
{
|
207
|
0
|
|
|
0
|
1
|
0
|
my $self = shift;
|
208
|
0
|
|
|
|
|
0
|
my($terms) = @_;
|
209
|
|
|
|
|
|
|
|
210
|
0
|
|
|
|
|
0
|
my($n, $d) = $self->convergent($terms);
|
211
|
0
|
|
|
|
|
0
|
return Math::BigRat->new($n, $d);
|
212
|
|
|
|
|
|
|
}
|
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
#
|
215
|
|
|
|
|
|
|
# ($numerator, $denominator) = $cf->convergent($nth);
|
216
|
|
|
|
|
|
|
#
|
217
|
|
|
|
|
|
|
# Get the fraction for the continued fraction at the nth term.
|
218
|
|
|
|
|
|
|
#
|
219
|
|
|
|
|
|
|
sub convergent
|
220
|
|
|
|
|
|
|
{
|
221
|
9
|
|
|
9
|
1
|
5408
|
my $self = shift;
|
222
|
9
|
|
|
|
|
17
|
my($terms) = @_;
|
223
|
9
|
|
|
|
|
17
|
my($repetitions, $remainder) = (0, 0);
|
224
|
9
|
|
|
|
|
24
|
my($sl, $rl) = $self->sequence_length();
|
225
|
|
|
|
|
|
|
|
226
|
4
|
|
|
4
|
|
2227
|
use integer;
|
|
4
|
|
|
|
|
10
|
|
|
4
|
|
|
|
|
17
|
|
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
#
|
229
|
|
|
|
|
|
|
### $terms
|
230
|
|
|
|
|
|
|
### $sl
|
231
|
|
|
|
|
|
|
### $rl
|
232
|
|
|
|
|
|
|
#
|
233
|
9
|
|
|
|
|
53
|
my $n = Math::BigInt->new(0);
|
234
|
9
|
|
|
|
|
958
|
my $d = Math::BigInt->new(1);
|
235
|
|
|
|
|
|
|
|
236
|
9
|
50
|
|
|
|
455
|
$terms = $sl + $rl unless ($terms);
|
237
|
9
|
50
|
66
|
|
|
47
|
$terms = $sl if ($terms > $sl and $rl == 0);
|
238
|
|
|
|
|
|
|
|
239
|
9
|
100
|
|
|
|
27
|
if ($terms >= $sl)
|
240
|
|
|
|
|
|
|
{
|
241
|
4
|
|
|
|
|
9
|
$repetitions = ($terms - $sl) / $rl;
|
242
|
4
|
|
|
|
|
19
|
$remainder = ($terms - $sl) % $rl;
|
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
#
|
245
|
|
|
|
|
|
|
### $repetitions
|
246
|
|
|
|
|
|
|
### $remainder
|
247
|
|
|
|
|
|
|
#
|
248
|
4
|
50
|
|
|
|
10
|
if ($remainder > 0)
|
249
|
|
|
|
|
|
|
{
|
250
|
0
|
|
|
|
|
0
|
my @remaining = (@{ $self->{repeat} }[0..$remainder]);
|
|
0
|
|
|
|
|
0
|
|
251
|
0
|
|
|
|
|
0
|
($n, $d) = $self->evaluate(\@remaining, $n, $d);
|
252
|
|
|
|
|
|
|
}
|
253
|
|
|
|
|
|
|
|
254
|
4
|
|
|
|
|
11
|
for (1..$repetitions)
|
255
|
|
|
|
|
|
|
{
|
256
|
10
|
|
|
|
|
30
|
($n, $d) = $self->evaluate($self->{repeat}, $n, $d);
|
257
|
|
|
|
|
|
|
}
|
258
|
|
|
|
|
|
|
|
259
|
4
|
|
|
|
|
13
|
return reverse $self->evaluate($self->{simple}, $n, $d);
|
260
|
|
|
|
|
|
|
}
|
261
|
|
|
|
|
|
|
|
262
|
5
|
|
|
|
|
10
|
my @partial = @{ $self->{simple} }[0..$terms];
|
|
5
|
|
|
|
|
16
|
|
263
|
5
|
|
|
|
|
17
|
return reverse $self->evaluate(\@partial, $n, $d);
|
264
|
|
|
|
|
|
|
}
|
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
sub evaluate
|
267
|
|
|
|
|
|
|
{
|
268
|
19
|
|
|
19
|
0
|
24
|
my $self = shift;
|
269
|
19
|
|
|
|
|
98
|
my($sequence, $n, $d) = @_;
|
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
#
|
272
|
|
|
|
|
|
|
### $sequence
|
273
|
|
|
|
|
|
|
### $n
|
274
|
|
|
|
|
|
|
### $d
|
275
|
|
|
|
|
|
|
#
|
276
|
|
|
|
|
|
|
# Add on the next group of continued fraction terms.
|
277
|
|
|
|
|
|
|
#
|
278
|
|
|
|
|
|
|
# a0 + 1
|
279
|
|
|
|
|
|
|
# ------
|
280
|
|
|
|
|
|
|
# a1 + 1
|
281
|
|
|
|
|
|
|
# ------
|
282
|
|
|
|
|
|
|
# a2 + n
|
283
|
|
|
|
|
|
|
# ---
|
284
|
|
|
|
|
|
|
# d
|
285
|
|
|
|
|
|
|
#
|
286
|
19
|
|
|
|
|
53
|
foreach my $a_k (reverse @$sequence)
|
287
|
|
|
|
|
|
|
{
|
288
|
34
|
|
|
|
|
105
|
$n += $d * $a_k;
|
289
|
34
|
|
|
|
|
7099
|
($n, $d) = ($d, $n); # Reciprocal
|
290
|
|
|
|
|
|
|
}
|
291
|
|
|
|
|
|
|
|
292
|
19
|
|
|
|
|
98
|
return ($n, $d);
|
293
|
|
|
|
|
|
|
}
|
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
#
|
296
|
|
|
|
|
|
|
# Get the array form of the continued fraction.
|
297
|
|
|
|
|
|
|
#
|
298
|
|
|
|
|
|
|
sub to_array
|
299
|
|
|
|
|
|
|
{
|
300
|
0
|
|
|
0
|
1
|
0
|
my $self = shift;
|
301
|
0
|
|
|
|
|
0
|
my $v = $self->{simple};
|
302
|
0
|
0
|
|
|
|
0
|
push @{ $v }, $self->{repeat} if ($self->{repeat});
|
|
0
|
|
|
|
|
0
|
|
303
|
|
|
|
|
|
|
|
304
|
0
|
|
|
|
|
0
|
return $v;
|
305
|
|
|
|
|
|
|
}
|
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
sub to_ascii
|
308
|
|
|
|
|
|
|
{
|
309
|
2
|
|
|
2
|
1
|
15
|
my $self = shift;
|
310
|
2
|
|
|
|
|
5
|
my $cf = '[' . join(", ", @{ $self->{simple} });
|
|
2
|
|
|
|
|
18
|
|
311
|
2
|
50
|
|
|
|
12
|
$cf .= ', [' . join(", ", @{ $self->{repeat} }) . ']' if ($self->{repeat});
|
|
0
|
|
|
|
|
0
|
|
312
|
2
|
|
|
|
|
9
|
return $cf .']';
|
313
|
|
|
|
|
|
|
}
|
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
#
|
316
|
|
|
|
|
|
|
# $class->_copy($self);
|
317
|
|
|
|
|
|
|
#
|
318
|
|
|
|
|
|
|
# Duplicate the continued fraction object.
|
319
|
|
|
|
|
|
|
#
|
320
|
|
|
|
|
|
|
sub _copy
|
321
|
|
|
|
|
|
|
{
|
322
|
0
|
|
|
0
|
|
|
my($other, $self) = @_;
|
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
#
|
325
|
|
|
|
|
|
|
# Direct copy of all keys, except for our arrays, which
|
326
|
|
|
|
|
|
|
# we'll do with a deeper copy.
|
327
|
|
|
|
|
|
|
#
|
328
|
0
|
|
|
|
|
|
foreach my $k (grep($_ !~ /simple|repeat/, keys %{$other}))
|
|
0
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
{
|
330
|
0
|
|
|
|
|
|
$self->{$k} = $other->{$k};
|
331
|
|
|
|
|
|
|
}
|
332
|
|
|
|
|
|
|
|
333
|
0
|
|
|
|
|
|
$self->{simple} = [ @$other->{simple} ];
|
334
|
0
|
0
|
|
|
|
|
$self->{repeat} = ($other->{repeat})? [ @$other->{repeat} ]: undef;
|
335
|
|
|
|
|
|
|
|
336
|
0
|
|
|
|
|
|
return $self;
|
337
|
|
|
|
|
|
|
}
|
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
=head1 NAME
|
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
Math::ContinuedFraction - Create and Manipulate Continued Fractions.
|
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
=head1 SYNOPSIS
|
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
Quick summary of what the module does.
|
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
Perhaps a little code snippet.
|
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
use Math::ContinuedFraction;
|
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
#
|
353
|
|
|
|
|
|
|
# Create new continued fraction objects.
|
354
|
|
|
|
|
|
|
#
|
355
|
|
|
|
|
|
|
my $cf = Math::ContinuedFraction->new([1, 4, 9, 25]);
|
356
|
|
|
|
|
|
|
my $cf_phi = Math::ContinuedFraction->new([1, [1]]);
|
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
my $cf_67div29 = Math::ContinuedFraction->from_ratio(67, 29);
|
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
=head1 DESCRIPTION
|
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
Continued fractions are expressions of the form
|
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
b1
|
366
|
|
|
|
|
|
|
a1 + -------
|
367
|
|
|
|
|
|
|
b2
|
368
|
|
|
|
|
|
|
a2 + -------
|
369
|
|
|
|
|
|
|
b3
|
370
|
|
|
|
|
|
|
a3 + -------
|
371
|
|
|
|
|
|
|
...
|
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
For most instances, the 'b' terms are 1, and the continued fraction
|
374
|
|
|
|
|
|
|
can be written as C<[a1, a2, a3, ...]>, etc. If the sequence of 'a' terms ends
|
375
|
|
|
|
|
|
|
at a certain point, the continued fraction is known as a finite continued
|
376
|
|
|
|
|
|
|
fraction, and can be exactly represented as a fraction. If the sequence of
|
377
|
|
|
|
|
|
|
'a' terms has a repeating sequence, it is normally written as
|
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
______
|
380
|
|
|
|
|
|
|
[a1, a2, a3, a4, a5]
|
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
where the line over a4 and a5 indicates that they repeat forever. Since we
|
383
|
|
|
|
|
|
|
can't use that method in perl code, we indicate the repeating portion by using an
|
384
|
|
|
|
|
|
|
array within the array:
|
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
[a1, a2, a3, [a4, a5]]
|
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
Note that in the examples in the L, C<$cf_phi> is created using
|
389
|
|
|
|
|
|
|
that notation.
|
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
=head2 Methods to Create Continued Fraction Objects
|
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
=head3 new()
|
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
Create a new continued fraction object from an array.
|
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
my $cf = Math::ContinuedFraction([1, [2, 1]]);
|
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
Arrays are in the form C<[finite_sequence, [repeating_sequence]]>. A continued fraction
|
400
|
|
|
|
|
|
|
with no repeating part simply omits the embedded array reference:
|
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
my $cf = Math::ContinuedFraction([1, 2, 1, 3, 1, 5]);
|
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
=head3 from_ratio()
|
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
Generate a continued fraction from a pair of relatively prime numbers.
|
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
=head2 Methods to Return Information
|
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
=head3 convergent()
|
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
Returns the fraction formed by calculating the rational approximation
|
413
|
|
|
|
|
|
|
of the continued fraction at a stopping point, and returning the
|
414
|
|
|
|
|
|
|
numerator and denominator.
|
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
Convergent term counts begin at 1. Continued fractions with a repeating
|
417
|
|
|
|
|
|
|
component can effectively have a term count as high as you like. Finite
|
418
|
|
|
|
|
|
|
continued fractions will stop at the end of the sequence without warning.
|
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
#
|
421
|
|
|
|
|
|
|
# Find the ratios that approximate pi.
|
422
|
|
|
|
|
|
|
#
|
423
|
|
|
|
|
|
|
# The array stops at seven elements for simplicity's sake,
|
424
|
|
|
|
|
|
|
# the sequence actually does not end.
|
425
|
|
|
|
|
|
|
#
|
426
|
|
|
|
|
|
|
my $cfpi = Math::ContinuedFraction([3, 7, 15, 1, 292, 1, 1]);
|
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
for my $j (1..4)
|
429
|
|
|
|
|
|
|
{
|
430
|
|
|
|
|
|
|
my($n, $d) = cfpi->convergent($j);
|
431
|
|
|
|
|
|
|
print $n->bstr() . "/". $d->bstr() . "\n";
|
432
|
|
|
|
|
|
|
}
|
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
The values returned are objects of type Math::BigInt.
|
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
=head3 brconvergent()
|
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
Behaves identically to convergent(), but returns a single Math::BigRat
|
439
|
|
|
|
|
|
|
object instead of two Math::BigInt objects.
|
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
#
|
442
|
|
|
|
|
|
|
# Find the ratios that approximate pi.
|
443
|
|
|
|
|
|
|
#
|
444
|
|
|
|
|
|
|
# The array stops at seven elements for simplicity's sake,
|
445
|
|
|
|
|
|
|
# the sequence actually does not end.
|
446
|
|
|
|
|
|
|
#
|
447
|
|
|
|
|
|
|
my $cfpi = Math::ContinuedFraction([3, 7, 15, 1, 292, 1, 1]);
|
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
for my $j (1..4)
|
450
|
|
|
|
|
|
|
{
|
451
|
|
|
|
|
|
|
my $r = cfpi->convergent($j);
|
452
|
|
|
|
|
|
|
print $r->bstr() . "\n";
|
453
|
|
|
|
|
|
|
}
|
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
=head3 to_array()
|
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
Returns an array reference that can be used to create a continued fraction (see L).
|
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
my $cf = Math::ContinuedFraction->from_ratio(0xfff1, 0x7fed);
|
461
|
|
|
|
|
|
|
my $aref = $cf->to_array()
|
462
|
|
|
|
|
|
|
my $cf2 = Math::ContinuedFraction->new($aref);
|
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
=head3 to_ascii()
|
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
Returns the string form of the array reference.
|
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
my $cf = Math::ContinuedFraction->from_ratio(0xfff1, 0x7fed);
|
469
|
|
|
|
|
|
|
print $cf->to_ascii(), "\n";
|
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
Returns C<[2, 1432, 1, 6, 1, 2]>.
|
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
=head1 AUTHOR
|
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
John Gamble, C<< >>
|
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS
|
478
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
Olds, C. D. I. New York: Random House, 1963.
|
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE
|
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
Copyright 2011 John Gamble.
|
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it
|
486
|
|
|
|
|
|
|
under the terms of either: the GNU General Public License as published
|
487
|
|
|
|
|
|
|
by the Free Software Foundation; or the Artistic License.
|
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
See http://dev.perl.org/licenses/ for more information.
|
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
=cut
|
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
1; # End of Math::ContinuedFraction
|