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 * Bcmath extension adapter
17 class Bcmath
implements AdapterInterface
21 * Sets Bcmath scale factor to zero
23 public function __construct()
29 * Create string representing big integer in decimal form from arbitrary integer format
31 * @param string $operand
32 * @param int|null $base
35 public function init($operand, $base = null)
37 $sign = (strpos($operand, '-') === 0) ?
'-' : '';
38 $operand = ltrim($operand, '-+');
42 if (preg_match('#^([1-9][0-9]*)$#', $operand, $m)) {
46 } elseif (preg_match('#^(0[0-7]+)$#', $operand, $m)) {
50 } elseif (preg_match('#^(?:0x)?([0-9a-f]+)$#', strtolower($operand), $m)) {
53 // scientific notation
54 } elseif (preg_match('#^([1-9]?\.?[0-9]+)[eE]\+?([0-9]+)$#', $operand, $m)) {
56 $operand = bcmul($m[1], bcpow('10', $m[2]));
63 $operand = $this->baseConvert($operand, $base, 10);
66 $prod = bcmul($operand, '1');
67 if (bccomp($operand, $prod) !== 0) {
71 return $sign . $operand;
75 * Add two big integers
77 * @param string $leftOperand
78 * @param string $rightOperand
81 public function add($leftOperand, $rightOperand)
83 return bcadd($leftOperand, $rightOperand);
87 * Subtract two big integers
89 * @param string $leftOperand
90 * @param string $rightOperand
93 public function sub($leftOperand, $rightOperand)
95 return bcsub($leftOperand, $rightOperand);
99 * Multiply two big integers
101 * @param string $leftOperand
102 * @param string $rightOperand
105 public function mul($leftOperand, $rightOperand)
107 return bcmul($leftOperand, $rightOperand);
111 * Divide two big integers and return integer part result.
112 * Raises exception if the divisor is zero.
114 * @param string $leftOperand
115 * @param string $rightOperand
117 * @throws Exception\DivisionByZeroException
119 public function div($leftOperand, $rightOperand)
121 if ($rightOperand == 0) {
122 throw new Exception\
DivisionByZeroException(
123 "Division by zero; divisor = {$rightOperand}"
127 $result = bcdiv($leftOperand, $rightOperand);
133 * Raise a big integers to another
135 * @param string $operand
139 public function pow($operand, $exp)
141 return bcpow($operand, $exp);
145 * Get the square root of a big integer
147 * @param string $operand
150 public function sqrt($operand)
152 return bcsqrt($operand);
156 * Get absolute value of a big integer
158 * @param string $operand
161 public function abs($operand)
163 return ltrim($operand, '-');
167 * Get modulus of a big integer
169 * @param string $leftOperand
170 * @param string $rightOperand
173 public function mod($leftOperand, $rightOperand)
175 return bcmod($leftOperand, $rightOperand);
179 * Raise a big integer to another, reduced by a specified modulus
181 * @param string $leftOperand
182 * @param string $rightOperand
183 * @param string $modulus
186 public function powmod($leftOperand, $rightOperand, $modulus)
188 return bcpowmod($leftOperand, $rightOperand, $modulus);
192 * Compare two big integers and returns result as an integer where
193 * Returns < 0 if leftOperand is less than rightOperand;
194 * > 0 if leftOperand is greater than rightOperand, and 0 if they are equal.
196 * @param string $leftOperand
197 * @param string $rightOperand
200 public function comp($leftOperand, $rightOperand)
202 return bccomp($leftOperand, $rightOperand);
206 * Convert big integer into it's binary number representation
208 * @param string $operand
209 * @param bool $twoc return in two's complement form
212 public function intToBin($operand, $twoc = false)
215 $isNegative = (strpos($operand, '-') === 0) ?
true : false;
216 $operand = ltrim($operand, '+-0');
218 if (empty($operand)) {
222 if ($isNegative && $twoc) {
223 $operand = bcsub($operand, '1');
227 while (bccomp($operand, '0', 0) > 0) {
228 $temp = bcmod($operand, '16777216');
229 $bytes = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $bytes;
230 $operand = bcdiv($operand, '16777216');
232 $bytes = ltrim($bytes, $nb);
235 if (ord($bytes[0]) & 0x80) {
236 $bytes = $nb . $bytes;
238 return $isNegative ? ~
$bytes : $bytes;
245 * Convert big integer into it's binary number representation
247 * @param string $bytes
248 * @param bool $twoc whether binary number is in twos' complement form
251 public function binToInt($bytes, $twoc = false)
253 $isNegative = ((ord($bytes[0]) & 0x80) && $twoc);
259 $len = (strlen($bytes) +
3) & 0xfffffffc;
260 $bytes = str_pad($bytes, $len, chr(0), STR_PAD_LEFT
);
263 for ($i = 0; $i < $len; $i +
= 4) {
264 $result = bcmul($result, '4294967296'); // 2**32
265 $result = bcadd($result, 0x1000000 * ord($bytes[$i]) +
266 ((ord($bytes[$i +
1]) << 16) |
267 (ord($bytes[$i +
2]) << 8) |
268 ord($bytes[$i +
3])));
272 $result = bcsub('-' . $result, '1');
279 * Base conversion. Bases 2..62 are supported
281 * @param string $operand
282 * @param int $fromBase
285 * @throws Exception\InvalidArgumentException
287 public function baseConvert($operand, $fromBase, $toBase = 10)
289 if ($fromBase == $toBase) {
293 if ($fromBase < 2 ||
$fromBase > 62) {
294 throw new Exception\
InvalidArgumentException(
295 "Unsupported base: {$fromBase}, should be 2..62"
298 if ($toBase < 2 ||
$toBase > 62) {
299 throw new Exception\
InvalidArgumentException(
300 "Unsupported base: {$toBase}, should be 2..62"
304 $sign = (strpos($operand, '-') === 0) ?
'-' : '';
305 $operand = ltrim($operand, '-+');
307 $chars = self
::BASE62_ALPHABET
;
309 // convert to decimal
310 if ($fromBase == 10) {
314 for ($i = 0, $len = strlen($operand); $i < $len; $i++
) {
315 $decimal = bcmul($decimal, $fromBase);
316 $decimal = bcadd($decimal, strpos($chars, $operand[$i]));
324 // convert decimal to base
327 $remainder = bcmod($decimal, $toBase);
328 $decimal = bcdiv($decimal, $toBase);
329 $result = $chars[$remainder] . $result;
330 } while (bccomp($decimal, '0'));
332 return $sign . $result;