### Overloaded addition operator sub _add { my ( $x, $y ) = @_; my ( $n_sum, $sum_str ); my ( $n1, $n2 ) = ( $x->{NUMER}, $y->{NUMER} ); my ( $d1, $d2 ) = ( $x->{DENOM}, $y->{DENOM} ); my $com_denom = ( $d1 == $d2 ) ? $d1 : $d1 * $d2; $n_sum = ( $d1 == $d2 ) ? $n1 + $n2 : do { $n1 = $n1 * ( $com_denom / $d1 ); $n2 = $n2 * ( $com_denom / $d2 ); $n1 + $n2; }; my $gcd = _simplify( $n_sum, $com_denom ); ( $n_sum, $com_denom ) = map { $_ /= $gcd } ( $n_sum, $com_denom ); $sum_str = ($com_denom) ? ( $n_sum == $com_denom ) ? "1" : "${n_sum}/${com_denom}" : "0"; return $sum_str; } ### Overloaded subtraction operator sub _sub { my ( $x, $y, ) = @_; my ( $n_diff, $diff_str ); my ( $n1, $n2 ) = ( $x->{NUMER}, $y->{NUMER} ); my ( $d1, $d2 ) = ( $x->{DENOM}, $y->{DENOM} ); my $com_denom = ( $d1 == $d2 ) ? $d1 : $d1 * $d2; $n_diff = ( $d1 == $d2 ) ? $n1 - $n2 : do { $n1 = $n1 * ( $com_denom / $d1 ); $n2 = $n2 * ( $com_denom / $d2 ); $n1 - $n2; }; my $gcd = _simplify( abs($n_diff), $com_denom ); ( $n_diff, $com_denom ) = map { $_ /= $gcd } ( $n_diff, $com_denom ); $diff_str = ($com_denom) ? ( $n_diff == $com_denom ) ? "1" : "${n_diff}/${com_denom}" : "0"; return $diff_str; } #### #!/usr/bin/perl use strict; use warnings; my $command = 0; print "\nThis program will perform arithmetic operations on fractions.\n"; print "Enter fractions like this: 3/4, 15/16, etc..., or \"exit\" to exit.\n"; while ( $command ne "Q" ) { print "\nEnter first fraction: "; chomp( my $frac01 = <> ); if ( $frac01 =~ /^\S+\/(\S+)$/ ) { print "Division by zero not allowed, starting over..." and redo unless ( $1 ); } print "Enter second fraction: "; chomp( my $frac02 = <> ); if ( $frac02 =~ /^\S+\/(\S+)$/ ) { print "Division by zero not allowed, starting over..." and redo unless ( $1 ); } exit if ( $frac01 eq "exit" || $frac02 eq "exit" ); my $f1 = RatNum->new($frac01); my $f2 = RatNum->new($frac02); while ( $command ne "Q" ) { print "\nChoose: (A)dd, (S)ubtract, (M)ultiply, (D)ivide\n"; print "\tTest for (E)quality, or (Q)uit\n"; print "Answer: "; chomp( $command = <> ); if ( $command eq "A" ) { my $total = RatNum->new( $f1 + $f2 ); print "\n" . $f1->to_string() . " + " . $f2->to_string() . " = " . $total->to_string() . "\n"; } elsif ( $command eq "S" ) { my $total = RatNum->new( $f1 - $f2 ); print "\n" . $f1->to_string() . " - " . $f2->to_string() . " = " . $total->to_string() . "\n"; } elsif ( $command eq "M" ) { my $total = RatNum->new( $f1 * $f2 ); print "\n" . $f1->to_string() . " * " . $f2->to_string() . " = " . $total->to_string() . "\n"; } elsif ( $command eq "D" ) { my $total = RatNum->new( $f1 / $f2 ); print "\n" . $f1->to_string() . " / " . $f2->to_string() . " = " . $total->to_string() . "\n"; } elsif ( $command eq "E" ) { my $is_equal = ( $f1 == $f2 ) ? q{ } : " not "; print "\n" . $f1->to_string() . " and " . $f2->to_string() . " are" . $is_equal . "equal.\n"; } elsif ( $command eq "Q" ) { last; } else { print "Command not recognized...\n"; } } print "Type (Q) again to exit or another character to start over: "; chomp( $command = <> ); if ( $command eq "Q" ) { print "Goodbye..\n"; exit; } } exit; ### Rational Number Package ### package RatNum; use overload "+" => \&_add, "-" => \&_sub, "*" => \&_mul, "/" => \&_div, "==" => \&_eql; sub new { my $class = shift; my $frac = { NUMER => undef, DENOM => undef, WHOLE => undef, }; bless $frac, $class; $frac->_make_frac(@_); return $frac; } ### Split string and assign NUMER, DENOM, and WHOLE sub _make_frac { no warnings; # expecting occasional empties my $self = shift; my $frac_str = shift; my ( $n, $d, $w ) = map { split /\//, $_ } ( $frac_str ); ## Checks for fraction entries that can be simply "1" ( $n, $d, $w ) = ( $n, $d || 1, ( $d > 1 ) ? 0 : 1 ); ( $n, $d, $w ) = (1) x 3 if ( $n == $d ); # when "2/2" should equal "1" ## Checks for "-" in denominator and adjusts accordingly $n = -$n and $d = -$d if ( ( $n > 0 ) && ( $d < 0 ) ); ( $self->{NUMER}, $self->{DENOM}, $self->{WHOLE} ) = ( $n, $d, $w ); return; } ### Stringify object to fracion sub to_string { my $self = shift; my ( $n, $d, $w ) = ( $self->{NUMER}, $self->{DENOM}, $self->{WHOLE} ); return "0" unless ( $n && $d ); return $n if ( $w ); return $n . "/" . $d; } ### Overloaded addition operator sub _add { my ( $x, $y ) = @_; my ( $n_sum, $sum_str ); my ( $n1, $n2 ) = ( $x->{NUMER}, $y->{NUMER} ); my ( $d1, $d2 ) = ( $x->{DENOM}, $y->{DENOM} ); my $com_denom = ( $d1 == $d2 ) ? $d1 : $d1 * $d2; $n_sum = ( $d1 == $d2 ) ? $n1 + $n2 : do { $n1 = $n1 * ( $com_denom / $d1 ); $n2 = $n2 * ( $com_denom / $d2 ); $n1 + $n2; }; my $gcd = _simplify( $n_sum, $com_denom ); ( $n_sum, $com_denom ) = map { $_ /= $gcd } ( $n_sum, $com_denom ); $sum_str = ($com_denom) ? ( $n_sum == $com_denom ) ? "1" : "${n_sum}/${com_denom}" : "0"; return $sum_str; } ### Overloaded subtraction operator sub _sub { my ( $x, $y, ) = @_; my ( $n_diff, $diff_str ); my ( $n1, $n2 ) = ( $x->{NUMER}, $y->{NUMER} ); my ( $d1, $d2 ) = ( $x->{DENOM}, $y->{DENOM} ); my $com_denom = ( $d1 == $d2 ) ? $d1 : $d1 * $d2; $n_diff = ( $d1 == $d2 ) ? $n1 - $n2 : do { $n1 = $n1 * ( $com_denom / $d1 ); $n2 = $n2 * ( $com_denom / $d2 ); $n1 - $n2; }; my $gcd = _simplify( abs($n_diff), $com_denom ); ( $n_diff, $com_denom ) = map { $_ /= $gcd } ( $n_diff, $com_denom ); $diff_str = ($com_denom) ? ( $n_diff == $com_denom ) ? "1" : "${n_diff}/${com_denom}" : "0"; return $diff_str; } ### Overloaded multiplication operator sub _mul { my ( $x, $y ) = @_; my ($n_prod) = ( $x->{NUMER} * $y->{NUMER} ); my ($d_prod) = ( $x->{DENOM} * $y->{DENOM} ); my $gcd = _simplify( $n_prod, $d_prod ); ( $n_prod, $d_prod ) = map { $_ /= $gcd } ( $n_prod, $d_prod ); my $prod_str = ( $n_prod == $d_prod ) ? "1" : "${n_prod}/${d_prod}"; return $prod_str; } ### Overloaded division operator sub _div { my ( $x, $y ) = @_; my ($n_quot) = ( $x->{NUMER} * $y->{DENOM} ); my ($d_quot) = ( $x->{DENOM} * $y->{NUMER} ); ( $n_quot, $d_quot ) = ( -$n_quot, -$d_quot ) if ( $n_quot < 0 && $d_quot < 0 ); my $gcd = _simplify( $n_quot, $d_quot ); ( $n_quot, $d_quot ) = map { $_ /= $gcd } ( $n_quot, $d_quot ); my $quot_str = ( $n_quot == $d_quot ) ? "1" : "${n_quot}/${d_quot}"; return $quot_str; } ### Checks for object equality sub _eql { my ( $x, $y ) = @_; return ( ( $x->{NUMER} == $y->{NUMER} ) && ( $x->{DENOM} == $y->{DENOM} ) ); } ### Simplify fraction using Euclid's algorithm sub _simplify { use integer; my ( $x, $y ) = @_; while ($y) { my $r = $x % $y; $r += $y if $r < 0; $x = $y; $y = $r; } return $x; } 1; # for whenever I make this a separate package file