#!/usr/bin/perl -w use strict; use warnings; use diagnostics; =head1 cf takes a bigrat for its input, and returns an array as a continued fraction. In textbooks a continued fraction is often represented as something like: 1 _______________ 2 + 1 ___________ 2 + 1 ____ 2 + ... Publishers hate this because it uses up lots of empty paper, which they find annoying for some reason. A shorthand way of writing this is: [1; 2, 2, 2, 2 ...], which is considerably easier to type. I follow this convention in these scripts, when discussing continued fractions. An intriguing property of continued fractions is that they will form a repeating set of numbers when square roots are represented in that form. For example, the square root of 2 is 1.41421356237309504880168872420969807..., give or take a bit. This representation continues indefinitely, meaning the number of digits in this representation is infinite. Not only that, the digits do not repeat any pattern. The continued fraction representation of sqrt(2) is simply [1; 2, 2, 2, ...]. Although the numbers continue indefinitely, the pattern repeats. This is true of all square roots of rational numbers. Some other values also have a repeating pattern, for example e. Its representation in continued fraction format is: [2; 1, 2, 1, 1, 4, 1, 1, 6, 1, 1, 8, 1, 1, 10, 1, 1, 12, 1, 1, 14, 1 1 16 1 1...] While it doesn't exactly *repeat*, it does have a discernible pattern that can be used to advantage. The sequence of digits can be expanded at will, and converting a continued fraction back into a bigrat will generate e to any desired accuracy. This also applies to square roots of rational numbers. =cut sub cf { use bigrat; my $number=Math::BigRat->new(shift); my $pvar = 50; # Arbitrary limit to number of continued fraction elements. my $count=0; my $int1; my @array; while($number &&($count<$pvar)) { $int1=$number->copy->bfloor($number); $array[$count]=($int1); $number-=$int1; if($number) { $number=(1/$number); } else { last; } $count++; } return @array; } =head1 This sub takes an array of values that it interprets as a continued fraction. For this sub, the format for a continued fraction is an array containing the integer part of the real number as its first element (zeroth element. Each successive element, if any, represents an integer formed by subtracting the previous integer from the value, and then inverting it. In other words, you take the number, subtract its integer portion (saving it in the array). If the fractional part is not zero, you then invert the remaining fractional part. Since this value was less than one before the inversion, it will be greater than 1 afterwards. This means it will again have an integer part that can be subtracted. You keep this up until you get zero as a remaining part, which of course can't be inverted. Or else, you just get tired, since any irrational number will repeat endlessly. Or you could just keep going, but this becomes tiresome after a while. =cut sub cf2rat(@) { my @a=@_; my $max=@a; if($max==1) { return(@a); } my (@p,,@q); $p[0]=$a[0]; $q[0]=1; $p[1]=$a[1]*$a[0]+1; $q[1]=$a[1]; my @r; my $k=2; while($k<$max) { $p[$k]=$a[$k]*$p[$k-1]+$p[$k-2]; $q[$k]=$a[$k]*$q[$k-1]+$q[$k-2]; $k++; } for(my $i=0;$i<$max;$i++) { $r[$i]="$p[$i]".'/'."$q[$i]"; } return(@r); } __END__ =head1 NAME CFrac =head1 SYNOPSIS Scripts for converting between rational numbers and continued fractions. Very alpha... =head1 DESCRIPTION One use of continued fractions is to generate arbitrarily accurate decimal expansions of certain irrational numbers. Since these particular continued fractions repeat or have a pattern, one can construct arbitrarily long continued fractions, and then perform the operations to convert the continued fraction back to a rational approximation to the irrational. The accuracy depends only on how long the continued fraction is. To calculate e out to a gazillion places, start with a continued fraction that is quite lengthy - I cannot actually say how long it must be, in order to attain a given accuracy. However, the longer, the better. For e, the pattern is [2; 1, 2, 1, 1, 4, 1, 1, 6, ..] - two ones, followed by a number that increases by 2 each time it shows up again. Simple enough. =head1 SEE ALSO Math::BigInt, Math::BigRat, bignum, bigrat, etc. =head1 AUTHOR Baruch Ben-David (baruch@cpan.org) Copyright 2005 Baruch Ben-David, All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc. 59 Temple Place - Suite 330 Boston, MA 02111-1307, USA. =cut