/*
   ###########################################################################
   This function performs arbitrary-precision signed integer fraction division
   with reduction option.

   All computed integers are EXACT values.

   (A/B) / (C/D) = (A*D) / (B*C) = E/F

   Raw:
   E = A*D
   F = B*C

   Reduced = G/H
   G = E/GCD
   H = F/GCD

   GCD = Greatest Common Divisor of both E and F
         If GCD == 1, then E/F cannot be reduced
         and G/H = E/F.

   To return results reduced to lowest terms, set
   the ReduceFlag to TRUE.  The default is FALSE
   and will return the raw, unreduced fraction.

   The fractions may be composed of any signed integers,
   such as '3747/-673' or '117/649'.

   ARGUMENTS:
   $A_B = Signed integer fraction = 'A/B' = 'A / B'
   $C_D = Signed integer fraction = 'C/D' = 'C / D'

   ERRORS:
   FALSE is returned if any of the arguments are non-numeric.

   NO DEPENDENCIES
   ###########################################################################
*/

   function BC_Div_Frac ($A_B, $C_D, $ReduceFlag=FALSE)
{
// Read integer fraction argument strings
// and strip out ALL spaces from strings.
   $A_B = Str_Replace(' ', '', trim($A_B));
   $C_D = Str_Replace(' ', '', trim($C_D));

// Account for integer arguments and convert to 'X/1' format.
   if (StrPos($A_B, '/') === FALSE) {$A_B .= '/1';}
   if (StrPos($C_D, '/') === FALSE) {$C_D .= '/1';}

// Parse fraction strings and extract the individual integer values.
   list($A, $B) = PReg_Split("[\/]", PReg_Replace("/\s+/", ' ', $A_B));
   list($C, $D) = PReg_Split("[\/]", PReg_Replace("/\s+/", ' ', $C_D));

// Remove any redundant white space from arguments.
   $A = trim($A);   $B = trim($B);   $C = trim($C);   $D = trim($D);

// Error if any of the (A, B, C, D) arguments are non-numeric.
   if (
      !Is_Numeric($A) or !Is_Numeric($B)
   or !Is_Numeric($C) or !Is_Numeric($D)
      )
      {return FALSE;}

// Compute numerator and denominator of the division and
// return RAW, unreduced signed integer fraction string.
   $E = bcMul($A, $D);
   $F = bcMul($B, $C);

// If ReduceFlag === TRUE,  then reduce to lowest
// terms.  Otherwise return raw, unreduced value.
   if ($ReduceFlag === TRUE)
{
   $A = Str_Replace('-', '', Str_Replace('+', '', $E));
   $B = Str_Replace('-', '', Str_Replace('+', '', $F));
   if (bcComp($B, $A) < 0) {$w=$B;  $B=$A;  $GCD=$w;} else {$GCD=$A;}
   while ($B <> 0) {$w=$B;   $B=bcMod($GCD, $B);   $GCD=$w;}

// Reduce E/F to lowest
// terms, if possible.
   $E = bcDiv($E, $GCD);
   $F = bcDiv($F, $GCD);
}
   return "$E/$F";

} // End of  BC_Div_Frac (...)