Basic Fractional Arithmetic
Below are PHP functions that were developed to perform signed arbitrary precision fractional arithmetic. Here, arbitrary precision means to virtually any number of digits.
In order to work with integer fractions, we need to establish the basic algebraic rules of fractional arithmetic. These algebraic rules will still hold true even when the numeric values are non-integers, but here we are using only integers. THE BASIC RULES OF FRACTIONAL ARITHMETIC Given Two Integer Fractions (A/B) and (C/D) GCD = Greatest Common Divisor of Both Numerator and Denominator <?php /* ================================================================== This PHP module contains functions to perform basic signed integer fraction arithmetic using arbitrary-precision arithmetic. Author : Jay Tanner - 2024 License : Public Domain --------------------------- 'A/B' , 'C/D' = Integer fractions as strings. 'E/F' = Returned fractional result as string. ReduceFlag = FALSE = Return raw, non-reduced fraction. (default) = TRUE = Return fraction reduced to lowest terms. ================================================================== */ /* ---------------------------------------------------------- This function adds two integer fractions with the option to reduce the result to lowest terms. (A/B) + (C/D) = (A*D + B*C) / (B*D) = E/F Where: E = A*D + B*C and F = B*D NO DEPENDENCIES ERRORS: FALSE is returned if invalid integer fraction is detected. ---------------------------------------------------------- */ function BC_Add_Frac ($A_Bstr, $C_Dstr, $ReduceFlag=FALSE) { $A_B = Str_Replace(' ', '', trim($A_Bstr)); $C_D = Str_Replace(' ', '', trim($C_Dstr)); if (Is_Numeric($A_B)) {$A_B = "$A_B/1";} if (Is_Numeric($C_D)) {$C_D = "$C_D/1";} list($A,$B) = PReg_Split("[\/]", $A_B); list($C,$D) = PReg_Split("[\/]", $C_D); if ( !Is_Numeric($A) or !Is_Numeric($B) or !Is_Numeric($C) or !Is_Numeric($D) ) {return FALSE;} $E = bcAdd(bcMul($A,$D), bcMul($B,$C)); $F = bcMul($B,$D); // If ReduceFlag === TRUE, then reduce to lowest terms. // Otherwise return the raw, non-reduced 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"; } /* ------------------------------------------------------------- This function subtracts two integer fractions with the option to reduce the result to lowest terms. (A/B) - (C/D) = (A*D - B*C) / (B*D) = E/F Where: E = A*D - B*C and F = B*D NO DEPENDENCIES ERRORS: FALSE is returned if invalid integer fraction is detected. ---------------------------------------------------------- */ function BC_Sub_Frac ($A_Bstr, $C_Dstr, $ReduceFlag=FALSE) { $A_B = Str_Replace(' ', '', trim($A_Bstr)); $C_D = Str_Replace(' ', '', trim($C_Dstr)); if (Is_Numeric($A_B)) {$A_B = "$A_B/1";} if (Is_Numeric($C_D)) {$C_D = "$C_D/1";} list($A,$B) = PReg_Split("[\/]", $A_B); list($C,$D) = PReg_Split("[\/]", $C_D); if ( !Is_Numeric($A) or !Is_Numeric($B) or !Is_Numeric($C) or !Is_Numeric($D) ) {return FALSE;} $E = bcSub(bcMul($A,$D), bcMul($B,$C)); $F = bcMul($B,$D); // If ReduceFlag === TRUE, then reduce to lowest terms. // Otherwise return the raw, non-reduced 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"; } /* ---------------------------------------------------------- This function multiplies two integer fractions with the option to reduce the result to lowest terms. A/B * C/D = (A*C)/(B*D) = E/F Where: E = A*C and F = B*D NO DEPENDENCIES ERRORS: FALSE is returned if invalid integer fraction is detected. ---------------------------------------------------------- */ function BC_Mul_Frac ($A_Bstr, $C_Dstr, $ReduceFlag=FALSE) { $A_B = Str_Replace(' ', '', trim($A_Bstr)); $C_D = Str_Replace(' ', '', trim($C_Dstr)); if (Is_Numeric($A_B)) {$A_B = "$A_B/1";} if (Is_Numeric($C_D)) {$C_D = "$C_D/1";} list($A,$B) = PReg_Split("[\/]", $A_B); list($C,$D) = PReg_Split("[\/]", $C_D); if ( !Is_Numeric($A) or !Is_Numeric($B) or !Is_Numeric($C) or !Is_Numeric($D) ) {return FALSE;} $E = bcMul($A,$C); $F = bcMul($B,$D); // If ReduceFlag === TRUE, then reduce to lowest terms. // Otherwise return the raw, non-reduced 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"; } /* ----------------------------------------------------------- This function divides two integer fractions with the option to reduce the result to lowest terms. (A/B) / (C/D) = (A*D) / (B*C) = E/F Where: E = A*D and F = B*C NO DEPENDENCIES ERRORS: FALSE is returned if invalid integer fraction is detected. ----------------------------------------------------------- */ function BC_Div_Frac ($A_Bstr, $C_Dstr, $ReduceFlag=FALSE) { $A_B = Str_Replace(' ', '', trim($A_Bstr)); $C_D = Str_Replace(' ', '', trim($C_Dstr)); if (Is_Numeric($A_B)) {$A_B = "$A_B/1";} if (Is_Numeric($C_D)) {$C_D = "$C_D/1";} list($A,$B) = PReg_Split("[\/]", $A_B); list($C,$D) = PReg_Split("[\/]", $C_D); if ( !Is_Numeric($A) or !Is_Numeric($B) or !Is_Numeric($C) or !Is_Numeric($D) ) {return FALSE;} $E = bcMul($A,$D); $F = bcMul($B,$C); // If ReduceFlag === TRUE, then reduce to lowest terms. // Otherwise return the raw, non-reduced 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"; } ?> | ||||||
Program by Jay Tanner Revised: Thursday, January 01, 1970 at 12:00:00 AM UTC |