ArbitraryIntegerTest.php 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147
  1. <?php
  2. namespace MathPHP\Tests\Number;
  3. use MathPHP\Number\ArbitraryInteger;
  4. use MathPHP\Number\Rational;
  5. use MathPHP\Exception;
  6. class ArbitraryIntegerTest extends \PHPUnit\Framework\TestCase
  7. {
  8. /**
  9. * @test createZeroValue
  10. */
  11. public function testCreateZeroValue()
  12. {
  13. // Given
  14. $zero = ArbitraryInteger::createZeroValue();
  15. // Then
  16. $this->assertEquals(0, $zero->toInt());
  17. }
  18. /**
  19. * @test String representation
  20. * @dataProvider dataProviderForIntToString
  21. * @dataProvider dataProviderForStringIntToString
  22. * @dataProvider dataProviderForBinaryToString
  23. * @dataProvider dataProviderForHexToString
  24. * @dataProvider dataProviderForOctalToString
  25. * @param mixed $int
  26. * @param string $expected
  27. * @throws \Exception
  28. */
  29. public function testStringToString($int, string $expected)
  30. {
  31. // Given
  32. $obj = new ArbitraryInteger($int);
  33. // When
  34. $stringRepresentation = (string) $obj;
  35. // Then
  36. $this->assertSame($expected, $stringRepresentation);
  37. }
  38. /**
  39. * @return array (numberAsString, stringRepresentation)
  40. */
  41. public function dataProviderForIntToString(): array
  42. {
  43. return [
  44. [-1, '-1'],
  45. [0, '0'],
  46. [1, '1'],
  47. [2, '2'],
  48. [3, '3'],
  49. [4, '4'],
  50. [5, '5'],
  51. [6, '6'],
  52. [7, '7'],
  53. [8, '8'],
  54. [9, '9'],
  55. [10, '10'],
  56. [200, '200'],
  57. [123456789012, '123456789012'],
  58. [-200, '-200'],
  59. [-31415, '-31415'],
  60. ];
  61. }
  62. /**
  63. * @return array (numberAsString, stringRepresentation)
  64. */
  65. public function dataProviderForStringIntToString(): array
  66. {
  67. return [
  68. ['-1', '-1'],
  69. ['0', '0'],
  70. ['1', '1'],
  71. ['2', '2'],
  72. ['3', '3'],
  73. ['4', '4'],
  74. ['5', '5'],
  75. ['6', '6'],
  76. ['7', '7'],
  77. ['8', '8'],
  78. ['9', '9'],
  79. ['10', '10'],
  80. ['200', '200'],
  81. ['123456789012345678901234567890', '123456789012345678901234567890'],
  82. ['-200', '-200'],
  83. ['-31415', '-31415'],
  84. ];
  85. }
  86. /**
  87. * @return array (numberAsString, stringRepresentation)
  88. */
  89. public function dataProviderForBinaryToString(): array
  90. {
  91. return [
  92. ['0b0', '0'],
  93. ['0b1', '1'],
  94. ['0b10', '2'],
  95. ['0b11', '3'],
  96. ['0b100', '4'],
  97. ['0b101', '5'],
  98. ['0b110', '6'],
  99. ['0b111', '7'],
  100. ['0b1000', '8'],
  101. ['0b1101', '13'],
  102. ['0b10001111110000110000011101111111001101110111', '9879237948279'],
  103. ['-0b1', '-1'],
  104. ['-0b10', '-2'],
  105. ['-0b11', '-3'],
  106. ['-0b100', '-4'],
  107. ['-0b101', '-5'],
  108. ['-0b110', '-6'],
  109. ['-0b111', '-7'],
  110. ['-0b1000', '-8'],
  111. ['-0b1101', '-13'],
  112. ['-0b10001111110000110000011101111111001101110111', '-9879237948279'],
  113. ];
  114. }
  115. /**
  116. * @return array (numberAsString, stringRepresentation)
  117. */
  118. public function dataProviderForHexToString(): array
  119. {
  120. return [
  121. ['0x0', '0'],
  122. ['0x1', '1'],
  123. ['0x2', '2'],
  124. ['0x3', '3'],
  125. ['0x4', '4'],
  126. ['0x5', '5'],
  127. ['0x6', '6'],
  128. ['0x7', '7'],
  129. ['0x8', '8'],
  130. ['0x9', '9'],
  131. ['0xA', '10'],
  132. ['0xB', '11'],
  133. ['0xC', '12'],
  134. ['0xD', '13'],
  135. ['0xE', '14'],
  136. ['0xF', '15'],
  137. ['0x10', '16'],
  138. ['0x11', '17'],
  139. ['-0x1', '-1'],
  140. ['-0x2', '-2'],
  141. ['-0x3', '-3'],
  142. ['-0x4', '-4'],
  143. ['-0x5', '-5'],
  144. ['-0x6', '-6'],
  145. ['-0x7', '-7'],
  146. ['-0x8', '-8'],
  147. ['-0x9', '-9'],
  148. ['-0xA', '-10'],
  149. ['-0xB', '-11'],
  150. ['-0xC', '-12'],
  151. ['-0xD', '-13'],
  152. ['-0xE', '-14'],
  153. ['-0xF', '-15'],
  154. ['-0x10', '-16'],
  155. ['-0x11', '-17'],
  156. ['0xff', '255'],
  157. ['-0xff', '-255'],
  158. ['0x7fff', '32767'],
  159. ['-0x7fff', '-32767'],
  160. ['0x7FFF', '32767'],
  161. ['-0x7FFF', '-32767'],
  162. ['0x8FC3077F377', '9879237948279'],
  163. ['-0x8FC3077F377', '-9879237948279'],
  164. ];
  165. }
  166. /**
  167. * @return array (numberAsString, stringRepresentation)
  168. */
  169. public function dataProviderForOctalToString(): array
  170. {
  171. return [
  172. ['00', '0'],
  173. ['01', '1'],
  174. ['02', '2'],
  175. ['03', '3'],
  176. ['04', '4'],
  177. ['05', '5'],
  178. ['06', '6'],
  179. ['07', '7'],
  180. ['010', '8'],
  181. ['011', '9'],
  182. ['012', '10'],
  183. ['-01', '-1'],
  184. ['-02', '-2'],
  185. ['-03', '-3'],
  186. ['-04', '-4'],
  187. ['-05', '-5'],
  188. ['-06', '-6'],
  189. ['-07', '-7'],
  190. ['-010', '-8'],
  191. ['-011', '-9'],
  192. ['-012', '-10'],
  193. ['0127', '87'],
  194. ['-0127', '-87'],
  195. ['077777', '32767'],
  196. ['-077777', '-32767'],
  197. ];
  198. }
  199. /**
  200. * @test Int representation
  201. * @dataProvider dataProviderForIntToInt
  202. * @param int $int
  203. * @throws \Exception
  204. */
  205. public function testIntToInt(int $int)
  206. {
  207. // Given
  208. $obj = new ArbitraryInteger($int);
  209. // When
  210. $intRepresentation = $obj->toInt();
  211. // Then
  212. $this->assertSame($int, $intRepresentation);
  213. }
  214. public function dataProviderForIntToInt(): array
  215. {
  216. return [
  217. [0],
  218. [1],
  219. [-1],
  220. [2],
  221. [-2],
  222. [200],
  223. [123456],
  224. [PHP_INT_MAX],
  225. [PHP_INT_MIN],
  226. [32767],
  227. [-32767],
  228. [31415],
  229. [-31415],
  230. ];
  231. }
  232. /**
  233. * @test Float representation
  234. * @dataProvider dataProviderForStringToFloat
  235. * @param string $int
  236. * @param float $float
  237. * @throws \Exception
  238. */
  239. public function testIntToFloat(string $int, float $float)
  240. {
  241. // Given
  242. $obj = new ArbitraryInteger($int);
  243. // When
  244. $floatRepresentation = $obj->toFloat();
  245. // Then
  246. $this->assertSame($float, $floatRepresentation);
  247. }
  248. public function dataProviderForStringToFloat(): array
  249. {
  250. return [
  251. ['0', 0.0],
  252. ['1', 1.0],
  253. ['-1', -1.0],
  254. ['2', 2.0],
  255. ['-2', -2.0],
  256. ['200', 200.0],
  257. ['123456', 123456.0],
  258. ['32767', 32767.0],
  259. ['-32767', -32767.0],
  260. ['9223372036854775807', 9.223372036854775807E+18],
  261. ['9223372036854775808', 9.223372036854775808E18],
  262. ['-9223372036854775808', -9.223372036854775808E18],
  263. ['-9223372036854775809', -9.223372036854775809E+18],
  264. ];
  265. }
  266. /**
  267. * @test Binary representation
  268. * @dataProvider dataProviderForIntToInt
  269. * @param int $int
  270. * @throws \Exception
  271. */
  272. public function testIntToBinary(int $int)
  273. {
  274. // Given
  275. $obj = new ArbitraryInteger($int);
  276. // When
  277. $binaryRepresentation = $obj->toBinary();
  278. // Then
  279. $this->assertNotEmpty($binaryRepresentation);
  280. }
  281. /**
  282. * @test isPositive
  283. * @dataProvider dataProviderForPositiveInt
  284. * @param string|int $int
  285. * @throws \Exception
  286. */
  287. public function testIsPositive($int)
  288. {
  289. // Given
  290. $obj = new ArbitraryInteger($int);
  291. // When
  292. $isPositive = $obj->isPositive();
  293. // Then
  294. $this->assertTrue($isPositive);
  295. }
  296. public function dataProviderForPositiveInt(): array
  297. {
  298. return [
  299. [0],
  300. [1],
  301. [2],
  302. [200],
  303. [123456],
  304. [PHP_INT_MAX],
  305. [32767],
  306. [31415],
  307. ['123456789012345678901234567890'],
  308. ];
  309. }
  310. /**
  311. * @test isPositive negative numbers
  312. * @dataProvider dataProviderForNegativeInt
  313. * @param string|int $int
  314. * @throws \Exception
  315. */
  316. public function testIsNotPositive($int)
  317. {
  318. // Given
  319. $obj = new ArbitraryInteger($int);
  320. // When
  321. $isPositive = $obj->isPositive();
  322. // Then
  323. $this->assertFalse($isPositive);
  324. }
  325. public function dataProviderForNegativeInt(): array
  326. {
  327. return [
  328. [-1],
  329. [-2],
  330. [-200],
  331. [-123456],
  332. [PHP_INT_MIN],
  333. [-32767],
  334. [-31415],
  335. ['-123456789012345678901234567890'],
  336. ];
  337. }
  338. /**
  339. * @test add
  340. * @dataProvider dataProviderForTestAddition
  341. * @param string $int1
  342. * @param string $int2
  343. * @param string $expected
  344. * @throws \Exception
  345. */
  346. public function testAddition(string $int1, string $int2, string $expected)
  347. {
  348. // Given
  349. $int1 = new ArbitraryInteger($int1);
  350. $int2 = new ArbitraryInteger($int2);
  351. // When
  352. $sum = $int1->add($int2);
  353. // Then
  354. $this->assertEquals($expected, (string) $sum);
  355. }
  356. public function dataProviderForTestAddition(): array
  357. {
  358. return [
  359. ['1', '0', '1'],
  360. ['0', '1', '1'],
  361. ['0', '-1', '-1'],
  362. ['1', '-1', '0'],
  363. ['-1', '0', '-1'],
  364. ['-1', '-2', '-3'],
  365. ['-2', '-1', '-3'],
  366. ['32767', '48937', '81704'],
  367. ['98372985472983', '73468763846876', '171841749319859'],
  368. ['983759729375923795837849', '98734957979279759843798', '1082494687355203555681647'],
  369. ['983759729375923795837849', '-98734957979279759843798', '885024771396644035994051'],
  370. ];
  371. }
  372. /**
  373. * @test subtract
  374. * @dataProvider dataProviderForTestSubtract
  375. * @param string $int1
  376. * @param string $int2
  377. * @param string $expected
  378. * @throws \Exception
  379. */
  380. public function testSubtract(string $int1, string $int2, string $expected)
  381. {
  382. // Given
  383. $int1 = new ArbitraryInteger($int1);
  384. $int2 = new ArbitraryInteger($int2);
  385. // When
  386. $difference = $int1->subtract($int2);
  387. // Then
  388. $this->assertEquals($expected, (string) $difference);
  389. }
  390. public function dataProviderForTestSubtract(): array
  391. {
  392. return [
  393. ['1', '0', '1'],
  394. ['1', '1', '0'],
  395. ['0', '1', '-1'],
  396. ['0', '-1', '1'],
  397. ['-1', '-2', '1'],
  398. ['-2', '-1', '-1'],
  399. ['32767', '48937', '-16170'],
  400. ['98372985472983', '73468763846876', '24904221626107'],
  401. ['983759729375923795837849', '98734957979279759843798', '885024771396644035994051'],
  402. ];
  403. }
  404. /**
  405. * @test multiply
  406. * @dataProvider dataProviderForTestMultiplication
  407. * @param string $int1
  408. * @param string $int2
  409. * @param string $expected
  410. * @throws \Exception
  411. */
  412. public function testMultiplication(string $int1, string $int2, string $expected)
  413. {
  414. // Given
  415. $int1 = new ArbitraryInteger($int1);
  416. $int2 = new ArbitraryInteger($int2);
  417. // When
  418. $sum = $int1->multiply($int2);
  419. // Then
  420. $this->assertEquals($expected, (string) $sum);
  421. }
  422. public function dataProviderForTestMultiplication(): array
  423. {
  424. return [
  425. ['1', '1', '1'],
  426. ['-1', '1', '-1'],
  427. ['1', '-1', '-1'],
  428. ['2', '-1', '-2'],
  429. ['-1', '2', '-2'],
  430. ['-300', '-400', '120000'],
  431. ['983759729375923795837849', '10000000000', '9837597293759237958378490000000000'],
  432. ];
  433. }
  434. /**
  435. * @test intdiv and mod calculate the correct whole and remainder
  436. * @dataProvider dataProviderForIntDivSmallDivisor
  437. * @param string $dividend
  438. * @param int $divisor
  439. * @param string $expectedQuotient
  440. * @param string $expectedMod
  441. * @throws \Exception
  442. */
  443. public function testIntDivAndModSmallDivisor(string $dividend, int $divisor, string $expectedQuotient, string $expectedMod)
  444. {
  445. // Given
  446. $obj = new ArbitraryInteger($dividend);
  447. // When
  448. $quotient = $obj->intdiv($divisor);
  449. $mod = $obj->mod($divisor);
  450. // Then
  451. $this->assertEquals($expectedQuotient, (string) $quotient);
  452. $this->assertEquals($expectedMod, (string) $mod);
  453. }
  454. /**
  455. * @test fullIntdiv calculates the correct whole and remainder
  456. * @dataProvider dataProviderForIntDivSmallDivisor
  457. * @param string $dividend
  458. * @param int $divisor
  459. * @param string $expectedQuotient
  460. * @param string $expectedMod
  461. * @throws \Exception
  462. */
  463. public function testFullIntDivSmallDivisor(string $dividend, int $divisor, string $expectedQuotient, string $expectedMod)
  464. {
  465. // Given
  466. $obj = new ArbitraryInteger($dividend);
  467. // When
  468. [$quotient, $mod] = $obj->fullIntdiv($divisor);
  469. // Then
  470. $this->assertEquals($expectedQuotient, (string) $quotient);
  471. $this->assertEquals($expectedMod, (string) $mod);
  472. }
  473. public function dataProviderForIntDivSmallDivisor(): array
  474. {
  475. return [
  476. ['5', 5, '1', '0'],
  477. ['10', 5, '2', '0'],
  478. ['11', 5, '2', '1'],
  479. ['12', 5, '2', '2'],
  480. ['2134567896543378631213', 2, '1067283948271689315606', '1'],
  481. ['2134567896543378631213', 100, '21345678965433786312', '13'],
  482. ['301', 300, '1', '1'],
  483. ['-1', 2, '-1', '1'],
  484. ['-3', 2, '-2', '1'],
  485. ['3', -2, '-1', '1'],
  486. ['-12', -5, '3', '3'],
  487. ['12', -5, '-2', '2'],
  488. ['-12', 5, '-3', '3'],
  489. ];
  490. }
  491. /**
  492. * @test intdiv and mod calculate the correct whole and remainder
  493. * @dataProvider dataProviderForIntDivLargeDivisor
  494. * @param string $dividend
  495. * @param string $divisor
  496. * @param string $expectedQuotient
  497. * @param string $expectedMod
  498. * @throws \Exception
  499. */
  500. public function testIntDivLargeDivisor(string $dividend, string $divisor, string $expectedQuotient, string $expectedMod)
  501. {
  502. // Given
  503. $obj = new ArbitraryInteger($dividend);
  504. $divisor = new ArbitraryInteger($divisor);
  505. // When
  506. $quotient = $obj->intdiv($divisor);
  507. $mod = $obj->mod($divisor);
  508. // Then
  509. $this->assertEquals($expectedQuotient, (string) $quotient);
  510. $this->assertEquals($expectedMod, (string) $mod);
  511. }
  512. /**
  513. * @test fullIntdiv calculates the correct whole and remainder
  514. * @dataProvider dataProviderForIntDivLargeDivisor
  515. * @param string $dividend
  516. * @param string $divisor
  517. * @param string $expectedQuotient
  518. * @param string $expectedMod
  519. * @throws \Exception
  520. */
  521. public function testFullIntDivLargeDivisor(string $dividend, string $divisor, string $expectedQuotient, string $expectedMod)
  522. {
  523. // Given
  524. $obj = new ArbitraryInteger($dividend);
  525. $divisor = new ArbitraryInteger($divisor);
  526. // When
  527. [$quotient, $mod] = $obj->fullIntdiv($divisor);
  528. // Then
  529. $this->assertEquals($expectedQuotient, (string) $quotient);
  530. $this->assertEquals($expectedMod, (string) $mod);
  531. }
  532. public function dataProviderForIntDivLargeDivisor(): array
  533. {
  534. return [
  535. ['2134567896543378631213', '1067283948271689315606', '2', '1'],
  536. ['2134567896543378631213', '21345678965433786312', '100', '13'],
  537. ];
  538. }
  539. /**
  540. * @test pow()
  541. * @dataProvider dataProviderForPow
  542. * @param int $int
  543. * @param int $exponent
  544. * @param string $expected
  545. */
  546. public function testPow(int $int, int $exponent, string $expected)
  547. {
  548. // Given
  549. $int = new ArbitraryInteger($int);
  550. // When
  551. $pow = $int->pow($exponent);
  552. // Then
  553. $this->assertSame($expected, (string) $pow);
  554. }
  555. public function dataProviderForPow(): array
  556. {
  557. return [
  558. [1, 0, '1'],
  559. [1, 1, '1'],
  560. [1, -1, '1'],
  561. [-1, -1, '-1'],
  562. [1, 2, '1'],
  563. [2, 0, '1'],
  564. [2, 1, '2'],
  565. [2, 2, '4'],
  566. [
  567. 1000000,
  568. 0,
  569. '1',
  570. ],
  571. [
  572. 1000000,
  573. 1,
  574. '1000000',
  575. ],
  576. [
  577. 1000000,
  578. 2,
  579. '1000000000000',
  580. ],
  581. [
  582. 1000000000,
  583. 0,
  584. '1',
  585. ],
  586. [
  587. 1000000000,
  588. 1,
  589. '1000000000',
  590. ],
  591. [
  592. 1000000000,
  593. 6,
  594. '1000000000000000000000000000000000000000000000000000000',
  595. ],
  596. [
  597. 2,
  598. 151,
  599. '2854495385411919762116571938898990272765493248',
  600. ],
  601. ];
  602. }
  603. /**
  604. * @test pow() return Rational
  605. * @dataProvider dataProviderForPowRational
  606. * @param int $int
  607. * @param int $exponent
  608. * @param Rational $expected
  609. */
  610. public function testPowRational(int $int, int $exponent, Rational $expected)
  611. {
  612. // Given
  613. $int = new ArbitraryInteger($int);
  614. // When
  615. $pow = $int->pow($exponent);
  616. // Then
  617. $this->assertEquals($expected, $pow);
  618. $this->assertSame((string) $expected, (string) $pow);
  619. }
  620. public function dataProviderForPowRational(): array
  621. {
  622. return [
  623. [2, -1, new Rational(0, 1, 2)],
  624. [2, -2, new Rational(0, 1, 4)],
  625. [3, -3, new Rational(0, 1, 27)],
  626. [-2, -1, new Rational(0, -1, 2)],
  627. [-2, -2, new Rational(0, 1, 4)],
  628. [-2, -3, new Rational(0, -1, 8)],
  629. [-2, -4, new Rational(0, 1, 16)],
  630. ];
  631. }
  632. /**
  633. * @test abs() returns the proper result
  634. * @dataProvider dataProviderForAbs
  635. * @param mixed $int
  636. * @param string $expected
  637. * @throws \Exception
  638. */
  639. public function testAbs($int, string $expected)
  640. {
  641. // Given
  642. $int = new ArbitraryInteger($int);
  643. // When
  644. $abs = $int->abs();
  645. // Then
  646. $this->assertEquals($expected, (string) $abs);
  647. }
  648. public function dataProviderForAbs(): array
  649. {
  650. return [
  651. [0, '0'],
  652. [1, '1'],
  653. [-1, '1'],
  654. ['-12345678910', '12345678910'],
  655. ['12345678910', '12345678910'],
  656. ['-798273948792837498273948289', '798273948792837498273948289'],
  657. ['798273948792837498273948289', '798273948792837498273948289'],
  658. ];
  659. }
  660. /**
  661. * @test negate()
  662. * @dataProvider dataProviderForNegate
  663. * @param string $int
  664. * @param string $expected
  665. * @throws \Exception
  666. */
  667. public function testNegate(string $int, string $expected)
  668. {
  669. // Given
  670. $int = new ArbitraryInteger($int);
  671. // When
  672. $neg = $int->negate();
  673. // Then
  674. $this->assertEquals($expected, (string) $neg);
  675. }
  676. public function dataProviderForNegate(): array
  677. {
  678. return [
  679. ['1', '-1'],
  680. ['-1', '1'],
  681. ['2', '-2'],
  682. ['-2', '2'],
  683. ['10', '-10'],
  684. ['-10', '10'],
  685. ['-123456789101112', '123456789101112'],
  686. ['123456789101112', '-123456789101112'],
  687. ['798273948792837498273948289', '-798273948792837498273948289'],
  688. ['-798273948792837498273948289', '798273948792837498273948289'],
  689. ];
  690. }
  691. /**
  692. * @test fact()
  693. * @dataProvider dataProviderForFact
  694. * @param int $int
  695. * @param string $expected
  696. * @throws \Exception
  697. */
  698. public function testFact(int $int, string $expected)
  699. {
  700. // Given
  701. $int = new ArbitraryInteger($int);
  702. $expectedInt = new ArbitraryInteger($expected);
  703. // When
  704. $fact = $int->fact();
  705. // Then
  706. $this->assertEquals($expectedInt->toBinary(), $fact->toBinary());
  707. $this->assertTrue($expectedInt->equals($fact));
  708. $this->assertSame($expected, (string) $fact);
  709. }
  710. public function dataProviderForFact(): array
  711. {
  712. return [
  713. [-1, '1'],
  714. [0, '1'],
  715. [1, '1'],
  716. [2, '2'],
  717. [3, '6'],
  718. [4, '24'],
  719. [5, '120'],
  720. [20, '2432902008176640000'],
  721. [
  722. 1000,
  723. '402387260077093773543702433923003985719374864210714632543799910429938512398629020592044208486969404800479988610197196058631666872994808558901323829669944590997424504087073759918823627727188732519779505950995276120874975462497043601418278094646496291056393887437886487337119181045825783647849977012476632889835955735432513185323958463075557409114262417474349347553428646576611667797396668820291207379143853719588249808126867838374559731746136085379534524221586593201928090878297308431392844403281231558611036976801357304216168747609675871348312025478589320767169132448426236131412508780208000261683151027341827977704784635868170164365024153691398281264810213092761244896359928705114964975419909342221566832572080821333186116811553615836546984046708975602900950537616475847728421889679646244945160765353408198901385442487984959953319101723355556602139450399736280750137837615307127761926849034352625200015888535147331611702103968175921510907788019393178114194545257223865541461062892187960223838971476088506276862967146674697562911234082439208160153780889893964518263243671616762179168909779911903754031274622289988005195444414282012187361745992642956581746628302955570299024324153181617210465832036786906117260158783520751516284225540265170483304226143974286933061690897968482590125458327168226458066526769958652682272807075781391858178889652208164348344825993266043367660176999612831860788386150279465955131156552036093988180612138558600301435694527224206344631797460594682573103790084024432438465657245014402821885252470935190620929023136493273497565513958720559654228749774011413346962715422845862377387538230483865688976461927383814900140767310446640259899490222221765904339901886018566526485061799702356193897017860040811889729918311021171229845901641921068884387121855646124960798722908519296819372388642614839657382291123125024186649353143970137428531926649875337218940694281434118520158014123344828015051399694290153483077644569099073152433278288269864602789864321139083506217095002597389863554277196742822248757586765752344220207573630569498825087968928162753848863396909959826280956121450994871701244516461260379029309120889086942028510640182154399457156805941872748998094254742173582401063677404595741785160829230135358081840096996372524230560855903700624271243416909004153690105933983835777939410970027753472000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
  724. ],
  725. ];
  726. }
  727. /**
  728. * @test isqrt
  729. * @dataProvider dataProviderForIsqrt
  730. * @param string $number
  731. * @param string $expected
  732. * @throws \Exception
  733. */
  734. public function testIsqrt(string $number, string $expected)
  735. {
  736. // Given
  737. $obj = new ArbitraryInteger($number);
  738. // When
  739. $isqrt = $obj->isqrt();
  740. // Then
  741. $this->assertEquals($expected, (string) $isqrt);
  742. }
  743. public function dataProviderForIsqrt(): array
  744. {
  745. return [
  746. ['0', '0'],
  747. ['1', '1'],
  748. ['2', '1'],
  749. ['3', '1'],
  750. ['4', '2'],
  751. ['5', '2'],
  752. ['6', '2'],
  753. ['7', '2'],
  754. ['8', '2'],
  755. ['9', '3'],
  756. ['10', '3'],
  757. ['11', '3'],
  758. ['12', '3'],
  759. ['13', '3'],
  760. ['14', '3'],
  761. ['15', '3'],
  762. ['16', '4'],
  763. ['17', '4'],
  764. ['18', '4'],
  765. ['19', '4'],
  766. ['20', '4'],
  767. ['110', '10'],
  768. ['64000', '252'],
  769. ['33600000', '5796'],
  770. ['123456789101112', '11111111'],
  771. ['152399025', '12345'],
  772. ['152399026', '12345'],
  773. ['152399024', '12344'],
  774. ];
  775. }
  776. /**
  777. * @test isqrt error for negative numbers
  778. * @throws \Exception
  779. */
  780. public function testIsqrtOutOfBoundsError()
  781. {
  782. // Given
  783. $int = new ArbitraryInteger(-1);
  784. // Then
  785. $this->expectException(Exception\OutOfBoundsException::class);
  786. // When
  787. $isqrt = $int->isqrt();
  788. }
  789. /**
  790. * @test leftShift
  791. * @dataProvider dataProviderForLeftShift
  792. * @param string $number
  793. * @param int $bits
  794. * @param string $expected
  795. * @throws Exception\BadParameterException
  796. * @throws Exception\IncorrectTypeException
  797. */
  798. public function testLeftShift(string $number, int $bits, string $expected)
  799. {
  800. // Given
  801. $int = new ArbitraryInteger($number);
  802. // When
  803. $shiftedInt = $int->leftShift($bits);
  804. // Then
  805. $this->assertEquals($expected, (string) $shiftedInt);
  806. }
  807. /**
  808. * @return array (number, bits, expected number)
  809. */
  810. public function dataProviderForLeftShift(): array
  811. {
  812. return [
  813. ['0', 0, '0'],
  814. ['0', 1, '0'],
  815. ['0', 2, '0'],
  816. ['1', 1, '2'],
  817. ['1', 2, '4'],
  818. ['1', 3, '8'],
  819. ['1', 4, '16'],
  820. ['1', 5, '32'],
  821. ['1', 20, '1048576'],
  822. ['1', 32, '4294967296'],
  823. ['1', 62, '4611686018427387904'],
  824. ['2', 0, '2'],
  825. ['2', 1, '4'],
  826. ['2', 2, '8'],
  827. ['2', 3, '16'],
  828. ['2', 4, '32'],
  829. ['2', 49, '1125899906842624'],
  830. ['2', 99, '1267650600228229401496703205376'],
  831. ['2', 150, '2854495385411919762116571938898990272765493248'],
  832. ];
  833. }
  834. /**
  835. * @test greaterThan
  836. * @dataProvider dataProviderForGreaterThan
  837. * @param string $int1
  838. * @param string $int2
  839. * @throws \Exception
  840. */
  841. public function testGreaterThan(string $int1, string $int2)
  842. {
  843. // Given
  844. $int1 = new ArbitraryInteger($int1);
  845. $int2 = new ArbitraryInteger($int2);
  846. // When
  847. $greaterThan = $int1->greaterThan($int2);
  848. // Then
  849. $this->assertTrue($greaterThan);
  850. }
  851. public function dataProviderForGreaterThan(): array
  852. {
  853. return [
  854. ['0', '-1'],
  855. ['1', '0'],
  856. ['1', '-1'],
  857. ['2', '1'],
  858. ['10', '4'],
  859. ['10', '9'],
  860. ['9839224', '8739'],
  861. ['2432902008176640000', '123456789101112'],
  862. ];
  863. }
  864. /**
  865. * @test not greaterThan
  866. * @dataProvider dataProviderForNotGreaterThan
  867. * @param string $int1
  868. * @param string $int2
  869. * @throws \Exception
  870. */
  871. public function testNotGreaterThan(string $int1, string $int2)
  872. {
  873. // Given
  874. $int1 = new ArbitraryInteger($int1);
  875. $int2 = new ArbitraryInteger($int2);
  876. // When
  877. $greaterThan = $int1->greaterThan($int2);
  878. // Then
  879. $this->assertFalse($greaterThan);
  880. }
  881. public function dataProviderForNotGreaterThan(): array
  882. {
  883. return [
  884. ['-1', '0'],
  885. ['0', '1'],
  886. ['2', '3'],
  887. ['9', '10'],
  888. ['8739', '9839224'],
  889. ['123456789101112', '2432902008176640000']
  890. ];
  891. }
  892. /**
  893. * @test lessThan
  894. * @dataProvider dataProviderForNotGreaterThan
  895. * @param string $int1
  896. * @param string $int2
  897. * @throws \Exception
  898. */
  899. public function testLessThan(string $int1, string $int2)
  900. {
  901. // Given
  902. $int1 = new ArbitraryInteger($int1);
  903. $int2 = new ArbitraryInteger($int2);
  904. // When
  905. $lessThan = $int1->lessThan($int2);
  906. // Then
  907. $this->assertTrue($lessThan);
  908. }
  909. /**
  910. * @test not lessThan
  911. * @dataProvider dataProviderForGreaterThan
  912. * @param string $int1
  913. * @param string $int2
  914. * @throws \Exception
  915. */
  916. public function testNotLessThan(string $int1, string $int2)
  917. {
  918. // Given
  919. $int1 = new ArbitraryInteger($int1);
  920. $int2 = new ArbitraryInteger($int2);
  921. // When
  922. $lessThan = $int1->lessThan($int2);
  923. // Then
  924. $this->assertFalse($lessThan);
  925. }
  926. /**
  927. * @test equals
  928. * @dataProvider dataProviderForIntToString
  929. * @dataProvider dataProviderForStringIntToString
  930. * @dataProvider dataProviderForBinaryToString
  931. * @dataProvider dataProviderForHexToString
  932. * @dataProvider dataProviderForOctalToString
  933. * @param mixed $int
  934. * @throws \Exception
  935. */
  936. public function testEquals($int)
  937. {
  938. // Given
  939. $obj = new ArbitraryInteger($int);
  940. // When
  941. $equals = $obj->equals($obj);
  942. // Then
  943. $this->assertTrue($equals);
  944. }
  945. /**
  946. * @test not equals
  947. * @dataProvider dataProviderForIntToString
  948. * @dataProvider dataProviderForStringIntToString
  949. * @dataProvider dataProviderForBinaryToString
  950. * @dataProvider dataProviderForHexToString
  951. * @dataProvider dataProviderForOctalToString
  952. * @param mixed $int
  953. * @throws \Exception
  954. */
  955. public function testNotEquals($int)
  956. {
  957. // Given
  958. $obj1 = new ArbitraryInteger($int);
  959. $obj2 = $obj1->add(1);
  960. // When
  961. $equals = $obj1->equals($obj2);
  962. // Then
  963. $this->assertFalse($equals);
  964. }
  965. /**
  966. * @test Constructor throws an exception when given an empty string
  967. * @throws \Exception
  968. */
  969. public function testEmptyStringException()
  970. {
  971. // Given
  972. $number = '';
  973. // Then
  974. $this->expectException(Exception\BadParameterException::class);
  975. // When
  976. $int = new ArbitraryInteger($number);
  977. }
  978. /**
  979. * @test Constructor throws an exception when given a float
  980. * @dataProvider dataProviderForTestIncorrectTypeException
  981. * @param mixed $number
  982. * @throws \Exception
  983. */
  984. public function testIncorrectTypeException($number)
  985. {
  986. // Then
  987. $this->expectException(Exception\IncorrectTypeException::class);
  988. // When
  989. $int = new ArbitraryInteger($number);
  990. }
  991. public function dataProviderForTestIncorrectTypeException(): array
  992. {
  993. return [
  994. 'float' => [3.14],
  995. 'array' => [['123', '456']],
  996. 'bool' => [true],
  997. 'object' => [new \stdClass()],
  998. ];
  999. }
  1000. /**
  1001. * @test prepareParameter throws an exception when an object is provided
  1002. * @throws \Exception
  1003. */
  1004. public function testIncorrectTypeExceptionPrepareParameter()
  1005. {
  1006. // Given
  1007. $number = new ArbitraryInteger(0);
  1008. $class = new \stdClass();
  1009. // Then
  1010. $this->expectException(Exception\IncorrectTypeException::class);
  1011. // When
  1012. $int = $number->add($class);
  1013. }
  1014. /**
  1015. * @test pow throws an exception when exponent is negative and int is large.
  1016. * @throws \Exception
  1017. */
  1018. public function testPowException()
  1019. {
  1020. // Given
  1021. $int = new ArbitraryInteger(\PHP_INT_MAX);
  1022. // Then
  1023. $this->expectException(Exception\OutOfBoundsException::class);
  1024. // When
  1025. $pow = $int->add(1)->pow(-1);
  1026. }
  1027. }