Arithmetic.php 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. <?php
  2. namespace MathPHP;
  3. use MathPHP\Exception\BadParameterException;
  4. class Arithmetic
  5. {
  6. /**
  7. * Calculate any nᵗʰ root of a value: ⁿ√x
  8. * Equivalent to x¹/ⁿ
  9. *
  10. * nᵗʰ root of a number x is a number r which, when raised to the power n yields x:
  11. *
  12. * Use the the PHP pow function if it is an even root or if $x is positive.
  13. * If $x is negative and it is an odd root, we can extend the native function.
  14. *
  15. * @param float $x value to find the root of
  16. * @param int $nᵗʰ root (magnitude of the root - 2 for square root, 3 for cube root, etc.)
  17. *
  18. * @return float
  19. */
  20. public static function root(float $x, int $nᵗʰ): float
  21. {
  22. if ($x >= 0 || $nᵗʰ % 2 === 0) {
  23. return \pow($x, 1 / $nᵗʰ);
  24. }
  25. return - \pow(\abs($x), 1 / $nᵗʰ);
  26. }
  27. /**
  28. * Cube root ³√x
  29. * This function is necessary because pow($x, 1/3) returns NAN for negative values.
  30. * PHP does not have the cbrt built-in function.
  31. *
  32. * @param float $x
  33. *
  34. * @return float
  35. */
  36. public static function cubeRoot(float $x): float
  37. {
  38. return self::root($x, 3);
  39. }
  40. /**
  41. * Integer square root |_√x_|
  42. * The positive integer which is the greatest integer less than or equal to the square root
  43. * https://en.wikipedia.org/wiki/Integer_square_root
  44. *
  45. * @param float $x
  46. *
  47. * @return int
  48. *
  49. * @throws BadParameterException
  50. */
  51. public static function isqrt(float $x): int
  52. {
  53. if ($x < 0) {
  54. throw new Exception\BadParameterException("x must be non-negative for isqrt - got $x");
  55. }
  56. return (int)\floor(\sqrt($x));
  57. }
  58. /**
  59. * Digit sum
  60. * Sum of all an integer's digits.
  61. * https://en.wikipedia.org/wiki/Digit_sum
  62. *
  63. * log x 1
  64. * ∑ -- (x mod bⁿ⁺¹ - x mod bⁿ)
  65. * ⁿ⁼⁰ bⁿ
  66. *
  67. * Example (base 10): 5031 = 5 + 0 + 3 + 1 = 9
  68. * Example (base 2): 0b1010 = 1 + 0 + 1 + 0 = 2
  69. *
  70. * @param int $x
  71. * @param int $b Base (Default is base 10)
  72. *
  73. * @return int
  74. */
  75. public static function digitSum(int $x, int $b = 10): int
  76. {
  77. $logx = \log($x, $b);
  78. $∑1/bⁿ⟮x mod bⁿ⁺¹ − x mod bⁿ⟯ = 0;
  79. for ($n = 0; $n <= $logx; $n++) {
  80. $∑1/bⁿ⟮x mod bⁿ⁺¹ − x mod bⁿ⟯ += \intdiv(($x % \pow($b, $n + 1)) - ($x % $b ** $n), ($b ** $n));
  81. }
  82. return $∑1/bⁿ⟮x mod bⁿ⁺¹ − x mod bⁿ⟯;
  83. }
  84. /**
  85. * Digital root (iterated digit sum, repeated digital sum)
  86. * The single digit value obtained by an iterative process of summing digits,
  87. * on each iteration using the result from the previous iteration to compute a digit sum.
  88. * The process continues until a single-digit number is reached.
  89. * https://en.wikipedia.org/wiki/Digital_root
  90. *
  91. * Example: 65,536 is 7, because 6 + 5 + 5 + 3 + 6 = 25 and 2 + 5 = 7
  92. *
  93. * @param int $x
  94. *
  95. * @return int
  96. */
  97. public static function digitalRoot(int $x): int
  98. {
  99. $root = $x;
  100. while ($root >= 10) {
  101. $root = self::digitSum($root);
  102. }
  103. return $root;
  104. }
  105. /**
  106. * Test if two numbers are almost equal, within a tolerance ε
  107. *
  108. * @param float $x
  109. * @param float $y
  110. * @param float $ε tolerance
  111. *
  112. * @return bool true if the numbers are equal within a tolerance; false if they are not
  113. */
  114. public static function almostEqual(float $x, float $y, $ε = 0.000000000001): bool
  115. {
  116. return \abs($x - $y) <= $ε;
  117. }
  118. /**
  119. * Returns the magnitude value with the sign of the sign number
  120. *
  121. * @param float $magnitude
  122. * @param float $sign
  123. *
  124. * @return float $magnitude with the sign of $sign
  125. */
  126. public static function copySign(float $magnitude, float $sign): float
  127. {
  128. return $sign >= 0
  129. ? \abs($magnitude)
  130. : -\abs($magnitude);
  131. }
  132. /**
  133. * Modulo (Binary operation)
  134. *
  135. * Modulo is different from the remainder function.
  136. * The PHP % operator is the remainder function, where the result has the same sign as the dividend.
  137. * The mod function's result has the same sign as the divisor.
  138. *
  139. * For positive dividends and divisors, the modulo function is the same as the remainder (%) operator.
  140. * For negative dividends or divisors, the modulo function has different behavior than the remainder (%) operator.
  141. *
  142. * a mod n
  143. * a - n ⌊a/n⌋ for n ≠ 0
  144. * a for n = 0
  145. * where
  146. * a is the dividend (integer)
  147. * n is the divisor, also known as the modulus (integer)
  148. * ⌊⌋ is the floor function
  149. *
  150. * https://en.wikipedia.org/wiki/Modulo_operation
  151. * https://en.wikipedia.org/wiki/Modulo_(mathematics)
  152. * Knuth, Donald. E. (1972). The Art of Computer Programming. Volume 1 Fundamental Algorithms. Addison-Wesley.
  153. * Graham, Knuth, Patashnik (1994). Concrete Mathematics, A Foundation For Computer Science. Addison-Wesley.
  154. *
  155. * @param int $a dividend
  156. * @param int $n divisor, also known as the modulus
  157. *
  158. * @return int
  159. */
  160. public static function modulo(int $a, int $n): int
  161. {
  162. if ($n === 0) {
  163. return $a;
  164. }
  165. return (int)($a - $n * \floor($a / $n));
  166. }
  167. }