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