• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

brick / math / 17160643849

22 Aug 2025 04:15PM UTC coverage: 99.74% (+0.001%) from 99.739%
17160643849

push

github

BenMorel
Seal BigNumber

1151 of 1154 relevant lines covered (99.74%)

1142.49 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.26
/src/BigInteger.php
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\IntegerOverflowException;
9
use Brick\Math\Exception\MathException;
10
use Brick\Math\Exception\NegativeNumberException;
11
use Brick\Math\Exception\NumberFormatException;
12
use Brick\Math\Internal\Calculator;
13
use Brick\Math\Internal\CalculatorRegistry;
14
use Override;
15

16
/**
17
 * An arbitrary-size integer.
18
 *
19
 * All methods accepting a number as a parameter accept either a BigInteger instance,
20
 * an integer, or a string representing an arbitrary size integer.
21
 */
22
final readonly class BigInteger extends BigNumber
23
{
24
    /**
25
     * The value, as a string of digits with optional leading minus sign.
26
     *
27
     * No leading zeros must be present.
28
     * No leading minus sign must be present if the number is zero.
29
     */
30
    private string $value;
31

32
    /**
33
     * Protected constructor. Use a factory method to obtain an instance.
34
     *
35
     * @param string $value A string of digits, with optional leading minus sign.
36
     *
37
     * @pure
38
     */
39
    protected function __construct(string $value)
40
    {
41
        $this->value = $value;
18,833✔
42
    }
43

44
    #[Override]
45
    protected static function from(BigNumber $number): static
46
    {
47
        return $number->toBigInteger();
13,154✔
48
    }
49

50
    /**
51
     * Creates a number from a string in a given base.
52
     *
53
     * The string can optionally be prefixed with the `+` or `-` sign.
54
     *
55
     * Bases greater than 36 are not supported by this method, as there is no clear consensus on which of the lowercase
56
     * or uppercase characters should come first. Instead, this method accepts any base up to 36, and does not
57
     * differentiate lowercase and uppercase characters, which are considered equal.
58
     *
59
     * For bases greater than 36, and/or custom alphabets, use the fromArbitraryBase() method.
60
     *
61
     * @param string $number The number to convert, in the given base.
62
     * @param int    $base   The base of the number, between 2 and 36.
63
     *
64
     * @throws NumberFormatException     If the number is empty, or contains invalid chars for the given base.
65
     * @throws \InvalidArgumentException If the base is out of range.
66
     *
67
     * @pure
68
     */
69
    public static function fromBase(string $number, int $base) : BigInteger
70
    {
71
        if ($number === '') {
2,093✔
72
            throw new NumberFormatException('The number cannot be empty.');
3✔
73
        }
74

75
        if ($base < 2 || $base > 36) {
2,090✔
76
            throw new \InvalidArgumentException(\sprintf('Base %d is not in range 2 to 36.', $base));
15✔
77
        }
78

79
        if ($number[0] === '-') {
2,075✔
80
            $sign = '-';
27✔
81
            $number = \substr($number, 1);
27✔
82
        } elseif ($number[0] === '+') {
2,048✔
83
            $sign = '';
27✔
84
            $number = \substr($number, 1);
27✔
85
        } else {
86
            $sign = '';
2,021✔
87
        }
88

89
        if ($number === '') {
2,075✔
90
            throw new NumberFormatException('The number cannot be empty.');
6✔
91
        }
92

93
        $number = \ltrim($number, '0');
2,069✔
94

95
        if ($number === '') {
2,069✔
96
            // The result will be the same in any base, avoid further calculation.
97
            return BigInteger::zero();
84✔
98
        }
99

100
        if ($number === '1') {
1,988✔
101
            // The result will be the same in any base, avoid further calculation.
102
            return new BigInteger($sign . '1');
75✔
103
        }
104

105
        $pattern = '/[^' . \substr(Calculator::ALPHABET, 0, $base) . ']/';
1,916✔
106

107
        if (\preg_match($pattern, \strtolower($number), $matches) === 1) {
1,916✔
108
            throw new NumberFormatException(\sprintf('"%s" is not a valid character in base %d.', $matches[0], $base));
111✔
109
        }
110

111
        if ($base === 10) {
1,805✔
112
            // The number is usable as is, avoid further calculation.
113
            return new BigInteger($sign . $number);
24✔
114
        }
115

116
        $result = CalculatorRegistry::get()->fromBase($number, $base);
1,781✔
117

118
        return new BigInteger($sign . $result);
1,781✔
119
    }
120

121
    /**
122
     * Parses a string containing an integer in an arbitrary base, using a custom alphabet.
123
     *
124
     * Because this method accepts an alphabet with any character, including dash, it does not handle negative numbers.
125
     *
126
     * @param string $number   The number to parse.
127
     * @param string $alphabet The alphabet, for example '01' for base 2, or '01234567' for base 8.
128
     *
129
     * @throws NumberFormatException     If the given number is empty or contains invalid chars for the given alphabet.
130
     * @throws \InvalidArgumentException If the alphabet does not contain at least 2 chars.
131
     *
132
     * @pure
133
     */
134
    public static function fromArbitraryBase(string $number, string $alphabet) : BigInteger
135
    {
136
        if ($number === '') {
411✔
137
            throw new NumberFormatException('The number cannot be empty.');
3✔
138
        }
139

140
        $base = \strlen($alphabet);
408✔
141

142
        if ($base < 2) {
408✔
143
            throw new \InvalidArgumentException('The alphabet must contain at least 2 chars.');
6✔
144
        }
145

146
        $pattern = '/[^' . \preg_quote($alphabet, '/') . ']/';
402✔
147

148
        if (\preg_match($pattern, $number, $matches) === 1) {
402✔
149
            throw NumberFormatException::charNotInAlphabet($matches[0]);
24✔
150
        }
151

152
        $number = CalculatorRegistry::get()->fromArbitraryBase($number, $alphabet, $base);
378✔
153

154
        return new BigInteger($number);
378✔
155
    }
156

157
    /**
158
     * Translates a string of bytes containing the binary representation of a BigInteger into a BigInteger.
159
     *
160
     * The input string is assumed to be in big-endian byte-order: the most significant byte is in the zeroth element.
161
     *
162
     * If `$signed` is true, the input is assumed to be in two's-complement representation, and the leading bit is
163
     * interpreted as a sign bit. If `$signed` is false, the input is interpreted as an unsigned number, and the
164
     * resulting BigInteger will always be positive or zero.
165
     *
166
     * This method can be used to retrieve a number exported by `toBytes()`, as long as the `$signed` flags match.
167
     *
168
     * @param string $value  The byte string.
169
     * @param bool   $signed Whether to interpret as a signed number in two's-complement representation with a leading
170
     *                       sign bit.
171
     *
172
     * @throws NumberFormatException If the string is empty.
173
     *
174
     * @pure
175
     */
176
    public static function fromBytes(string $value, bool $signed = true) : BigInteger
177
    {
178
        if ($value === '') {
1,224✔
179
            throw new NumberFormatException('The byte string must not be empty.');
3✔
180
        }
181

182
        $twosComplement = false;
1,221✔
183

184
        if ($signed) {
1,221✔
185
            $x = \ord($value[0]);
984✔
186

187
            if (($twosComplement = ($x >= 0x80))) {
984✔
188
                $value = ~$value;
906✔
189
            }
190
        }
191

192
        $number = self::fromBase(\bin2hex($value), 16);
1,221✔
193

194
        if ($twosComplement) {
1,221✔
195
            return $number->plus(1)->negated();
906✔
196
        }
197

198
        return $number;
315✔
199
    }
200

201
    /**
202
     * Generates a pseudo-random number in the range 0 to 2^numBits - 1.
203
     *
204
     * Using the default random bytes generator, this method is suitable for cryptographic use.
205
     *
206
     * @param int                          $numBits              The number of bits.
207
     * @param (callable(int): string)|null $randomBytesGenerator A function that accepts a number of bytes, and returns
208
     *                                                           a string of random bytes of the given length. Defaults
209
     *                                                           to the `random_bytes()` function.
210
     *
211
     * @throws \InvalidArgumentException If $numBits is negative.
212
     */
213
    public static function randomBits(int $numBits, ?callable $randomBytesGenerator = null) : BigInteger
214
    {
215
        if ($numBits < 0) {
165✔
216
            throw new \InvalidArgumentException('The number of bits cannot be negative.');
3✔
217
        }
218

219
        if ($numBits === 0) {
162✔
220
            return BigInteger::zero();
3✔
221
        }
222

223
        if ($randomBytesGenerator === null) {
159✔
224
            $randomBytesGenerator = random_bytes(...);
×
225
        }
226

227
        /** @var int<1, max> $byteLength */
228
        $byteLength = \intdiv($numBits - 1, 8) + 1;
159✔
229

230
        $extraBits = ($byteLength * 8 - $numBits);
159✔
231
        $bitmask   = \chr(0xFF >> $extraBits);
159✔
232

233
        $randomBytes    = $randomBytesGenerator($byteLength);
159✔
234
        $randomBytes[0] = $randomBytes[0] & $bitmask;
159✔
235

236
        return self::fromBytes($randomBytes, false);
159✔
237
    }
238

239
    /**
240
     * Generates a pseudo-random number between `$min` and `$max`.
241
     *
242
     * Using the default random bytes generator, this method is suitable for cryptographic use.
243
     *
244
     * @param BigNumber|int|float|string   $min                  The lower bound. Must be convertible to a BigInteger.
245
     * @param BigNumber|int|float|string   $max                  The upper bound. Must be convertible to a BigInteger.
246
     * @param (callable(int): string)|null $randomBytesGenerator A function that accepts a number of bytes, and returns
247
     *                                                           a string of random bytes of the given length. Defaults
248
     *                                                           to the `random_bytes()` function.
249
     *
250
     * @throws MathException If one of the parameters cannot be converted to a BigInteger,
251
     *                       or `$min` is greater than `$max`.
252
     */
253
    public static function randomRange(
254
        BigNumber|int|float|string $min,
255
        BigNumber|int|float|string $max,
256
        ?callable $randomBytesGenerator = null
257
    ) : BigInteger {
258
        $min = BigInteger::of($min);
84✔
259
        $max = BigInteger::of($max);
84✔
260

261
        if ($min->isGreaterThan($max)) {
84✔
262
            throw new MathException('$min cannot be greater than $max.');
3✔
263
        }
264

265
        if ($min->isEqualTo($max)) {
81✔
266
            return $min;
3✔
267
        }
268

269
        $diff      = $max->minus($min);
78✔
270
        $bitLength = $diff->getBitLength();
78✔
271

272
        // try until the number is in range (50% to 100% chance of success)
273
        do {
274
            $randomNumber = self::randomBits($bitLength, $randomBytesGenerator);
78✔
275
        } while ($randomNumber->isGreaterThan($diff));
78✔
276

277
        return $randomNumber->plus($min);
78✔
278
    }
279

280
    /**
281
     * Returns a BigInteger representing zero.
282
     *
283
     * @pure
284
     */
285
    public static function zero() : BigInteger
286
    {
287
        /** @var BigInteger|null $zero */
288
        static $zero;
111✔
289

290
        if ($zero === null) {
111✔
291
            $zero = new BigInteger('0');
×
292
        }
293

294
        return $zero;
111✔
295
    }
296

297
    /**
298
     * Returns a BigInteger representing one.
299
     *
300
     * @pure
301
     */
302
    public static function one() : BigInteger
303
    {
304
        /** @var BigInteger|null $one */
305
        static $one;
444✔
306

307
        if ($one === null) {
444✔
308
            $one = new BigInteger('1');
3✔
309
        }
310

311
        return $one;
444✔
312
    }
313

314
    /**
315
     * Returns a BigInteger representing ten.
316
     *
317
     * @pure
318
     */
319
    public static function ten() : BigInteger
320
    {
321
        /** @var BigInteger|null $ten */
322
        static $ten;
6✔
323

324
        if ($ten === null) {
6✔
325
            $ten = new BigInteger('10');
3✔
326
        }
327

328
        return $ten;
6✔
329
    }
330

331
    /**
332
     * @pure
333
     */
334
    public static function gcdMultiple(BigInteger $a, BigInteger ...$n): BigInteger
335
    {
336
        $result = $a;
1,563✔
337

338
        foreach ($n as $next) {
1,563✔
339
            $result = $result->gcd($next);
1,548✔
340

341
            if ($result->isEqualTo(1)) {
1,548✔
342
                return $result;
345✔
343
            }
344
        }
345

346
        return $result;
1,218✔
347
    }
348

349
    /**
350
     * Returns the sum of this number and the given one.
351
     *
352
     * @param BigNumber|int|float|string $that The number to add. Must be convertible to a BigInteger.
353
     *
354
     * @throws MathException If the number is not valid, or is not convertible to a BigInteger.
355
     *
356
     * @pure
357
     */
358
    public function plus(BigNumber|int|float|string $that) : BigInteger
359
    {
360
        $that = BigInteger::of($that);
1,569✔
361

362
        if ($that->value === '0') {
1,569✔
363
            return $this;
21✔
364
        }
365

366
        if ($this->value === '0') {
1,548✔
367
            return $that;
63✔
368
        }
369

370
        $value = CalculatorRegistry::get()->add($this->value, $that->value);
1,506✔
371

372
        return new BigInteger($value);
1,506✔
373
    }
374

375
    /**
376
     * Returns the difference of this number and the given one.
377
     *
378
     * @param BigNumber|int|float|string $that The number to subtract. Must be convertible to a BigInteger.
379
     *
380
     * @throws MathException If the number is not valid, or is not convertible to a BigInteger.
381
     *
382
     * @pure
383
     */
384
    public function minus(BigNumber|int|float|string $that) : BigInteger
385
    {
386
        $that = BigInteger::of($that);
888✔
387

388
        if ($that->value === '0') {
888✔
389
            return $this;
24✔
390
        }
391

392
        $value = CalculatorRegistry::get()->sub($this->value, $that->value);
870✔
393

394
        return new BigInteger($value);
870✔
395
    }
396

397
    /**
398
     * Returns the product of this number and the given one.
399
     *
400
     * @param BigNumber|int|float|string $that The multiplier. Must be convertible to a BigInteger.
401
     *
402
     * @throws MathException If the multiplier is not a valid number, or is not convertible to a BigInteger.
403
     *
404
     * @pure
405
     */
406
    public function multipliedBy(BigNumber|int|float|string $that) : BigInteger
407
    {
408
        $that = BigInteger::of($that);
1,149✔
409

410
        if ($that->value === '1') {
1,149✔
411
            return $this;
270✔
412
        }
413

414
        if ($this->value === '1') {
1,137✔
415
            return $that;
294✔
416
        }
417

418
        $value = CalculatorRegistry::get()->mul($this->value, $that->value);
1,050✔
419

420
        return new BigInteger($value);
1,050✔
421
    }
422

423
    /**
424
     * Returns the result of the division of this number by the given one.
425
     *
426
     * @param BigNumber|int|float|string $that         The divisor. Must be convertible to a BigInteger.
427
     * @param RoundingMode               $roundingMode An optional rounding mode, defaults to UNNECESSARY.
428
     *
429
     * @throws MathException If the divisor is not a valid number, is not convertible to a BigInteger, is zero,
430
     *                       or RoundingMode::UNNECESSARY is used and the remainder is not zero.
431
     *
432
     * @pure
433
     */
434
    public function dividedBy(BigNumber|int|float|string $that, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigInteger
435
    {
436
        $that = BigInteger::of($that);
1,980✔
437

438
        if ($that->value === '1') {
1,971✔
439
            return $this;
3✔
440
        }
441

442
        if ($that->value === '0') {
1,968✔
443
            throw DivisionByZeroException::divisionByZero();
6✔
444
        }
445

446
        $result = CalculatorRegistry::get()->divRound($this->value, $that->value, $roundingMode);
1,962✔
447

448
        return new BigInteger($result);
1,869✔
449
    }
450

451
    /**
452
     * Returns this number exponentiated to the given value.
453
     *
454
     * @throws \InvalidArgumentException If the exponent is not in the range 0 to 1,000,000.
455
     *
456
     * @pure
457
     */
458
    public function power(int $exponent) : BigInteger
459
    {
460
        if ($exponent === 0) {
1,827✔
461
            return BigInteger::one();
21✔
462
        }
463

464
        if ($exponent === 1) {
1,806✔
465
            return $this;
198✔
466
        }
467

468
        if ($exponent < 0 || $exponent > Calculator::MAX_POWER) {
1,608✔
469
            throw new \InvalidArgumentException(\sprintf(
6✔
470
                'The exponent %d is not in the range 0 to %d.',
6✔
471
                $exponent,
6✔
472
                Calculator::MAX_POWER
6✔
473
            ));
6✔
474
        }
475

476
        return new BigInteger(CalculatorRegistry::get()->pow($this->value, $exponent));
1,602✔
477
    }
478

479
    /**
480
     * Returns the quotient of the division of this number by the given one.
481
     *
482
     * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger.
483
     *
484
     * @throws DivisionByZeroException If the divisor is zero.
485
     *
486
     * @pure
487
     */
488
    public function quotient(BigNumber|int|float|string $that) : BigInteger
489
    {
490
        $that = BigInteger::of($that);
969✔
491

492
        if ($that->value === '1') {
969✔
493
            return $this;
66✔
494
        }
495

496
        if ($that->value === '0') {
903✔
497
            throw DivisionByZeroException::divisionByZero();
3✔
498
        }
499

500
        $quotient = CalculatorRegistry::get()->divQ($this->value, $that->value);
900✔
501

502
        return new BigInteger($quotient);
900✔
503
    }
504

505
    /**
506
     * Returns the remainder of the division of this number by the given one.
507
     *
508
     * The remainder, when non-zero, has the same sign as the dividend.
509
     *
510
     * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger.
511
     *
512
     * @throws DivisionByZeroException If the divisor is zero.
513
     *
514
     * @pure
515
     */
516
    public function remainder(BigNumber|int|float|string $that) : BigInteger
517
    {
518
        $that = BigInteger::of($that);
159✔
519

520
        if ($that->value === '1') {
159✔
521
            return BigInteger::zero();
12✔
522
        }
523

524
        if ($that->value === '0') {
147✔
525
            throw DivisionByZeroException::divisionByZero();
3✔
526
        }
527

528
        $remainder = CalculatorRegistry::get()->divR($this->value, $that->value);
144✔
529

530
        return new BigInteger($remainder);
144✔
531
    }
532

533
    /**
534
     * Returns the quotient and remainder of the division of this number by the given one.
535
     *
536
     * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger.
537
     *
538
     * @return array{BigInteger, BigInteger} An array containing the quotient and the remainder.
539
     *
540
     * @throws DivisionByZeroException If the divisor is zero.
541
     *
542
     * @pure
543
     */
544
    public function quotientAndRemainder(BigNumber|int|float|string $that) : array
545
    {
546
        $that = BigInteger::of($that);
159✔
547

548
        if ($that->value === '0') {
159✔
549
            throw DivisionByZeroException::divisionByZero();
3✔
550
        }
551

552
        [$quotient, $remainder] = CalculatorRegistry::get()->divQR($this->value, $that->value);
156✔
553

554
        return [
156✔
555
            new BigInteger($quotient),
156✔
556
            new BigInteger($remainder)
156✔
557
        ];
156✔
558
    }
559

560
    /**
561
     * Returns the modulo of this number and the given one.
562
     *
563
     * The modulo operation yields the same result as the remainder operation when both operands are of the same sign,
564
     * and may differ when signs are different.
565
     *
566
     * The result of the modulo operation, when non-zero, has the same sign as the divisor.
567
     *
568
     * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger.
569
     *
570
     * @throws DivisionByZeroException If the divisor is zero.
571
     *
572
     * @pure
573
     */
574
    public function mod(BigNumber|int|float|string $that) : BigInteger
575
    {
576
        $that = BigInteger::of($that);
195✔
577

578
        if ($that->value === '0') {
195✔
579
            throw DivisionByZeroException::modulusMustNotBeZero();
3✔
580
        }
581

582
        $value = CalculatorRegistry::get()->mod($this->value, $that->value);
192✔
583

584
        return new BigInteger($value);
192✔
585
    }
586

587
    /**
588
     * Returns the modular multiplicative inverse of this BigInteger modulo $m.
589
     *
590
     * @throws DivisionByZeroException If $m is zero.
591
     * @throws NegativeNumberException If $m is negative.
592
     * @throws MathException           If this BigInteger has no multiplicative inverse mod m (that is, this BigInteger
593
     *                                 is not relatively prime to m).
594
     *
595
     * @pure
596
     */
597
    public function modInverse(BigInteger $m) : BigInteger
598
    {
599
        if ($m->value === '0') {
66✔
600
            throw DivisionByZeroException::modulusMustNotBeZero();
6✔
601
        }
602

603
        if ($m->isNegative()) {
60✔
604
            throw new NegativeNumberException('Modulus must not be negative.');
3✔
605
        }
606

607
        if ($m->value === '1') {
57✔
608
            return BigInteger::zero();
3✔
609
        }
610

611
        $value = CalculatorRegistry::get()->modInverse($this->value, $m->value);
54✔
612

613
        if ($value === null) {
54✔
614
            throw new MathException('Unable to compute the modInverse for the given modulus.');
15✔
615
        }
616

617
        return new BigInteger($value);
39✔
618
    }
619

620
    /**
621
     * Returns this number raised into power with modulo.
622
     *
623
     * This operation only works on positive numbers.
624
     *
625
     * @param BigNumber|int|float|string $exp The exponent. Must be positive or zero.
626
     * @param BigNumber|int|float|string $mod The modulus. Must be strictly positive.
627
     *
628
     * @throws NegativeNumberException If any of the operands is negative.
629
     * @throws DivisionByZeroException If the modulus is zero.
630
     *
631
     * @pure
632
     */
633
    public function modPow(BigNumber|int|float|string $exp, BigNumber|int|float|string $mod) : BigInteger
634
    {
635
        $exp = BigInteger::of($exp);
47✔
636
        $mod = BigInteger::of($mod);
47✔
637

638
        if ($this->isNegative() || $exp->isNegative() || $mod->isNegative()) {
47✔
639
            throw new NegativeNumberException('The operands cannot be negative.');
9✔
640
        }
641

642
        if ($mod->isZero()) {
38✔
643
            throw DivisionByZeroException::modulusMustNotBeZero();
3✔
644
        }
645

646
        $result = CalculatorRegistry::get()->modPow($this->value, $exp->value, $mod->value);
35✔
647

648
        return new BigInteger($result);
35✔
649
    }
650

651
    /**
652
     * Returns the greatest common divisor of this number and the given one.
653
     *
654
     * The GCD is always positive, unless both operands are zero, in which case it is zero.
655
     *
656
     * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number.
657
     *
658
     * @pure
659
     */
660
    public function gcd(BigNumber|int|float|string $that) : BigInteger
661
    {
662
        $that = BigInteger::of($that);
3,198✔
663

664
        if ($that->value === '0' && $this->value[0] !== '-') {
3,198✔
665
            return $this;
60✔
666
        }
667

668
        if ($this->value === '0' && $that->value[0] !== '-') {
3,138✔
669
            return $that;
30✔
670
        }
671

672
        $value = CalculatorRegistry::get()->gcd($this->value, $that->value);
3,108✔
673

674
        return new BigInteger($value);
3,108✔
675
    }
676

677
    /**
678
     * Returns the integer square root number of this number, rounded down.
679
     *
680
     * The result is the largest x such that x² ≤ n.
681
     *
682
     * @throws NegativeNumberException If this number is negative.
683
     *
684
     * @pure
685
     */
686
    public function sqrt() : BigInteger
687
    {
688
        if ($this->value[0] === '-') {
1,008✔
689
            throw new NegativeNumberException('Cannot calculate the square root of a negative number.');
3✔
690
        }
691

692
        $value = CalculatorRegistry::get()->sqrt($this->value);
1,005✔
693

694
        return new BigInteger($value);
1,005✔
695
    }
696

697
    /**
698
     * Returns the absolute value of this number.
699
     *
700
     * @pure
701
     */
702
    public function abs() : BigInteger
703
    {
704
        return $this->isNegative() ? $this->negated() : $this;
678✔
705
    }
706

707
    /**
708
     * Returns the inverse of this number.
709
     *
710
     * @pure
711
     */
712
    public function negated() : BigInteger
713
    {
714
        return new BigInteger(CalculatorRegistry::get()->neg($this->value));
2,838✔
715
    }
716

717
    /**
718
     * Returns the integer bitwise-and combined with another integer.
719
     *
720
     * This method returns a negative BigInteger if and only if both operands are negative.
721
     *
722
     * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number.
723
     *
724
     * @pure
725
     */
726
    public function and(BigNumber|int|float|string $that) : BigInteger
727
    {
728
        $that = BigInteger::of($that);
153✔
729

730
        return new BigInteger(CalculatorRegistry::get()->and($this->value, $that->value));
153✔
731
    }
732

733
    /**
734
     * Returns the integer bitwise-or combined with another integer.
735
     *
736
     * This method returns a negative BigInteger if and only if either of the operands is negative.
737
     *
738
     * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number.
739
     *
740
     * @pure
741
     */
742
    public function or(BigNumber|int|float|string $that) : BigInteger
743
    {
744
        $that = BigInteger::of($that);
138✔
745

746
        return new BigInteger(CalculatorRegistry::get()->or($this->value, $that->value));
138✔
747
    }
748

749
    /**
750
     * Returns the integer bitwise-xor combined with another integer.
751
     *
752
     * This method returns a negative BigInteger if and only if exactly one of the operands is negative.
753
     *
754
     * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number.
755
     *
756
     * @pure
757
     */
758
    public function xor(BigNumber|int|float|string $that) : BigInteger
759
    {
760
        $that = BigInteger::of($that);
144✔
761

762
        return new BigInteger(CalculatorRegistry::get()->xor($this->value, $that->value));
144✔
763
    }
764

765
    /**
766
     * Returns the bitwise-not of this BigInteger.
767
     *
768
     * @pure
769
     */
770
    public function not() : BigInteger
771
    {
772
        return $this->negated()->minus(1);
57✔
773
    }
774

775
    /**
776
     * Returns the integer left shifted by a given number of bits.
777
     *
778
     * @pure
779
     */
780
    public function shiftedLeft(int $distance) : BigInteger
781
    {
782
        if ($distance === 0) {
594✔
783
            return $this;
6✔
784
        }
785

786
        if ($distance < 0) {
588✔
787
            return $this->shiftedRight(- $distance);
198✔
788
        }
789

790
        return $this->multipliedBy(BigInteger::of(2)->power($distance));
390✔
791
    }
792

793
    /**
794
     * Returns the integer right shifted by a given number of bits.
795
     *
796
     * @pure
797
     */
798
    public function shiftedRight(int $distance) : BigInteger
799
    {
800
        if ($distance === 0) {
1,518✔
801
            return $this;
66✔
802
        }
803

804
        if ($distance < 0) {
1,452✔
805
            return $this->shiftedLeft(- $distance);
195✔
806
        }
807

808
        $operand = BigInteger::of(2)->power($distance);
1,257✔
809

810
        if ($this->isPositiveOrZero()) {
1,257✔
811
            return $this->quotient($operand);
672✔
812
        }
813

814
        return $this->dividedBy($operand, RoundingMode::UP);
585✔
815
    }
816

817
    /**
818
     * Returns the number of bits in the minimal two's-complement representation of this BigInteger, excluding a sign bit.
819
     *
820
     * For positive BigIntegers, this is equivalent to the number of bits in the ordinary binary representation.
821
     * Computes (ceil(log2(this < 0 ? -this : this+1))).
822
     *
823
     * @pure
824
     */
825
    public function getBitLength() : int
826
    {
827
        if ($this->value === '0') {
321✔
828
            return 0;
12✔
829
        }
830

831
        if ($this->isNegative()) {
315✔
832
            return $this->abs()->minus(1)->getBitLength();
120✔
833
        }
834

835
        return \strlen($this->toBase(2));
309✔
836
    }
837

838
    /**
839
     * Returns the index of the rightmost (lowest-order) one bit in this BigInteger.
840
     *
841
     * Returns -1 if this BigInteger contains no one bits.
842
     *
843
     * @pure
844
     */
845
    public function getLowestSetBit() : int
846
    {
847
        $n = $this;
81✔
848
        $bitLength = $this->getBitLength();
81✔
849

850
        for ($i = 0; $i <= $bitLength; $i++) {
81✔
851
            if ($n->isOdd()) {
81✔
852
                return $i;
78✔
853
            }
854

855
            $n = $n->shiftedRight(1);
51✔
856
        }
857

858
        return -1;
3✔
859
    }
860

861
    /**
862
     * Returns whether this number is even.
863
     *
864
     * @pure
865
     */
866
    public function isEven() : bool
867
    {
868
        return \in_array($this->value[-1], ['0', '2', '4', '6', '8'], true);
60✔
869
    }
870

871
    /**
872
     * Returns whether this number is odd.
873
     *
874
     * @pure
875
     */
876
    public function isOdd() : bool
877
    {
878
        return \in_array($this->value[-1], ['1', '3', '5', '7', '9'], true);
1,011✔
879
    }
880

881
    /**
882
     * Returns true if and only if the designated bit is set.
883
     *
884
     * Computes ((this & (1<<n)) != 0).
885
     *
886
     * @param int $n The bit to test, 0-based.
887
     *
888
     * @throws \InvalidArgumentException If the bit to test is negative.
889
     *
890
     * @pure
891
     */
892
    public function testBit(int $n) : bool
893
    {
894
        if ($n < 0) {
873✔
895
            throw new \InvalidArgumentException('The bit to test cannot be negative.');
3✔
896
        }
897

898
        return $this->shiftedRight($n)->isOdd();
870✔
899
    }
900

901
    #[Override]
902
    public function compareTo(BigNumber|int|float|string $that) : int
903
    {
904
        $that = BigNumber::of($that);
2,282✔
905

906
        if ($that instanceof BigInteger) {
2,282✔
907
            return CalculatorRegistry::get()->cmp($this->value, $that->value);
2,174✔
908
        }
909

910
        return - $that->compareTo($this);
108✔
911
    }
912

913
    #[Override]
914
    public function getSign() : int
915
    {
916
        return ($this->value === '0') ? 0 : (($this->value[0] === '-') ? -1 : 1);
3,173✔
917
    }
918

919
    #[Override]
920
    public function toBigInteger() : BigInteger
921
    {
922
        return $this;
13,088✔
923
    }
924

925
    #[Override]
926
    public function toBigDecimal() : BigDecimal
927
    {
928
        return self::newBigDecimal($this->value);
3,900✔
929
    }
930

931
    #[Override]
932
    public function toBigRational() : BigRational
933
    {
934
        return self::newBigRational($this, BigInteger::one(), false);
393✔
935
    }
936

937
    #[Override]
938
    public function toScale(int $scale, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
939
    {
940
        return $this->toBigDecimal()->toScale($scale, $roundingMode);
9✔
941
    }
942

943
    #[Override]
944
    public function toInt() : int
945
    {
946
        $intValue = (int) $this->value;
87✔
947

948
        if ($this->value !== (string) $intValue) {
87✔
949
            throw IntegerOverflowException::toIntOverflow($this);
15✔
950
        }
951

952
        return $intValue;
72✔
953
    }
954

955
    #[Override]
956
    public function toFloat() : float
957
    {
958
        return (float) $this->value;
48✔
959
    }
960

961
    /**
962
     * Returns a string representation of this number in the given base.
963
     *
964
     * The output will always be lowercase for bases greater than 10.
965
     *
966
     * @throws \InvalidArgumentException If the base is out of range.
967
     *
968
     * @pure
969
     */
970
    public function toBase(int $base) : string
971
    {
972
        if ($base === 10) {
1,293✔
973
            return $this->value;
12✔
974
        }
975

976
        if ($base < 2 || $base > 36) {
1,281✔
977
            throw new \InvalidArgumentException(\sprintf('Base %d is out of range [2, 36]', $base));
15✔
978
        }
979

980
        return CalculatorRegistry::get()->toBase($this->value, $base);
1,266✔
981
    }
982

983
    /**
984
     * Returns a string representation of this number in an arbitrary base with a custom alphabet.
985
     *
986
     * Because this method accepts an alphabet with any character, including dash, it does not handle negative numbers;
987
     * a NegativeNumberException will be thrown when attempting to call this method on a negative number.
988
     *
989
     * @param string $alphabet The alphabet, for example '01' for base 2, or '01234567' for base 8.
990
     *
991
     * @throws NegativeNumberException   If this number is negative.
992
     * @throws \InvalidArgumentException If the given alphabet does not contain at least 2 chars.
993
     *
994
     * @pure
995
     */
996
    public function toArbitraryBase(string $alphabet) : string
997
    {
998
        $base = \strlen($alphabet);
135✔
999

1000
        if ($base < 2) {
135✔
1001
            throw new \InvalidArgumentException('The alphabet must contain at least 2 chars.');
6✔
1002
        }
1003

1004
        if ($this->value[0] === '-') {
129✔
1005
            throw new NegativeNumberException(__FUNCTION__ . '() does not support negative numbers.');
3✔
1006
        }
1007

1008
        return CalculatorRegistry::get()->toArbitraryBase($this->value, $alphabet, $base);
126✔
1009
    }
1010

1011
    /**
1012
     * Returns a string of bytes containing the binary representation of this BigInteger.
1013
     *
1014
     * The string is in big-endian byte-order: the most significant byte is in the zeroth element.
1015
     *
1016
     * If `$signed` is true, the output will be in two's-complement representation, and a sign bit will be prepended to
1017
     * the output. If `$signed` is false, no sign bit will be prepended, and this method will throw an exception if the
1018
     * number is negative.
1019
     *
1020
     * The string will contain the minimum number of bytes required to represent this BigInteger, including a sign bit
1021
     * if `$signed` is true.
1022
     *
1023
     * This representation is compatible with the `fromBytes()` factory method, as long as the `$signed` flags match.
1024
     *
1025
     * @param bool $signed Whether to output a signed number in two's-complement representation with a leading sign bit.
1026
     *
1027
     * @throws NegativeNumberException If $signed is false, and the number is negative.
1028
     *
1029
     * @pure
1030
     */
1031
    public function toBytes(bool $signed = true) : string
1032
    {
1033
        if (! $signed && $this->isNegative()) {
534✔
1034
            throw new NegativeNumberException('Cannot convert a negative number to a byte string when $signed is false.');
3✔
1035
        }
1036

1037
        $hex = $this->abs()->toBase(16);
531✔
1038

1039
        if (\strlen($hex) % 2 !== 0) {
531✔
1040
            $hex = '0' . $hex;
219✔
1041
        }
1042

1043
        $baseHexLength = \strlen($hex);
531✔
1044

1045
        if ($signed) {
531✔
1046
            if ($this->isNegative()) {
492✔
1047
                $bin = \hex2bin($hex);
453✔
1048
                assert($bin !== false);
1049

1050
                $hex = \bin2hex(~$bin);
453✔
1051
                $hex = self::fromBase($hex, 16)->plus(1)->toBase(16);
453✔
1052

1053
                $hexLength = \strlen($hex);
453✔
1054

1055
                if ($hexLength < $baseHexLength) {
453✔
1056
                    $hex = \str_repeat('0', $baseHexLength - $hexLength) . $hex;
72✔
1057
                }
1058

1059
                if ($hex[0] < '8') {
453✔
1060
                    $hex = 'FF' . $hex;
114✔
1061
                }
1062
            } else {
1063
                if ($hex[0] >= '8') {
39✔
1064
                    $hex = '00' . $hex;
21✔
1065
                }
1066
            }
1067
        }
1068

1069
        $result = \hex2bin($hex);
531✔
1070
        assert($result !== false);
1071

1072
        return $result;
531✔
1073
    }
1074

1075
    /**
1076
     * @return numeric-string
1077
     */
1078
    #[Override]
1079
    public function __toString() : string
1080
    {
1081
        /** @var numeric-string */
1082
        return $this->value;
12,921✔
1083
    }
1084

1085
    /**
1086
     * This method is required for serializing the object and SHOULD NOT be accessed directly.
1087
     *
1088
     * @internal
1089
     *
1090
     * @return array{value: string}
1091
     */
1092
    public function __serialize(): array
1093
    {
1094
        return ['value' => $this->value];
6✔
1095
    }
1096

1097
    /**
1098
     * This method is only here to allow unserializing the object and cannot be accessed directly.
1099
     *
1100
     * @internal
1101
     *
1102
     * @param array{value: string} $data
1103
     *
1104
     * @throws \LogicException
1105
     */
1106
    public function __unserialize(array $data): void
1107
    {
1108
        /** @phpstan-ignore isset.initializedProperty */
1109
        if (isset($this->value)) {
9✔
1110
            throw new \LogicException('__unserialize() is an internal function, it must not be called directly.');
3✔
1111
        }
1112

1113
        /** @phpstan-ignore deadCode.unreachable */
1114
        $this->value = $data['value'];
6✔
1115
    }
1116
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc