2015-07-13 13:35:54 +02:00
## Brick\Math
< img src = "https://raw.githubusercontent.com/brick/brick/master/logo.png" alt = "" align = "left" height = "64" >
2014-08-31 14:17:36 +02:00
2015-06-26 00:35:31 +02:00
A library to work with arbitrary precision numbers.
2014-08-31 14:17:36 +02:00
2015-01-21 19:58:38 +01:00
[![Build Status ](https://secure.travis-ci.org/brick/math.svg?branch=master )](http://travis-ci.org/brick/math)
[![Coverage Status ](https://coveralls.io/repos/brick/math/badge.svg?branch=master )](https://coveralls.io/r/brick/math?branch=master)
2015-07-05 13:13:10 +02:00
[![Latest Stable Version ](https://poser.pugx.org/brick/math/v/stable )](https://packagist.org/packages/brick/math)
[![License ](https://poser.pugx.org/brick/math/license )](https://packagist.org/packages/brick/math)
2014-08-31 14:17:36 +02:00
2015-07-05 00:24:47 +02:00
For a complete list of classes and methods, check the [API documentation ](http://brick.io/math/ ).
2015-07-13 13:35:54 +02:00
### Installation
2014-08-31 15:46:00 +02:00
This library is installable via [Composer ](https://getcomposer.org/ ).
Just define the following requirement in your `composer.json` file:
2015-07-13 13:35:54 +02:00
```json
{
"require": {
"brick/math": "0.5.*"
2014-08-31 15:46:00 +02:00
}
2015-07-13 13:35:54 +02:00
}
```
2014-08-31 15:46:00 +02:00
2015-07-13 13:35:54 +02:00
### Requirements
2014-08-31 15:46:00 +02:00
2015-06-07 15:06:25 +02:00
This library requires PHP 5.6, PHP 7 or [HHVM ](http://hhvm.com/ ).
2014-08-31 15:46:00 +02:00
2015-06-07 15:06:25 +02:00
Although the library can work seamlessly on any PHP installation, it is highly recommended that you install the
2014-08-31 15:46:00 +02:00
[GMP ](http://php.net/manual/en/book.gmp.php ) or [BCMath ](http://php.net/manual/en/book.bc.php ) extension
to speed up calculations. The fastest available calculator implementation will be automatically selected at runtime.
2015-07-13 13:35:54 +02:00
### Project status & release process
2015-06-20 23:54:06 +02:00
While this library is still under development, it is well tested and should be stable enough to use in production
environments.
The current releases are numbered `0.x.y` . When a non-breaking change is introduced (adding new methods, optimizing
existing code, etc.), `y` is incremented.
**When a breaking change is introduced, a new `0.x` version cycle is always started.**
2015-07-04 22:40:13 +02:00
It is therefore safe to lock your project to a given release cycle, such as `0.5.*` .
2015-06-20 23:54:06 +02:00
2015-08-06 13:17:56 +02:00
If you want to use the latest version, and receive any non-breaking update, use `~0.5.2` .
2015-07-05 13:13:10 +02:00
2015-06-20 23:54:06 +02:00
If you need to upgrade to a newer release cycle, check the [release history ](https://github.com/brick/math/releases )
for a list of changes introduced by each further `0.x.0` version.
2015-07-13 13:35:54 +02:00
### Package contents
2014-08-31 17:43:39 +02:00
2015-07-05 00:24:47 +02:00
This library provides the following public classes in the [Brick\Math ](http://brick.io/math/namespace-Brick.Math.html ) namespace:
2014-08-31 17:43:39 +02:00
2015-07-05 00:24:47 +02:00
- [BigNumber ](http://brick.io/math/class-Brick.Math.BigNumber.html ): base class for `BigInteger` , `BigDecimal` and `BigRational`
- [BigInteger ](http://brick.io/math/class-Brick.Math.BigInteger.html ): represents an arbitrary-precision integer number.
- [BigDecimal ](http://brick.io/math/class-Brick.Math.BigDecimal.html ): represents an arbitrary-precision decimal number.
- [BigRational ](http://brick.io/math/class-Brick.Math.BigRational.html ): represents an arbitrary-precision rational number (fraction).
- [RoundingMode ](http://brick.io/math/class-Brick.Math.RoundingMode.html ): holds constants for the [rounding modes ](http://brick.io/math/class-Brick.Math.RoundingMode.html ).
2015-07-04 22:40:13 +02:00
2015-07-05 00:24:47 +02:00
And the following exceptions in the [Brick\Math\Exception ](http://brick.io/math/namespace-Brick.Math.Exception.html ) namespace:
2015-07-04 22:40:13 +02:00
2015-07-05 00:24:47 +02:00
- [ArithmeticException ](http://brick.io/math/class-Brick.Math.Exception.ArithmeticException.html ): base class for all exceptions
- [DivisionByZeroException ](http://brick.io/math/class-Brick.Math.Exception.DivisionByZeroException.html ): thrown when a division by zero occurs
- [NumberFormatException ](http://brick.io/math/class-Brick.Math.Exception.NumberFormatException.html ): thrown when parsing a number string in an invalid format
- [RoundingNecessaryException ](http://brick.io/math/class-Brick.Math.Exception.RoundingNecessaryException.html ): thrown when the result of the operation cannot be represented without explicit rounding
2014-08-31 17:43:39 +02:00
2015-07-13 13:35:54 +02:00
### Overview
2014-08-31 15:46:00 +02:00
2015-07-13 13:35:54 +02:00
#### Instantiation
2014-08-31 15:46:00 +02:00
2015-07-04 22:40:13 +02:00
The constructors of the classes are not public, you must use a factory method to obtain an instance.
All classes provide an `of()` factory method that accepts any of the following types:
- `BigNumber` instances
- `int` numbers
- `float` numbers
- `string` representations of integer, decimal and rational numbers
Example:
2015-07-13 13:35:54 +02:00
```php
BigInteger::of(123546);
BigInteger::of('9999999999999999999999999999999999999999999');
2015-07-04 22:40:13 +02:00
2015-07-13 13:35:54 +02:00
BigDecimal::of(1.2);
BigDecimal::of('9.99999999999999999999999999999999999999999999');
2014-08-31 15:46:00 +02:00
2015-07-13 13:35:54 +02:00
BigRational::of('2/3');
BigRational::of('1.1'); // 11/10
```
2014-08-31 15:46:00 +02:00
2015-07-04 22:40:13 +02:00
Note that all `of()` methods accept all of the representations above, *as long as it can be safely converted to
the current type*:
2014-08-31 15:46:00 +02:00
2015-07-13 13:35:54 +02:00
```php
BigInteger::of('1.00'); // 1
BigInteger::of('1.01'); // ArithmeticException
2014-08-31 15:46:00 +02:00
2015-07-13 13:35:54 +02:00
BigDecimal::of('1/8'); // 0.125
BigDecimal::of('1/3'); // ArithmeticException
```
2014-08-31 15:46:00 +02:00
2015-07-04 22:40:13 +02:00
Note about native integers: instantiating from an `int` is safe *as long as you don't exceed the maximum
value for your platform* (`PHP_INT_MAX`), in which case it would be transparently converted to `float` by PHP without
notice, and could result in a loss of information. In doubt, prefer instantiating from a `string` , which supports
an unlimited numbers of digits:
2015-07-13 13:35:54 +02:00
```php
echo BigInteger::of(999999999999999999999); // 1000000000000000000000
echo BigInteger::of('999999999999999999999'); // 999999999999999999999
```
2015-07-04 22:40:13 +02:00
Note about floating-point values: instantiating from a `float` might be unsafe, as floating-point values are
imprecise by design, and could result in a loss of information. Always prefer instantiating from a `string` , which
supports an unlimited number of digits:
2015-07-13 13:35:54 +02:00
```php
echo BigDecimal::of(1.99999999999999999999); // 2
echo BigDecimal::of('1.99999999999999999999'); // 1.99999999999999999999
```
2015-07-04 22:40:13 +02:00
2015-07-13 13:35:54 +02:00
#### Immutability & chaining
2014-08-31 15:46:00 +02:00
2015-06-13 00:10:28 +02:00
The `BigInteger` , `BigDecimal` and `BigRational` classes are immutable: their value never changes,
so that they can be safely passed around. All methods that return a `BigInteger` , `BigDecimal` or `BigRational`
return a new object, leaving the original object unaffected:
2014-08-31 15:46:00 +02:00
2015-07-13 13:35:54 +02:00
```php
$ten = BigInteger::of(10);
2014-08-31 15:46:00 +02:00
2015-07-13 13:35:54 +02:00
echo $ten->plus(5); // 15
echo $ten->multipliedBy(3); // 30
```
2014-08-31 15:46:00 +02:00
2015-07-04 22:40:13 +02:00
The methods can be chained for better readability:
2015-07-13 13:35:54 +02:00
```php
echo BigInteger::of(10)->plus(5)->multipliedBy(3); // 30
```
2015-07-04 22:40:13 +02:00
2015-07-13 13:35:54 +02:00
#### Parameter types
2014-08-31 15:46:00 +02:00
2015-07-04 22:40:13 +02:00
All methods that accept a number: `plus()` , `minus()` , `multipliedBy()` , etc. accept the same types as `of()` .
For example, given the following number:
2014-08-31 15:46:00 +02:00
2015-07-13 13:35:54 +02:00
```php
$integer = BigInteger::of(123);
```
2014-08-31 15:46:00 +02:00
The following lines are equivalent:
2015-07-13 13:35:54 +02:00
```php
$integer->multipliedBy(123);
$integer->multipliedBy('123');
$integer->multipliedBy($integer);
```
2014-08-31 15:46:00 +02:00
2015-07-04 22:40:13 +02:00
Just like `of()` , other types of `BigNumber` are acceptable, as long as they can be safely converted to the current type:
2014-08-31 15:46:00 +02:00
2015-07-13 13:35:54 +02:00
```php
echo BigInteger::of(2)->multipliedBy(BigDecimal::of('2.0')); // 4
echo BigInteger::of(2)->multipliedBy(BigDecimal::of('2.5')); // ArithmeticException
echo BigDecimal::of(2.5)->multipliedBy(BigInteger::of(2)); // 5.0
```
2014-08-31 15:46:00 +02:00
2015-07-13 13:35:54 +02:00
#### Division & rounding
2014-08-31 15:46:00 +02:00
2015-07-13 13:35:54 +02:00
##### BigInteger
2014-08-31 15:46:00 +02:00
2015-07-04 22:40:13 +02:00
By default, dividing a `BigInteger` returns the exact result of the division, or throws an exception if the remainder
of the division is not zero:
2015-07-13 13:35:54 +02:00
```php
echo BigInteger::of(999)->dividedBy(3); // 333
echo BigInteger::of(1000)->dividedBy(3); // RoundingNecessaryException
```
2015-07-04 22:40:13 +02:00
2015-07-05 00:24:47 +02:00
You can pass an optional [rounding mode ](http://brick.io/math/class-Brick.Math.RoundingMode.html ) to round the result, if necessary:
2015-06-12 11:55:44 +02:00
2015-07-13 13:35:54 +02:00
```php
echo BigInteger::of(1000)->dividedBy(3, RoundingMode::DOWN); // 333
echo BigInteger::of(1000)->dividedBy(3, RoundingMode::UP); // 334
```
2015-06-12 11:55:44 +02:00
2015-07-04 22:40:13 +02:00
If you're into quotients and remainders, there are methods for this, too:
2015-06-12 11:55:44 +02:00
2015-07-13 13:35:54 +02:00
```php
echo BigInteger::of(1000)->quotient(3); // 333
echo BigInteger::of(1000)->remainder(3); // 1
```
2015-06-12 11:55:44 +02:00
2015-07-04 22:40:13 +02:00
You can even get both at the same time:
2015-06-12 11:55:44 +02:00
2015-07-13 13:35:54 +02:00
```php
list ($quotient, $remainder) = BigInteger::of(1000)->quotientAndRemainder(3);
```
2015-06-12 11:55:44 +02:00
2015-07-13 13:35:54 +02:00
##### BigDecimal
2015-06-12 11:55:44 +02:00
2015-07-04 22:40:13 +02:00
Dividing a `BigDecimal` always requires a scale to be specified. If the exact result of the division does not fit in
2015-07-05 00:24:47 +02:00
the given scale, a [rounding mode ](http://brick.io/math/class-Brick.Math.RoundingMode.html ) must be provided.
2015-06-12 11:55:44 +02:00
2015-07-13 13:35:54 +02:00
```php
echo BigDecimal::of(1)->dividedBy('8', 3); // 0.125
echo BigDecimal::of(1)->dividedBy('8', 2); // RoundingNecessaryException
echo BigDecimal::of(1)->dividedBy('8', 2, RoundingMode::HALF_DOWN); // 0.12
echo BigDecimal::of(1)->dividedBy('8', 2, RoundingMode::HALF_UP); // 0.13
```
2014-08-31 15:46:00 +02:00
2015-07-04 22:40:13 +02:00
If you know that the division yields a finite number of decimals places, you can use `exactlyDividedBy()` , which will
automatically compute the required scale to fit the result, or throw an exception if the division yields an infinite
repeating decimal:
2015-07-13 13:35:54 +02:00
```php
echo BigDecimal::of(1)->exactlyDividedBy(256); // 0.00390625
echo BigDecimal::of(1)->exactlyDividedBy(11); // RoundingNecessaryException
```
2015-07-04 22:40:13 +02:00
2015-07-13 13:35:54 +02:00
##### BigRational
2014-08-31 15:46:00 +02:00
2015-07-04 22:40:13 +02:00
The result of the division of a `BigRational` can always be represented exactly:
2014-08-31 15:46:00 +02:00
2015-07-13 13:35:54 +02:00
```php
echo BigRational::of('123/456')->dividedBy('7'); // 123/3192
echo BigRational::of('123/456')->dividedBy('9/8'); // 984/4104
```
2014-09-01 22:51:47 +02:00
2015-07-13 13:35:54 +02:00
#### Serialization
2014-08-31 15:46:00 +02:00
2015-06-13 00:10:28 +02:00
`BigInteger` , `BigDecimal` and `BigRational` can be safely serialized on a machine and unserialized on another,
2015-06-12 12:59:24 +02:00
even if these machines do not share the same set of PHP extensions.
For example, serializing on a machine with GMP support and unserializing on a machine that does not have this extension
installed will still work as expected.