BigInteger.php 32 KB

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