Re: [QUIZ] Perl 'Easy' Quiz of the Week #2006-04-02 - Rounded Fractions

"Kester Allen" <[email protected]> Thu, 6 Apr 2006 09:42:16 -0700
Newsgroups gmane.comp.lang.perl.qotw.discuss
Message-ID <[email protected]>
Here's my solution:

#!/usr/bin/perl

use strict;
use warnings;

eval {
    main ();
};
if ( my $err =3D $@ ) {
    print STDERR "# $0: $err\n";
    exit 1 ;
}
exit 0;

sub main {
    my $in_frac1 =3D shift @ARGV or die "need two inputs";
    my $in_frac2 =3D shift @ARGV or die "need two inputs";

    my $dec1 =3D frac2dec( $in_frac1 );
    my $dec2 =3D frac2dec( $in_frac2 );
    my $frac =3D dec2frac( $dec1 * $dec2 );

    print "$in_frac1 X $in_frac2 =3D $frac\n",
          "$dec1 X $dec2 =3D ", $dec1 * $dec2, "\n";
}

sub dec2frac {
    my $dec =3D shift () or die "no input in dec2frac";
    my $intpart =3D int $dec;

    # We need to round to the closest 1/4, 1/3, or 1/2.  Convert
    #    the fraction into x/12, and then simplify the fraction:
    #
    my $denom =3D 12;
    my $neum  =3D int ( $denom * ($dec - $intpart) + 0.5 ); #rounding
    foreach my $div ( 2, 3 ) {
        while( 0 =3D=3D $neum % $div ) {
            $neum  /=3D $div;
            $denom /=3D $div;
        }
    }
    return "$intpart $neum / $denom";
}

sub frac2dec {
    my $frac =3D shift () or die "no input in frac2dec";

    # strip leading and trailing whitespace
    #
    $frac =3D~ s/^\s+|\s+$//g;

    # Split the fraction on slashes surrounded by zero-or-more whitespaces,=
 or
    #   whitespaces themselves.  This split should produce an array with ei=
ther
    #   one (just a number), two (for a pure fraction), or three (for a
    #   number-plus-fraction) elements:
    #
    my @frac_decomp =3D split /\s*\/\s*|\s+/, $frac;
    my ( $prop, $neumerator, $denomenator )
        =3D ( scalar @frac_decomp =3D=3D 3 ) ? @frac_decomp
        : ( scalar @frac_decomp =3D=3D 2 ) ? ( 0, @frac_decomp[0,1] )
        : ( scalar @frac_decomp =3D=3D 1 ) ? ( $frac_decomp[0], 0, 1 )
        : die "input is bad: \"@frac_decomp\"";
    # Return the decimal value:
    #
    return $prop + $neumerator / $denomenator;
}