#!/usr/bin/perl package Fraction; use Exporter; @ISA = qw(Exporter); @EXPORT_OK = qw(decimal_to_continued_fraction continued_fraction_to_fraction decimal_to_fraction convergents ); $DEFAULT_PRECISION = 2**(-24); sub decimal_to_continued_fraction { my ($n, $e) = @_; $e = $DEFAULT_PRECISION unless defined $e; my $i = int $n; my $f = $n - $i; # print ">> $i + $f ($e)\n"; if ($f <= $e) { return $i; } elsif (1-$f <= $e) { return $i + 1; } my @result = decimal_to_continued_fraction(1/$f, $e*$i); return ($i, @result); } sub continued_fraction_to_fraction { my @cf = reverse @_; my ($n, $d) = (shift @cf,1); while (@cf) { ($n, $d) = ($d, $n); $n += $d * shift(@cf); } ($n, $d); } sub convergents { my @cf = decimal_to_continued_fraction(@_); my @c; my @result; for (@cf) { push @c, $_; push @result, [continued_fraction_to_fraction(@c)]; } @result; } unless (caller) { while ($r = <>) { @l = decimal_to_continued_fraction($r, 1e-14); ($n, $d) = continued_fraction_to_fraction(@l); print "That looks like $n/$d.\nLet me check.\n"; $r2 = $n/$d; if ($r2 == $r) { print "Yup!\n"; } elsif (abs($r2 - $r) < $DEFAULT_PRECISION) { print "Close enough.\n"; } else { print "No, $n/$d is actually $r2. Something is wrong.\n" } } } 1;