PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 5.6.0
Defender Security – Malware Scanner, Login Security & Firewall v5.6.0
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
defender-security / vendor / brick / math / src / BigRational.php

BigRational.php in Defender Security – Malware Scanner, Login Security & Firewall 5.6.0, at vendor/brick/math/src/BigRational.php

524 lines 13.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare(strict_types=1);
4
5 namespace Brick\Math;
6
7 use Brick\Math\Exception\DivisionByZeroException;
8 use Brick\Math\Exception\MathException;
9 use Brick\Math\Exception\NumberFormatException;
10 use Brick\Math\Exception\RoundingNecessaryException;
11
12 /**
13 * An arbitrarily large rational number.
14 *
15 * This class is immutable.
16 *
17 * @psalm-immutable
18 */
19 final class BigRational extends BigNumber
20 {
21 /**
22 * The numerator.
23 *
24 * @var BigInteger
25 */
26 private $numerator;
27
28 /**
29 * The denominator. Always strictly positive.
30 *
31 * @var BigInteger
32 */
33 private $denominator;
34
35 /**
36 * Protected constructor. Use a factory method to obtain an instance.
37 *
38 * @param BigInteger $numerator The numerator.
39 * @param BigInteger $denominator The denominator.
40 * @param bool $checkDenominator Whether to check the denominator for negative and zero.
41 *
42 * @throws DivisionByZeroException If the denominator is zero.
43 */
44 protected function __construct(BigInteger $numerator, BigInteger $denominator, bool $checkDenominator)
45 {
46 if ($checkDenominator) {
47 if ($denominator->isZero()) {
48 throw DivisionByZeroException::denominatorMustNotBeZero();
49 }
50
51 if ($denominator->isNegative()) {
52 $numerator = $numerator->negated();
53 $denominator = $denominator->negated();
54 }
55 }
56
57 $this->numerator = $numerator;
58 $this->denominator = $denominator;
59 }
60
61 /**
62 * Creates a BigRational of the given value.
63 *
64 * @param BigNumber|int|float|string $value
65 *
66 * @return BigRational
67 *
68 * @throws MathException If the value cannot be converted to a BigRational.
69 *
70 * @psalm-pure
71 */
72 public static function of($value) : BigNumber
73 {
74 return parent::of($value)->toBigRational();
75 }
76
77 /**
78 * Creates a BigRational out of a numerator and a denominator.
79 *
80 * If the denominator is negative, the signs of both the numerator and the denominator
81 * will be inverted to ensure that the denominator is always positive.
82 *
83 * @param BigNumber|int|float|string $numerator The numerator. Must be convertible to a BigInteger.
84 * @param BigNumber|int|float|string $denominator The denominator. Must be convertible to a BigInteger.
85 *
86 * @return BigRational
87 *
88 * @throws NumberFormatException If an argument does not represent a valid number.
89 * @throws RoundingNecessaryException If an argument represents a non-integer number.
90 * @throws DivisionByZeroException If the denominator is zero.
91 *
92 * @psalm-pure
93 */
94 public static function nd($numerator, $denominator) : BigRational
95 {
96 $numerator = BigInteger::of($numerator);
97 $denominator = BigInteger::of($denominator);
98
99 return new BigRational($numerator, $denominator, true);
100 }
101
102 /**
103 * Returns a BigRational representing zero.
104 *
105 * @return BigRational
106 *
107 * @psalm-pure
108 */
109 public static function zero() : BigRational
110 {
111 /**
112 * @psalm-suppress ImpureStaticVariable
113 * @var BigRational|null $zero
114 */
115 static $zero;
116
117 if ($zero === null) {
118 $zero = new BigRational(BigInteger::zero(), BigInteger::one(), false);
119 }
120
121 return $zero;
122 }
123
124 /**
125 * Returns a BigRational representing one.
126 *
127 * @return BigRational
128 *
129 * @psalm-pure
130 */
131 public static function one() : BigRational
132 {
133 /**
134 * @psalm-suppress ImpureStaticVariable
135 * @var BigRational|null $one
136 */
137 static $one;
138
139 if ($one === null) {
140 $one = new BigRational(BigInteger::one(), BigInteger::one(), false);
141 }
142
143 return $one;
144 }
145
146 /**
147 * Returns a BigRational representing ten.
148 *
149 * @return BigRational
150 *
151 * @psalm-pure
152 */
153 public static function ten() : BigRational
154 {
155 /**
156 * @psalm-suppress ImpureStaticVariable
157 * @var BigRational|null $ten
158 */
159 static $ten;
160
161 if ($ten === null) {
162 $ten = new BigRational(BigInteger::ten(), BigInteger::one(), false);
163 }
164
165 return $ten;
166 }
167
168 /**
169 * @return BigInteger
170 */
171 public function getNumerator() : BigInteger
172 {
173 return $this->numerator;
174 }
175
176 /**
177 * @return BigInteger
178 */
179 public function getDenominator() : BigInteger
180 {
181 return $this->denominator;
182 }
183
184 /**
185 * Returns the quotient of the division of the numerator by the denominator.
186 *
187 * @return BigInteger
188 */
189 public function quotient() : BigInteger
190 {
191 return $this->numerator->quotient($this->denominator);
192 }
193
194 /**
195 * Returns the remainder of the division of the numerator by the denominator.
196 *
197 * @return BigInteger
198 */
199 public function remainder() : BigInteger
200 {
201 return $this->numerator->remainder($this->denominator);
202 }
203
204 /**
205 * Returns the quotient and remainder of the division of the numerator by the denominator.
206 *
207 * @return BigInteger[]
208 */
209 public function quotientAndRemainder() : array
210 {
211 return $this->numerator->quotientAndRemainder($this->denominator);
212 }
213
214 /**
215 * Returns the sum of this number and the given one.
216 *
217 * @param BigNumber|int|float|string $that The number to add.
218 *
219 * @return BigRational The result.
220 *
221 * @throws MathException If the number is not valid.
222 */
223 public function plus($that) : BigRational
224 {
225 $that = BigRational::of($that);
226
227 $numerator = $this->numerator->multipliedBy($that->denominator);
228 $numerator = $numerator->plus($that->numerator->multipliedBy($this->denominator));
229 $denominator = $this->denominator->multipliedBy($that->denominator);
230
231 return new BigRational($numerator, $denominator, false);
232 }
233
234 /**
235 * Returns the difference of this number and the given one.
236 *
237 * @param BigNumber|int|float|string $that The number to subtract.
238 *
239 * @return BigRational The result.
240 *
241 * @throws MathException If the number is not valid.
242 */
243 public function minus($that) : BigRational
244 {
245 $that = BigRational::of($that);
246
247 $numerator = $this->numerator->multipliedBy($that->denominator);
248 $numerator = $numerator->minus($that->numerator->multipliedBy($this->denominator));
249 $denominator = $this->denominator->multipliedBy($that->denominator);
250
251 return new BigRational($numerator, $denominator, false);
252 }
253
254 /**
255 * Returns the product of this number and the given one.
256 *
257 * @param BigNumber|int|float|string $that The multiplier.
258 *
259 * @return BigRational The result.
260 *
261 * @throws MathException If the multiplier is not a valid number.
262 */
263 public function multipliedBy($that) : BigRational
264 {
265 $that = BigRational::of($that);
266
267 $numerator = $this->numerator->multipliedBy($that->numerator);
268 $denominator = $this->denominator->multipliedBy($that->denominator);
269
270 return new BigRational($numerator, $denominator, false);
271 }
272
273 /**
274 * Returns the result of the division of this number by the given one.
275 *
276 * @param BigNumber|int|float|string $that The divisor.
277 *
278 * @return BigRational The result.
279 *
280 * @throws MathException If the divisor is not a valid number, or is zero.
281 */
282 public function dividedBy($that) : BigRational
283 {
284 $that = BigRational::of($that);
285
286 $numerator = $this->numerator->multipliedBy($that->denominator);
287 $denominator = $this->denominator->multipliedBy($that->numerator);
288
289 return new BigRational($numerator, $denominator, true);
290 }
291
292 /**
293 * Returns this number exponentiated to the given value.
294 *
295 * @param int $exponent The exponent.
296 *
297 * @return BigRational The result.
298 *
299 * @throws \InvalidArgumentException If the exponent is not in the range 0 to 1,000,000.
300 */
301 public function power(int $exponent) : BigRational
302 {
303 if ($exponent === 0) {
304 $one = BigInteger::one();
305
306 return new BigRational($one, $one, false);
307 }
308
309 if ($exponent === 1) {
310 return $this;
311 }
312
313 return new BigRational(
314 $this->numerator->power($exponent),
315 $this->denominator->power($exponent),
316 false
317 );
318 }
319
320 /**
321 * Returns the reciprocal of this BigRational.
322 *
323 * The reciprocal has the numerator and denominator swapped.
324 *
325 * @return BigRational
326 *
327 * @throws DivisionByZeroException If the numerator is zero.
328 */
329 public function reciprocal() : BigRational
330 {
331 return new BigRational($this->denominator, $this->numerator, true);
332 }
333
334 /**
335 * Returns the absolute value of this BigRational.
336 *
337 * @return BigRational
338 */
339 public function abs() : BigRational
340 {
341 return new BigRational($this->numerator->abs(), $this->denominator, false);
342 }
343
344 /**
345 * Returns the negated value of this BigRational.
346 *
347 * @return BigRational
348 */
349 public function negated() : BigRational
350 {
351 return new BigRational($this->numerator->negated(), $this->denominator, false);
352 }
353
354 /**
355 * Returns the simplified value of this BigRational.
356 *
357 * @return BigRational
358 */
359 public function simplified() : BigRational
360 {
361 $gcd = $this->numerator->gcd($this->denominator);
362
363 $numerator = $this->numerator->quotient($gcd);
364 $denominator = $this->denominator->quotient($gcd);
365
366 return new BigRational($numerator, $denominator, false);
367 }
368
369 /**
370 * {@inheritdoc}
371 */
372 public function compareTo($that) : int
373 {
374 return $this->minus($that)->getSign();
375 }
376
377 /**
378 * {@inheritdoc}
379 */
380 public function getSign() : int
381 {
382 return $this->numerator->getSign();
383 }
384
385 /**
386 * {@inheritdoc}
387 */
388 public function toBigInteger() : BigInteger
389 {
390 $simplified = $this->simplified();
391
392 if (! $simplified->denominator->isEqualTo(1)) {
393 throw new RoundingNecessaryException('This rational number cannot be represented as an integer value without rounding.');
394 }
395
396 return $simplified->numerator;
397 }
398
399 /**
400 * {@inheritdoc}
401 */
402 public function toBigDecimal() : BigDecimal
403 {
404 return $this->numerator->toBigDecimal()->exactlyDividedBy($this->denominator);
405 }
406
407 /**
408 * {@inheritdoc}
409 */
410 public function toBigRational() : BigRational
411 {
412 return $this;
413 }
414
415 /**
416 * {@inheritdoc}
417 */
418 public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
419 {
420 return $this->numerator->toBigDecimal()->dividedBy($this->denominator, $scale, $roundingMode);
421 }
422
423 /**
424 * {@inheritdoc}
425 */
426 public function toInt() : int
427 {
428 return $this->toBigInteger()->toInt();
429 }
430
431 /**
432 * {@inheritdoc}
433 */
434 public function toFloat() : float
435 {
436 return $this->numerator->toFloat() / $this->denominator->toFloat();
437 }
438
439 /**
440 * {@inheritdoc}
441 */
442 public function __toString() : string
443 {
444 $numerator = (string) $this->numerator;
445 $denominator = (string) $this->denominator;
446
447 if ($denominator === '1') {
448 return $numerator;
449 }
450
451 return $this->numerator . '/' . $this->denominator;
452 }
453
454 /**
455 * This method is required for serializing the object and SHOULD NOT be accessed directly.
456 *
457 * @internal
458 *
459 * @return array{numerator: BigInteger, denominator: BigInteger}
460 */
461 public function __serialize(): array
462 {
463 return ['numerator' => $this->numerator, 'denominator' => $this->denominator];
464 }
465
466 /**
467 * This method is only here to allow unserializing the object and cannot be accessed directly.
468 *
469 * @internal
470 * @psalm-suppress RedundantPropertyInitializationCheck
471 *
472 * @param array{numerator: BigInteger, denominator: BigInteger} $data
473 *
474 * @return void
475 *
476 * @throws \LogicException
477 */
478 public function __unserialize(array $data): void
479 {
480 if (isset($this->numerator)) {
481 throw new \LogicException('__unserialize() is an internal function, it must not be called directly.');
482 }
483
484 $this->numerator = $data['numerator'];
485 $this->denominator = $data['denominator'];
486 }
487
488 /**
489 * This method is required by interface Serializable and SHOULD NOT be accessed directly.
490 *
491 * @internal
492 *
493 * @return string
494 */
495 public function serialize() : string
496 {
497 return $this->numerator . '/' . $this->denominator;
498 }
499
500 /**
501 * This method is only here to implement interface Serializable and cannot be accessed directly.
502 *
503 * @internal
504 * @psalm-suppress RedundantPropertyInitializationCheck
505 *
506 * @param string $value
507 *
508 * @return void
509 *
510 * @throws \LogicException
511 */
512 public function unserialize($value) : void
513 {
514 if (isset($this->numerator)) {
515 throw new \LogicException('unserialize() is an internal function, it must not be called directly.');
516 }
517
518 [$numerator, $denominator] = \explode('/', $value);
519
520 $this->numerator = BigInteger::of($numerator);
521 $this->denominator = BigInteger::of($denominator);
522 }
523 }
524