Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <?php
- /**
- *
- * @ This file is created by deZender.Net
- * @ deZender (PHP5 Decoder for ionCube Loader)
- *
- * @ Version : 2.0.0.3
- * @ Author : DeZender
- * @ Release on : 06.05.2013
- * @ Official site : http://DeZender.Net
- *
- */
- function strlen_safe($str) {
- return function_exists("mb_strlen") ? mb_strlen($str, "8bit") : strlen($str);
- }
- function strpos_safe($str, $needle, $offset = 0) {
- return function_exists("mb_strpos") ? mb_strpos($str, $needle, $offset, "8bit") : strpos($str, $needle, $offset);
- }
- function strrpos_safe($str, $needle, $offset = 0) {
- return function_exists("mb_strrpos") ? mb_strrpos($str, $needle, $offset, "8bit") : strrpos($str, $needle, $offset);
- }
- function substr_safe($str, $start, $length = 10000) {
- return function_exists("mb_substr") ? mb_substr($str, $start, $length, "8bit") : substr($str, $start, $length);
- }
- /**
- * Pure-PHP arbitrary precision integer arithmetic library. Supports base-2, base-10, base-16, and base-256
- * numbers.
- *
- * @package Math_BigInteger
- * @author Jim Wigginton <terrafrost@php.net>
- * @access public
- */
- class Math_BigInteger {
- /**
- * Holds the BigInteger's value.
- *
- * @var Array
- * @access private
- */
- public $value = null;
- /**
- * Holds the BigInteger's magnitude.
- *
- * @var Boolean
- * @access private
- */
- public $is_negative = false;
- /**
- * Random number generator function
- *
- * @see setRandomGenerator()
- * @access private
- */
- public $generator = "mt_rand";
- /**
- * Precision
- *
- * @see setPrecision()
- * @access private
- */
- public $precision = -1;
- /**
- * Precision Bitmask
- *
- * @see setPrecision()
- * @access private
- */
- public $bitmask = false;
- /**
- * Mode independent value used for serialization.
- *
- * If the bcmath or gmp extensions are installed $this->value will be a non-serializable resource, hence the need for
- * a variable that'll be serializable regardless of whether or not extensions are being used. Unlike $this->value,
- * however, $this->hex is only calculated when $this->__sleep() is called.
- *
- * @see __sleep()
- * @see __wakeup()
- * @var String
- * @access private
- */
- public $hex = null;
- /**
- * Converts base-2, base-10, base-16, and binary strings (base-256) to BigIntegers.
- *
- * If the second parameter - $base - is negative, then it will be assumed that the number's are encoded using
- * two's compliment. The sole exception to this is -10, which is treated the same as 10 is.
- *
- * Here's an example:
- * <code>
- * <?php
- * include 'Math/BigInteger.php';
- *
- * $a = new Math_BigInteger('0x32', 16); // 50 in base-16
- *
- * echo $a->toString(); // outputs 50
- * ?>
- * </code>
- *
- * @param optional $x base-10 number or base-$base number if $base set.
- * @param optional integer $base
- * @return Math_BigInteger
- * @access public
- */
- public function Math_BigInteger($x = 0, $base = 10) {
- if (!(defined("MATH_BIGINTEGER_MODE"))) {
- switch (true) {
- case extension_loaded("gmp"):
- define("MATH_BIGINTEGER_MODE", MATH_BIGINTEGER_MODE_GMP);
- break;
- case extension_loaded("bcmath"):
- define("MATH_BIGINTEGER_MODE", MATH_BIGINTEGER_MODE_BCMATH);
- break;
- default:
- define("MATH_BIGINTEGER_MODE", MATH_BIGINTEGER_MODE_INTERNAL);
- }
- }
- if (function_exists("openssl_public_encrypt") && !(defined("MATH_BIGINTEGER_OPENSSL_DISABLE")) && !(defined("MATH_BIGINTEGER_OPENSSL_ENABLED"))) {
- ob_start();
- @phpinfo();
- $content = ob_get_contents();
- ob_end_clean();
- preg_match_all("#OpenSSL (Header|Library) Version(.*)#im", $content, $matches);
- $versions = array();
- if (!(empty($matches[1]))) {
- $i = 0;
- while ($i < count($matches[1])) {
- $versions[$matches[1][$i]] = trim(str_replace("=>", "", strip_tags($matches[2][$i])));
- ++$i;
- }
- }
- switch (true) {
- case !(isset($versions["Header"])):
- case !(isset($versions["Library"])):
- case $versions["Header"] == $versions["Library"]:
- define("MATH_BIGINTEGER_OPENSSL_ENABLED", true);
- break;
- default:
- define("MATH_BIGINTEGER_OPENSSL_DISABLE", true);
- }
- }
- if (!(defined("PHP_INT_SIZE"))) {
- define("PHP_INT_SIZE", 4);
- }
- if (!(defined("MATH_BIGINTEGER_BASE")) && MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_INTERNAL) {
- switch (PHP_INT_SIZE) {
- case 8:
- define("MATH_BIGINTEGER_BASE", 31);
- define("MATH_BIGINTEGER_BASE_FULL", 2147483648.000000);
- define("MATH_BIGINTEGER_MAX_DIGIT", 2147483647);
- define("MATH_BIGINTEGER_MSB", 1073741824);
- define("MATH_BIGINTEGER_MAX10", 1000000000);
- define("MATH_BIGINTEGER_MAX10_LEN", 9);
- define("MATH_BIGINTEGER_MAX_DIGIT2", pow(2, 62));
- break;
- default:
- define("MATH_BIGINTEGER_BASE", 26);
- define("MATH_BIGINTEGER_BASE_FULL", 67108864);
- define("MATH_BIGINTEGER_MAX_DIGIT", 67108863);
- define("MATH_BIGINTEGER_MSB", 33554432);
- define("MATH_BIGINTEGER_MAX10", 10000000);
- define("MATH_BIGINTEGER_MAX10_LEN", 7);
- define("MATH_BIGINTEGER_MAX_DIGIT2", pow(2, 52));
- }
- }
- switch (MATH_BIGINTEGER_MODE) {
- case MATH_BIGINTEGER_MODE_GMP:
- if (is_resource($x) && get_resource_type($x) == "GMP integer") {
- $this->value = $x;
- return null;
- }
- $this->value = gmp_init(0);
- break;
- case MATH_BIGINTEGER_MODE_BCMATH:
- $this->value = "0";
- break;
- default:
- $this->value = array();
- }
- if (empty($x) && abs($base) != 256 || $x !== "0") {
- return null;
- }
- switch ($base) {
- case -256:
- if (ord($x[0]) & 128) {
- $x = ~$x;
- $this->is_negative = true;
- }
- case 256:
- switch (MATH_BIGINTEGER_MODE) {
- case MATH_BIGINTEGER_MODE_GMP:
- $sign = $this->is_negative ? "-" : "";
- $this->value = gmp_init($sign . "0x" . bin2hex($x));
- break;
- case MATH_BIGINTEGER_MODE_BCMATH:
- $len = strlen_safe($x) + 3 & 4294967292.000000;
- $x = str_pad($x, $len, chr(0), STR_PAD_LEFT);
- $i = 0;
- while ($i < $len) {
- $this->value = bcmul($this->value, "4294967296", 0);
- $this->value = bcadd($this->value, 16777216 * ord($x[$i]) + (ord($x[$i + 1]) << 16 | ord($x[$i + 2]) << 8 | ord($x[$i + 3])), 0);
- $i += 4;
- }
- if ($this->is_negative) {
- $this->value = "-" . $this->value;
- }
- break;
- label_0:
- default:
- if (strlen_safe($x)) {
- $this->value[] = $this->_bytes2int($this->_base256_rshift($x, MATH_BIGINTEGER_BASE));
- goto label_0;
- }
- }
- if ($this->is_negative) {
- if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) {
- $this->is_negative = false;
- }
- $temp = $this->add(new Math_BigInteger("-1"));
- $this->value = $temp->value;
- }
- break;
- case 16:
- case -16:
- if (0 < $base && $x[0] == "-") {
- $this->is_negative = true;
- $x = substr_safe($x, 1);
- }
- $x = preg_replace("#^(?:0x)?([A-Fa-f0-9]*).*#", "\$1", $x);
- $is_negative = false;
- if ($base < 0 && 8 <= hexdec($x[0])) {
- $this->is_negative = $is_negative = true;
- $x = bin2hex(~(pack("H*", $x)));
- }
- switch (MATH_BIGINTEGER_MODE) {
- case MATH_BIGINTEGER_MODE_GMP:
- $temp = $this->is_negative ? "-0x" . $x : "0x" . $x;
- $this->value = gmp_init($temp);
- $this->is_negative = false;
- break;
- case MATH_BIGINTEGER_MODE_BCMATH:
- $x = strlen_safe($x) & 1 ? "0" . $x : $x;
- $temp = new Math_BigInteger(pack("H*", $x), 256);
- $this->value = $this->is_negative ? "-" . $temp->value : $temp->value;
- $this->is_negative = false;
- break;
- default:
- $x = strlen_safe($x) & 1 ? "0" . $x : $x;
- $temp = new Math_BigInteger(pack("H*", $x), 256);
- $this->value = $temp->value;
- }
- if ($is_negative) {
- $temp = $this->add(new Math_BigInteger("-1"));
- $this->value = $temp->value;
- }
- break;
- case 10:
- case -10:
- $x = preg_replace("#(?<!^)(?:-).*|(?<=^|-)0*|[^-0-9].*#", "", $x);
- switch (MATH_BIGINTEGER_MODE) {
- case MATH_BIGINTEGER_MODE_GMP:
- $this->value = gmp_init($x);
- break;
- case MATH_BIGINTEGER_MODE_BCMATH:
- $this->value = $x === "-" ? "0" : (string)$x;
- break;
- default:
- $temp = new Math_BigInteger();
- $multiplier = new Math_BigInteger();
- $multiplier->value = array(MATH_BIGINTEGER_MAX10);
- if ($x[0] == "-") {
- $this->is_negative = true;
- $x = substr_safe($x, 1);
- }
- $x = str_pad($x, strlen_safe($x) + (MATH_BIGINTEGER_MAX10_LEN - 1) * strlen_safe($x) % MATH_BIGINTEGER_MAX10_LEN, 0, STR_PAD_LEFT);
- while (strlen_safe($x)) {
- $temp = $temp->multiply($multiplier);
- $temp = $temp->add(new Math_BigInteger($this->_int2bytes(substr_safe($x, 0, MATH_BIGINTEGER_MAX10_LEN)), 256));
- $x = substr_safe($x, MATH_BIGINTEGER_MAX10_LEN);
- }
- $this->value = $temp->value;
- }
- break;
- case 2:
- case -2:
- if (0 < $base && $x[0] == "-") {
- $this->is_negative = true;
- $x = substr_safe($x, 1);
- }
- $x = preg_replace("#^([01]*).*#", "\$1", $x);
- $x = str_pad($x, strlen_safe($x) + 3 * strlen_safe($x) % 4, 0, STR_PAD_LEFT);
- $str = "0x";
- while (strlen_safe($x)) {
- $part = substr_safe($x, 0, 4);
- $str .= dechex(bindec($part));
- $x = substr_safe($x, 4);
- }
- if ($this->is_negative) {
- $str = "-" . $str;
- }
- $temp = new Math_BigInteger($str, 8 * $base);
- $this->value = $temp->value;
- $this->is_negative = $temp->is_negative;
- break;
- }
- }
- /**
- * Converts a BigInteger to a byte string (eg. base-256).
- *
- * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
- * saved as two's compliment.
- *
- * Here's an example:
- * <code>
- * <?php
- * include 'Math/BigInteger.php';
- *
- * $a = new Math_BigInteger('65');
- *
- * echo $a->toBytes(); // outputs chr(65)
- * ?>
- * </code>
- *
- * @param Boolean $twos_compliment
- * @return String
- * @access public
- * @internal Converts a base-2**26 number to base-2**8
- */
- public function toBytes($twos_compliment = false) {
- if ($twos_compliment) {
- $comparison = $this->compare(new Math_BigInteger());
- if ($comparison == 0) {
- return 0 < $this->precision ? str_repeat(chr(0), $this->precision + 1 >> 3) : "";
- }
- $temp = $comparison < 0 ? $this->add(new Math_BigInteger(1)) : $this->copy();
- $bytes = $temp->toBytes();
- if (empty($bytes)) {
- $bytes = chr(0);
- }
- if (ord($bytes[0]) & 128) {
- $bytes = chr(0) . $bytes;
- }
- return $comparison < 0 ? ~$bytes : $bytes;
- }
- switch (MATH_BIGINTEGER_MODE) {
- case MATH_BIGINTEGER_MODE_GMP:
- if (gmp_cmp($this->value, gmp_init(0)) == 0) {
- return 0 < $this->precision ? str_repeat(chr(0), $this->precision + 1 >> 3) : "";
- }
- $temp = gmp_strval(gmp_abs($this->value), 16);
- $temp = strlen_safe($temp) & 1 ? "0" . $temp : $temp;
- $temp = pack("H*", $temp);
- return 0 < $this->precision ? substr_safe(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT), 0 - ($this->precision >> 3)) : ltrim($temp, chr(0));
- case MATH_BIGINTEGER_MODE_BCMATH:
- if ($this->value === "0") {
- return 0 < $this->precision ? str_repeat(chr(0), $this->precision + 1 >> 3) : "";
- }
- $value = "";
- $current = $this->value;
- if ($current[0] == "-") {
- $current = substr_safe($current, 1);
- }
- while (0 < bccomp($current, "0", 0)) {
- $temp = bcmod($current, "16777216");
- $value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $value;
- $current = bcdiv($current, "16777216", 0);
- }
- return 0 < $this->precision ? substr_safe(str_pad($value, $this->precision >> 3, chr(0), STR_PAD_LEFT), 0 - ($this->precision >> 3)) : ltrim($value, chr(0));
- }
- if (!(count($this->value))) {
- return 0 < $this->precision ? str_repeat(chr(0), $this->precision + 1 >> 3) : "";
- }
- $result = $this->_int2bytes($this->value[count($this->value) - 1]);
- $temp = $this->copy();
- $i = count($temp->value) - 2;
- while (0 <= $i) {
- $temp->_base256_lshift($result, MATH_BIGINTEGER_BASE);
- $result = $result | str_pad($temp->_int2bytes($temp->value[$i]), strlen_safe($result), chr(0), STR_PAD_LEFT);
- --$i;
- }
- return 0 < $this->precision ? str_pad(substr_safe($result, 0 - ($this->precision + 7 >> 3)), $this->precision + 7 >> 3, chr(0), STR_PAD_LEFT) : $result;
- }
- /**
- * Converts a BigInteger to a hex string (eg. base-16)).
- *
- * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
- * saved as two's compliment.
- *
- * Here's an example:
- * <code>
- * <?php
- * include 'Math/BigInteger.php';
- *
- * $a = new Math_BigInteger('65');
- *
- * echo $a->toHex(); // outputs '41'
- * ?>
- * </code>
- *
- * @param Boolean $twos_compliment
- * @return String
- * @access public
- * @internal Converts a base-2**26 number to base-2**8
- */
- public function toHex($twos_compliment = false) {
- return bin2hex($this->toBytes($twos_compliment));
- }
- /**
- * Converts a BigInteger to a bit string (eg. base-2).
- *
- * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
- * saved as two's compliment.
- *
- * Here's an example:
- * <code>
- * <?php
- * include 'Math/BigInteger.php';
- *
- * $a = new Math_BigInteger('65');
- *
- * echo $a->toBits(); // outputs '1000001'
- * ?>
- * </code>
- *
- * @param Boolean $twos_compliment
- * @return String
- * @access public
- * @internal Converts a base-2**26 number to base-2**2
- */
- public function toBits($twos_compliment = false) {
- $hex = $this->toHex($twos_compliment);
- $bits = "";
- $i = strlen_safe($hex) - 8;
- $start = strlen_safe($hex) & 7;
- while ($start <= $i) {
- $bits = str_pad(decbin(hexdec(substr_safe($hex, $i, 8))), 32, "0", STR_PAD_LEFT) . $bits;
- $i -= 8;
- }
- if ($start) {
- $bits = str_pad(decbin(hexdec(substr_safe($hex, 0, $start))), 8, "0", STR_PAD_LEFT) . $bits;
- }
- $result = 0 < $this->precision ? substr_safe($bits, 0 - $this->precision) : ltrim($bits, "0");
- if ($twos_compliment && 0 < $this->compare(new Math_BigInteger()) && $this->precision <= 0) {
- return "0" . $result;
- }
- return $result;
- }
- /**
- * Converts a BigInteger to a base-10 number.
- *
- * Here's an example:
- * <code>
- * <?php
- * include 'Math/BigInteger.php';
- *
- * $a = new Math_BigInteger('50');
- *
- * echo $a->toString(); // outputs 50
- * ?>
- * </code>
- *
- * @return String
- * @access public
- * @internal Converts a base-2**26 number to base-10**7 (which is pretty much base-10)
- */
- public function toString() {
- switch (MATH_BIGINTEGER_MODE) {
- case MATH_BIGINTEGER_MODE_GMP:
- return gmp_strval($this->value);
- case MATH_BIGINTEGER_MODE_BCMATH:
- if ($this->value === "0") {
- return "0";
- }
- return ltrim($this->value, "0");
- }
- if (!(count($this->value))) {
- return "0";
- }
- $temp = $this->copy();
- $temp->is_negative = false;
- $divisor = new Math_BigInteger();
- $divisor->value = array(MATH_BIGINTEGER_MAX10);
- $result = "";
- while (count($temp->value)) {
- list($temp, $mod) = $temp->divide($divisor);
- $result = str_pad(isset($mod->value[0]) ? $mod->value[0] : "", MATH_BIGINTEGER_MAX10_LEN, "0", STR_PAD_LEFT) . $result;
- }
- $result = ltrim($result, "0");
- if (empty($result)) {
- $result = "0";
- }
- if ($this->is_negative) {
- $result = "-" . $result;
- }
- return $result;
- }
- /**
- * Copy an object
- *
- * PHP5 passes objects by reference while PHP4 passes by value. As such, we need a function to guarantee
- * that all objects are passed by value, when appropriate. More information can be found here:
- *
- * {@link http://php.net/language.oop5.basic#51624}
- *
- * @access public
- * @see __clone()
- * @return Math_BigInteger
- */
- public function copy() {
- $temp = new Math_BigInteger();
- $temp->value = $this->value;
- $temp->is_negative = $this->is_negative;
- $temp->generator = $this->generator;
- $temp->precision = $this->precision;
- $temp->bitmask = $this->bitmask;
- return $temp;
- }
- /**
- * __toString() magic method
- *
- * Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call
- * toString().
- *
- * @access public
- * @internal Implemented per a suggestion by Techie-Michael - thanks!
- */
- public function __toString() {
- return $this->toString();
- }
- /**
- * __clone() magic method
- *
- * Although you can call Math_BigInteger::__toString() directly in PHP5, you cannot call Math_BigInteger::__clone()
- * 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
- * only syntax of $y = clone $x. As such, if you're trying to write an application that works on both PHP4 and PHP5,
- * call Math_BigInteger::copy(), instead.
- *
- * @access public
- * @see copy()
- * @return Math_BigInteger
- */
- public function __clone() {
- return $this->copy();
- }
- /**
- * __sleep() magic method
- *
- * Will be called, automatically, when serialize() is called on a Math_BigInteger object.
- *
- * @see __wakeup()
- * @access public
- */
- public function __sleep() {
- $this->hex = $this->toHex(true);
- $vars = array("hex");
- if ($this->generator != "mt_rand") {
- $vars[] = "generator";
- }
- if (0 < $this->precision) {
- $vars[] = "precision";
- }
- return $vars;
- }
- /**
- * __wakeup() magic method
- *
- * Will be called, automatically, when unserialize() is called on a Math_BigInteger object.
- *
- * @see __sleep()
- * @access public
- */
- public function __wakeup() {
- $temp = new Math_BigInteger($this->hex, -16);
- $this->value = $temp->value;
- $this->is_negative = $temp->is_negative;
- $this->setRandomGenerator($this->generator);
- if (0 < $this->precision) {
- $this->setPrecision($this->precision);
- }
- }
- /**
- * Adds two BigIntegers.
- *
- * Here's an example:
- * <code>
- * <?php
- * include 'Math/BigInteger.php';
- *
- * $a = new Math_BigInteger('10');
- * $b = new Math_BigInteger('20');
- *
- * $c = $a->add($b);
- *
- * echo $c->toString(); // outputs 30
- * ?>
- * </code>
- *
- * @param Math_BigInteger $y
- * @return Math_BigInteger
- * @access public
- * @internal Performs base-2**52 addition
- */
- public function add($y) {
- switch (MATH_BIGINTEGER_MODE) {
- case MATH_BIGINTEGER_MODE_GMP:
- $temp = new Math_BigInteger();
- $temp->value = gmp_add($this->value, $y->value);
- return $this->_normalize($temp);
- case MATH_BIGINTEGER_MODE_BCMATH:
- $temp = new Math_BigInteger();
- $temp->value = bcadd($this->value, $y->value, 0);
- return $this->_normalize($temp);
- }
- $temp = $this->_add($this->value, $this->is_negative, $y->value, $y->is_negative);
- $result = new Math_BigInteger();
- $result->value = $temp[MATH_BIGINTEGER_VALUE];
- $result->is_negative = $temp[MATH_BIGINTEGER_SIGN];
- return $this->_normalize($result);
- }
- /**
- * Performs addition.
- *
- * @param Array $x_value
- * @param Boolean $x_negative
- * @param Array $y_value
- * @param Boolean $y_negative
- * @return Array
- * @access private
- */
- public function _add($x_value, $x_negative, $y_value, $y_negative) {
- $x_size = count($x_value);
- $y_size = count($y_value);
- if ($x_size == 0) {
- return array(MATH_BIGINTEGER_VALUE => $y_value, MATH_BIGINTEGER_SIGN => $y_negative);
- }
- if ($y_size == 0) {
- return array(MATH_BIGINTEGER_VALUE => $x_value, MATH_BIGINTEGER_SIGN => $x_negative);
- }
- if ($x_negative != $y_negative) {
- if ($x_value == $y_value) {
- return array(MATH_BIGINTEGER_VALUE => array(), MATH_BIGINTEGER_SIGN => false);
- }
- $temp = $this->_subtract($x_value, false, $y_value, false);
- $temp[MATH_BIGINTEGER_SIGN] = 0 < $this->_compare($x_value, false, $y_value, false) ? $x_negative : $y_negative;
- return $temp;
- }
- if ($x_size < $y_size) {
- $size = $x_size;
- $value = $y_value;
- }
- else {
- $size = $y_size;
- $value = $x_value;
- }
- $value[] = 0;
- $carry = 0;
- $i = 0;
- $j = 1;
- while ($j < $size) {
- $sum = $x_value[$j] * MATH_BIGINTEGER_BASE_FULL + $x_value[$i] + $y_value[$j] * MATH_BIGINTEGER_BASE_FULL + $y_value[$i] + $carry;
- $carry = MATH_BIGINTEGER_MAX_DIGIT2 <= $sum;
- $sum = $carry ? $sum - MATH_BIGINTEGER_MAX_DIGIT2 : $sum;
- $temp = MATH_BIGINTEGER_BASE === 26 ? intval($sum / 67108864) : $sum >> 31;
- $value[$i] = (int)$sum - MATH_BIGINTEGER_BASE_FULL * $temp;
- $value[$j] = $temp;
- $i += 2;
- $j += 2;
- continue;
- }
- if ($j == $size) {
- $sum = $x_value[$i] + $y_value[$i] + $carry;
- $carry = MATH_BIGINTEGER_BASE_FULL <= $sum;
- $value[$i] = $carry ? $sum - MATH_BIGINTEGER_BASE_FULL : $sum;
- ++$i;
- }
- if ($carry) {
- while ($value[$i] == MATH_BIGINTEGER_MAX_DIGIT) {
- $value[$i] = 0;
- ++$i;
- }
- ++$value[$i];
- }
- return array(MATH_BIGINTEGER_VALUE => $this->_trim($value), MATH_BIGINTEGER_SIGN => $x_negative);
- }
- /**
- * Subtracts two BigIntegers.
- *
- * Here's an example:
- * <code>
- * <?php
- * include 'Math/BigInteger.php';
- *
- * $a = new Math_BigInteger('10');
- * $b = new Math_BigInteger('20');
- *
- * $c = $a->subtract($b);
- *
- * echo $c->toString(); // outputs -10
- * ?>
- * </code>
- *
- * @param Math_BigInteger $y
- * @return Math_BigInteger
- * @access public
- * @internal Performs base-2**52 subtraction
- */
- public function subtract($y) {
- switch (MATH_BIGINTEGER_MODE) {
- case MATH_BIGINTEGER_MODE_GMP:
- $temp = new Math_BigInteger();
- $temp->value = gmp_sub($this->value, $y->value);
- return $this->_normalize($temp);
- case MATH_BIGINTEGER_MODE_BCMATH:
- $temp = new Math_BigInteger();
- $temp->value = bcsub($this->value, $y->value, 0);
- return $this->_normalize($temp);
- }
- $temp = $this->_subtract($this->value, $this->is_negative, $y->value, $y->is_negative);
- $result = new Math_BigInteger();
- $result->value = $temp[MATH_BIGINTEGER_VALUE];
- $result->is_negative = $temp[MATH_BIGINTEGER_SIGN];
- return $this->_normalize($result);
- }
- /**
- * Performs subtraction.
- *
- * @param Array $x_value
- * @param Boolean $x_negative
- * @param Array $y_value
- * @param Boolean $y_negative
- * @return Array
- * @access private
- */
- public function _subtract($x_value, $x_negative, $y_value, $y_negative) {
- $x_size = count($x_value);
- $y_size = count($y_value);
- if ($x_size == 0) {
- return array(MATH_BIGINTEGER_VALUE => $y_value, MATH_BIGINTEGER_SIGN => !$y_negative);
- }
- if ($y_size == 0) {
- return array(MATH_BIGINTEGER_VALUE => $x_value, MATH_BIGINTEGER_SIGN => $x_negative);
- }
- if ($x_negative != $y_negative) {
- $temp = $this->_add($x_value, false, $y_value, false);
- $temp[MATH_BIGINTEGER_SIGN] = $x_negative;
- return $temp;
- }
- $diff = $this->_compare($x_value, $x_negative, $y_value, $y_negative);
- if (!$diff) {
- return array(MATH_BIGINTEGER_VALUE => array(), MATH_BIGINTEGER_SIGN => false);
- }
- if (!$x_negative && $diff < 0 || $x_negative && 0 < $diff) {
- $temp = $x_value;
- $x_value = $y_value;
- $y_value = $temp;
- $x_negative = !$x_negative;
- $x_size = count($x_value);
- $y_size = count($y_value);
- }
- $carry = 0;
- $i = 0;
- $j = 1;
- while ($j < $y_size) {
- $sum = $x_value[$j] * MATH_BIGINTEGER_BASE_FULL + $x_value[$i] - $y_value[$j] * MATH_BIGINTEGER_BASE_FULL - $y_value[$i] - $carry;
- $carry = $sum < 0;
- $sum = $carry ? $sum + MATH_BIGINTEGER_MAX_DIGIT2 : $sum;
- $temp = MATH_BIGINTEGER_BASE === 26 ? intval($sum / 67108864) : $sum >> 31;
- $x_value[$i] = (int)$sum - MATH_BIGINTEGER_BASE_FULL * $temp;
- $x_value[$j] = $temp;
- $i += 2;
- $j += 2;
- }
- if ($j == $y_size) {
- $sum = $x_value[$i] - $y_value[$i] - $carry;
- $carry = $sum < 0;
- $x_value[$i] = $carry ? $sum + MATH_BIGINTEGER_BASE_FULL : $sum;
- ++$i;
- }
- if ($carry) {
- while (!$x_value[$i]) {
- $x_value[$i] = MATH_BIGINTEGER_MAX_DIGIT;
- ++$i;
- }
- --$x_value[$i];
- }
- return array(MATH_BIGINTEGER_VALUE => $this->_trim($x_value), MATH_BIGINTEGER_SIGN => $x_negative);
- }
- /**
- * Multiplies two BigIntegers
- *
- * Here's an example:
- * <code>
- * <?php
- * include 'Math/BigInteger.php';
- *
- * $a = new Math_BigInteger('10');
- * $b = new Math_BigInteger('20');
- *
- * $c = $a->multiply($b);
- *
- * echo $c->toString(); // outputs 200
- * ?>
- * </code>
- *
- * @param Math_BigInteger $x
- * @return Math_BigInteger
- * @access public
- */
- public function multiply($x) {
- switch (MATH_BIGINTEGER_MODE) {
- case MATH_BIGINTEGER_MODE_GMP:
- $temp = new Math_BigInteger();
- $temp->value = gmp_mul($this->value, $x->value);
- return $this->_normalize($temp);
- case MATH_BIGINTEGER_MODE_BCMATH:
- $temp = new Math_BigInteger();
- $temp->value = bcmul($this->value, $x->value, 0);
- return $this->_normalize($temp);
- }
- $temp = $this->_multiply($this->value, $this->is_negative, $x->value, $x->is_negative);
- $product = new Math_BigInteger();
- $product->value = $temp[MATH_BIGINTEGER_VALUE];
- $product->is_negative = $temp[MATH_BIGINTEGER_SIGN];
- return $this->_normalize($product);
- }
- /**
- * Performs multiplication.
- *
- * @param Array $x_value
- * @param Boolean $x_negative
- * @param Array $y_value
- * @param Boolean $y_negative
- * @return Array
- * @access private
- */
- public function _multiply($x_value, $x_negative, $y_value, $y_negative) {
- $x_length = count($x_value);
- $y_length = count($y_value);
- if (!$x_length || !$y_length) {
- return array(MATH_BIGINTEGER_VALUE => array(), MATH_BIGINTEGER_SIGN => false);
- }
- return array(MATH_BIGINTEGER_VALUE => min($x_length, $y_length) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ? $this->_trim($this->_regularMultiply($x_value, $y_value)) : $this->_trim($this->_karatsuba($x_value, $y_value)), MATH_BIGINTEGER_SIGN => $x_negative != $y_negative);
- }
- /**
- * Performs long multiplication on two BigIntegers
- *
- * Modeled after 'multiply' in MutableBigInteger.java.
- *
- * @param Array $x_value
- * @param Array $y_value
- * @return Array
- * @access private
- */
- public function _regularMultiply($x_value, $y_value) {
- $x_length = count($x_value);
- $y_length = count($y_value);
- if (!$x_length || !$y_length) {
- return array();
- }
- if ($x_length < $y_length) {
- $temp = $x_value;
- $x_value = $y_value;
- $y_value = $temp;
- $x_length = count($x_value);
- $y_length = count($y_value);
- }
- $product_value = $this->_array_repeat(0, $x_length + $y_length);
- $carry = 0;
- $j = 0;
- while ($j < $x_length) {
- $temp = $x_value[$j] * $y_value[0] + $carry;
- $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 67108864) : $temp >> 31;
- $product_value[$j] = (int)$temp - MATH_BIGINTEGER_BASE_FULL * $carry;
- ++$j;
- }
- $product_value[$j] = $carry;
- $i = 1;
- while ($i < $y_length) {
- $carry = 0;
- $j = 0;
- $k = $i;
- while ($j < $x_length) {
- $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
- $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 67108864) : $temp >> 31;
- $product_value[$k] = (int)$temp - MATH_BIGINTEGER_BASE_FULL * $carry;
- ++$j;
- ++$k;
- }
- $product_value[$k] = $carry;
- ++$i;
- continue;
- }
- return $product_value;
- }
- /**
- * Performs Karatsuba multiplication on two BigIntegers
- *
- * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
- * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=120 MPM 5.2.3}.
- *
- * @param Array $x_value
- * @param Array $y_value
- * @return Array
- * @access private
- */
- public function _karatsuba($x_value, $y_value) {
- $m = min(count($x_value) >> 1, count($y_value) >> 1);
- if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) {
- return $this->_regularMultiply($x_value, $y_value);
- }
- $x1 = array_slice($x_value, $m);
- $x0 = array_slice($x_value, 0, $m);
- $y1 = array_slice($y_value, $m);
- $y0 = array_slice($y_value, 0, $m);
- $z2 = $this->_karatsuba($x1, $y1);
- $z0 = $this->_karatsuba($x0, $y0);
- $z1 = $this->_add($x1, false, $x0, false);
- $temp = $this->_add($y1, false, $y0, false);
- $z1 = $this->_karatsuba($z1[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_VALUE]);
- $temp = $this->_add($z2, false, $z0, false);
- $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false);
- $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
- $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]);
- $xy = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]);
- $xy = $this->_add($xy[MATH_BIGINTEGER_VALUE], $xy[MATH_BIGINTEGER_SIGN], $z0, false);
- return $xy[MATH_BIGINTEGER_VALUE];
- }
- /**
- * Performs squaring
- *
- * @param Array $x
- * @return Array
- * @access private
- */
- public function _square($x = false) {
- return count($x) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ? $this->_trim($this->_baseSquare($x)) : $this->_trim($this->_karatsubaSquare($x));
- }
- /**
- * Performs traditional squaring on two BigIntegers
- *
- * Squaring can be done faster than multiplying a number by itself can be. See
- * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=7 HAC 14.2.4} /
- * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=141 MPM 5.3} for more information.
- *
- * @param Array $value
- * @return Array
- * @access private
- */
- public function _baseSquare($value) {
- if (empty($value)) {
- return array();
- }
- $square_value = $this->_array_repeat(0, 2 * count($value));
- $i = 0;
- $max_index = count($value) - 1;
- while ($i <= $max_index) {
- $i2 = $i << 1;
- $temp = $square_value[$i2] + $value[$i] * $value[$i];
- $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 67108864) : $temp >> 31;
- $square_value[$i2] = (int)$temp - MATH_BIGINTEGER_BASE_FULL * $carry;
- $j = $i + 1;
- $k = $i2 + 1;
- while ($j <= $max_index) {
- $temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry;
- $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 67108864) : $temp >> 31;
- $square_value[$k] = (int)$temp - MATH_BIGINTEGER_BASE_FULL * $carry;
- ++$j;
- ++$k;
- continue;
- }
- $square_value[$i + $max_index + 1] = $carry;
- ++$i;
- }
- return $square_value;
- }
- /**
- * Performs Karatsuba "squaring" on two BigIntegers
- *
- * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
- * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=151 MPM 5.3.4}.
- *
- * @param Array $value
- * @return Array
- * @access private
- */
- public function _karatsubaSquare($value) {
- $m = count($value) >> 1;
- if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) {
- return $this->_baseSquare($value);
- }
- $x1 = array_slice($value, $m);
- $x0 = array_slice($value, 0, $m);
- $z2 = $this->_karatsubaSquare($x1);
- $z0 = $this->_karatsubaSquare($x0);
- $z1 = $this->_add($x1, false, $x0, false);
- $z1 = $this->_karatsubaSquare($z1[MATH_BIGINTEGER_VALUE]);
- $temp = $this->_add($z2, false, $z0, false);
- $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false);
- $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
- $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]);
- $xx = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]);
- $xx = $this->_add($xx[MATH_BIGINTEGER_VALUE], $xx[MATH_BIGINTEGER_SIGN], $z0, false);
- return $xx[MATH_BIGINTEGER_VALUE];
- }
- /**
- * Divides two BigIntegers.
- *
- * Returns an array whose first element contains the quotient and whose second element contains the
- * "common residue". If the remainder would be positive, the "common residue" and the remainder are the
- * same. If the remainder would be negative, the "common residue" is equal to the sum of the remainder
- * and the divisor (basically, the "common residue" is the first positive modulo).
- *
- * Here's an example:
- * <code>
- * <?php
- * include 'Math/BigInteger.php';
- *
- * $a = new Math_BigInteger('10');
- * $b = new Math_BigInteger('20');
- *
- * list($quotient, $remainder) = $a->divide($b);
- *
- * echo $quotient->toString(); // outputs 0
- * echo "\r\n";
- * echo $remainder->toString(); // outputs 10
- * ?>
- * </code>
- *
- * @param Math_BigInteger $y
- * @return Array
- * @access public
- * @internal This function is based off of {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=9 HAC 14.20}.
- */
- public function divide($y) {
- switch (MATH_BIGINTEGER_MODE) {
- case MATH_BIGINTEGER_MODE_GMP:
- $quotient = new Math_BigInteger();
- $remainder = new Math_BigInteger();
- list($quotient->value, $remainder->value) = gmp_div_qr($this->value, $y->value);
- if (gmp_sign($remainder->value) < 0) {
- $remainder->value = gmp_add($remainder->value, gmp_abs($y->value));
- }
- return array($this->_normalize($quotient), $this->_normalize($remainder));
- case MATH_BIGINTEGER_MODE_BCMATH:
- $quotient = new Math_BigInteger();
- $remainder = new Math_BigInteger();
- $quotient->value = bcdiv($this->value, $y->value, 0);
- $remainder->value = bcmod($this->value, $y->value);
- if ($remainder->value[0] == "-") {
- $remainder->value = bcadd($remainder->value, $y->value[0] == "-" ? substr_safe($y->value, 1) : $y->value, 0);
- }
- return array($this->_normalize($quotient), $this->_normalize($remainder));
- }
- if (count($y->value) == 1) {
- list($q, $r) = $this->_divide_digit($this->value, $y->value[0]);
- $quotient = new Math_BigInteger();
- $remainder = new Math_BigInteger();
- $quotient->value = $q;
- $remainder->value = array($r);
- $quotient->is_negative = $this->is_negative != $y->is_negative;
- return array($this->_normalize($quotient), $this->_normalize($remainder));
- }
- static $zero;
- if (!(isset($zero))) {
- $zero = new Math_BigInteger();
- }
- $x = $this->copy();
- $y = $y->copy();
- $x_sign = $x->is_negative;
- $y_sign = $y->is_negative;
- $x->is_negative = $y->is_negative = false;
- $diff = $x->compare($y);
- if (!$diff) {
- $temp = new Math_BigInteger();
- $temp->value = array(1);
- $temp->is_negative = $x_sign != $y_sign;
- return array($this->_normalize($temp), $this->_normalize(new Math_BigInteger()));
- }
- if ($diff < 0) {
- if ($x_sign) {
- $x = $y->subtract($x);
- }
- ..........................................................
- .........................
- ..........
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement