ArithmeticAxiomsTest.php 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. <?php
  2. namespace MathPHP\Tests\Arithmetic;
  3. use MathPHP\Arithmetic;
  4. /**
  5. * Tests of arithmetic axioms
  6. * These tests don't test specific functions,
  7. * but rather arithmetic axioms which in term make use of multiple functions.
  8. * If all the arithmetic math is implemented properly, these tests should
  9. * all work out according to the axioms.
  10. *
  11. * Axioms tested:
  12. * - Digital root
  13. * - dr(n) = n ⇔ n ∈ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
  14. * - dr(n) < n ⇔ n ≥ 10
  15. * - dr(a+b) = dr(dr(a) + dr(b))
  16. * - dr(a×b) = dr(dr(a) × dr(b))
  17. * - dr(n) = 0 ⇔ n = 9m for m = 1, 2, 3 ⋯
  18. * - Modulo
  19. * - Identity: (a mod n) mod n = a mod n
  20. * - Identity: nˣ mod n = 0 for all positive integer values of x
  21. * - Inverse: [(−a mod n) + (a mod n)] mod n = 0
  22. * - Distributive: (a + b) mod n = [(a mod n) + (b mod n)] mod n
  23. * - Distributive: ab mod n = [(a mod n)(b mod n)] mod n
  24. * - Distributive: c(x mod y) = (cx) mod (cy)
  25. */
  26. class ArithmeticAxiomsTest extends \PHPUnit\Framework\TestCase
  27. {
  28. /**
  29. * @test Axiom: dr(n) = n ⇔ n ∈ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
  30. * The digital root of n is n itself if and only if the number has exactly one digit.
  31. */
  32. public function testDigitalRootEqualsN()
  33. {
  34. // Given
  35. for ($n = 0; $n < 10; $n++) {
  36. // When
  37. $digitalRoot = Arithmetic::digitalRoot($n);
  38. // Then
  39. $this->assertEquals($n, $digitalRoot);
  40. }
  41. }
  42. /**
  43. * @test Axiom: dr(n) < n ⇔ n ≥ 10
  44. * The digital root of n is less than n if and only if the number is greater than or equal to 10.
  45. */
  46. public function testDigitalRootLessThanN()
  47. {
  48. // Given
  49. for ($n = 10; $n <= 100; $n++) {
  50. // When
  51. $digitalRoot = Arithmetic::digitalRoot($n);
  52. // Then
  53. $this->assertLessThan($n, $digitalRoot);
  54. }
  55. }
  56. /**
  57. * @test Axiom: dr(a+b) = dr(dr(a) + dr(b))
  58. * The digital root of a + b is digital root of the sum of the digital root of a and the digital root of b.
  59. * @dataProvider dataProviderDigitalRootArithmetic
  60. * @param int $a
  61. * @param int $b
  62. */
  63. public function testDigitalRootAddition(int $a, int $b)
  64. {
  65. // When
  66. $dr⟮a+b⟯ = Arithmetic::digitalRoot($a + $b);
  67. $dr⟮dr⟮a⟯+dr⟮b⟯⟯ = Arithmetic::digitalRoot(Arithmetic::digitalRoot($a) + Arithmetic::digitalRoot($b));
  68. // Then
  69. $this->assertEquals($dr⟮a+b⟯, $dr⟮dr⟮a⟯+dr⟮b⟯⟯);
  70. }
  71. /**
  72. * @test Axiom: dr(a×b) = dr(dr(a) × dr(b))
  73. * The digital root of a × b is digital root of the product of the digital root of a and the digital root of b.
  74. * @dataProvider dataProviderDigitalRootArithmetic
  75. * @param int $a
  76. * @param int $b
  77. */
  78. public function testDigitalRootProduct(int $a, int $b)
  79. {
  80. // When
  81. $dr⟮ab⟯ = Arithmetic::digitalRoot($a * $b);
  82. $dr⟮dr⟮a⟯×dr⟮b⟯⟯ = Arithmetic::digitalRoot(Arithmetic::digitalRoot($a) * Arithmetic::digitalRoot($b));
  83. // Then
  84. $this->assertEquals($dr⟮ab⟯, $dr⟮dr⟮a⟯×dr⟮b⟯⟯);
  85. }
  86. /**
  87. * @return array
  88. */
  89. public function dataProviderDigitalRootArithmetic(): array
  90. {
  91. return [
  92. [0, 0],
  93. [1, 0],
  94. [0, 1],
  95. [1, 1],
  96. [1, 2],
  97. [2, 2],
  98. [5, 4],
  99. [16, 42],
  100. [10, 10],
  101. [8041, 2301],
  102. [241, 325],
  103. [48, 332],
  104. [89, 404804],
  105. [12345, 67890],
  106. [405, 3],
  107. [0, 34434],
  108. [398792873, 2059872903],
  109. ];
  110. }
  111. /**
  112. * @test Axiom: dr(n) = 0 ⇔ n = 9m for m = 1, 2, 3 ⋯
  113. * The digital root of a nonzero number is 9 if and only if the number is itself a multiple of 9.
  114. */
  115. public function testDigitalRootMultipleOfNine()
  116. {
  117. // Given
  118. for ($n = 9; $n <= 900; $n += 9) {
  119. // When
  120. $digitalRoot = Arithmetic::digitalRoot($n);
  121. // Then
  122. $this->assertEquals(9, $digitalRoot);
  123. }
  124. }
  125. /**
  126. * @test Axiom Identity: (a mod n) mod n = a mod n
  127. * https://en.wikipedia.org/wiki/Modulo_operation#Properties_(identities)
  128. */
  129. public function testModuloIdentity()
  130. {
  131. // Given
  132. foreach (\range(-20, 20) as $a) {
  133. foreach (\range(-20, 20) as $n) {
  134. // When
  135. $⟮a mod n⟯ mod n = Arithmetic::modulo(Arithmetic::modulo($a, $n), $n);
  136. $a mod n = Arithmetic::modulo($a, $n);
  137. // Then
  138. $this->assertEquals($⟮a mod n⟯ mod n, $a mod n);
  139. }
  140. }
  141. }
  142. /**
  143. * @test Axiom Identity: nˣ mod n = 0 for all positive integer values of x
  144. * https://en.wikipedia.org/wiki/Modulo_operation#Properties_(identities)
  145. */
  146. public function testModuloIdentityOfPowers()
  147. {
  148. foreach (\range(-20, 20) as $n) {
  149. foreach (\range(1, 5) as $ˣ) {
  150. // Given
  151. $nˣ = $n ** $ˣ;
  152. // When
  153. $nˣ mod n = Arithmetic::modulo($nˣ, $n);
  154. // Then
  155. $this->assertEquals(0, $nˣ mod n);
  156. }
  157. }
  158. }
  159. /**
  160. * @test Axiom Inverse: [(−a mod n) + (a mod n)] mod n = 0
  161. * https://en.wikipedia.org/wiki/Modulo_operation#Properties_(identities)
  162. */
  163. public function testModuloInverse()
  164. {
  165. // Given
  166. foreach (\range(-20, 20) as $a) {
  167. foreach (\range(-20, 20) as $n) {
  168. // When
  169. $⟦⟮−a mod n⟯ + ⟮a mod n⟯⟧ mod n = Arithmetic::modulo(
  170. Arithmetic::modulo(-$a, $n) + Arithmetic::modulo($a, $n),
  171. $n
  172. );
  173. // Then
  174. $this->assertEquals(0, $⟦⟮−a mod n⟯ + ⟮a mod n⟯⟧ mod n);
  175. }
  176. }
  177. }
  178. /**
  179. * @test Axiom Distributive: (a + b) mod n = [(a mod n) + (b mod n)] mod n
  180. * https://en.wikipedia.org/wiki/Modulo_operation#Properties_(identities)
  181. */
  182. public function testModuloDistributiveAdditionProperty()
  183. {
  184. // Given
  185. foreach (\range(-5, 5) as $a) {
  186. foreach (\range(-5, 5) as $b) {
  187. foreach (\range(-6, 6) as $n) {
  188. // When
  189. $⟮a + b⟯ mod n = Arithmetic::modulo($a + $b, $n);
  190. $⟦⟮a mod n⟯ + ⟮b mod n⟧⟯ mod n = Arithmetic::modulo(
  191. Arithmetic::modulo($a, $n) + Arithmetic::modulo($b, $n),
  192. $n
  193. );
  194. // Then
  195. $this->assertEquals($⟮a + b⟯ mod n, $⟦⟮a mod n⟯ + ⟮b mod n⟧⟯ mod n);
  196. }
  197. }
  198. }
  199. }
  200. /**
  201. * @test Axiom Distributive: ab mod n = [(a mod n)(b mod n)] mod n
  202. * https://en.wikipedia.org/wiki/Modulo_operation#Properties_(identities)
  203. */
  204. public function testModuloDistributiveMultiplicationProperty()
  205. {
  206. // Given
  207. foreach (\range(-5, 5) as $a) {
  208. foreach (\range(-5, 5) as $b) {
  209. foreach (\range(-6, 6) as $n) {
  210. // When
  211. $ab mod n = Arithmetic::modulo($a * $b, $n);
  212. $⟦⟮a mod n⟯⟮b mod n⟧⟯ mod n = Arithmetic::modulo(
  213. Arithmetic::modulo($a, $n) * Arithmetic::modulo($b, $n),
  214. $n
  215. );
  216. // Then
  217. $this->assertEquals($ab mod n, $⟦⟮a mod n⟯⟮b mod n⟧⟯ mod n);
  218. }
  219. }
  220. }
  221. }
  222. /**
  223. * @test Axiom Distributive: c(x mod y) = (cx) mod (cy)
  224. * Graham, Knuth, Patashnik (1994). Concrete Mathematics, A Foundation For Computer Science. Addison-Wesley.
  225. */
  226. public function testModuloDistributiveLaw()
  227. {
  228. // Given
  229. foreach (\range(-5, 5) as $x) {
  230. foreach (\range(-5, 5) as $y) {
  231. foreach (\range(-6, 6) as $c) {
  232. // When
  233. $c⟮x mod y⟯ = $c * Arithmetic::modulo($x, $y);
  234. $⟮cx⟯ mod ⟮cy⟯ = Arithmetic::modulo($c * $x, $c * $y);
  235. // Then
  236. $this->assertEquals($c⟮x mod y⟯, $⟮cx⟯ mod ⟮cy⟯);
  237. }
  238. }
  239. }
  240. }
  241. }