PageRenderTime 64ms CodeModel.GetById 5ms app.highlight 46ms RepoModel.GetById 1ms app.codeStats 1ms

/fuel/core/vendor/phpseclib/Math/BigInteger.php

https://bitbucket.org/arkross/venus
PHP | 3547 lines | 1864 code | 467 blank | 1216 comment | 367 complexity | 3b41dc93206fc52b7bb37b8c57571624 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
   3
   4namespace PHPSecLib;
   5
   6/**
   7 * Pure-PHP arbitrary precision integer arithmetic library.
   8 *
   9 * Supports base-2, base-10, base-16, and base-256 numbers.  Uses the GMP or BCMath extensions, if available,
  10 * and an internal implementation, otherwise.
  11 *
  12 * PHP versions 4 and 5
  13 *
  14 * {@internal (all DocBlock comments regarding implementation - such as the one that follows - refer to the
  15 * {@link MATH_BIGINTEGER_MODE_INTERNAL MATH_BIGINTEGER_MODE_INTERNAL} mode)
  16 *
  17 * Math_BigInteger uses base-2**26 to perform operations such as multiplication and division and
  18 * base-2**52 (ie. two base 2**26 digits) to perform addition and subtraction.  Because the largest possible
  19 * value when multiplying two base-2**26 numbers together is a base-2**52 number, double precision floating
  20 * point numbers - numbers that should be supported on most hardware and whose significand is 53 bits - are
  21 * used.  As a consequence, bitwise operators such as >> and << cannot be used, nor can the modulo operator %,
  22 * which only supports integers.  Although this fact will slow this library down, the fact that such a high
  23 * base is being used should more than compensate.
  24 *
  25 * When PHP version 6 is officially released, we'll be able to use 64-bit integers.  This should, once again,
  26 * allow bitwise operators, and will increase the maximum possible base to 2**31 (or 2**62 for addition /
  27 * subtraction).
  28 *
  29 * Numbers are stored in {@link http://en.wikipedia.org/wiki/Endianness little endian} format.  ie.
  30 * (new Math_BigInteger(pow(2, 26)))->value = array(0, 1)
  31 *
  32 * Useful resources are as follows:
  33 *
  34 *  - {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf Handbook of Applied Cryptography (HAC)}
  35 *  - {@link http://math.libtomcrypt.com/files/tommath.pdf Multi-Precision Math (MPM)}
  36 *  - Java's BigInteger classes.  See /j2se/src/share/classes/java/math in jdk-1_5_0-src-jrl.zip
  37 *
  38 * Here's an example of how to use this library:
  39 * <code>
  40 * <?php
  41 *    include('Math/BigInteger.php');
  42 *
  43 *    $a = new Math_BigInteger(2);
  44 *    $b = new Math_BigInteger(3);
  45 *
  46 *    $c = $a->add($b);
  47 *
  48 *    echo $c->toString(); // outputs 5
  49 * ?>
  50 * </code>
  51 *
  52 * LICENSE: This library is free software; you can redistribute it and/or
  53 * modify it under the terms of the GNU Lesser General Public
  54 * License as published by the Free Software Foundation; either
  55 * version 2.1 of the License, or (at your option) any later version.
  56 *
  57 * This library is distributed in the hope that it will be useful,
  58 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  59 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  60 * Lesser General Public License for more details.
  61 *
  62 * You should have received a copy of the GNU Lesser General Public
  63 * License along with this library; if not, write to the Free Software
  64 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  65 * MA  02111-1307  USA
  66 *
  67 * @category   Math
  68 * @package    Math_BigInteger
  69 * @author     Jim Wigginton <terrafrost@php.net>
  70 * @copyright  MMVI Jim Wigginton
  71 * @license    http://www.gnu.org/licenses/lgpl.txt
  72 * @version    $Id: BigInteger.php,v 1.33 2010/03/22 22:32:03 terrafrost Exp $
  73 * @link       http://pear.php.net/package/Math_BigInteger
  74 */
  75
  76/**#@+
  77 * Reduction constants
  78 *
  79 * @access private
  80 * @see Math_BigInteger::_reduce()
  81 */
  82/**
  83 * @see Math_BigInteger::_montgomery()
  84 * @see Math_BigInteger::_prepMontgomery()
  85 */
  86define('MATH_BIGINTEGER_MONTGOMERY', 0);
  87/**
  88 * @see Math_BigInteger::_barrett()
  89 */
  90define('MATH_BIGINTEGER_BARRETT', 1);
  91/**
  92 * @see Math_BigInteger::_mod2()
  93 */
  94define('MATH_BIGINTEGER_POWEROF2', 2);
  95/**
  96 * @see Math_BigInteger::_remainder()
  97 */
  98define('MATH_BIGINTEGER_CLASSIC', 3);
  99/**
 100 * @see Math_BigInteger::__clone()
 101 */
 102define('MATH_BIGINTEGER_NONE', 4);
 103/**#@-*/
 104
 105/**#@+
 106 * Array constants
 107 *
 108 * Rather than create a thousands and thousands of new Math_BigInteger objects in repeated function calls to add() and
 109 * multiply() or whatever, we'll just work directly on arrays, taking them in as parameters and returning them.
 110 *
 111 * @access private
 112 */
 113/**
 114 * $result[MATH_BIGINTEGER_VALUE] contains the value.
 115 */
 116define('MATH_BIGINTEGER_VALUE', 0);
 117/**
 118 * $result[MATH_BIGINTEGER_SIGN] contains the sign.
 119 */
 120define('MATH_BIGINTEGER_SIGN', 1);
 121/**#@-*/
 122
 123/**#@+
 124 * @access private
 125 * @see Math_BigInteger::_montgomery()
 126 * @see Math_BigInteger::_barrett()
 127 */
 128/**
 129 * Cache constants
 130 *
 131 * $cache[MATH_BIGINTEGER_VARIABLE] tells us whether or not the cached data is still valid.
 132 */
 133define('MATH_BIGINTEGER_VARIABLE', 0);
 134/**
 135 * $cache[MATH_BIGINTEGER_DATA] contains the cached data.
 136 */
 137define('MATH_BIGINTEGER_DATA', 1);
 138/**#@-*/
 139
 140/**#@+
 141 * Mode constants.
 142 *
 143 * @access private
 144 * @see Math_BigInteger::Math_BigInteger()
 145 */
 146/**
 147 * To use the pure-PHP implementation
 148 */
 149define('MATH_BIGINTEGER_MODE_INTERNAL', 1);
 150/**
 151 * To use the BCMath library
 152 *
 153 * (if enabled; otherwise, the internal implementation will be used)
 154 */
 155define('MATH_BIGINTEGER_MODE_BCMATH', 2);
 156/**
 157 * To use the GMP library
 158 *
 159 * (if present; otherwise, either the BCMath or the internal implementation will be used)
 160 */
 161define('MATH_BIGINTEGER_MODE_GMP', 3);
 162/**#@-*/
 163
 164/**
 165 * The largest digit that may be used in addition / subtraction
 166 *
 167 * (we do pow(2, 52) instead of using 4503599627370496, directly, because some PHP installations
 168 *  will truncate 4503599627370496)
 169 *
 170 * @access private
 171 */
 172define('MATH_BIGINTEGER_MAX_DIGIT52', pow(2, 52));
 173
 174/**
 175 * Karatsuba Cutoff
 176 *
 177 * At what point do we switch between Karatsuba multiplication and schoolbook long multiplication?
 178 *
 179 * @access private
 180 */
 181define('MATH_BIGINTEGER_KARATSUBA_CUTOFF', 25);
 182
 183/**
 184 * Pure-PHP arbitrary precision integer arithmetic library. Supports base-2, base-10, base-16, and base-256
 185 * numbers.
 186 *
 187 * @author  Jim Wigginton <terrafrost@php.net>
 188 * @version 1.0.0RC4
 189 * @access  public
 190 * @package Math_BigInteger
 191 */
 192class Math_BigInteger {
 193    /**
 194     * Holds the BigInteger's value.
 195     *
 196     * @var Array
 197     * @access private
 198     */
 199    var $value;
 200
 201    /**
 202     * Holds the BigInteger's magnitude.
 203     *
 204     * @var Boolean
 205     * @access private
 206     */
 207    var $is_negative = false;
 208
 209    /**
 210     * Random number generator function
 211     *
 212     * @see setRandomGenerator()
 213     * @access private
 214     */
 215    var $generator = 'mt_rand';
 216
 217    /**
 218     * Precision
 219     *
 220     * @see setPrecision()
 221     * @access private
 222     */
 223    var $precision = -1;
 224
 225    /**
 226     * Precision Bitmask
 227     *
 228     * @see setPrecision()
 229     * @access private
 230     */
 231    var $bitmask = false;
 232
 233    /**
 234     * Mode independant value used for serialization.
 235     *
 236     * If the bcmath or gmp extensions are installed $this->value will be a non-serializable resource, hence the need for
 237     * a variable that'll be serializable regardless of whether or not extensions are being used.  Unlike $this->value,
 238     * however, $this->hex is only calculated when $this->__sleep() is called.
 239     *
 240     * @see __sleep()
 241     * @see __wakeup()
 242     * @var String
 243     * @access private
 244     */
 245    var $hex;
 246
 247    /**
 248     * Converts base-2, base-10, base-16, and binary strings (eg. base-256) to BigIntegers.
 249     *
 250     * If the second parameter - $base - is negative, then it will be assumed that the number's are encoded using
 251     * two's compliment.  The sole exception to this is -10, which is treated the same as 10 is.
 252     *
 253     * Here's an example:
 254     * <code>
 255     * <?php
 256     *    include('Math/BigInteger.php');
 257     *
 258     *    $a = new Math_BigInteger('0x32', 16); // 50 in base-16
 259     *
 260     *    echo $a->toString(); // outputs 50
 261     * ?>
 262     * </code>
 263     *
 264     * @param optional $x base-10 number or base-$base number if $base set.
 265     * @param optional integer $base
 266     * @return Math_BigInteger
 267     * @access public
 268     */
 269    function __construct($x = 0, $base = 10)
 270    {
 271        if ( !defined('MATH_BIGINTEGER_MODE') ) {
 272            switch (true) {
 273                case extension_loaded('gmp'):
 274                    define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_GMP);
 275                    break;
 276                case extension_loaded('bcmath'):
 277                    define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_BCMATH);
 278                    break;
 279                default:
 280                    define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_INTERNAL);
 281            }
 282        }
 283
 284        switch ( MATH_BIGINTEGER_MODE ) {
 285            case MATH_BIGINTEGER_MODE_GMP:
 286                if (is_resource($x) && get_resource_type($x) == 'GMP integer') {
 287                    $this->value = $x;
 288                    return;
 289                }
 290                $this->value = gmp_init(0);
 291                break;
 292            case MATH_BIGINTEGER_MODE_BCMATH:
 293                $this->value = '0';
 294                break;
 295            default:
 296                $this->value = array();
 297        }
 298
 299        if (empty($x)) {
 300            return;
 301        }
 302
 303        switch ($base) {
 304            case -256:
 305                if (ord($x[0]) & 0x80) {
 306                    $x = ~$x;
 307                    $this->is_negative = true;
 308                }
 309            case  256:
 310                switch ( MATH_BIGINTEGER_MODE ) {
 311                    case MATH_BIGINTEGER_MODE_GMP:
 312                        $sign = $this->is_negative ? '-' : '';
 313                        $this->value = gmp_init($sign . '0x' . bin2hex($x));
 314                        break;
 315                    case MATH_BIGINTEGER_MODE_BCMATH:
 316                        // round $len to the nearest 4 (thanks, DavidMJ!)
 317                        $len = (strlen($x) + 3) & 0xFFFFFFFC;
 318
 319                        $x = str_pad($x, $len, chr(0), STR_PAD_LEFT);
 320
 321                        for ($i = 0; $i < $len; $i+= 4) {
 322                            $this->value = bcmul($this->value, '4294967296', 0); // 4294967296 == 2**32
 323                            $this->value = bcadd($this->value, 0x1000000 * ord($x[$i]) + ((ord($x[$i + 1]) << 16) | (ord($x[$i + 2]) << 8) | ord($x[$i + 3])), 0);
 324                        }
 325
 326                        if ($this->is_negative) {
 327                            $this->value = '-' . $this->value;
 328                        }
 329
 330                        break;
 331                    // converts a base-2**8 (big endian / msb) number to base-2**26 (little endian / lsb)
 332                    default:
 333                        while (strlen($x)) {
 334                            $this->value[] = $this->_bytes2int($this->_base256_rshift($x, 26));
 335                        }
 336                }
 337
 338                if ($this->is_negative) {
 339                    if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) {
 340                        $this->is_negative = false;
 341                    }
 342                    $temp = $this->add(new Math_BigInteger('-1'));
 343                    $this->value = $temp->value;
 344                }
 345                break;
 346            case  16:
 347            case -16:
 348                if ($base > 0 && $x[0] == '-') {
 349                    $this->is_negative = true;
 350                    $x = substr($x, 1);
 351                }
 352
 353                $x = preg_replace('#^(?:0x)?([A-Fa-f0-9]*).*#', '$1', $x);
 354
 355                $is_negative = false;
 356                if ($base < 0 && hexdec($x[0]) >= 8) {
 357                    $this->is_negative = $is_negative = true;
 358                    $x = bin2hex(~pack('H*', $x));
 359                }
 360
 361                switch ( MATH_BIGINTEGER_MODE ) {
 362                    case MATH_BIGINTEGER_MODE_GMP:
 363                        $temp = $this->is_negative ? '-0x' . $x : '0x' . $x;
 364                        $this->value = gmp_init($temp);
 365                        $this->is_negative = false;
 366                        break;
 367                    case MATH_BIGINTEGER_MODE_BCMATH:
 368                        $x = ( strlen($x) & 1 ) ? '0' . $x : $x;
 369                        $temp = new Math_BigInteger(pack('H*', $x), 256);
 370                        $this->value = $this->is_negative ? '-' . $temp->value : $temp->value;
 371                        $this->is_negative = false;
 372                        break;
 373                    default:
 374                        $x = ( strlen($x) & 1 ) ? '0' . $x : $x;
 375                        $temp = new Math_BigInteger(pack('H*', $x), 256);
 376                        $this->value = $temp->value;
 377                }
 378
 379                if ($is_negative) {
 380                    $temp = $this->add(new Math_BigInteger('-1'));
 381                    $this->value = $temp->value;
 382                }
 383                break;
 384            case  10:
 385            case -10:
 386                $x = preg_replace('#^(-?[0-9]*).*#', '$1', $x);
 387
 388                switch ( MATH_BIGINTEGER_MODE ) {
 389                    case MATH_BIGINTEGER_MODE_GMP:
 390                        $this->value = gmp_init($x);
 391                        break;
 392                    case MATH_BIGINTEGER_MODE_BCMATH:
 393                        // explicitly casting $x to a string is necessary, here, since doing $x[0] on -1 yields different
 394                        // results then doing it on '-1' does (modInverse does $x[0])
 395                        $this->value = (string) $x;
 396                        break;
 397                    default:
 398                        $temp = new Math_BigInteger();
 399
 400                        // array(10000000) is 10**7 in base-2**26.  10**7 is the closest to 2**26 we can get without passing it.
 401                        $multiplier = new Math_BigInteger();
 402                        $multiplier->value = array(10000000);
 403
 404                        if ($x[0] == '-') {
 405                            $this->is_negative = true;
 406                            $x = substr($x, 1);
 407                        }
 408
 409                        $x = str_pad($x, strlen($x) + (6 * strlen($x)) % 7, 0, STR_PAD_LEFT);
 410
 411                        while (strlen($x)) {
 412                            $temp = $temp->multiply($multiplier);
 413                            $temp = $temp->add(new Math_BigInteger($this->_int2bytes(substr($x, 0, 7)), 256));
 414                            $x = substr($x, 7);
 415                        }
 416
 417                        $this->value = $temp->value;
 418                }
 419                break;
 420            case  2: // base-2 support originally implemented by Lluis Pamies - thanks!
 421            case -2:
 422                if ($base > 0 && $x[0] == '-') {
 423                    $this->is_negative = true;
 424                    $x = substr($x, 1);
 425                }
 426
 427                $x = preg_replace('#^([01]*).*#', '$1', $x);
 428                $x = str_pad($x, strlen($x) + (3 * strlen($x)) % 4, 0, STR_PAD_LEFT);
 429
 430                $str = '0x';
 431                while (strlen($x)) {
 432                    $part = substr($x, 0, 4);
 433                    $str.= dechex(bindec($part));
 434                    $x = substr($x, 4);
 435                }
 436
 437                if ($this->is_negative) {
 438                    $str = '-' . $str;
 439                }
 440
 441                $temp = new Math_BigInteger($str, 8 * $base); // ie. either -16 or +16
 442                $this->value = $temp->value;
 443                $this->is_negative = $temp->is_negative;
 444
 445                break;
 446            default:
 447                // base not supported, so we'll let $this == 0
 448        }
 449    }
 450
 451    /**
 452     * Converts a BigInteger to a byte string (eg. base-256).
 453     *
 454     * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
 455     * saved as two's compliment.
 456     *
 457     * Here's an example:
 458     * <code>
 459     * <?php
 460     *    include('Math/BigInteger.php');
 461     *
 462     *    $a = new Math_BigInteger('65');
 463     *
 464     *    echo $a->toBytes(); // outputs chr(65)
 465     * ?>
 466     * </code>
 467     *
 468     * @param Boolean $twos_compliment
 469     * @return String
 470     * @access public
 471     * @internal Converts a base-2**26 number to base-2**8
 472     */
 473    function toBytes($twos_compliment = false)
 474    {
 475        if ($twos_compliment) {
 476            $comparison = $this->compare(new Math_BigInteger());
 477            if ($comparison == 0) {
 478                return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
 479            }
 480
 481            $temp = $comparison < 0 ? $this->add(new Math_BigInteger(1)) : $this->copy();
 482            $bytes = $temp->toBytes();
 483
 484            if (empty($bytes)) { // eg. if the number we're trying to convert is -1
 485                $bytes = chr(0);
 486            }
 487
 488            if (ord($bytes[0]) & 0x80) {
 489                $bytes = chr(0) . $bytes;
 490            }
 491
 492            return $comparison < 0 ? ~$bytes : $bytes;
 493        }
 494
 495        switch ( MATH_BIGINTEGER_MODE ) {
 496            case MATH_BIGINTEGER_MODE_GMP:
 497                if (gmp_cmp($this->value, gmp_init(0)) == 0) {
 498                    return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
 499                }
 500
 501                $temp = gmp_strval(gmp_abs($this->value), 16);
 502                $temp = ( strlen($temp) & 1 ) ? '0' . $temp : $temp;
 503                $temp = pack('H*', $temp);
 504
 505                return $this->precision > 0 ?
 506                    substr(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
 507                    ltrim($temp, chr(0));
 508            case MATH_BIGINTEGER_MODE_BCMATH:
 509                if ($this->value === '0') {
 510                    return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
 511                }
 512
 513                $value = '';
 514                $current = $this->value;
 515
 516                if ($current[0] == '-') {
 517                    $current = substr($current, 1);
 518                }
 519
 520                while (bccomp($current, '0', 0) > 0) {
 521                    $temp = bcmod($current, '16777216');
 522                    $value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $value;
 523                    $current = bcdiv($current, '16777216', 0);
 524                }
 525
 526                return $this->precision > 0 ?
 527                    substr(str_pad($value, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
 528                    ltrim($value, chr(0));
 529        }
 530
 531        if (!count($this->value)) {
 532            return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
 533        }
 534        $result = $this->_int2bytes($this->value[count($this->value) - 1]);
 535
 536        $temp = $this->copy();
 537
 538        for ($i = count($temp->value) - 2; $i >= 0; --$i) {
 539            $temp->_base256_lshift($result, 26);
 540            $result = $result | str_pad($temp->_int2bytes($temp->value[$i]), strlen($result), chr(0), STR_PAD_LEFT);
 541        }
 542
 543        return $this->precision > 0 ?
 544            str_pad(substr($result, -(($this->precision + 7) >> 3)), ($this->precision + 7) >> 3, chr(0), STR_PAD_LEFT) :
 545            $result;
 546    }
 547
 548    /**
 549     * Converts a BigInteger to a hex string (eg. base-16)).
 550     *
 551     * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
 552     * saved as two's compliment.
 553     *
 554     * Here's an example:
 555     * <code>
 556     * <?php
 557     *    include('Math/BigInteger.php');
 558     *
 559     *    $a = new Math_BigInteger('65');
 560     *
 561     *    echo $a->toHex(); // outputs '41'
 562     * ?>
 563     * </code>
 564     *
 565     * @param Boolean $twos_compliment
 566     * @return String
 567     * @access public
 568     * @internal Converts a base-2**26 number to base-2**8
 569     */
 570    function toHex($twos_compliment = false)
 571    {
 572        return bin2hex($this->toBytes($twos_compliment));
 573    }
 574
 575    /**
 576     * Converts a BigInteger to a bit string (eg. base-2).
 577     *
 578     * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
 579     * saved as two's compliment.
 580     *
 581     * Here's an example:
 582     * <code>
 583     * <?php
 584     *    include('Math/BigInteger.php');
 585     *
 586     *    $a = new Math_BigInteger('65');
 587     *
 588     *    echo $a->toBits(); // outputs '1000001'
 589     * ?>
 590     * </code>
 591     *
 592     * @param Boolean $twos_compliment
 593     * @return String
 594     * @access public
 595     * @internal Converts a base-2**26 number to base-2**2
 596     */
 597    function toBits($twos_compliment = false)
 598    {
 599        $hex = $this->toHex($twos_compliment);
 600        $bits = '';
 601        for ($i = 0; $i < strlen($hex); $i+=8) {
 602            $bits.= str_pad(decbin(hexdec(substr($hex, $i, 8))), 32, '0', STR_PAD_LEFT);
 603        }
 604        return $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0');
 605    }
 606
 607    /**
 608     * Converts a BigInteger to a base-10 number.
 609     *
 610     * Here's an example:
 611     * <code>
 612     * <?php
 613     *    include('Math/BigInteger.php');
 614     *
 615     *    $a = new Math_BigInteger('50');
 616     *
 617     *    echo $a->toString(); // outputs 50
 618     * ?>
 619     * </code>
 620     *
 621     * @return String
 622     * @access public
 623     * @internal Converts a base-2**26 number to base-10**7 (which is pretty much base-10)
 624     */
 625    function toString()
 626    {
 627        switch ( MATH_BIGINTEGER_MODE ) {
 628            case MATH_BIGINTEGER_MODE_GMP:
 629                return gmp_strval($this->value);
 630            case MATH_BIGINTEGER_MODE_BCMATH:
 631                if ($this->value === '0') {
 632                    return '0';
 633                }
 634
 635                return ltrim($this->value, '0');
 636        }
 637
 638        if (!count($this->value)) {
 639            return '0';
 640        }
 641
 642        $temp = $this->copy();
 643        $temp->is_negative = false;
 644
 645        $divisor = new Math_BigInteger();
 646        $divisor->value = array(10000000); // eg. 10**7
 647        $result = '';
 648        while (count($temp->value)) {
 649            list($temp, $mod) = $temp->divide($divisor);
 650            $result = str_pad(isset($mod->value[0]) ? $mod->value[0] : '', 7, '0', STR_PAD_LEFT) . $result;
 651        }
 652        $result = ltrim($result, '0');
 653        if (empty($result)) {
 654            $result = '0';
 655        }
 656
 657        if ($this->is_negative) {
 658            $result = '-' . $result;
 659        }
 660
 661        return $result;
 662    }
 663
 664    /**
 665     * Copy an object
 666     *
 667     * PHP5 passes objects by reference while PHP4 passes by value.  As such, we need a function to guarantee
 668     * that all objects are passed by value, when appropriate.  More information can be found here:
 669     *
 670     * {@link http://php.net/language.oop5.basic#51624}
 671     *
 672     * @access public
 673     * @see __clone()
 674     * @return Math_BigInteger
 675     */
 676    function copy()
 677    {
 678        $temp = new Math_BigInteger();
 679        $temp->value = $this->value;
 680        $temp->is_negative = $this->is_negative;
 681        $temp->generator = $this->generator;
 682        $temp->precision = $this->precision;
 683        $temp->bitmask = $this->bitmask;
 684        return $temp;
 685    }
 686
 687    /**
 688     *  __toString() magic method
 689     *
 690     * Will be called, automatically, if you're supporting just PHP5.  If you're supporting PHP4, you'll need to call
 691     * toString().
 692     *
 693     * @access public
 694     * @internal Implemented per a suggestion by Techie-Michael - thanks!
 695     */
 696    function __toString()
 697    {
 698        return $this->toString();
 699    }
 700
 701    /**
 702     * __clone() magic method
 703     *
 704     * Although you can call Math_BigInteger::__toString() directly in PHP5, you cannot call Math_BigInteger::__clone()
 705     * directly in PHP5.  You can in PHP4 since it's not a magic method, but in PHP5, you have to call it by using the PHP5
 706     * only syntax of $y = clone $x.  As such, if you're trying to write an application that works on both PHP4 and PHP5,
 707     * call Math_BigInteger::copy(), instead.
 708     *
 709     * @access public
 710     * @see copy()
 711     * @return Math_BigInteger
 712     */
 713    function __clone()
 714    {
 715        return $this->copy();
 716    }
 717
 718    /**
 719     *  __sleep() magic method
 720     *
 721     * Will be called, automatically, when serialize() is called on a Math_BigInteger object.
 722     *
 723     * @see __wakeup()
 724     * @access public
 725     */
 726    function __sleep()
 727    {
 728        $this->hex = $this->toHex(true);
 729        $vars = array('hex');
 730        if ($this->generator != 'mt_rand') {
 731            $vars[] = 'generator';
 732        }
 733        if ($this->precision > 0) {
 734            $vars[] = 'precision';
 735        }
 736        return $vars;
 737
 738    }
 739
 740    /**
 741     *  __wakeup() magic method
 742     *
 743     * Will be called, automatically, when unserialize() is called on a Math_BigInteger object.
 744     *
 745     * @see __sleep()
 746     * @access public
 747     */
 748    function __wakeup()
 749    {
 750        $temp = new Math_BigInteger($this->hex, -16);
 751        $this->value = $temp->value;
 752        $this->is_negative = $temp->is_negative;
 753        $this->setRandomGenerator($this->generator);
 754        if ($this->precision > 0) {
 755            // recalculate $this->bitmask
 756            $this->setPrecision($this->precision);
 757        }
 758    }
 759
 760    /**
 761     * Adds two BigIntegers.
 762     *
 763     * Here's an example:
 764     * <code>
 765     * <?php
 766     *    include('Math/BigInteger.php');
 767     *
 768     *    $a = new Math_BigInteger('10');
 769     *    $b = new Math_BigInteger('20');
 770     *
 771     *    $c = $a->add($b);
 772     *
 773     *    echo $c->toString(); // outputs 30
 774     * ?>
 775     * </code>
 776     *
 777     * @param Math_BigInteger $y
 778     * @return Math_BigInteger
 779     * @access public
 780     * @internal Performs base-2**52 addition
 781     */
 782    function add($y)
 783    {
 784        switch ( MATH_BIGINTEGER_MODE ) {
 785            case MATH_BIGINTEGER_MODE_GMP:
 786                $temp = new Math_BigInteger();
 787                $temp->value = gmp_add($this->value, $y->value);
 788
 789                return $this->_normalize($temp);
 790            case MATH_BIGINTEGER_MODE_BCMATH:
 791                $temp = new Math_BigInteger();
 792                $temp->value = bcadd($this->value, $y->value, 0);
 793
 794                return $this->_normalize($temp);
 795        }
 796
 797        $temp = $this->_add($this->value, $this->is_negative, $y->value, $y->is_negative);
 798
 799        $result = new Math_BigInteger();
 800        $result->value = $temp[MATH_BIGINTEGER_VALUE];
 801        $result->is_negative = $temp[MATH_BIGINTEGER_SIGN];
 802
 803        return $this->_normalize($result);
 804    }
 805
 806    /**
 807     * Performs addition.
 808     *
 809     * @param Array $x_value
 810     * @param Boolean $x_negative
 811     * @param Array $y_value
 812     * @param Boolean $y_negative
 813     * @return Array
 814     * @access private
 815     */
 816    function _add($x_value, $x_negative, $y_value, $y_negative)
 817    {
 818        $x_size = count($x_value);
 819        $y_size = count($y_value);
 820
 821        if ($x_size == 0) {
 822            return array(
 823                MATH_BIGINTEGER_VALUE => $y_value,
 824                MATH_BIGINTEGER_SIGN => $y_negative
 825            );
 826        } else if ($y_size == 0) {
 827            return array(
 828                MATH_BIGINTEGER_VALUE => $x_value,
 829                MATH_BIGINTEGER_SIGN => $x_negative
 830            );
 831        }
 832
 833        // subtract, if appropriate
 834        if ( $x_negative != $y_negative ) {
 835            if ( $x_value == $y_value ) {
 836                return array(
 837                    MATH_BIGINTEGER_VALUE => array(),
 838                    MATH_BIGINTEGER_SIGN => false
 839                );
 840            }
 841
 842            $temp = $this->_subtract($x_value, false, $y_value, false);
 843            $temp[MATH_BIGINTEGER_SIGN] = $this->_compare($x_value, false, $y_value, false) > 0 ?
 844                                          $x_negative : $y_negative;
 845
 846            return $temp;
 847        }
 848
 849        if ($x_size < $y_size) {
 850            $size = $x_size;
 851            $value = $y_value;
 852        } else {
 853            $size = $y_size;
 854            $value = $x_value;
 855        }
 856
 857        $value[] = 0; // just in case the carry adds an extra digit
 858
 859        $carry = 0;
 860        for ($i = 0, $j = 1; $j < $size; $i+=2, $j+=2) {
 861            $sum = $x_value[$j] * 0x4000000 + $x_value[$i] + $y_value[$j] * 0x4000000 + $y_value[$i] + $carry;
 862            $carry = $sum >= MATH_BIGINTEGER_MAX_DIGIT52; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
 863            $sum = $carry ? $sum - MATH_BIGINTEGER_MAX_DIGIT52 : $sum;
 864
 865            $temp = (int) ($sum / 0x4000000);
 866
 867            $value[$i] = (int) ($sum - 0x4000000 * $temp); // eg. a faster alternative to fmod($sum, 0x4000000)
 868            $value[$j] = $temp;
 869        }
 870
 871        if ($j == $size) { // ie. if $y_size is odd
 872            $sum = $x_value[$i] + $y_value[$i] + $carry;
 873            $carry = $sum >= 0x4000000;
 874            $value[$i] = $carry ? $sum - 0x4000000 : $sum;
 875            ++$i; // ie. let $i = $j since we've just done $value[$i]
 876        }
 877
 878        if ($carry) {
 879            for (; $value[$i] == 0x3FFFFFF; ++$i) {
 880                $value[$i] = 0;
 881            }
 882            ++$value[$i];
 883        }
 884
 885        return array(
 886            MATH_BIGINTEGER_VALUE => $this->_trim($value),
 887            MATH_BIGINTEGER_SIGN => $x_negative
 888        );
 889    }
 890
 891    /**
 892     * Subtracts two BigIntegers.
 893     *
 894     * Here's an example:
 895     * <code>
 896     * <?php
 897     *    include('Math/BigInteger.php');
 898     *
 899     *    $a = new Math_BigInteger('10');
 900     *    $b = new Math_BigInteger('20');
 901     *
 902     *    $c = $a->subtract($b);
 903     *
 904     *    echo $c->toString(); // outputs -10
 905     * ?>
 906     * </code>
 907     *
 908     * @param Math_BigInteger $y
 909     * @return Math_BigInteger
 910     * @access public
 911     * @internal Performs base-2**52 subtraction
 912     */
 913    function subtract($y)
 914    {
 915        switch ( MATH_BIGINTEGER_MODE ) {
 916            case MATH_BIGINTEGER_MODE_GMP:
 917                $temp = new Math_BigInteger();
 918                $temp->value = gmp_sub($this->value, $y->value);
 919
 920                return $this->_normalize($temp);
 921            case MATH_BIGINTEGER_MODE_BCMATH:
 922                $temp = new Math_BigInteger();
 923                $temp->value = bcsub($this->value, $y->value, 0);
 924
 925                return $this->_normalize($temp);
 926        }
 927
 928        $temp = $this->_subtract($this->value, $this->is_negative, $y->value, $y->is_negative);
 929
 930        $result = new Math_BigInteger();
 931        $result->value = $temp[MATH_BIGINTEGER_VALUE];
 932        $result->is_negative = $temp[MATH_BIGINTEGER_SIGN];
 933
 934        return $this->_normalize($result);
 935    }
 936
 937    /**
 938     * Performs subtraction.
 939     *
 940     * @param Array $x_value
 941     * @param Boolean $x_negative
 942     * @param Array $y_value
 943     * @param Boolean $y_negative
 944     * @return Array
 945     * @access private
 946     */
 947    function _subtract($x_value, $x_negative, $y_value, $y_negative)
 948    {
 949        $x_size = count($x_value);
 950        $y_size = count($y_value);
 951
 952        if ($x_size == 0) {
 953            return array(
 954                MATH_BIGINTEGER_VALUE => $y_value,
 955                MATH_BIGINTEGER_SIGN => !$y_negative
 956            );
 957        } else if ($y_size == 0) {
 958            return array(
 959                MATH_BIGINTEGER_VALUE => $x_value,
 960                MATH_BIGINTEGER_SIGN => $x_negative
 961            );
 962        }
 963
 964        // add, if appropriate (ie. -$x - +$y or +$x - -$y)
 965        if ( $x_negative != $y_negative ) {
 966            $temp = $this->_add($x_value, false, $y_value, false);
 967            $temp[MATH_BIGINTEGER_SIGN] = $x_negative;
 968
 969            return $temp;
 970        }
 971
 972        $diff = $this->_compare($x_value, $x_negative, $y_value, $y_negative);
 973
 974        if ( !$diff ) {
 975            return array(
 976                MATH_BIGINTEGER_VALUE => array(),
 977                MATH_BIGINTEGER_SIGN => false
 978            );
 979        }
 980
 981        // switch $x and $y around, if appropriate.
 982        if ( (!$x_negative && $diff < 0) || ($x_negative && $diff > 0) ) {
 983            $temp = $x_value;
 984            $x_value = $y_value;
 985            $y_value = $temp;
 986
 987            $x_negative = !$x_negative;
 988
 989            $x_size = count($x_value);
 990            $y_size = count($y_value);
 991        }
 992
 993        // at this point, $x_value should be at least as big as - if not bigger than - $y_value
 994
 995        $carry = 0;
 996        for ($i = 0, $j = 1; $j < $y_size; $i+=2, $j+=2) {
 997            $sum = $x_value[$j] * 0x4000000 + $x_value[$i] - $y_value[$j] * 0x4000000 - $y_value[$i] - $carry;
 998            $carry = $sum < 0; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
 999            $sum = $carry ? $sum + MATH_BIGINTEGER_MAX_DIGIT52 : $sum;
1000
1001            $temp = (int) ($sum / 0x4000000);
1002
1003            $x_value[$i] = (int) ($sum - 0x4000000 * $temp);
1004            $x_value[$j] = $temp;
1005        }
1006
1007        if ($j == $y_size) { // ie. if $y_size is odd
1008            $sum = $x_value[$i] - $y_value[$i] - $carry;
1009            $carry = $sum < 0;
1010            $x_value[$i] = $carry ? $sum + 0x4000000 : $sum;
1011            ++$i;
1012        }
1013
1014        if ($carry) {
1015            for (; !$x_value[$i]; ++$i) {
1016                $x_value[$i] = 0x3FFFFFF;
1017            }
1018            --$x_value[$i];
1019        }
1020
1021        return array(
1022            MATH_BIGINTEGER_VALUE => $this->_trim($x_value),
1023            MATH_BIGINTEGER_SIGN => $x_negative
1024        );
1025    }
1026
1027    /**
1028     * Multiplies two BigIntegers
1029     *
1030     * Here's an example:
1031     * <code>
1032     * <?php
1033     *    include('Math/BigInteger.php');
1034     *
1035     *    $a = new Math_BigInteger('10');
1036     *    $b = new Math_BigInteger('20');
1037     *
1038     *    $c = $a->multiply($b);
1039     *
1040     *    echo $c->toString(); // outputs 200
1041     * ?>
1042     * </code>
1043     *
1044     * @param Math_BigInteger $x
1045     * @return Math_BigInteger
1046     * @access public
1047     */
1048    function multiply($x)
1049    {
1050        switch ( MATH_BIGINTEGER_MODE ) {
1051            case MATH_BIGINTEGER_MODE_GMP:
1052                $temp = new Math_BigInteger();
1053                $temp->value = gmp_mul($this->value, $x->value);
1054
1055                return $this->_normalize($temp);
1056            case MATH_BIGINTEGER_MODE_BCMATH:
1057                $temp = new Math_BigInteger();
1058                $temp->value = bcmul($this->value, $x->value, 0);
1059
1060                return $this->_normalize($temp);
1061        }
1062
1063        $temp = $this->_multiply($this->value, $this->is_negative, $x->value, $x->is_negative);
1064
1065        $product = new Math_BigInteger();
1066        $product->value = $temp[MATH_BIGINTEGER_VALUE];
1067        $product->is_negative = $temp[MATH_BIGINTEGER_SIGN];
1068
1069        return $this->_normalize($product);
1070    }
1071
1072    /**
1073     * Performs multiplication.
1074     *
1075     * @param Array $x_value
1076     * @param Boolean $x_negative
1077     * @param Array $y_value
1078     * @param Boolean $y_negative
1079     * @return Array
1080     * @access private
1081     */
1082    function _multiply($x_value, $x_negative, $y_value, $y_negative)
1083    {
1084        //if ( $x_value == $y_value ) {
1085        //    return array(
1086        //        MATH_BIGINTEGER_VALUE => $this->_square($x_value),
1087        //        MATH_BIGINTEGER_SIGN => $x_sign != $y_value
1088        //    );
1089        //}
1090
1091        $x_length = count($x_value);
1092        $y_length = count($y_value);
1093
1094        if ( !$x_length || !$y_length ) { // a 0 is being multiplied
1095            return array(
1096                MATH_BIGINTEGER_VALUE => array(),
1097                MATH_BIGINTEGER_SIGN => false
1098            );
1099        }
1100
1101        return array(
1102            MATH_BIGINTEGER_VALUE => min($x_length, $y_length) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ?
1103                $this->_trim($this->_regularMultiply($x_value, $y_value)) :
1104                $this->_trim($this->_karatsuba($x_value, $y_value)),
1105            MATH_BIGINTEGER_SIGN => $x_negative != $y_negative
1106        );
1107    }
1108
1109    /**
1110     * Performs long multiplication on two BigIntegers
1111     *
1112     * Modeled after 'multiply' in MutableBigInteger.java.
1113     *
1114     * @param Array $x_value
1115     * @param Array $y_value
1116     * @return Array
1117     * @access private
1118     */
1119    function _regularMultiply($x_value, $y_value)
1120    {
1121        $x_length = count($x_value);
1122        $y_length = count($y_value);
1123
1124        if ( !$x_length || !$y_length ) { // a 0 is being multiplied
1125            return array();
1126        }
1127
1128        if ( $x_length < $y_length ) {
1129            $temp = $x_value;
1130            $x_value = $y_value;
1131            $y_value = $temp;
1132
1133            $x_length = count($x_value);
1134            $y_length = count($y_value);
1135        }
1136
1137        $product_value = $this->_array_repeat(0, $x_length + $y_length);
1138
1139        // the following for loop could be removed if the for loop following it
1140        // (the one with nested for loops) initially set $i to 0, but
1141        // doing so would also make the result in one set of unnecessary adds,
1142        // since on the outermost loops first pass, $product->value[$k] is going
1143        // to always be 0
1144
1145        $carry = 0;
1146
1147        for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0
1148            $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
1149            $carry = (int) ($temp / 0x4000000);
1150            $product_value[$j] = (int) ($temp - 0x4000000 * $carry);
1151        }
1152
1153        $product_value[$j] = $carry;
1154
1155        // the above for loop is what the previous comment was talking about.  the
1156        // following for loop is the "one with nested for loops"
1157        for ($i = 1; $i < $y_length; ++$i) {
1158            $carry = 0;
1159
1160            for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) {
1161                $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
1162                $carry = (int) ($temp / 0x4000000);
1163                $product_value[$k] = (int) ($temp - 0x4000000 * $carry);
1164            }
1165
1166            $product_value[$k] = $carry;
1167        }
1168
1169        return $product_value;
1170    }
1171
1172    /**
1173     * Performs Karatsuba multiplication on two BigIntegers
1174     *
1175     * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
1176     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=120 MPM 5.2.3}.
1177     *
1178     * @param Array $x_value
1179     * @param Array $y_value
1180     * @return Array
1181     * @access private
1182     */
1183    function _karatsuba($x_value, $y_value)
1184    {
1185        $m = min(count($x_value) >> 1, count($y_value) >> 1);
1186
1187        if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) {
1188            return $this->_regularMultiply($x_value, $y_value);
1189        }
1190
1191        $x1 = array_slice($x_value, $m);
1192        $x0 = array_slice($x_value, 0, $m);
1193        $y1 = array_slice($y_value, $m);
1194        $y0 = array_slice($y_value, 0, $m);
1195
1196        $z2 = $this->_karatsuba($x1, $y1);
1197        $z0 = $this->_karatsuba($x0, $y0);
1198
1199        $z1 = $this->_add($x1, false, $x0, false);
1200        $temp = $this->_add($y1, false, $y0, false);
1201        $z1 = $this->_karatsuba($z1[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_VALUE]);
1202        $temp = $this->_add($z2, false, $z0, false);
1203        $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false);
1204
1205        $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
1206        $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]);
1207
1208        $xy = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]);
1209        $xy = $this->_add($xy[MATH_BIGINTEGER_VALUE], $xy[MATH_BIGINTEGER_SIGN], $z0, false);
1210
1211        return $xy[MATH_BIGINTEGER_VALUE];
1212    }
1213
1214    /**
1215     * Performs squaring
1216     *
1217     * @param Array $x
1218     * @return Array
1219     * @access private
1220     */
1221    function _square($x = false)
1222    {
1223        return count($x) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ?
1224            $this->_trim($this->_baseSquare($x)) :
1225            $this->_trim($this->_karatsubaSquare($x));
1226    }
1227
1228    /**
1229     * Performs traditional squaring on two BigIntegers
1230     *
1231     * Squaring can be done faster than multiplying a number by itself can be.  See
1232     * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=7 HAC 14.2.4} /
1233     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=141 MPM 5.3} for more information.
1234     *
1235     * @param Array $value
1236     * @return Array
1237     * @access private
1238     */
1239    function _baseSquare($value)
1240    {
1241        if ( empty($value) ) {
1242            return array();
1243        }
1244        $square_value = $this->_array_repeat(0, 2 * count($value));
1245
1246        for ($i = 0, $max_index = count($value) - 1; $i <= $max_index; ++$i) {
1247            $i2 = $i << 1;
1248
1249            $temp = $square_value[$i2] + $value[$i] * $value[$i];
1250            $carry = (int) ($temp / 0x4000000);
1251            $square_value[$i2] = (int) ($temp - 0x4000000 * $carry);
1252
1253            // note how we start from $i+1 instead of 0 as we do in multiplication.
1254            for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) {
1255                $temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry;
1256                $carry = (int) ($temp / 0x4000000);
1257                $square_value[$k] = (int) ($temp - 0x4000000 * $carry);
1258            }
1259
1260            // the following line can yield values larger 2**15.  at this point, PHP should switch
1261            // over to floats.
1262            $square_value[$i + $max_index + 1] = $carry;
1263        }
1264
1265        return $square_value;
1266    }
1267
1268    /**
1269     * Performs Karatsuba "squaring" on two BigIntegers
1270     *
1271     * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
1272     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=151 MPM 5.3.4}.
1273     *
1274     * @param Array $value
1275     * @return Array
1276     * @access private
1277     */
1278    function _karatsubaSquare($value)
1279    {
1280        $m = count($value) >> 1;
1281
1282        if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) {
1283            return $this->_baseSquare($value);
1284        }
1285
1286        $x1 = array_slice($value, $m);
1287        $x0 = array_slice($value, 0, $m);
1288
1289        $z2 = $this->_karatsubaSquare($x1);
1290        $z0 = $this->_karatsubaSquare($x0);
1291
1292        $z1 = $this->_add($x1, false, $x0, false);
1293        $z1 = $this->_karatsubaSquare($z1[MATH_BIGINTEGER_VALUE]);
1294        $temp = $this->_add($z2, false, $z0, false);
1295        $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false);
1296
1297        $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
1298        $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]);
1299
1300        $xx = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]);
1301        $xx = $this->_add($xx[MATH_BIGINTEGER_VALUE], $xx[MATH_BIGINTEGER_SIGN], $z0, false);
1302
1303        return $xx[MATH_BIGINTEGER_VALUE];
1304    }
1305
1306    /**
1307     * Divides two BigIntegers.
1308     *
1309     * Returns an array whose first element contains the quotient and whose second element contains the
1310     * "common residue".  If the remainder would be positive, the "common residue" and the remainder are the
1311     * same.  If the remainder would be negative, the "common residue" is equal to the sum of the remainder
1312     * and the divisor (basically, the "common residue" is the first positive modulo).
1313     *
1314     * Here's an example:
1315     * <code>
1316     * <?php
1317     *    include('Math/BigInteger.php');
1318     *
1319     *    $a = new Math_BigInteger('10');
1320     *    $b = new Math_BigInteger('20');
1321     *
1322     *    list($quotient, $remainder) = $a->divide($b);
1323     *
1324     *    echo $quotient->toString(); // outputs 0
1325     *    echo "\r\n";
1326     *    echo $remainder->toString(); // outputs 10
1327     * ?>
1328     * </code>
1329     *
1330     * @param Math_BigInteger $y
1331     * @return Array
1332     * @access public
1333     * @internal This function is based off of {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=9 HAC 14.20}.
1334     */
1335    function divide($y)
1336    {
1337        switch ( MATH_BIGINTEGER_MODE ) {
1338            case MATH_BIGINTEGER_MODE_GMP:
1339                $quotient = new Math_BigInteger();
1340                $remainder = new Math_BigInteger();
1341
1342                list($quotient->value, $remainder->value) = gmp_div_qr($this->value, $y->value);
1343
1344                if (gmp_sign($remainder->value) < 0) {
1345                    $remainder->value = gmp_add($remainder->value, gmp_abs($y->value));
1346                }
1347
1348                return array($this->_normalize($quotient), $this->_normalize($remainder));
1349            case MATH_BIGINTEGER_MODE_BCMATH:
1350                $quotient = new Math_BigInteger();
1351                $remainder = new Math_BigInteger();
1352
1353                $quotient->value = bcdiv($this->value, $y->value, 0);
1354                $remainder->value = bcmod($this->value, $y->value);
1355
1356                if ($remainder->value[0] == '-') {
1357                    $remainder->value = bcadd($remainder->value, $y->value[0] == '-' ? substr($y->value, 1) : $y->value, 0);
1358                }
1359
1360                return array($this->_normalize($quotient), $this->_normalize($remainder));
1361        }
1362
1363        if (count($y->value) == 1) {
1364            list($q, $r) = $this->_divide_digit($this->value, $y->value[0]);
1365            $quotient = new Math_BigInteger();
1366            $remainder = new Math_BigInteger();
1367            $quotient->value = $q;
1368            $remainder->value = array($r);
1369            $quotient->is_negative = $this->is_negative != $y->is_negative;
1370            return array($this->_normalize($quotient), $this->_normalize($remainder));
1371        }
1372
1373        static $zero;
1374        if ( !isset($zero) ) {
1375            $zero = new Math_BigInteger();
1376        }
1377
1378        $x = $this->copy();
1379        $y = $y->copy();
1380
1381        $x_sign = $x->is_negative;
1382        $y_sign = $y->is_negative;
1383
1384        $x->is_negative = $y->is_negative = false;
1385
1386        $diff = $x->compare($y);
1387
1388        if ( !$diff ) {
1389            $temp = new Math_BigInteger();
1390            $temp->value = array(1);
1391            $temp->is_negative = $x_sign != $y_sign;
1392            return array($this->_normalize($temp), $this->_normalize(new Math_BigInteger()));
1393        }
1394
1395        if ( $diff < 0 ) {
1396            // if $x is negative, "add" $y.
1397            if ( $x_sign ) {
1398                $x = $y->subtract($x);
1399            }
1400            return array($this->_normalize(new Math_BigInteger()), $this->_normalize($x));
1401        }
1402
1403        // normalize $x and $y as described in HAC 14.23 / 14.24
1404        $msb = $y->value[count($y->value) - 1];
1405        for ($shift = 0; !($msb & 0x2000000); ++$shift) {
1406            $msb <<= 1;
1407        }
1408        $x->_lshift($shift);
1409        $y->_lshift($shift);
1410        $y_value = &$y->value;
1411
1412        $x_max = count($x->value) - 1;
1413        $y_max = count($y->value) - 1;
1414
1415        $quotient = new Math_BigInteger();
1416        $quotient_value = &$quotient->value;
1417        $quotient_value = $this->_array_repeat(0, $x_max - $y_max + 1);
1418
1419        static $temp, $lhs, $rhs;
1420        if (!isset($temp)) {
1421            $temp = new Math_BigInteger();
1422            $lhs =  new Math_BigInteger();
1423            $rhs =  new Math_BigInteger();
1424        }
1425        $temp_value = &$temp->value;
1426        $rhs_value =  &$rhs->value;
1427
1428        // $temp = $y << ($x_max - $y_max-1) in base 2**26
1429        $temp_value = array_merge($this->_array_repeat(0, $x_max - $y_max), $y_value);
1430
1431        while ( $x->compare($temp) >= 0 ) {
1432            // calculate the "common residue"
1433            ++$quotient_value[$x_max - $y_max];
1434            $x = $x->subtract($temp);
1435            $x_max = count($x->value) - 1;
1436        }
1437
1438        for ($i = $x_max; $i >= $y_max + 1; --$i) {
1439            $x_value = &$x->value;
1440            $x_window = array(
1441                isset($x_value[$i]) ? $x_value[$i] : 0,
1442                isset($x_value[$i - 1]) ? $x_value[$i - 1] : 0,
1443                isset($x_value[$i - 2]) ? $x_value[$i - 2] : 0
1444            );
1445            $y_window = array(
1446                $y_value[$y_max],
1447                ( $y_max > 0 ) ? $y_value[$y_max - 1] : 0
1448            );
1449
1450            $q_index = $i - $y_max - 1;
1451            if ($x_window[0] == $y_window[0]) {
1452                $quotient_value[$q_index] = 0x3FFFFFF;
1453            } else {
1454                $quotient_value[$q_index] = (int) (
1455                    ($x_window[0] * 0x4000000 + $x_window[1])
1456                    /
1457                    $y_window[0]
1458                );
1459            }
1460
1461            $temp_value = array($y_window[1], $y_window[0]);
1462
1463            $lhs->value = array($quotient_value[$q_index]);
1464            $lhs = $lhs->multiply($temp);
1465
1466            $rhs_value = array($x_window[2], $x_window[1], $x_window[0]);
1467
1468            while ( $lhs->compare($rhs) > 0 ) {
1469                --$quotient_value[$q_index];
1470
1471                $lhs->value = array($quotient_value[$q_index]);
1472                $lhs = $lhs->multiply($temp);
1473            }
1474
1475            $adjust = $this->_array_repeat(0, $q_index);
1476            $temp_value = array($quotient_value[$q_index]);
1477            $temp = $temp->multiply($y);
1478            $temp_value = &$temp->value;
1479            $temp_value = array_merge($adjust, $temp_value);
1480
1481            $x = $x->subtract($temp);
1482
1483            if ($x->compare($zero) < 0) {
1484                $temp_value =

Large files files are truncated, but you can click here to view the full file