Implements floating point numbers of arbitrary length and precision
Version: $Date: 2009/08/02 08:09:39 $
Copyright: 2007 by icosaedro.it di Umberto Salsi
License: BSD-style
PHP version: 5
Required modules:
standard, spl, simplexml, dom, pcre
Required packages:
BigInt.php
Author: Umberto Salsi <salsi@icosaedro.it>
BigFloat are floating point numbers with sign and arbitrary length and precision suitable for monetary calculations and other numerical non-intensive tasks. Big floating numbers can be entered using a syntax similar to that of regular floating point numbers of the PHP language, included sign, fractional part and scale coefficient. For example:
+12.3456789012e+123
All the operations are performed with absolute precision using a decimal internal representation. A number can take as many digits as needed, either in the integer part or in the decimal part. Only the division requires to set a limit to the precision.
Example:
$price = new BigFloat("56.78");
$VAT = $price
->mul( new BigFloat("0.20") ) # apply VAT 20%
->round(-2); # round to 2 decimal digits
$total = $price->add($VAT);
echo "Price: ", $price->format(2), "\n";
echo "VAT : ", $VAT->format(2), "\n";
echo "Total: ", $total->format(2), "\n";
The code above displays:
Price: 56.78
VAT : 11.36
Total: 68.14
Currently the exponent part of the number is handled as int
number and possible overflows are not detected. The method BigFloat::isValid(), devoted to validate input submitted by the user, sets a quite
arbitrary limit of +/-9999 to the exponent, and this should be enough to
protect the application. However, it is unlikely that so big numbers can
ever be required by real-world applications.
A note about the interface provided by this class. Every object of the class
holds a big floating point number, so most of the methods have this value
as implicit argument, here represented with the word "$this".
Methods that require two or more numbers take $this as the
first argument.
Once created, an object is never changed, i.e. it is immutable.
Source code and updates: www.icosaedro.it/bignumbers
See also: www.php.net/manual/en/ref.bc.php (BCMath extension)
class BigFloat
{
UPDATES = "http://www.icosaedro.it/cvs.html"
VERSION = "$Date: 2009/08/02 08:09:39 $"static boolean isValid(
string $f)Returns TRUE if the string represents a valid BigFloat
Valid BigFloat numbers looks like regular PHP floating point numbers with the only difference that, if a decimal point is present, at least a digit must be present before and after that decimal point. To be more precise, a BigFloat may have a sign +/- followed by one or more decimal digits with possibly a decimal point followed by one or more digits and an exponent. The exponent can range from -9999 up to +9999. Spaces and any other character are not allowed. Examples:
0 -1.5 +0.012345 1e6 12.34E-128Invalid examples:
.1 100. 1^6 1,234
Parameters:
$fThe string to be evaluated as BigFloat. Return: TRUE if the string represents a valid BigFloat.
void __construct(
mixed $x)Builds a new BigFloat number
int numbers and
BigIntnumbers can always be converted exactly into BigFloat numbers.If $x is a string, always use
BigFloat::isValid()before passing arbitrary strings, i.e. user submitted input. Spaces are not allowed, so usetrim().If $x is a float it is converted exactly into its corresponding decimal representation. BigFloat guarantees all the bits of a floating point number be preserved, but this does not prevent "unexpected" values from appearing. INF and NAN yield exception as they cannot be represented internally.
WARNING: avoid to use floating-point numbers at all as they may give unexpected results due to the rounding that occurs in the conversion process from decimal to binary form operated at the parsing stage by the PHP interpreter. For example printf("%.0F", 1e23) prints "99999999999999991611392" rather than the expected "1" followed by 23 zeroes just because 1e23 requires 54 bits, one more than those available in a double-precision IEEE 754 register; so $f must store a truncated value. Also numbers as simple as 0.1 cannot be stored in a float without loss of precision. To avoid these problems avoid passing float numbers to the constructor
new BigFloat(0.1)but instead use the string notationnew BigFloat("0.1")as this latter preserves the precision.
Parameters:
$xThe value to be converted to BigFloat. It may be: int, float, string or BigInt.Throws:
- unchecked
InvalidArgumentExceptionif the argument passed is a string that does not represent a valid floating point number, or it is a non-finite floating point number, or it is any another unexpected type of data.string __toString()Returns the number represented as string
Return: An optional "-" is followed by one or more digits and a possible fractional part.
string format(
int $decimals,
string $dec_point = ".",
string $thousands_sep = ",")Pretty formatting
WARNING! The number is truncated as needed, but not rounded. If a rounding is required, apply
BigFloat::round()before formatting.
Parameters:
$decimalsNumber of digits in the fractional part. The BigFloat is truncated or some zero is added if required. If negative, the fractional part is omitted. $dec_pointSeparator string between integral part and fractional part. $thousands_sepSeparator string between thousands. Return: The BigFloat formatted.
int sign()Returns the sign of the number
Return: +1 if the number is positive, -1 if negative, 0 if zero.
int scale()Returns the scale factor, that is the power of the first digit
For example, the scale of 1230 is 4, the scale of 0.00123 is -3.
BigFloatabs()Returns the number without the sign
Return: The number without the sign.
BigFloatminus()Returns the number with the sign reversed
Return: The number with the sign reversed.
int cmp(
BigFloat$b)Compare $this with $b
Parameters:
$bThe number to be compared. Return: Negative if $this is less than $b, positive if $this is greater than $b, zero if they are equal.
BigFloatadd(
BigFloat$b)Addition
Parameters:
$bThe second term to add. Return: The sum $this+$b.
BigFloatsub(
BigFloat$b)Subtraction
Parameters:
$bThe term to subtract. Return: The difference $this-$b.
BigFloatmul(
BigFloat$b)Multiplication
Parameters:
$bThe second factor. Return: The product $this*$b.
BigFloatdiv(
BigFloat$b,
int $precision)Returns $this/$b
Calculate the quotient $q=$this/$b precise up to the digit of the power 1e$precision. For example, to obtain a result with 5 decimal digits you must set $precision to -5. Note that the result is truncated. If a rounding is required, the division must be performed with higher precision -6 and the result can then be rounded:
$q = $n ->div($d, -6) ->round(-5);
Parameters:
$bThe divisor. $precisionPower of ten of the last digit to calculate. For example, to calculate up to the second fractional digit, set $precision to -2. Setting $precision=0 would return the integral part of the division. Positive values would stop the calculation to the given power of ten. Examples: echo $a->div( new BigFloat(3), -2), "\n"; # 1.66 echo $a->div( new BigFloat(3), 0), "\n"; # 1 echo $a->div( new BigFloat(3), 1), "\n"; # 0Return: The quotient calculated up to the given precision.
Throws:
- unchecked
InvalidArgumentExceptionif the divisor $b is zero.BigFloatdiv_rem(
BigFloat$b,
int $precision,
returnBigFloat& $rem)Returns $this/$b and the remainder
Returns the quotient $q=$this/$b precise up to the power 1e$precision, just like
BigFloat::div()does, but it returns also the remainder $rem = $this - $q*$b. For example, having to divide 100 EUR into 3 parts with precision of 1 cent ($precision=-2) we get the quotient 100/3=33.33 with remainder 0.01.
Parameters:
$bThe divisor. $precisionPower of ten of the last digit to calculate. $remRemainder of the division. Return: The quotient calculated up to the given precision.
Throws:
- unchecked
InvalidArgumentExceptionif the divisor $b is zero.BigFloattrunc(
int $precision)Returns the number truncated to a given power of ten
The digits of power 1e($precision-1), 1e($precision-2), ... are simply discarded.
trunc(0)returns the integer part of the number. Examples:$n = new BigFloat("12.345"); echo $n->trunc(-2); # 12.34 echo $n->trunc( 1); # 10 echo $n->trunc( 2); # 0 echo $n->trunc(-9); # 12.345Note that if the $precision is greater than the scale of the number, zero is returned.
Parameters:
$precisionPower of ten of the last digit to retain. Return: The truncated number.
BigFloattrunc_rem(
int $precision,
returnBigFloat& $rem)Returns the truncated number and the remainder
The same as
BigFloat::trunc()but it returns also the truncated remainder $rem. Note that the truncated number added to the remainder give back the original number.
Parameters:
$precisionPower of ten of the last digit to retain. $remThe truncated part. Return: The truncated number.
BigFloatround(
int $precision)Rounds the number to a given power of ten
Returns $this truncated just as explained for
BigFloat::trunc(). If the first digit of the remainder is 5 or greater, the truncated number is also rounded. For example, round(0) returns the nearest integer. Examples:$n = new BigFloat("1.4"); echo $n->round(0); # displays 1 $n = new BigFloat("1.5"); echo $n->round(0); # displays 2 $n = new BigFloat("-1.4"); echo $n->round(0); # displays -1 $n = new BigFloat("-1.5"); echo $n->round(0); # displays -2See also: http://en.wikipedia.org/wiki/Rounding for a discussion of various rounding methods.
Parameters:
$precisionPower of ten of the last digit to retain. Return: The rounded number.
BigFloatceil()Return the smallest integral value not less than $this
Return: The ceil of $this.
BigFloatfloor()Return the largest integral value not greater than $this
Return: The floor of $this.
int toInt()Return the integral part of $this as an int number
Return: If $this is positive the floor() is returned, otherwise the ceil() is returned, so for example 1.2 gives 1 while -1.2 gives -1.
Throws:
- unchecked
OutOfRangeExceptionif the resulting number is too big to fit int.float toFloat()Return the best approximating floating point representation
WARNING: 1) very large positive numbers may give INF, while negative ones may give -INF; 2) some BigFloat decimal numbers cannot be represented exactly under the float binary representation and must be rounded; 3) precision may be lost as float numbers can hold typically only about 15 decimal digits, and with very large number the precision decreases even further. Because of that, conversion from BigFloat to float requires maximum care and should be avoided.
Return: The best approximating floating point representation.
BigInttoBigInt()Return the integral part of $this as a BigInt number
Return: If $this is positive the floor() is returned, otherwise the ceil() is returned, so for example 1.2 gives 1 while -1.2 gives -1.
BigFloatsqrt(
int $precision)Returns the square root of $this
The result il calculated up to the digit of power 1e$precision. No rounding is performed. If a rounding is required, the sqrt() can be calculated with higher precision ($precision+1) then the result can be rounded at $precision. Example:
$x = new BigFloat("2"); echo $x->sqrt(-5); # displays 1.41421
Parameters:
$precisionThe power of ten of the last digit to calculate. Return: The square root.
Throws:
- unchecked
InvalidArgumentExceptionif $this is negative.
}
Generated by PHPLint Documentator