BigInteger.php 32 KB

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