DefaultMathAdapter   A
last analyzed

Complexity

Total Complexity 31

Size/Duplication

Total Lines 316
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 93.24%

Importance

Changes 0
Metric Value
wmc 31
lcom 1
cbo 5
dl 0
loc 316
ccs 69
cts 74
cp 0.9324
rs 9.8
c 0
b 0
f 0

20 Methods

Rating   Name   Duplication   Size   Complexity  
A add() 0 4 1
A subtract() 0 4 1
A multiply() 0 4 1
A divide() 0 8 2
A compare() 0 10 1
A modulus() 0 4 1
A power() 0 4 1
A squareRoot() 0 4 1
A absolute() 0 4 1
A negate() 0 4 1
A factorial() 0 10 2
A gcd() 0 10 2
A root() 0 19 4
A nextPrime() 0 4 1
B isPrime() 0 25 6
A isPerfectSquare() 0 4 1
A gamma() 0 4 1
A logGamma() 0 4 1
A getDefaultDelegates() 0 9 1
A createNotRealNumberException() 0 4 1
1
<?php
2
3
namespace Tdn\PhpTypes\Math;
4
5
use Tdn\PhpTypes\Exception\InvalidNumberException;
6
use Tdn\PhpTypes\Math\Library\BcMath;
7
use Tdn\PhpTypes\Math\Library\Gmp;
8
use Tdn\PhpTypes\Math\Library\MathLibraryInterface;
9
use Tdn\PhpTypes\Math\Library\Spl;
10
11
/**
12
 * Class DefaultMathLibraryAdapter.
13
 */
14
class DefaultMathAdapter extends AbstractMathAdapter implements MathAdapterInterface
15
{
16
    /**
17
     * Add two arbitrary precision numbers.
18
     *
19
     * @param string $leftOperand
20
     * @param string $rightOperand
21
     * @param int    $precision
22
     *
23
     * @return string
24
     */
25 5
    public function add(string $leftOperand, string $rightOperand, int $precision = 0): string
26
    {
27 5
        return $this->getDelegateResult(__FUNCTION__, $leftOperand, $rightOperand, $precision);
28
    }
29
30
    /**
31
     * Subtract two arbitrary precision numbers.
32
     *
33
     * @param string $leftOperand
34
     * @param string $rightOperand
35
     * @param int    $precision
36
     *
37
     * @return string
38
     */
39 3
    public function subtract(string $leftOperand, string $rightOperand, int $precision = 0): string
40
    {
41 3
        return $this->getDelegateResult(__FUNCTION__, $leftOperand, $rightOperand, $precision);
42
    }
43
44
    /**
45
     * Multiply two arbitrary precision numbers.
46
     *
47
     * @param string $leftOperand
48
     * @param string $rightOperand
49
     * @param int    $precision
50
     *
51
     * @return string
52
     */
53 3
    public function multiply(string $leftOperand, string $rightOperand, int $precision = 0): string
54
    {
55 3
        return $this->getDelegateResult(__FUNCTION__, $leftOperand, $rightOperand, $precision);
56
    }
57
58
    /**
59
     * Divide two arbitrary precision numbers.
60
     *
61
     * @param string $leftOperand
62
     * @param string $rightOperand
63
     * @param int    $precision
64
     *
65
     * @return string
66
     *
67
     * @throws \DivisionByZeroError
68
     */
69 4
    public function divide(string $leftOperand, string $rightOperand, int $precision = 0): string
70
    {
71 4
        if ($rightOperand == '0') {
72 1
            throw new \DivisionByZeroError();
73
        }
74
75 3
        return $this->getDelegateResult(__FUNCTION__, $leftOperand, $rightOperand, $precision);
76
    }
77
78
    /**
79
     * Compare two arbitrary precision numbers.
80
     *
81
     * @param string $leftOperand
82
     * @param string $rightOperand
83
     * @param int    $precision
84
     *
85
     * @return string
86
     */
87 3
    public function compare(string $leftOperand, string $rightOperand, int $precision = 0): string
88
    {
89 3
        return $this->getDelegateResult(
90 3
            __FUNCTION__,
91 3
            $leftOperand,
92 3
            $rightOperand,
93 3
            $precision,
94 3
            MathInterface::TYPE_FLOAT
95
        );
96
    }
97
98
    /**
99
     * Get modulus of an arbitrary precision number.
100
     *
101
     * @param string $operand
102
     * @param string $modulus
103
     * @param int    $precision
104
     *
105
     * @return string
106
     */
107 3
    public function modulus(string $operand, string $modulus, int $precision = 0): string
108
    {
109 3
        return $this->getDelegateResult(__FUNCTION__, $operand, $modulus, $precision);
110
    }
111
112
    /**
113
     * Raise an arbitrary precision number to another.
114
     *
115
     * @param string $leftOperand
116
     * @param string $rightOperand
117
     * @param int    $precision
118
     *
119
     * @return string
120
     */
121 3
    public function power(string $leftOperand, string $rightOperand, int $precision = 0): string
122
    {
123 3
        return $this->getDelegateResult(__FUNCTION__, $leftOperand, $rightOperand, $precision);
124
    }
125
126
    /**
127
     * Get the square root of an arbitrary precision number.
128
     *
129
     * @param string $operand
130
     * @param int    $precision
131
     *
132
     * @return string
133
     */
134 3
    public function squareRoot(string $operand, int $precision = 0): string
135
    {
136 3
        return $this->getDelegateResult(__FUNCTION__, $operand, null, $precision);
137
    }
138
139
    /**
140
     * Returns absolute value of operand.
141
     *
142
     * @param string $operand
143
     *
144
     * @return string
145
     */
146 3
    public function absolute(string $operand): string
147
    {
148 3
        return $this->getDelegateResult(__FUNCTION__, $operand);
149
    }
150
151
    /**
152
     * Negates a number. Opposite of absolute/abs.
153
     *
154
     * @param string $operand
155
     *
156
     * @return string
157
     */
158 3
    public function negate(string $operand): string
159
    {
160 3
        return $this->getDelegateResult(__FUNCTION__, $operand);
161
    }
162
163
    /**
164
     * Returns the factorial of operand.
165
     *
166
     * @param string $operand
167
     *
168
     * @return string
169
     */
170 4
    public function factorial(string $operand): string
171
    {
172 4
        $type = $this->getOperationType($operand);
173
174 4
        if ($this->isRealNumber($type, $operand)) {
175 3
            return $this->getDelegateResult(__FUNCTION__, $operand);
176
        }
177
178 1
        throw $this->createNotRealNumberException();
179
    }
180
181
    /**
182
     * Greatest common divisor.
183
     *
184
     * @param string $leftOperand
185
     * @param string $rightOperand
186
     *
187
     * @return string
188
     */
189 4
    public function gcd(string $leftOperand, string $rightOperand): string
190
    {
191 4
        $type = $this->getOperationType($leftOperand, $rightOperand);
192
193 4
        if ($this->isRealNumber($type, $leftOperand, $rightOperand)) {
194 3
            return $this->getDelegateResult(__FUNCTION__, $leftOperand, $rightOperand);
195
        }
196
197 1
        throw $this->createNotRealNumberException();
198
    }
199
200
    /**
201
     * Calculates to the nth root.
202
     *
203
     * @param string $operand
204
     * @param int    $nth
205
     *
206
     * @return string
207
     */
208 4
    public function root(string $operand, int $nth): string
209
    {
210 4
        $type = $this->getOperationType($operand);
211 4
        $exception = null;
212
213 4
        if ($this->isRealNumber($type, $operand)) {
214 3
            foreach ($this->getDelegates($type) as $library) {
215
                try {
216 3
                    return $library->root($operand, $nth);
217 3
                } catch (\Throwable $e) {
218
                    // Save last exception and try next library.
219 3
                    $exception = new \RuntimeException($e->getMessage(), $e->getCode(), $e);
220 3
                    continue;
221
                }
222
            }
223
        }
224
225 1
        throw $exception ?? $this->createNotRealNumberException();
226
    }
227
228
    /**
229
     * Gets the next prime after operand.
230
     *
231
     * @param string $operand
232
     *
233
     * @return string
234
     */
235 3
    public function nextPrime(string $operand): string
236
    {
237 3
        return $this->getDelegateResult(__FUNCTION__, $operand);
238
    }
239
240
    /**
241
     * @param string $operand
242
     * @param int    $reps
243
     *
244
     * @return bool
245
     */
246 3
    public function isPrime(string $operand, int $reps = 10): bool
247
    {
248 3
        $type = $this->getOperationType($operand);
249 3
        $exception = null;
250
251 3
        if ($this->getPrecision($operand) > 0 || $operand == '1') {
252 2
            return false;
253
        }
254
255 3
        if ($operand == '2') {
256 1
            return true;
257
        }
258
259 3
        foreach ($this->getDelegates($type) as $library) {
260
            try {
261 3
                return $library->isPrime($operand, $reps);
262 3
            } catch (\Throwable $e) {
263
                // Save last exception and try next library.
264 3
                $exception = new \RuntimeException($e->getMessage(), $e->getCode(), $e);
265 3
                continue;
266
            }
267
        }
268
269
        throw $exception ?? $this->createNewUnknownErrorException();
270
    }
271
272
    /**
273
     * Checks if operand is perfect square.
274
     *
275
     * @param string $operand
276
     * @param int    $precision
277
     *
278
     * @return bool
279
     */
280 3
    public function isPerfectSquare(string $operand, int $precision = 0): bool
281
    {
282 3
        return $this->getDelegateResult(__FUNCTION__, $operand, null, $precision);
283
    }
284
285
    /**
286
     * The gamma function.
287
     *
288
     * @param string $operand
289
     *
290
     * @return string
291
     */
292
    public function gamma(string $operand): string
293
    {
294
        return $this->getDelegateResult(__FUNCTION__, $operand);
295
    }
296
297
    /**
298
     * The log-gamma function.
299
     *
300
     * @param string $operand
301
     *
302
     * @return string
303
     */
304
    public function logGamma(string $operand): string
305
    {
306
        return $this->getDelegateResult(__FUNCTION__, $operand);
307
    }
308
309
    /**
310
     * @return MathLibraryInterface[]
311
     */
312 85
    protected function getDefaultDelegates(): array
313
    {
314
        //Array is sorted in order of preference. Override in child class if so desired.
315
        return [
316 85
            'bcmath' => new BcMath($this->getRoundingStrategy()),
317 85
            'gmp' => new Gmp(),
318 85
            'spl' => new Spl($this->getRoundingStrategy()),
319
        ];
320
    }
321
322
    /**
323
     * @return InvalidNumberException
324
     */
325 3
    private function createNotRealNumberException(): InvalidNumberException
326
    {
327 3
        return new InvalidNumberException('Arguments must be real numbers.');
328
    }
329
}
330