PluginProbe
Media Cloud Sync / 1.3.11
Media Cloud Sync v1.3.11
1.4.0 1.3.12 1.3.11 1.3.10 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.2.0 1.2.10 1.2.11 1.2.12 1.2.13 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 All 34 releases
media-cloud-sync / includes / sdk / google / brick / math / src / BigInteger.php

BigInteger.php in Media Cloud Sync 1.3.11, at includes/sdk/google/brick/math/src/BigInteger.php

880 lines 32.2 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 namespace Dudlewebs\WPMCS\GCP\Brick\Math;
5
6 use Dudlewebs\WPMCS\GCP\Brick\Math\Exception\DivisionByZeroException;
7 use Dudlewebs\WPMCS\GCP\Brick\Math\Exception\IntegerOverflowException;
8 use Dudlewebs\WPMCS\GCP\Brick\Math\Exception\MathException;
9 use Dudlewebs\WPMCS\GCP\Brick\Math\Exception\NegativeNumberException;
10 use Dudlewebs\WPMCS\GCP\Brick\Math\Exception\NumberFormatException;
11 use Dudlewebs\WPMCS\GCP\Brick\Math\Internal\Calculator;
12 use Dudlewebs\WPMCS\GCP\Override;
13 /**
14 * An arbitrary-size integer.
15 *
16 * All methods accepting a number as a parameter accept either a BigInteger instance,
17 * an integer, or a string representing an arbitrary size integer.
18 *
19 * @psalm-immutable
20 */
21 final class BigInteger extends BigNumber
22 {
23 /**
24 * The value, as a string of digits with optional leading minus sign.
25 *
26 * No leading zeros must be present.
27 * No leading minus sign must be present if the number is zero.
28 */
29 private readonly string $value;
30 /**
31 * Protected constructor. Use a factory method to obtain an instance.
32 *
33 * @param string $value A string of digits, with optional leading minus sign.
34 */
35 protected function __construct(string $value)
36 {
37 $this->value = $value;
38 }
39 /**
40 * @psalm-pure
41 */
42 #[\Override]
43 protected static function from(BigNumber $number) : static
44 {
45 return $number->toBigInteger();
46 }
47 /**
48 * Creates a number from a string in a given base.
49 *
50 * The string can optionally be prefixed with the `+` or `-` sign.
51 *
52 * Bases greater than 36 are not supported by this method, as there is no clear consensus on which of the lowercase
53 * or uppercase characters should come first. Instead, this method accepts any base up to 36, and does not
54 * differentiate lowercase and uppercase characters, which are considered equal.
55 *
56 * For bases greater than 36, and/or custom alphabets, use the fromArbitraryBase() method.
57 *
58 * @param string $number The number to convert, in the given base.
59 * @param int $base The base of the number, between 2 and 36.
60 *
61 * @throws NumberFormatException If the number is empty, or contains invalid chars for the given base.
62 * @throws \InvalidArgumentException If the base is out of range.
63 *
64 * @psalm-pure
65 */
66 public static function fromBase(string $number, int $base) : BigInteger
67 {
68 if ($number === '') {
69 throw new NumberFormatException('The number cannot be empty.');
70 }
71 if ($base < 2 || $base > 36) {
72 throw new \InvalidArgumentException(\sprintf('Base %d is not in range 2 to 36.', $base));
73 }
74 if ($number[0] === '-') {
75 $sign = '-';
76 $number = \substr($number, 1);
77 } elseif ($number[0] === '+') {
78 $sign = '';
79 $number = \substr($number, 1);
80 } else {
81 $sign = '';
82 }
83 if ($number === '') {
84 throw new NumberFormatException('The number cannot be empty.');
85 }
86 $number = \ltrim($number, '0');
87 if ($number === '') {
88 // The result will be the same in any base, avoid further calculation.
89 return BigInteger::zero();
90 }
91 if ($number === '1') {
92 // The result will be the same in any base, avoid further calculation.
93 return new BigInteger($sign . '1');
94 }
95 $pattern = '/[^' . \substr(Calculator::ALPHABET, 0, $base) . ']/';
96 if (\preg_match($pattern, \strtolower($number), $matches) === 1) {
97 throw new NumberFormatException(\sprintf('"%s" is not a valid character in base %d.', $matches[0], $base));
98 }
99 if ($base === 10) {
100 // The number is usable as is, avoid further calculation.
101 return new BigInteger($sign . $number);
102 }
103 $result = Calculator::get()->fromBase($number, $base);
104 return new BigInteger($sign . $result);
105 }
106 /**
107 * Parses a string containing an integer in an arbitrary base, using a custom alphabet.
108 *
109 * Because this method accepts an alphabet with any character, including dash, it does not handle negative numbers.
110 *
111 * @param string $number The number to parse.
112 * @param string $alphabet The alphabet, for example '01' for base 2, or '01234567' for base 8.
113 *
114 * @throws NumberFormatException If the given number is empty or contains invalid chars for the given alphabet.
115 * @throws \InvalidArgumentException If the alphabet does not contain at least 2 chars.
116 *
117 * @psalm-pure
118 */
119 public static function fromArbitraryBase(string $number, string $alphabet) : BigInteger
120 {
121 if ($number === '') {
122 throw new NumberFormatException('The number cannot be empty.');
123 }
124 $base = \strlen($alphabet);
125 if ($base < 2) {
126 throw new \InvalidArgumentException('The alphabet must contain at least 2 chars.');
127 }
128 $pattern = '/[^' . \preg_quote($alphabet, '/') . ']/';
129 if (\preg_match($pattern, $number, $matches) === 1) {
130 throw NumberFormatException::charNotInAlphabet($matches[0]);
131 }
132 $number = Calculator::get()->fromArbitraryBase($number, $alphabet, $base);
133 return new BigInteger($number);
134 }
135 /**
136 * Translates a string of bytes containing the binary representation of a BigInteger into a BigInteger.
137 *
138 * The input string is assumed to be in big-endian byte-order: the most significant byte is in the zeroth element.
139 *
140 * If `$signed` is true, the input is assumed to be in two's-complement representation, and the leading bit is
141 * interpreted as a sign bit. If `$signed` is false, the input is interpreted as an unsigned number, and the
142 * resulting BigInteger will always be positive or zero.
143 *
144 * This method can be used to retrieve a number exported by `toBytes()`, as long as the `$signed` flags match.
145 *
146 * @param string $value The byte string.
147 * @param bool $signed Whether to interpret as a signed number in two's-complement representation with a leading
148 * sign bit.
149 *
150 * @throws NumberFormatException If the string is empty.
151 */
152 public static function fromBytes(string $value, bool $signed = \true) : BigInteger
153 {
154 if ($value === '') {
155 throw new NumberFormatException('The byte string must not be empty.');
156 }
157 $twosComplement = \false;
158 if ($signed) {
159 $x = \ord($value[0]);
160 if ($twosComplement = $x >= 0x80) {
161 $value = ~$value;
162 }
163 }
164 $number = self::fromBase(\bin2hex($value), 16);
165 if ($twosComplement) {
166 return $number->plus(1)->negated();
167 }
168 return $number;
169 }
170 /**
171 * Generates a pseudo-random number in the range 0 to 2^numBits - 1.
172 *
173 * Using the default random bytes generator, this method is suitable for cryptographic use.
174 *
175 * @psalm-param (callable(int): string)|null $randomBytesGenerator
176 *
177 * @param int $numBits The number of bits.
178 * @param callable|null $randomBytesGenerator A function that accepts a number of bytes as an integer, and returns a
179 * string of random bytes of the given length. Defaults to the
180 * `random_bytes()` function.
181 *
182 * @throws \InvalidArgumentException If $numBits is negative.
183 */
184 public static function randomBits(int $numBits, ?callable $randomBytesGenerator = null) : BigInteger
185 {
186 if ($numBits < 0) {
187 throw new \InvalidArgumentException('The number of bits cannot be negative.');
188 }
189 if ($numBits === 0) {
190 return BigInteger::zero();
191 }
192 if ($randomBytesGenerator === null) {
193 $randomBytesGenerator = \random_bytes(...);
194 }
195 /** @var int<1, max> $byteLength */
196 $byteLength = \intdiv($numBits - 1, 8) + 1;
197 $extraBits = $byteLength * 8 - $numBits;
198 $bitmask = \chr(0xff >> $extraBits);
199 $randomBytes = $randomBytesGenerator($byteLength);
200 $randomBytes[0] = $randomBytes[0] & $bitmask;
201 return self::fromBytes($randomBytes, \false);
202 }
203 /**
204 * Generates a pseudo-random number between `$min` and `$max`.
205 *
206 * Using the default random bytes generator, this method is suitable for cryptographic use.
207 *
208 * @psalm-param (callable(int): string)|null $randomBytesGenerator
209 *
210 * @param BigNumber|int|float|string $min The lower bound. Must be convertible to a BigInteger.
211 * @param BigNumber|int|float|string $max The upper bound. Must be convertible to a BigInteger.
212 * @param callable|null $randomBytesGenerator A function that accepts a number of bytes as an integer,
213 * and returns a string of random bytes of the given length.
214 * Defaults to the `random_bytes()` function.
215 *
216 * @throws MathException If one of the parameters cannot be converted to a BigInteger,
217 * or `$min` is greater than `$max`.
218 */
219 public static function randomRange(BigNumber|int|float|string $min, BigNumber|int|float|string $max, ?callable $randomBytesGenerator = null) : BigInteger
220 {
221 $min = BigInteger::of($min);
222 $max = BigInteger::of($max);
223 if ($min->isGreaterThan($max)) {
224 throw new MathException('$min cannot be greater than $max.');
225 }
226 if ($min->isEqualTo($max)) {
227 return $min;
228 }
229 $diff = $max->minus($min);
230 $bitLength = $diff->getBitLength();
231 // try until the number is in range (50% to 100% chance of success)
232 do {
233 $randomNumber = self::randomBits($bitLength, $randomBytesGenerator);
234 } while ($randomNumber->isGreaterThan($diff));
235 return $randomNumber->plus($min);
236 }
237 /**
238 * Returns a BigInteger representing zero.
239 *
240 * @psalm-pure
241 */
242 public static function zero() : BigInteger
243 {
244 /**
245 * @psalm-suppress ImpureStaticVariable
246 * @var BigInteger|null $zero
247 */
248 static $zero;
249 if ($zero === null) {
250 $zero = new BigInteger('0');
251 }
252 return $zero;
253 }
254 /**
255 * Returns a BigInteger representing one.
256 *
257 * @psalm-pure
258 */
259 public static function one() : BigInteger
260 {
261 /**
262 * @psalm-suppress ImpureStaticVariable
263 * @var BigInteger|null $one
264 */
265 static $one;
266 if ($one === null) {
267 $one = new BigInteger('1');
268 }
269 return $one;
270 }
271 /**
272 * Returns a BigInteger representing ten.
273 *
274 * @psalm-pure
275 */
276 public static function ten() : BigInteger
277 {
278 /**
279 * @psalm-suppress ImpureStaticVariable
280 * @var BigInteger|null $ten
281 */
282 static $ten;
283 if ($ten === null) {
284 $ten = new BigInteger('10');
285 }
286 return $ten;
287 }
288 public static function gcdMultiple(BigInteger $a, BigInteger ...$n) : BigInteger
289 {
290 $result = $a;
291 foreach ($n as $next) {
292 $result = $result->gcd($next);
293 if ($result->isEqualTo(1)) {
294 return $result;
295 }
296 }
297 return $result;
298 }
299 /**
300 * Returns the sum of this number and the given one.
301 *
302 * @param BigNumber|int|float|string $that The number to add. Must be convertible to a BigInteger.
303 *
304 * @throws MathException If the number is not valid, or is not convertible to a BigInteger.
305 */
306 public function plus(BigNumber|int|float|string $that) : BigInteger
307 {
308 $that = BigInteger::of($that);
309 if ($that->value === '0') {
310 return $this;
311 }
312 if ($this->value === '0') {
313 return $that;
314 }
315 $value = Calculator::get()->add($this->value, $that->value);
316 return new BigInteger($value);
317 }
318 /**
319 * Returns the difference of this number and the given one.
320 *
321 * @param BigNumber|int|float|string $that The number to subtract. Must be convertible to a BigInteger.
322 *
323 * @throws MathException If the number is not valid, or is not convertible to a BigInteger.
324 */
325 public function minus(BigNumber|int|float|string $that) : BigInteger
326 {
327 $that = BigInteger::of($that);
328 if ($that->value === '0') {
329 return $this;
330 }
331 $value = Calculator::get()->sub($this->value, $that->value);
332 return new BigInteger($value);
333 }
334 /**
335 * Returns the product of this number and the given one.
336 *
337 * @param BigNumber|int|float|string $that The multiplier. Must be convertible to a BigInteger.
338 *
339 * @throws MathException If the multiplier is not a valid number, or is not convertible to a BigInteger.
340 */
341 public function multipliedBy(BigNumber|int|float|string $that) : BigInteger
342 {
343 $that = BigInteger::of($that);
344 if ($that->value === '1') {
345 return $this;
346 }
347 if ($this->value === '1') {
348 return $that;
349 }
350 $value = Calculator::get()->mul($this->value, $that->value);
351 return new BigInteger($value);
352 }
353 /**
354 * Returns the result of the division of this number by the given one.
355 *
356 * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger.
357 * @param RoundingMode $roundingMode An optional rounding mode, defaults to UNNECESSARY.
358 *
359 * @throws MathException If the divisor is not a valid number, is not convertible to a BigInteger, is zero,
360 * or RoundingMode::UNNECESSARY is used and the remainder is not zero.
361 */
362 public function dividedBy(BigNumber|int|float|string $that, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigInteger
363 {
364 $that = BigInteger::of($that);
365 if ($that->value === '1') {
366 return $this;
367 }
368 if ($that->value === '0') {
369 throw DivisionByZeroException::divisionByZero();
370 }
371 $result = Calculator::get()->divRound($this->value, $that->value, $roundingMode);
372 return new BigInteger($result);
373 }
374 /**
375 * Returns this number exponentiated to the given value.
376 *
377 * @throws \InvalidArgumentException If the exponent is not in the range 0 to 1,000,000.
378 */
379 public function power(int $exponent) : BigInteger
380 {
381 if ($exponent === 0) {
382 return BigInteger::one();
383 }
384 if ($exponent === 1) {
385 return $this;
386 }
387 if ($exponent < 0 || $exponent > Calculator::MAX_POWER) {
388 throw new \InvalidArgumentException(\sprintf('The exponent %d is not in the range 0 to %d.', $exponent, Calculator::MAX_POWER));
389 }
390 return new BigInteger(Calculator::get()->pow($this->value, $exponent));
391 }
392 /**
393 * Returns the quotient of the division of this number by the given one.
394 *
395 * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger.
396 *
397 * @throws DivisionByZeroException If the divisor is zero.
398 */
399 public function quotient(BigNumber|int|float|string $that) : BigInteger
400 {
401 $that = BigInteger::of($that);
402 if ($that->value === '1') {
403 return $this;
404 }
405 if ($that->value === '0') {
406 throw DivisionByZeroException::divisionByZero();
407 }
408 $quotient = Calculator::get()->divQ($this->value, $that->value);
409 return new BigInteger($quotient);
410 }
411 /**
412 * Returns the remainder of the division of this number by the given one.
413 *
414 * The remainder, when non-zero, has the same sign as the dividend.
415 *
416 * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger.
417 *
418 * @throws DivisionByZeroException If the divisor is zero.
419 */
420 public function remainder(BigNumber|int|float|string $that) : BigInteger
421 {
422 $that = BigInteger::of($that);
423 if ($that->value === '1') {
424 return BigInteger::zero();
425 }
426 if ($that->value === '0') {
427 throw DivisionByZeroException::divisionByZero();
428 }
429 $remainder = Calculator::get()->divR($this->value, $that->value);
430 return new BigInteger($remainder);
431 }
432 /**
433 * Returns the quotient and remainder of the division of this number by the given one.
434 *
435 * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger.
436 *
437 * @return BigInteger[] An array containing the quotient and the remainder.
438 *
439 * @psalm-return array{BigInteger, BigInteger}
440 *
441 * @throws DivisionByZeroException If the divisor is zero.
442 */
443 public function quotientAndRemainder(BigNumber|int|float|string $that) : array
444 {
445 $that = BigInteger::of($that);
446 if ($that->value === '0') {
447 throw DivisionByZeroException::divisionByZero();
448 }
449 [$quotient, $remainder] = Calculator::get()->divQR($this->value, $that->value);
450 return [new BigInteger($quotient), new BigInteger($remainder)];
451 }
452 /**
453 * Returns the modulo of this number and the given one.
454 *
455 * The modulo operation yields the same result as the remainder operation when both operands are of the same sign,
456 * and may differ when signs are different.
457 *
458 * The result of the modulo operation, when non-zero, has the same sign as the divisor.
459 *
460 * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger.
461 *
462 * @throws DivisionByZeroException If the divisor is zero.
463 */
464 public function mod(BigNumber|int|float|string $that) : BigInteger
465 {
466 $that = BigInteger::of($that);
467 if ($that->value === '0') {
468 throw DivisionByZeroException::modulusMustNotBeZero();
469 }
470 $value = Calculator::get()->mod($this->value, $that->value);
471 return new BigInteger($value);
472 }
473 /**
474 * Returns the modular multiplicative inverse of this BigInteger modulo $m.
475 *
476 * @throws DivisionByZeroException If $m is zero.
477 * @throws NegativeNumberException If $m is negative.
478 * @throws MathException If this BigInteger has no multiplicative inverse mod m (that is, this BigInteger
479 * is not relatively prime to m).
480 */
481 public function modInverse(BigInteger $m) : BigInteger
482 {
483 if ($m->value === '0') {
484 throw DivisionByZeroException::modulusMustNotBeZero();
485 }
486 if ($m->isNegative()) {
487 throw new NegativeNumberException('Modulus must not be negative.');
488 }
489 if ($m->value === '1') {
490 return BigInteger::zero();
491 }
492 $value = Calculator::get()->modInverse($this->value, $m->value);
493 if ($value === null) {
494 throw new MathException('Unable to compute the modInverse for the given modulus.');
495 }
496 return new BigInteger($value);
497 }
498 /**
499 * Returns this number raised into power with modulo.
500 *
501 * This operation only works on positive numbers.
502 *
503 * @param BigNumber|int|float|string $exp The exponent. Must be positive or zero.
504 * @param BigNumber|int|float|string $mod The modulus. Must be strictly positive.
505 *
506 * @throws NegativeNumberException If any of the operands is negative.
507 * @throws DivisionByZeroException If the modulus is zero.
508 */
509 public function modPow(BigNumber|int|float|string $exp, BigNumber|int|float|string $mod) : BigInteger
510 {
511 $exp = BigInteger::of($exp);
512 $mod = BigInteger::of($mod);
513 if ($this->isNegative() || $exp->isNegative() || $mod->isNegative()) {
514 throw new NegativeNumberException('The operands cannot be negative.');
515 }
516 if ($mod->isZero()) {
517 throw DivisionByZeroException::modulusMustNotBeZero();
518 }
519 $result = Calculator::get()->modPow($this->value, $exp->value, $mod->value);
520 return new BigInteger($result);
521 }
522 /**
523 * Returns the greatest common divisor of this number and the given one.
524 *
525 * The GCD is always positive, unless both operands are zero, in which case it is zero.
526 *
527 * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number.
528 */
529 public function gcd(BigNumber|int|float|string $that) : BigInteger
530 {
531 $that = BigInteger::of($that);
532 if ($that->value === '0' && $this->value[0] !== '-') {
533 return $this;
534 }
535 if ($this->value === '0' && $that->value[0] !== '-') {
536 return $that;
537 }
538 $value = Calculator::get()->gcd($this->value, $that->value);
539 return new BigInteger($value);
540 }
541 /**
542 * Returns the integer square root number of this number, rounded down.
543 *
544 * The result is the largest x such that x² ≤ n.
545 *
546 * @throws NegativeNumberException If this number is negative.
547 */
548 public function sqrt() : BigInteger
549 {
550 if ($this->value[0] === '-') {
551 throw new NegativeNumberException('Cannot calculate the square root of a negative number.');
552 }
553 $value = Calculator::get()->sqrt($this->value);
554 return new BigInteger($value);
555 }
556 /**
557 * Returns the absolute value of this number.
558 */
559 public function abs() : BigInteger
560 {
561 return $this->isNegative() ? $this->negated() : $this;
562 }
563 /**
564 * Returns the inverse of this number.
565 */
566 public function negated() : BigInteger
567 {
568 return new BigInteger(Calculator::get()->neg($this->value));
569 }
570 /**
571 * Returns the integer bitwise-and combined with another integer.
572 *
573 * This method returns a negative BigInteger if and only if both operands are negative.
574 *
575 * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number.
576 */
577 public function and(BigNumber|int|float|string $that) : BigInteger
578 {
579 $that = BigInteger::of($that);
580 return new BigInteger(Calculator::get()->and($this->value, $that->value));
581 }
582 /**
583 * Returns the integer bitwise-or combined with another integer.
584 *
585 * This method returns a negative BigInteger if and only if either of the operands is negative.
586 *
587 * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number.
588 */
589 public function or(BigNumber|int|float|string $that) : BigInteger
590 {
591 $that = BigInteger::of($that);
592 return new BigInteger(Calculator::get()->or($this->value, $that->value));
593 }
594 /**
595 * Returns the integer bitwise-xor combined with another integer.
596 *
597 * This method returns a negative BigInteger if and only if exactly one of the operands is negative.
598 *
599 * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number.
600 */
601 public function xor(BigNumber|int|float|string $that) : BigInteger
602 {
603 $that = BigInteger::of($that);
604 return new BigInteger(Calculator::get()->xor($this->value, $that->value));
605 }
606 /**
607 * Returns the bitwise-not of this BigInteger.
608 */
609 public function not() : BigInteger
610 {
611 return $this->negated()->minus(1);
612 }
613 /**
614 * Returns the integer left shifted by a given number of bits.
615 */
616 public function shiftedLeft(int $distance) : BigInteger
617 {
618 if ($distance === 0) {
619 return $this;
620 }
621 if ($distance < 0) {
622 return $this->shiftedRight(-$distance);
623 }
624 return $this->multipliedBy(BigInteger::of(2)->power($distance));
625 }
626 /**
627 * Returns the integer right shifted by a given number of bits.
628 */
629 public function shiftedRight(int $distance) : BigInteger
630 {
631 if ($distance === 0) {
632 return $this;
633 }
634 if ($distance < 0) {
635 return $this->shiftedLeft(-$distance);
636 }
637 $operand = BigInteger::of(2)->power($distance);
638 if ($this->isPositiveOrZero()) {
639 return $this->quotient($operand);
640 }
641 return $this->dividedBy($operand, RoundingMode::UP);
642 }
643 /**
644 * Returns the number of bits in the minimal two's-complement representation of this BigInteger, excluding a sign bit.
645 *
646 * For positive BigIntegers, this is equivalent to the number of bits in the ordinary binary representation.
647 * Computes (ceil(log2(this < 0 ? -this : this+1))).
648 */
649 public function getBitLength() : int
650 {
651 if ($this->value === '0') {
652 return 0;
653 }
654 if ($this->isNegative()) {
655 return $this->abs()->minus(1)->getBitLength();
656 }
657 return \strlen($this->toBase(2));
658 }
659 /**
660 * Returns the index of the rightmost (lowest-order) one bit in this BigInteger.
661 *
662 * Returns -1 if this BigInteger contains no one bits.
663 */
664 public function getLowestSetBit() : int
665 {
666 $n = $this;
667 $bitLength = $this->getBitLength();
668 for ($i = 0; $i <= $bitLength; $i++) {
669 if ($n->isOdd()) {
670 return $i;
671 }
672 $n = $n->shiftedRight(1);
673 }
674 return -1;
675 }
676 /**
677 * Returns whether this number is even.
678 */
679 public function isEven() : bool
680 {
681 return \in_array($this->value[-1], ['0', '2', '4', '6', '8'], \true);
682 }
683 /**
684 * Returns whether this number is odd.
685 */
686 public function isOdd() : bool
687 {
688 return \in_array($this->value[-1], ['1', '3', '5', '7', '9'], \true);
689 }
690 /**
691 * Returns true if and only if the designated bit is set.
692 *
693 * Computes ((this & (1<<n)) != 0).
694 *
695 * @param int $n The bit to test, 0-based.
696 *
697 * @throws \InvalidArgumentException If the bit to test is negative.
698 */
699 public function testBit(int $n) : bool
700 {
701 if ($n < 0) {
702 throw new \InvalidArgumentException('The bit to test cannot be negative.');
703 }
704 return $this->shiftedRight($n)->isOdd();
705 }
706 #[\Override]
707 public function compareTo(BigNumber|int|float|string $that) : int
708 {
709 $that = BigNumber::of($that);
710 if ($that instanceof BigInteger) {
711 return Calculator::get()->cmp($this->value, $that->value);
712 }
713 return -$that->compareTo($this);
714 }
715 #[\Override]
716 public function getSign() : int
717 {
718 return $this->value === '0' ? 0 : ($this->value[0] === '-' ? -1 : 1);
719 }
720 #[\Override]
721 public function toBigInteger() : BigInteger
722 {
723 return $this;
724 }
725 #[\Override]
726 public function toBigDecimal() : BigDecimal
727 {
728 return self::newBigDecimal($this->value);
729 }
730 #[\Override]
731 public function toBigRational() : BigRational
732 {
733 return self::newBigRational($this, BigInteger::one(), \false);
734 }
735 #[\Override]
736 public function toScale(int $scale, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
737 {
738 return $this->toBigDecimal()->toScale($scale, $roundingMode);
739 }
740 #[\Override]
741 public function toInt() : int
742 {
743 $intValue = (int) $this->value;
744 if ($this->value !== (string) $intValue) {
745 throw IntegerOverflowException::toIntOverflow($this);
746 }
747 return $intValue;
748 }
749 #[\Override]
750 public function toFloat() : float
751 {
752 return (float) $this->value;
753 }
754 /**
755 * Returns a string representation of this number in the given base.
756 *
757 * The output will always be lowercase for bases greater than 10.
758 *
759 * @throws \InvalidArgumentException If the base is out of range.
760 */
761 public function toBase(int $base) : string
762 {
763 if ($base === 10) {
764 return $this->value;
765 }
766 if ($base < 2 || $base > 36) {
767 throw new \InvalidArgumentException(\sprintf('Base %d is out of range [2, 36]', $base));
768 }
769 return Calculator::get()->toBase($this->value, $base);
770 }
771 /**
772 * Returns a string representation of this number in an arbitrary base with a custom alphabet.
773 *
774 * Because this method accepts an alphabet with any character, including dash, it does not handle negative numbers;
775 * a NegativeNumberException will be thrown when attempting to call this method on a negative number.
776 *
777 * @param string $alphabet The alphabet, for example '01' for base 2, or '01234567' for base 8.
778 *
779 * @throws NegativeNumberException If this number is negative.
780 * @throws \InvalidArgumentException If the given alphabet does not contain at least 2 chars.
781 */
782 public function toArbitraryBase(string $alphabet) : string
783 {
784 $base = \strlen($alphabet);
785 if ($base < 2) {
786 throw new \InvalidArgumentException('The alphabet must contain at least 2 chars.');
787 }
788 if ($this->value[0] === '-') {
789 throw new NegativeNumberException(__FUNCTION__ . '() does not support negative numbers.');
790 }
791 return Calculator::get()->toArbitraryBase($this->value, $alphabet, $base);
792 }
793 /**
794 * Returns a string of bytes containing the binary representation of this BigInteger.
795 *
796 * The string is in big-endian byte-order: the most significant byte is in the zeroth element.
797 *
798 * If `$signed` is true, the output will be in two's-complement representation, and a sign bit will be prepended to
799 * the output. If `$signed` is false, no sign bit will be prepended, and this method will throw an exception if the
800 * number is negative.
801 *
802 * The string will contain the minimum number of bytes required to represent this BigInteger, including a sign bit
803 * if `$signed` is true.
804 *
805 * This representation is compatible with the `fromBytes()` factory method, as long as the `$signed` flags match.
806 *
807 * @param bool $signed Whether to output a signed number in two's-complement representation with a leading sign bit.
808 *
809 * @throws NegativeNumberException If $signed is false, and the number is negative.
810 */
811 public function toBytes(bool $signed = \true) : string
812 {
813 if (!$signed && $this->isNegative()) {
814 throw new NegativeNumberException('Cannot convert a negative number to a byte string when $signed is false.');
815 }
816 $hex = $this->abs()->toBase(16);
817 if (\strlen($hex) % 2 !== 0) {
818 $hex = '0' . $hex;
819 }
820 $baseHexLength = \strlen($hex);
821 if ($signed) {
822 if ($this->isNegative()) {
823 $bin = \hex2bin($hex);
824 \assert($bin !== \false);
825 $hex = \bin2hex(~$bin);
826 $hex = self::fromBase($hex, 16)->plus(1)->toBase(16);
827 $hexLength = \strlen($hex);
828 if ($hexLength < $baseHexLength) {
829 $hex = \str_repeat('0', $baseHexLength - $hexLength) . $hex;
830 }
831 if ($hex[0] < '8') {
832 $hex = 'FF' . $hex;
833 }
834 } else {
835 if ($hex[0] >= '8') {
836 $hex = '00' . $hex;
837 }
838 }
839 }
840 return \hex2bin($hex);
841 }
842 /**
843 * @return numeric-string
844 */
845 #[\Override]
846 public function __toString() : string
847 {
848 /** @var numeric-string */
849 return $this->value;
850 }
851 /**
852 * This method is required for serializing the object and SHOULD NOT be accessed directly.
853 *
854 * @internal
855 *
856 * @return array{value: string}
857 */
858 public function __serialize() : array
859 {
860 return ['value' => $this->value];
861 }
862 /**
863 * This method is only here to allow unserializing the object and cannot be accessed directly.
864 *
865 * @internal
866 * @psalm-suppress RedundantPropertyInitializationCheck
867 *
868 * @param array{value: string} $data
869 *
870 * @throws \LogicException
871 */
872 public function __unserialize(array $data) : void
873 {
874 if (isset($this->value)) {
875 throw new \LogicException('__unserialize() is an internal function, it must not be called directly.');
876 }
877 $this->value = $data['value'];
878 }
879 }
880