BigInteger.php 34 KB

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