The fNumber class is a value object to represent large integers and arbitrary precision decimal values. The fNumber class is essential when dealing with calculations that must be precise, such as monetary value (consequently the fMoney class is built on top of fNumber). It supplies the same math functionality that is built into PHP, minus the trigonometric operations.
An fNumber object requires just a single parameter for the constructor, the value to represent. It can be a string, an object with a __toString()
method, or an integer. If the value being represented is too large to store in an integer, the integer value should be enter via a string to prevent data loss. Also, float values should never be used since they have an inherent loss of precision that this class is designed to overcome.
$five = new fNumber(5);
$four_point_two = new fNumber('4.2');
$zero_point_one = new fNumber('0.1');
There is a second optional parameter to the constructor that allows specifying the precision of the number. If no precision is specified, the precision of the value is used.
// Represents 1.000
$one = new fNumber(1, 3);
Basic arithmetic is performed using the method add()
, sub()
, mul()
and div()
. Since the fNumber class is a value object, all operations return a new fNumber object instead of modifying the existing one. Also, all methods accept any valid number representation including strings, fNumber objects and integers.
The returned fNumber object will have the same precision as the object being called unless the optional parameter $scale
is included.
Addition is performed by calling the method add()
and providing an $addend
.
// Addition using different addend number forms
$six = $five->add(1);
$six = $five->add($one);
$eight_point_four = $four_point_two->add('4.2');
// Without scale the 0.1 is lost
$five = $five->add('0.1');
// By specifying a scale of 1 we retain the 0.1
$five_point_one = $five->add('0.1', 1);
Subtraction is performed by calling the method sub()
and providing a $subtrahend
.
// Basic subtraction
$two = $five->sub(3);
// Since $five has a scale of zero, the result is still five
$five = $five->sub('0.3');
// All arithmetic methods support positive and negative numbers
$five_point_three = $five->sub('-0.3', 1);
Multiplication is performed by calling the method mul()
and providing a $multiplicand
.
// Simple multiplication
$ten = $five->mul(2);
// A comparison of multiplication with 0 and 1 scale
$twelve = $five->mul('2.5');
$twelve_point_five = $five->mul('2.5', 1);
Division is performed by calling the method div()
and providing a $divisor
.
// Basic division
$two = $five->div(2);
// Division with a specific scale
$two_point_five = $five->div(2, 1);
The remainder of integer division can be calculated by the method mod()
and the remainder of fractional division can be calculated by the method fmod()
.
The mod()
method will convert the current number to an integer and then divide it by the single parameter, $divisor
, that is passed to the method. The $divisor
is also converted to an integer before the calculation is performed.
// Simple integer division
$one = $three->mod('2');
// The number and divisor are both converted to integers first
$one = $three_point_two->mod('2.1');
The fmod()
method allows dividing a fractional number by another fractional number, returning the remainder. The first parameter is the $divisor
to use, while a second optional parameter, $scale
, allows specifying the scale of the remainder that is being returned.
$zero_point_three = $four_point_seven->fmod('1.1');
$one_point_four_zero = $four_point_four->fmod('1.5', 2);
The fNumber class provides functionality to calculate both square roots and integer powers via the sqrt()
and pow()
methods.
The sqrt()
method accepts a single optional parameter, the $scale
of the result.
$three = $nine->sqrt();
$three_point_eight = $fifteen->sqrt(1);
The pow()
method accepts two parameters, the required $exponent
to raise the number to, and the optional $scale
for the resulting number.
$twenty_five = $five->pow(2);
$nine_point_two_six = $two_point_one->pow(3, 2);
Under certain situations, especially when dealing with cryptography, it is necessary to raise integers to large powers and then calculate the remainder of the division of that product by another integer. Normal calculation by raising the original number to a large power and then dividing to find the remainder often takes far too much computation. There are, however, some mathematical shortcuts to make such calculations significantly faster.
The powmod()
method allows calculating the remainder of the original number raised to an $exponent
and then divided by the $modulus
.
$four_fourty_five = $four->powmod('13', '497');
The fNumber class include comparison methods for testing equality - eq()
, less than - lt()
, less than or equal - lte()
, greater than - gt()
and greater than or equal - gte()
. Each method accepts two parameters, the $number
to compare to and an optional $scale
to use for comparison.
The $number
to compare to may be any valid fNumber object, string or integer. The $scale
parameter sets how many digits after the decimal point to use during comparison. If no scale is specified, the highest scale of the two numbers will be used.
$true = $five->eq(5);
$false = $five->eq('5.1');
$true = $five->eq('5.1', 0);
$true = $five->lt($six);
$true = $five->lte('5.00', 4);
$false = $five->gt($six, 0);
$false = $five->gte('5.1', 1);
There are two options to format fNumber objects, either __toString()
or format()
. The format()
method will include thousands separators in the returned value, while __toString()
will not. The inherent scale of the number will be used when displaying the value. To change the scale, use the trunc()
or round()
method first.
echo $one_thousand_two_hundred->format() . "\n";
echo $one_thousand_two_hundred->__toString() . "\n";
echo $negative_five_point_two->format() . "\n";
echo $negative_five_point_two->__toString() . "\n";
echo $negative_five_point_two->trunc()->__toString();
would output the following
1,200
1200
-5.2
-5.2
-5
If the parameter $remove_zero_fraction
is set to TRUE
and the value has a fraction that is just zeros, the resulting output will not contain a decimal point or a fraction.
// This will print: 5
$five = new fNumber('5.0');
echo $five->format(TRUE);
$two_fifty_three = new fNumber('2.53');
// This will print: 2.53
echo $two_fifty_three->format(TRUE);
The precision of an fNumber can be modified by using the ceil()
, floor()
, round()
and trunc()
methods.
The ceil()
method performs a ceiling operation, rounding up to the next highest integer.
$six = $five_point_two->ceil();
The floor()
method preforms a floor operation, rounding down to the next lowest integer.
$negative_six = $negative_five_point_two->floor();
The trunc()
method changes the scale of the number to 0 without performing any rounding.
$five = $five_point_two->trunc();
The round()
method allows rounding a number to a specified number of decimal places, using the $scale
parameter. It is even possible to round left of the decimal point using negative scales. Rounding is done using the common method, that is when the digit one place beyond the $scale
is 5 or greater the $scale
digit is increased vy 1, otherwise the digit is left the same.
// Rounding positive numbers
$five = $five_point_two->round();
$six = $five_point_five->round();
// Rounding negative numbers
$negative_two = $negative_one_point_six->round();
$negative_one = $negative_one_point_one->round();
// Rounding to a specific scale
$one_point_three = $one_point_three_three->round(1);
$ten = $thirteen->round(-1);
The fNumber class can calculate the absolute value of a number via the abs()
method, the negated value via the neg()
method and can return the sign of a number via the sign()
method.
Here are a few basic example of using the abs()
and neg()
methods:
// Calculating the absolute value
$five = $five->abs();
$five = $negative_five->abs();
// Negating numbers
$negative_five = $five->neg();
$five = $negative_five->neg();
The sign()
method will return -1
if the number is negative, 0
if the number is zero and 1
if the number is positive.
$true = $five->sign() == 1;
$true = $zero->sign() == 0;
$false = $zero->sign() == -1;
$true = $negative_one->sign() == -1;
The value of pi can be obtained up to a scale of 500 by calling the static method pi()
and providing the desired $scale
.
// 3.14
$pi = fNumber::pi(2);
// 3.1415926535897932384626433
$pi = fNumber::pi(25);
For some calculations, representing numbers in a base other than base 10 is necessary. The static method baseConvert()
allow converting integers between any two bases ranging from base 2 (binary) to base 16 (hexadecimal). Three parameters are required, the integer to convert, the base being converted from and the base being converted to.
echo fNumber::baseConvert($five, 10, 2) . "\n";
echo fNumber::baseConvert('10110100110', 2, 16) . "\n";
echo fNumber::baseConvert('10110100110', 2, 8);
would output the following
101
5A6
2646
When formatting numbers in different locales, it will often be the case that the thousands separator and decimal point are different than the one in the United States. The methods registerFormatCallback()
and registerUnformatCallback()
allow for both creating a different formatting and also removing such formatting when creating a new fNumber object.
// Function to format numbers for Italian
function italian_number_format($number, $remove_zero_fraction=FALSE)
{
$parts = explode('.', $number);
$integer = $parts[0];
$fraction = (isset($parts[1])) ? ',' . $parts[1] : '';
if ($remove_zero_fraction && rtrim($fraction, ',0') === '') {
$fraction = '';
}
return number_format($integer, 0, ',', '.') . $fraction;
}
// Function to change a formatted to a plain number
function italian_number_unformat($value)
{
return str_replace(array('.', ','), array('', '.'), $value);
}
fNumber::registerFormatCallback('italian_number_format');
fNumber::registerUnformatCallback('italian_number_unformat');