BigFloat

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-128

Invalid examples:

.1 100. 1^6 1,234

Parameters:
$f   The 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 BigInt numbers 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 use trim().

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 notation new BigFloat("0.1") as this latter preserves the precision.

Parameters:
$x   The value to be converted to BigFloat. It may be: int, float, string or BigInt.

Throws:

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:
$decimals   Number 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_point   Separator string between integral part and fractional part.
$thousands_sep   Separator 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.


BigFloat abs()

Returns the number without the sign

Return: The number without the sign.


BigFloat minus()

Returns the number with the sign reversed

Return: The number with the sign reversed.


int cmp(
        BigFloat $b)

Compare $this with $b

Parameters:
$b   The number to be compared.

Return: Negative if $this is less than $b, positive if $this is greater than $b, zero if they are equal.


BigFloat add(
        BigFloat $b)

Addition

Parameters:
$b   The second term to add.

Return: The sum $this+$b.


BigFloat sub(
        BigFloat $b)

Subtraction

Parameters:
$b   The term to subtract.

Return: The difference $this-$b.


BigFloat mul(
        BigFloat $b)

Multiplication

Parameters:
$b   The second factor.

Return: The product $this*$b.


BigFloat div(
        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:
$b   The divisor.
$precision   Power 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";  # 0
 

Return: The quotient calculated up to the given precision.

Throws:

BigFloat div_rem(
        BigFloat $b,
        int $precision,
        return BigFloat & $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:
$b   The divisor.
$precision   Power of ten of the last digit to calculate.
$rem   Remainder of the division.

Return: The quotient calculated up to the given precision.

Throws:

BigFloat trunc(
        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.345
  
Note that if the $precision is greater than the scale of the number, zero is returned.

Parameters:
$precision   Power of ten of the last digit to retain.

Return: The truncated number.


BigFloat trunc_rem(
        int $precision,
        return BigFloat & $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:
$precision   Power of ten of the last digit to retain.
$rem   The truncated part.

Return: The truncated number.


BigFloat round(
        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 -2
  

See also: http://en.wikipedia.org/wiki/Rounding for a discussion of various rounding methods.

Parameters:
$precision   Power of ten of the last digit to retain.

Return: The rounded number.


BigFloat ceil()

Return the smallest integral value not less than $this

Return: The ceil of $this.


BigFloat floor()

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:

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.


BigInt toBigInt()

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.


BigFloat sqrt(
        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:
$precision   The power of ten of the last digit to calculate.

Return: The square root.

Throws:

}


Generated by PHPLint Documentator