designerdecimal.pl (1505B)
1 #!/usr/bin/perl 2 3 # For describing a performant rational approximation algorithm, thanks to: 4 # John Kennedy, "Algorithm to Convert a Decimal to a Fraction" 5 # http://homepage.smc.edu/kennedy_john/DEC2FRAC.PDF 6 7 use strict; 8 use warnings; 9 use Math::BigFloat; 10 11 my $name = "Santa Claus"; 12 if (scalar(@ARGV) > 0) { 13 $name = join(' ', @ARGV); 14 } 15 16 my @chars = split(//, $name); 17 my $ascii = ''; 18 foreach my $char (@chars) { 19 $ascii .= sprintf('%03s' , ord($char)); 20 } 21 $ascii = '1.' . $ascii . '004'; 22 my $accuracy = length($ascii) - 1; 23 24 my $x = Math::BigFloat->new($ascii); 25 $x->accuracy($accuracy); 26 my $z = $x->copy(); 27 my $dMinTwo = Math::BigFloat->bzero(); 28 my $d = Math::BigFloat->bone(); 29 my $n = Math::BigFloat->bzero(); 30 my $i = 0; 31 32 print "For the name '$name':\n Your designer decimal is $ascii\n"; 33 my $q = $n->copy(); 34 $q->bdiv($d); 35 $q->accuracy($accuracy); 36 37 until (BigFloatEqual($q, $x)) { 38 my $zInt = $z->copy(); 39 $zInt->bfloor(); 40 my $zSub = $z->copy(); 41 $zSub->bsub($zInt); 42 $z = Math::BigFloat->bone(); 43 $z->bdiv($zSub); 44 45 $zInt = $z->copy(); 46 $zInt->bfloor(); 47 48 my $dCpy = $d->copy(); 49 $d->bmul($zInt->as_int()); 50 $d->badd($dMinTwo); 51 $dMinTwo = $dCpy->copy(); 52 53 $n = $d->copy(); 54 $n->bmul($x); 55 $n->bfround(0, 'odd'); 56 57 $q = $n->copy(); 58 $q->round_mode('trunc'); 59 $q->accuracy($accuracy); 60 $q->bdiv($d); 61 62 $i++; 63 } 64 65 print " Your rational approximation is $n / $d\nTook $i iterations.\n"; 66 67 sub BigFloatEqual { 68 my ($x, $y) = @_; 69 if ($x->bcmp($y) == 0) { 70 return 1; 71 } 72 return 0; 73 }