/*
###########################################################################
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 (...)