/*
###########################################################################
This PHP function performs arbitrary-precision integer fraction subtraction
with reduction option.
(A/B) - (C/D) = (A*D - B*C) / (B*D) = 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 '17/49' or '23/-2871'.
ARGUMENTS:
$A_B = Signed integer fraction = 'A / B'
$C_D = Signed integer fraction = 'C / D'
ERRORS:
FALSE is returned if any of the arguments are non-numeric.
NO DEPENDENCIES
###########################################################################
*/
function BC_Sub_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+/", ' ', 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);
// 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 subtraction and
// return RAW, unreduced signed integer fraction string.
$E = bcSub(bcMul($A,$D), bcMul($B,$C));
$F = 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, if possible.
$E = bcDiv($E, $GCD);
$F = bcDiv($F, $GCD);
}
return "$E/$F";
} // End of BC_Sub_Frac (...)