3 * Zend Framework (http://framework.zend.com/)
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
10 namespace Zend\Math\BigInteger\Adapter
;
12 use Zend\Math\BigInteger\Exception
;
15 * GMP extension adapter
17 class Gmp
implements AdapterInterface
20 * Create string representing big integer in decimal form from arbitrary integer format
22 * @param string $operand
23 * @param int|null $base
26 public function init($operand, $base = null)
28 $sign = (strpos($operand, '-') === 0) ?
'-' : '';
29 $operand = ltrim($operand, '-+');
32 // scientific notation
33 if (preg_match('#^(?:([1-9])\.)?([0-9]+)[eE]\+?([0-9]+)$#', $operand, $m)) {
35 if ($m[3] < strlen($m[2])) {
41 $operand = str_pad(($m[1] . $m[2]), ($m[3] +
1), '0', STR_PAD_RIGHT
);
48 $res = gmp_init($sign . $operand, $base);
53 return gmp_strval($res);
57 * Add two big integers
59 * @param string $leftOperand
60 * @param string $rightOperand
63 public function add($leftOperand, $rightOperand)
65 $result = gmp_add($leftOperand, $rightOperand);
66 return gmp_strval($result);
70 * Subtract two big integers
72 * @param string $leftOperand
73 * @param string $rightOperand
76 public function sub($leftOperand, $rightOperand)
78 $result = gmp_sub($leftOperand, $rightOperand);
79 return gmp_strval($result);
83 * Multiply two big integers
85 * @param string $leftOperand
86 * @param string $rightOperand
89 public function mul($leftOperand, $rightOperand)
91 $result = gmp_mul($leftOperand, $rightOperand);
92 return gmp_strval($result);
96 * Divide two big integers and return integer part result.
97 * Raises exception if the divisor is zero.
99 * @param string $leftOperand
100 * @param string $rightOperand
101 * @return string|null
102 * @throws Exception\DivisionByZeroException
104 public function div($leftOperand, $rightOperand)
106 if ($rightOperand == 0) {
107 throw new Exception\
DivisionByZeroException(
108 "Division by zero; divisor = {$rightOperand}"
112 $result = gmp_div_q($leftOperand, $rightOperand);
113 return gmp_strval($result);
117 * Raise a big integers to another
119 * @param string $operand
123 public function pow($operand, $exp)
125 $result = gmp_pow($operand, $exp);
126 return gmp_strval($result);
130 * Get the square root of a big integer
132 * @param string $operand
135 public function sqrt($operand)
137 $result = gmp_sqrt($operand);
138 return gmp_strval($result);
142 * Get absolute value of a big integer
144 * @param string $operand
147 public function abs($operand)
149 $result = gmp_abs($operand);
150 return gmp_strval($result);
154 * Get modulus of a big integer
156 * @param string $leftOperand
157 * @param string $modulus
160 public function mod($leftOperand, $modulus)
162 $result = gmp_mod($leftOperand, $modulus);
163 return gmp_strval($result);
167 * Raise a big integer to another, reduced by a specified modulus
169 * @param string $leftOperand
170 * @param string $rightOperand
171 * @param string $modulus
174 public function powmod($leftOperand, $rightOperand, $modulus)
176 $result = gmp_powm($leftOperand, $rightOperand, $modulus);
177 return gmp_strval($result);
181 * Compare two big integers and returns result as an integer where
182 * Returns < 0 if leftOperand is less than rightOperand;
183 * > 0 if leftOperand is greater than rightOperand, and 0 if they are equal.
185 * @param string $leftOperand
186 * @param string $rightOperand
189 public function comp($leftOperand, $rightOperand)
191 return gmp_cmp($leftOperand, $rightOperand);
195 * Convert big integer into it's binary number representation
198 * @param bool $twoc return in twos' complement form
201 public function intToBin($int, $twoc = false)
204 $isNegative = (strpos($int, '-') === 0) ?
true : false;
205 $int = ltrim($int, '+-0');
211 if ($isNegative && $twoc) {
212 $int = gmp_sub($int, '1');
215 $hex = gmp_strval($int, 16);
216 if (strlen($hex) & 1) {
220 $bytes = pack('H*', $hex);
221 $bytes = ltrim($bytes, $nb);
224 if (ord($bytes[0]) & 0x80) {
225 $bytes = $nb . $bytes;
227 return $isNegative ? ~
$bytes : $bytes;
234 * Convert binary number into big integer
236 * @param string $bytes
237 * @param bool $twoc whether binary number is in twos' complement form
240 public function binToInt($bytes, $twoc = false)
242 $isNegative = ((ord($bytes[0]) & 0x80) && $twoc);
250 $result = gmp_init($sign . bin2hex($bytes), 16);
253 $result = gmp_sub($result, '1');
256 return gmp_strval($result);
260 * Base conversion. Bases 2..62 are supported
262 * @param string $operand
263 * @param int $fromBase
266 * @throws Exception\InvalidArgumentException
268 public function baseConvert($operand, $fromBase, $toBase = 10)
270 if ($fromBase == $toBase) {
274 if ($fromBase < 2 ||
$fromBase > 62) {
275 throw new Exception\
InvalidArgumentException(
276 "Unsupported base: {$fromBase}, should be 2..62"
279 if ($toBase < 2 ||
$toBase > 62) {
280 throw new Exception\
InvalidArgumentException(
281 "Unsupported base: {$toBase}, should be 2..62"
285 if ($fromBase <= 36 && $toBase <= 36) {
286 return gmp_strval(gmp_init($operand, $fromBase), $toBase);
289 $sign = (strpos($operand, '-') === 0) ?
'-' : '';
290 $operand = ltrim($operand, '-+');
292 $chars = self
::BASE62_ALPHABET
;
294 // convert operand to decimal
295 if ($fromBase !== 10) {
297 for ($i = 0, $len = strlen($operand); $i < $len; $i++
) {
298 $decimal = gmp_mul($decimal, $fromBase);
299 $decimal = gmp_add($decimal, strpos($chars, $operand[$i]));
302 $decimal = gmp_init($operand);
306 return gmp_strval($decimal);
309 // convert decimal to base
312 list($decimal, $remainder) = gmp_div_qr($decimal, $toBase);
313 $pos = gmp_strval($remainder);
314 $result = $chars[$pos] . $result;
315 } while (gmp_cmp($decimal, '0'));
317 return $sign . $result;