BigInteger.php 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. <?php
  2. /*
  3. * This file is part of the PHPASN1 library.
  4. *
  5. * For the full copyright and license information, please view the LICENSE
  6. * file that was distributed with this source code.
  7. */
  8. namespace FG\Utility;
  9. /**
  10. * Class BigInteger
  11. * Utility class to remove dependence on a single large number library. Not intended for external use, this class only
  12. * implements the functionality needed throughout this project.
  13. *
  14. * Instances are immutable, all operations return a new instance with the result.
  15. *
  16. * @package FG\Utility
  17. * @internal
  18. */
  19. abstract class BigInteger
  20. {
  21. /**
  22. * Force a preference on the underlying big number implementation, useful for testing.
  23. * @var string|null
  24. */
  25. private static $_prefer;
  26. public static function setPrefer($prefer = null)
  27. {
  28. self::$_prefer = $prefer;
  29. }
  30. /**
  31. * Create a BigInteger instance based off the base 10 string or an integer.
  32. * @param string|int $val
  33. * @return BigInteger
  34. * @throws \InvalidArgumentException
  35. */
  36. public static function create($val)
  37. {
  38. if (self::$_prefer) {
  39. switch (self::$_prefer) {
  40. case 'gmp':
  41. $ret = new BigIntegerGmp();
  42. break;
  43. case 'bcmath':
  44. $ret = new BigIntegerBcmath();
  45. break;
  46. default:
  47. throw new \UnexpectedValueException('Unknown number implementation: ' . self::$_prefer);
  48. }
  49. }
  50. else {
  51. // autodetect
  52. if (function_exists('gmp_add')) {
  53. $ret = new BigIntegerGmp();
  54. }
  55. elseif (function_exists('bcadd')) {
  56. $ret = new BigIntegerBcmath();
  57. } else {
  58. throw new \RuntimeException('Requires GMP or bcmath extension.');
  59. }
  60. }
  61. if (is_int($val)) {
  62. $ret->_fromInteger($val);
  63. }
  64. else {
  65. // convert to string, if not already one
  66. $val = (string)$val;
  67. // validate string
  68. if (!preg_match('/^-?[0-9]+$/', $val)) {
  69. throw new \InvalidArgumentException('Expects a string representation of an integer.');
  70. }
  71. $ret->_fromString($val);
  72. }
  73. return $ret;
  74. }
  75. /**
  76. * BigInteger constructor.
  77. * Prevent directly instantiating object, use BigInteger::create instead.
  78. */
  79. protected function __construct()
  80. {
  81. }
  82. /**
  83. * Subclasses must provide clone functionality.
  84. * @return BigInteger
  85. */
  86. abstract public function __clone();
  87. /**
  88. * Assign the instance value from base 10 string.
  89. * @param string $str
  90. */
  91. abstract protected function _fromString($str);
  92. /**
  93. * Assign the instance value from an integer type.
  94. * @param int $integer
  95. */
  96. abstract protected function _fromInteger($integer);
  97. /**
  98. * Must provide string implementation that returns base 10 number.
  99. * @return string
  100. */
  101. abstract public function __toString();
  102. /* INFORMATIONAL FUNCTIONS */
  103. /**
  104. * Return integer, if possible. Throws an exception if the number can not be represented as a native integer.
  105. * @return int
  106. * @throws \OverflowException
  107. */
  108. abstract public function toInteger();
  109. /**
  110. * Is represented integer negative?
  111. * @return bool
  112. */
  113. abstract public function isNegative();
  114. /**
  115. * Compare the integer with $number, returns a negative integer if $this is less than number, returns 0 if $this is
  116. * equal to number and returns a positive integer if $this is greater than number.
  117. * @param BigInteger|string|int $number
  118. * @return int
  119. */
  120. abstract public function compare($number);
  121. /* MODIFY */
  122. /**
  123. * Add another integer $b and returns the result.
  124. * @param BigInteger|string|int $b
  125. * @return BigInteger
  126. */
  127. abstract public function add($b);
  128. /**
  129. * Subtract $b from $this and returns the result.
  130. * @param BigInteger|string|int $b
  131. * @return BigInteger
  132. */
  133. abstract public function subtract($b);
  134. /**
  135. * Multiply value.
  136. * @param BigInteger|string|int $b
  137. * @return BigInteger
  138. */
  139. abstract public function multiply($b);
  140. /**
  141. * The value $this modulus $b.
  142. * @param BigInteger|string|int $b
  143. * @return BigInteger
  144. */
  145. abstract public function modulus($b);
  146. /**
  147. * Raise $this to the power of $b and returns the result.
  148. * @param BigInteger|string|int $b
  149. * @return BigInteger
  150. */
  151. abstract public function toPower($b);
  152. /**
  153. * Shift the value to the right by a set number of bits and returns the result.
  154. * @param int $bits
  155. * @return BigInteger
  156. */
  157. abstract public function shiftRight($bits = 8);
  158. /**
  159. * Shift the value to the left by a set number of bits and returns the result.
  160. * @param int $bits
  161. * @return BigInteger
  162. */
  163. abstract public function shiftLeft($bits = 8);
  164. /**
  165. * Returns the absolute value.
  166. * @return BigInteger
  167. */
  168. abstract public function absoluteValue();
  169. }