#!/home/johnh/BIN/perl5 -w # # rational_approximations.pl # $Id$ # # Copyright (C) 1998-1999 by John Heidemann # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License, # version 2, as published by the Free Software Foundation. # # 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. # sub usage { print STDERR <= 0 && $ARGV[0] eq '-?'); my(%opts); &GetOptions(\%opts, qw(d v)); # &usage if ($#ARGV < 0); my($verbose) = defined($opts{'v'}); my($debug) = defined($opts{'d'}); my($limit) = ($#ARGV >= 0) ? $ARGV[0] : (2<<31); # # Start with pi to 40 digits. # Verified against http://cad.ucla.edu/repository/useful/PI.txt, # and we know that everything on the web is true. # # Note: current floating point systems will discard many of these spare digits. # my($R) = 3.1415926535897932384626433832795028841971; my($a, $e); my($last_a, $last_e); $last_a = $a = 3; $last_e = $R - $last_a; print "#h a b r e new\n"; my($best_a, $best_b, $best_e); my($i) = 1; for (; $i <= $limit;) { # # show current iteration # my($r) = $a / ($i + 0.0); $e = abs($R - $r); my($value) = $e == $last_e ? "same" : ($e < $last_e ? "better" : "worse"); my($show, $new); if (!defined($best_e) || $e < $best_e) { $best_a = $a; $best_b = $i; $best_e = $e; $show = 1; $new = '*'; } else { $new = '.'; }; # print "$a[$i]/$i = $r ($e[$i], $value)\n";n printf ("%-8s %-8s %1.16f %1.16e %s\n", $a, $i, $r, $e, $new) if ($show || $verbose); # # find next iteration # my($j) = $i+1; # a/b = c/b+1 # # c = a(b+1)/b = ab/b + a/b = a + a/b # # ie # # 3/1 = 3 # 6/2 = 3 # /3 my($c) = $a + int($a/$i); my($best_d, $best_d_error); my($d); foreach $d (0, -1, 1) { my($trial) = $c + $d; my($result) = $trial/($j+0.0); my($error) = $R - $result; $error = -$error if ($error < 0); my($best) = ' '; if (!defined($best_d_error) || $error < $best_d_error) { $best_d = $d; $best_d_error = $error; $best = '*'; }; print " $best $trial/$j = $result ($error)\n" if ($debug); }; $last_a = $a; $last_e = $e; $a = $c + $best_d; $i = $j; }; exit 0;