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

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

   Raw E/F
   E = A*D + B*C
   F = B*D

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

   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.

   The fractions may be composed of any signed
   integers, such as '-4/23' or '157/3741'.

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

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

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

   function BC_Add_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 possible 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+/", ' ', trim($A_B)));
   list($C,$D) = PReg_Split("[\/]", PReg_Replace("/\s+/", ' ', trim($C_D)));

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

// Return FALSE 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 final fractional raw E/F result
   $E = $G = bcAdd(bcMul($A,$D), bcMul($B,$C));
   $F = $H = bcMul($B,$D);

// 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 (G/H) if possible.
   $G = bcDiv($E, $GCD);
   $H = bcDiv($F, $GCD);
}

// Done.
   return "$G/$H";

} // End of  BC_Add_Frac (...)