Working With NumberInterface
Arithmetic can be performed on any class that implements the NumberInterface
, and the rules for using arithmetic methods are consistent and straight-forward: you can put any value that is valid for an ImmutableNumber
constructor in, or you can put in any instance of an object that implements NumberInterface
itself.
You Might Not Expect
If two objects which have different calculation modes are used in an arithmetic operation, the calculation mode of the object which makes the function call is used, and the calculation mode of the object supplied as an argument is ignored.
Additionally, the object returned will be of the same class as the object making the function call if that is possible. This means that fractions will be converted to decimals when they are the argument for a decimal function call, or visa versa.
If the result must be represented in a particular way, such as with complex numbers, the returned value will be the immutable version of the class that can respresent the result. This means adding two classes that implement DecimalInterface
can return a class that implements ComplexNumberInterface
if one is an imaginary number, and one is a real number.
The following arithmetic methods are available.
add(int|float|numeric|NumberInterface $num): self
This adds the argument to the Value using the ArithmeticProvider
or the native +
operator depending on the calculation mode of the original object.
When an object that implements DecimalInterface
and another that implements FractionInterface
are added together, the one that is provided as an argument is coerced into the type of original object. The result is returned as an instance of a value object, depending on the result of the calculation.
subtract(int|float|numeric|NumberInterface $num): self
This subtracts the argument from the Value using the ArithmeticProvider
(which uses the BCMath library internally) and returns the newly calculated Value.
When an object that implements DecimalInterface
and another that implements FractionInterface
are subtracted, the one that is provided as an argument is coerced into the type of original object. For example:
1 <?php
2
3 use Samsara\Fermat\Values\ImmutableNumber;
4 use Samsara\Fermat\Values\ImmutableFraction;
5
6 $five = new ImmutableNumber(5);
7 $oneQuarter = new ImmutableFraction(1, 4);
8
9 echo $five->subtract($oneQuarter); // Prints: "4.75"
10 // The asDecimal() method is called on $oneQuarter
11
12 echo $oneQuarter->subtract($five); // Prints: "-19/4"
13 // Calls getValue() on $five and instantiates a new ImmutableFraction
multiply(int|float|numeric|NumberInterface $num): self
This multiplies the argument from the Value using the ArithmeticProvider
(which uses the BCMath library internally) and returns the newly calculated Value.
When an object that implements DecimalInterface
and another that implements FractionInterface
are multiplied, the one that is provided as an argument is coerced into the type of original object. For example:
1 <?php
2
3 use Samsara\Fermat\Values\ImmutableNumber;
4 use Samsara\Fermat\Values\ImmutableFraction;
5
6 $five = new ImmutableNumber(5);
7 $oneQuarter = new ImmutableFraction(1, 4);
8
9 echo $five->multiply($oneQuarter); // Prints: "1.25"
10 // The asDecimal() method is called on $oneQuarter
11
12 echo $oneQuarter->multiply($five); // Prints: "5/4"
13 // Calls getValue() on $five and instantiates a new ImmutableFraction
divide(int|float|numeric|NumberInterface $num, int $scale = null): self
This divides the argument from the Value using the ArithmeticProvider
(which uses the BCMath library internally) and returns the newly calculated Value.
The $scale argument tells the Value how many decimals of accuracy you want in your division (if that is relevant to the division), and defaults to the scale of the calling object if null. The default scale of a Value, if you do not set it during instantiation, is 10.
When an object that implements DecimalInterface
and another that implements FractionInterface
are divided, the one that is provided as an argument is coerced into the type of original object. For example:
1 <?php
2
3 use Samsara\Fermat\Values\ImmutableNumber;
4 use Samsara\Fermat\Values\ImmutableFraction;
5
6 $five = new ImmutableNumber(5);
7 $oneQuarter = new ImmutableFraction(1, 4);
8
9 echo $five->divide($oneQuarter); // Prints: "20"
10 // The asDecimal() method is called on $oneQuarter
11
12 echo $oneQuarter->divide($five); // Prints: "1/20"
13 // Calls getValue() on $five and instantiates a new ImmutableFraction
pow(int|float|numeric|NumberInterface $num): self
This raises the Value to the power of $num, and will work even if $num has a decimal component. NOTE: This method will only return Real numbers as Values, as Complex numbers are not currently supported.
When an object that implements DecimalInterface
and another that implements FractionInterface
are raised to a power, the one that is provided as an argument is coerced into the type of original object. For example:
1 <?php
2
3 use Samsara\Fermat\Values\ImmutableNumber;
4 use Samsara\Fermat\Values\ImmutableFraction;
5
6 $five = new ImmutableNumber(5);
7 $oneQuarter = new ImmutableFraction(1, 4);
8
9 echo $five->pow($oneQuarter); // Prints: "1.4953487812"
10 // The asDecimal() method is called on $oneQuarter
11 // Because $scale was not supplied to the constructor, $scale is 10
12
13 echo $oneQuarter->pow($five); // Prints: "1/1024"
14 // Calls getValue() on $five and instantiates a new ImmutableFraction
sqrt(): self
This takes the square root of the current object.
1 <?php
2
3 use Samsara\Fermat\Values\ImmutableNumber;
4 use Samsara\Fermat\Values\ImmutableFraction;
5
6 $five = new ImmutableNumber(5);
7 $oneQuarter = new ImmutableFraction(1, 4);
8
9 echo $five->sqrt(); // Prints: "2.2360679775"
10 // Because $scale was not supplied to the constructor, $scale is 10
11
12 echo $oneQuarter->sqrt(); // Prints: "1/2"
Working with DecimalInterface
Additional arithmetic can be performed on objects that implement the DecimalInterface
, and the rules for using arithmetic methods are the same as with NumberInterface
methods: you can put any value that is valid for an ImmutableNumber
constructor in, or you can put in any instance of an object that implements DecimalInterface
itself.
factorial(): self
This takes the factorial of the current Value, however the Value must be a whole number.
1 <?php
2
3 use Samsara\Fermat\Values\ImmutableNumber;
4
5 $five = new ImmutableNumber(5);
6
7 echo $five->factorial(); // Prints: "120"
doubleFactorial(): self, semiFactorial(): self
This takes the double factorial (x!!) of the current Value. Note: If you are not familiar with this operation, it is NOT the same as taking the factorial twice: (x!)!. Instead it is like taking a factorial where you decrease the number by two instead of one:
10! = 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1
10!! = 10 * 8 * 6 * 4 * 2
1 <?php
2
3 use Samsara\Fermat\Values\ImmutableNumber;
4
5 $five = new ImmutableNumber(5);
6
7 echo $five->doubleFactorial(); // Prints: "15"
ln(int $scale = 10, $round = true): self
This takes the natural log of the current Value, accurate to $scale decimal places.
If the $round argument is true
the last digit will be rounded; if the $round argument is false
the last digit will be truncated. It is important to note that the last digit (prior to rounding) is guaranteed to be accurate, so rounding will actually reduce the scale, in effect, by one. However, it will capture some of the behavior after the scale limit.
1 <?php
2
3 use Samsara\Fermat\Values\ImmutableNumber;
4
5 $five = new ImmutableNumber(5);
6
7 echo $five->ln(11); // Prints: "1.60943791243"
log10(int $scale = 10, $round = true): self
This takes the log base10 of the current Value, accurate to $scale decimal places.
If the $round argument is true
the last digit will be rounded; if the $round argument is false
the last digit will be truncated. It is important to note that the last digit (prior to rounding) is guaranteed to be accurate, so rounding will actually reduce the scale, in effect, by one. However, it will capture some of the behavior after the scale limit.
1 <?php
2
3 use Samsara\Fermat\Values\ImmutableNumber;
4
5 $five = new ImmutableNumber(5);
6
7 echo $five->log10(11); // Prints: "0.69897000434"
Working With ArithmeticProvider
Directly
The ArithmeticProvider
is a wrapper for the BCMath library, and it is ultimately what performs most operations inside the objects that implement NumberInterface
, DecimalInterface
, FractionInterface
, and CoordinateInterface
.
All of its methods are static, and can be accessed without instantiating the class.
All arguments to this provider must be strings which only contain numeric values.
add(string $number1, string $number2): string
Calls bcadd($number1, $number2)
with a scale setting of 100.
subtract(string $left, string $right): string
Calls bcsub($left, $right)
with a scale setting of 100.
multiply(string $number1, string $number2): string
Calls bcmul($number1, $number2)
with a scale setting of 100.
divide(string $numerator, string $denominator, int $scale = 100): string
Calls bcdiv($numerator, $denominator, $scale)
.
pow(string $base, string $exponent): string
Calls bcpow($base, $exponent)
with a scale of 100. Note: Unlike the pow()
method on NumberInterface
objects, the exponent must be a whole number.
squareRoot(string $number, int $scale = 100): string
Calls bcsqrt($number, $scale)
.
modulo(string $number, string $modulo): string
Calls bcmod($number, $modulo)
. Note: Unlike the continuousModulo()
method on DecimalInterface
objects, the modulus must be a whole number.
compare(string $left, string $right, int $scale = 100): int
Calls bccomp($left, $right, $scale)
. Its output format is identical to the compare()
helper method on NumberInterface
objects.
powmod(string left, string $right, string $modulus, int $scale = 100): string
Calls bcpowmod($left, $right, $modulus, $scale)
.
factorial(string $number): string
Calls bcmul()
repeatedly to return the factorial. Note: The factorial()
method on DecimalInterface
objects does not use this method, and instead uses gmp_fact()
if the method is available, and makes repeated calls to multiply()
if it is not.