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);
return "$G / $H";
} // end of BC_Add_Frac (...)
/*
============================================================================
This 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 results reduced to lowest terms, set
the ReduceFlag to TRUE. The default is FALSE
and will return the raw, unreduced fraction.
GCD = Greatest Common Divisor of both E and F
If GCD == 1, then E/F cannot be reduced
and G/H === E/F.
Reduced:
G = E / GCD
H = F / GCD
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:
If (B*D == 0), then it is a division by zero error.
FALSE is returned if any of the arguments are non-
numeric or a division by zero error is detected.
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);
// 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;}
// Return FALSE if division by zero error detected.
if (bcMul($B,$D) == 0) {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.
$GCD = 1;
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);
return "$G / $H";
} // end of BC_Sub_Frac (...)
/*
============================================================================
This function performs arbitrary-precision integer
fraction multiplication with reduction option.
(A/B) * (C/D) = (A*C) / (B*D) = (E/F)
Raw E/F
E = A*C
F = B*D
To return results reduced to lowest terms, set
the ReduceFlag to TRUE. The default is FALSE
and will return the raw, unreduced fraction.
GCD = Greatest Common Divisor of both E and F
If GCD == 1, then E/F cannot be reduced
and G/H === E/F.
Reduced:
G = E / GCD
H = F / GCD
The fractions may be composed of any signed integers,
such as '48/-130' or '165/55'.
ARGUMENTS:
A_B = Signed integer fraction = 'A / B'
C_D = Signed integer fraction = 'C / D'
ERRORS:
If (B*D == 0), then it is a division by zero error.
FALSE is returned if any of the arguments are non-
numeric or a division by zero error is detected.
NO DEPENDENCIES
*/
function BC_Mul_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 multiplication
// and return resulting signed integer fraction string.
$E = bcMul($A,$C);
$F = bcMul($B,$D);
// Return FALSE if division by zero error detected.
if ($F == 0) {return FALSE;}
// If ReduceFlag === TRUE, then reduce to lowest
// terms. Otherwise return raw, unreduced value.
$GCD = 1;
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);
return "$G / $H";
} // end of BC_Mul_Frac (...)
/*
============================================================================
This function performs arbitrary-precision integer
fraction division with reduction option.
(A/B) / (C/D) = (A*D) / (B*C) = E/F
Raw:
E = A*D
F = B*C
GCD = Greatest Common Divisor of both E and F
If GCD == 1, then E/F cannot be reduced
and G/H === E/F.
Reduced:
G = F/GCD
H = F/GCD
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:
If (B*C == 0), then it is a division by zero error.
FALSE is returned if any of the arguments are non-
numeric or a division by zero error is detected.
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);
// Return FALSE if division by zero error detected.
// exit("$F");
if ($F == 0) {return FALSE;}
// If ReduceFlag === TRUE, then reduce to lowest
// terms. Otherwise return raw, unreduced value.
$GCD = 1;
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);
return "$G / $H";
} // end of BC_Div_Frac (...)
/*
===========================================================================
This function checks to see if a fractional value like 'A/B' is valid.
X_Y = The signed integer fraction string 'Y/X'
TRUE is returned if the fraction is valid.
FALSE is returned if either argument is non-numeric or a division by zero
error is detected.
NO DEPENDENCIES
*/
function Is_Valid_Frac ($Y_X)
{
$w = trim($Y_X);
// Error if no slash (/) separator found.
if (StrPos($w, '/') === FALSE) {return FALSE;}
// Parse (Y/X) integer values, if slash (/) separator found.
list($Y,$X) = PregSplit("[ ]", PReg_Replace("/\s+/", " ", trim($w)));
$Y=trim($Y); $X=trim($X);
// Return FALSE if either argument is non-numeric
// or a division by zero error is detected.
if (!Is_Numeric($Y) or !Is_Numeric($X) or $X==0)
{return FALSE;}
// If all is OK, then return TRUE.
return TRUE;
}
/*
===========================================================================
This function returns the GCD (Greatest Common Divisor)
for the given integer fraction argument string ('Y/X').
*/
function GCD_Frac ($Y_X)
{
$w = trim($Y_X);
// Error if no slash (/) separator found.
if (StrPos($w, '/') === FALSE) {return FALSE;}
// Parse (Y/X) integer values, if slash (/) separator found.
list($Y,$X) = Preg_Split("[\/]", PReg_Replace("/\s+/", " ", trim($w)));
$Y=trim($Y); $X=trim($X);
// Return FALSE if either argument is non-numeric.
if (!Is_Numeric($Y) or !Is_Numeric($X)) {return FALSE;}
// If all is OK, then compute GCD.
$Y = Str_Replace('+', '', Str_Replace('-', '', $Y));
$X = Str_Replace('+', '', Str_Replace('-', '', $X));
if (bcComp($X, $Y) < 0) {$w=$X; $X=$Y; $GCD=$w;} else {$GCD=$Y;}
while ($X <> 0) {$w=$X; $X=bcMod($GCD, $X); $GCD=$w;}
return $GCD;
}
/*
===========================================================================
This function returns an arbitrary-precision decimal value for a given
signed integer fraction argument (Y/X).
X_Y = The signed integer fraction string 'Y/X'.
ERRORS:
FALSE is returned if either Y,X argument is non-numeric or a division by
zero error is detected.
NO DEPENDENCIES
*/
function Int_Frac_to_Dec_Frac($Y_X, $Decimals=16)
{
// Read arguments.
$w = RTrim(trim($Y_X), '.');
$q = IntVal(abs(trim($Decimals)));
// Return as-is, if argument is a simple integer string.
if (Is_Numeric($w) and StrPos($w, '.') === FALSE) {return $w;}
// Error if no slash (/) separator found.
if (StrPos($w, '/') === FALSE) {return FALSE;}
// Otherwise, parse (Y/X) integer values.
list($Y, $X) = Preg_Split("[\/]", PReg_Replace("/\s+/", " ", trim($w)));
$Y=trim($Y); $X=trim($X);
// Error if either argument is non-numeric or
// if a division by zero error is detected.
if (!Is_Numeric($Y) or !Is_Numeric($X) or $X == 0) {return FALSE;}
// Compute decimal equivalent ot fraction to given decimals.
return bcDiv($Y, $X, $q);
}
/*
===========================================================================
This function converts a number into BC computation format if it is not
already in usable BC format.
Handles up to 1000 decimals by default, but this can be changed.
ERRORS:
FALSE is returned if argument is non-numeric.
===========================================================================
*/
function Sci_to_BC ($NumericString)
{
// Read numeric string argument.
$x = StrToUpper(trim($NumericString));
// Set internal working decimals limit.
$q = 1000;
// Do this if no exponent symbol (E) is found.
if (StrIPos($x, 'E') === FALSE)
{
// Return FALSE if non-numeric string.
if (!Is_Numeric($x)) {return FALSE;}
return $x;
}
// ========================================
// Do this if exponent symbol (E) is found.
$j = StrIPos($x, 'E');
if ($j !== FALSE)
{
// Return FALSE if non-numeric string.
if (!Is_Numeric($x)) {return FALSE;}
// Split into numeric and exponential parts.
$xExpPart = substr($x, $j+1, StrLen($x));
$xNumPart = substr($x, 0, $j);
// Multiply numerical part by exponential power of 10.
$w = ($xExpPart < 0)?
bcDiv('1', bcPow('10', abs($xExpPart)), $q) : bcPow('10', $xExpPart);
$X = bcMul($xNumPart, $w, $q);
}
else
{
if (!Is_Numeric($x)) {return FALSE;}
}
$X = RTrim(RTrim($X,'0'),'.');
// Remove any numerical (-/+) sign.
if (substr($X,0,2) == '-.') {$X = Str_Replace('-.', '-0.', $X);}
if (substr($X,0,2) == '+.') {$X = Str_Replace('-.', '-0.', $X);}
// Append missing '0' at beginning of number.
if (substr($X,0,1) == '.') {$X = Str_Replace('.', '0.', $X);}
return $X;
}
/*
===========================================================================
This function converts a signed decimal fractional value string
like (12.3/256.96) into its corresponding signed integer fraction
string (Y/X).
EXAMPLE:
The argument '184.9036572' would return the
fraction string '462259143 / 2500000'
which is an exactly equivalent ratio
in terms of the smallest possible
integer values.
DecValue = Decimal number value string.
DecFracStr = Non-integer decimal fraction string
in the format: '128.45678/68.654'
ERRORS:
FALSE is returned if argument is non-numeric.
===========================================================================
*/
function Dec_Frac_to_Int_Frac($DecFracStr)
{
// Read decimal fractional argument string.
$X = RTrim(trim($DecFracStr), '.');
// Do this ONLY if argument X is a simple integer string.
if (Is_Numeric($X) and StrPos($X, '.') === FALSE) {return "$X/1";}
// Do this ONLY if X is a simple number with a decimal point.
$i = StrPos($X, '.'); $j = StrPos($X, '/');
if (Is_Numeric($X) and $i !== FALSE and $j === FALSE) {$X = "$X/1";}
// Prepend any missing zero to X string.
if (substr($X,0,1) == '.') {$X = "0$X";}
$X = Str_Replace('-.','-0.', $X);
$X = Str_Replace('+.','+0.', $X);
// Split X into numerator and denominator parts.
list($numer,$denom) = PReg_Split("[\/]", $X);
$numer = trim($numer);
$denom = trim($denom);
// Count decimal places.
$i = StrPos($numer, '.');
$Pow10 = bcPow('10', StrLen($numer) - $i - 1);
// Multiply both numerator and denominator by power
// of 10 equal to the number of decimals to obtain
// integer values with the same equivalent ratio.
$A = $numer = bcMul($numer, $Pow10);
$B = $denom = bcMul($denom, $Pow10);
// Reduce final integer fraction to lowest terms, if possible.
$A = Str_Replace('-', '', Str_Replace('+', '', $A));
$B = Str_Replace('-', '', Str_Replace('+', '', $B));
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;}
$numer = bcDiv($numer, $GCD);
$denom = bcDiv($denom, $GCD);
return "$numer / $denom";
}
?>
-----
\\
** Here is a complete PHP demo program to test the fractional arithmetic module above.\\ **
\\
To use this demo program, put it into a folder called **fractional-arithmetic-demo/**\\
and name the file **index.php** \\
\\
Put the **Fractional-Arithmetic-Module.php** file into the same folder and the demo should be ready to run.\\
\\
Example WWW calling format: \\
**[[https://www.phpsciencelabs.com/fractional-arithmetic-demo/|Your-Web-Site-Name.com/fractional-arithmetic-demo/]]**
\\
Your URL ending with the folder name would be the program calling name on the WWW.\\
The program can also be run on a local PC web server such as XAMPP.
***************************************************************************
ARBITRARY-PRECISION SIGNED INTEGER FRACTION ARITHMETIC DEMO
===========================================================================
GIVEN THE TWO INTEGER FRACTION STRINGS BELOW, THE FOUR BASIC ARITHMETIC
OPERATIONS (ADD, SUB, MUL and DIV) ARE PERFORMED ON THEM. REFRESH THIS
PAGE FOR NEW RANDOMIZED EXAMPLE FRACTIONS.
A/B = ($A_B)
and
C/D = ($C_D)
===========================================================================
ADD: (A/B) + (C/D) = (A*D + B*C) / (B*D) = E / F
= ($A_B) + ($C_D)
Raw Fraction = $AddOutRaw
GCD = $AddOutGCD
Reduced Fraction = $AddOutRed
Plain decimal value truncated at $q decimals without rounding =
$AddOutDec
===========================================================================
SUBTRACT: (A/B) − (C/D) = (A*D − B*C) / (B*D) = E / F
= ($A_B) - ($C_D)
Raw Fraction = $SubOutRaw
GCD = $SubOutGCD
Reduced Fraction = $SubOutRed
Plain decimal value truncated at $q decimals without rounding =
$SubOutDec
===========================================================================
MULTIPLY: (A/B)*(C/D) = (A*C) / (B*D) = E / F
= ($A_B) * ($C_D)
Raw Fraction = $MulOutRaw
GCD = $MulOutGCD
Reduced Fraction = $MulOutRed
Plain decimal value truncated at $q decimals without rounding =
$MulOutDec
===========================================================================
DIVIDE: (A/B) / (C/D) = (A*D) / (B*C) = E / F
= ($A_B) / ($C_D)
Raw Fraction = $DivOutRaw
GCD = $DivOutGCD
Reduced Fraction = $DivOutRed
Plain decimal value truncated at $q decimals without rounding =
$DivOutDec
===========================================================================
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
";
?>