* $int1 = new GTBigInteger(4); * $int2 = new GTBigInteger("-12312321351878937123123098123"); * $int3 = new GTBigInteger(array(1, 226, 64)); * * * @throws GTException * @param string|int|array $value value as string or integer or byte array */ public function __construct($value) { if ($value === null || $value === '') { throw new GTException("parameter value is required"); } if (is_array($value)) { $bytes = $value; $value = '0'; $sign = ''; $length = count($bytes); if ($length <= 0) { throw new GTException("Invalid length: {$length}"); } if ($bytes[0] >> 7 == 1) { $sign = '-'; for ($i = 0; $i < $length; $i++) { $bytes[$i] = ~$bytes[$i] & 0xFF; } } for ($i = 0; $i < $length; $i++) { $value = bcadd($value, bcmul($bytes[$i], bcpow(256, $length - $i - 1, 0), 0), 0); } if ($sign == '-') { $value = bcadd($value, 1); } $value = $sign . $value; } else if ($value instanceof GTBigInteger) { $value = $value->getValue(); } $value = (string) $value; $chars = array( '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-' ); foreach (GTUtil::toArray($value) as $c) { if (!in_array($c, $chars, true)) { throw new GTException("parameter value contains invalid character: {$c}"); } } $this->value = $value; } /** * Gets the integer value as string. * * @return string integer value as string */ public function getValue() { return $this->value; } /** * Compares this GTBigInteger to another GTBigInteger. * * @param GTBigInteger $integer the other GTBigInteger * @return int 0 if both integers are equal, 1 if current integer is larger than the other, -1 otherwise */ public function comp(GTBigInteger $integer) { return bccomp($this->value, $integer->value, 0); } /** * Adds this GTBigInteger and another GTBigInteger. * * @param GTBigInteger $integer the other GTBigInteger * @return GTBigInteger the sum of the two integers */ public function add(GTBigInteger $integer) { return new GTBigInteger(bcadd($this->value, $integer->value, 0)); } /** * Subtracts another GTBigInteger from this integer. * * @param GTBigInteger $integer the GTBigInteger to subtract from this one * @return GTBigInteger the result of the subtraction */ public function sub(GTBigInteger $integer) { return new GTBigInteger(bcsub($this->value, $integer->value, 0)); } /** * Multiplies another GTBigInteger with this GTBigInteger. * * @param GTBigInteger $integer the GTBigInteger to multiply with * @return GTBigInteger the result of the multiplication */ public function mul(GTBigInteger $integer) { return new GTBigInteger(bcmul($this->value, $integer->value, 0)); } /** * Divides this GTBigInteger with another GTBigInteger. * * @param GTBigInteger $integer the GTBigInteger to divide by * @return GTBigInteger the result of the division */ public function div(GTBigInteger $integer) { return new GTBigInteger(bcdiv($this->value, $integer->value, 0)); } /** * Gets the modulus of this GTBigInteger using another GTBigInteger as modulus. * * @param int $integer modulus * @return GTBigInteger the modulus */ public function mod($modulus) { return new GTBigInteger(bcmod($this->value, $modulus)); } /** * Raises this GTBigInteger to the power of another GTBigInteger. * * @param GTBigInteger $integer power * @return GTBigInteger result of raising this GTBigInteger to the power of another GTBigInteger */ public function pow(GTBigInteger $integer) { return new GTBigInteger(bcpow($this->value, $integer->value, 0)); } /** * Returns a GTBigInteger whose value is (this << $step). * * @param int $step shift distance * @return GTBigInteger this << $step */ public function shiftLeft($step) { return new GTBigInteger(bcmul($this->value, bcpow(2, $step))); } /** * Returns a GTBigInteger whose value is (this >> $step). * * @param int $step shift distance * @return GTBigInteger this >> $step */ public function shiftRight($step) { return new GTBigInteger(bcdiv($this->value, bcpow(2, $step))); } /** * Returns a GTBitInteger whose value is ($this | $integer). * * @param GTBigInteger $integer value to be OR'ed with this GTBigInteger * @return GTBigInteger $this | $integer */ public function bitOr(GTBigInteger $integer) { $bytes1 = $this->toBytes(); $bytes2 = $integer->toBytes(); $length = max(count($bytes1), count($bytes2)); GTUtil::lpad($bytes1, $length, 0x0); GTUtil::lpad($bytes2, $length, 0x0); $result = array(); for ($i = 0; $i < $length; $i++) { $result[$i] = $bytes1[$i] | $bytes2[$i]; } return new GTBigInteger($result); } /** * Returns a GTBigInteger whose value is ($this ^ $integer). * * @param GTBigInteger $integer value to be XOR'ed with this GTBigInteger * @return GTBigInteger $this | $integer */ public function bitXor(GTBigInteger $integer) { $bytes1 = $this->toBytes(); $bytes2 = $integer->toBytes(); $length = max(count($bytes1), count($bytes2)); GTUtil::lpad($bytes1, $length, 0x0); GTUtil::lpad($bytes2, $length, 0x0); $result = array(); for ($i = 0; $i < $length; $i++) { $result[$i] = $bytes1[$i] ^ $bytes2[$i]; } return new GTBigInteger($result); } /** * Returns a GTBigInteger whose value is ($this & $integer). * * @param GTBigInteger $integer value to be AND'ed with this GTBigInteger * @return GTBigInteger $this & $integer */ public function bitAnd(GTBigInteger $integer) { $bytes1 = $this->toBytes(); $bytes2 = $integer->toBytes(); $length = max(count($bytes1), count($bytes2)); GTUtil::lpad($bytes1, $length, 0x0); GTUtil::lpad($bytes2, $length, 0x0); $result = array(); for ($i = 0; $i < $length; $i++) { $result[$i] = $bytes1[$i] & $bytes2[$i]; } return new GTBigInteger($result); } /** * Returns a GTBigInteger whose value is (~$this). * * * @return GTBigInteger ~$this */ public function bitNot() { $result = array(); foreach ($this->toBytes() as $byte) { array_push($result, ~$byte & 0xFF); } return new GTBigInteger($result); } /** * Returns an array of bytes that contains this integers two's complement representation. * * Example: * * * $int = new GTBigInteger(123456); * * print_r($int->toBytes()); * * // Array * // ( * // [0] => 1 * // [1] => 226 * // [2] => 64 * // ) * * * @return array byte array that contains two's complement representation of this integer */ public function toBytes() { $result = ''; $buff = $this->value; $sign = ''; if ($buff{0} == '-') { $sign = '-'; $buff = substr($buff, 1); } while (bccomp($buff, 255, 0) == 1) { $rest = bcmod($buff, 256); $buff = bcdiv($buff, 256, 0); $result = chr($rest) . $result; } $result = chr($buff) . $result; $bytes = GTUtil::toByteArray($result); if ($sign == '-') { for ($i = 0; $i < count($bytes); $i++) { $bytes[$i] = ~$bytes[$i] & 0xFF; } array_unshift($bytes, 0x0); $int = new GTBigInteger($bytes); $int = $int->add(new GTBigInteger(1)); $bytes = $int->toBytes(); // strip leading 0 bytes while (count($bytes) > 0 && $bytes[0] == 0x0) { array_shift($bytes); } return $bytes; } else { // add leading 0x0 so the integer isn't considered negative if (count($bytes) > 0 && $bytes[0] >> 7 == 1) { array_unshift($bytes, 0x0); } return $bytes; } } /** * Returns a bit string that contains the bits of this integer. * * Example: * * * $int = new GTBigInteger(4); * echo $int->toBits(); * * // 00000100 * * * @return string bit string containing the bits of this integer */ public function toBits() { $result = ''; foreach ($this->toBytes() as $byte) { $byte = decbin($byte); while (strlen($byte) % 8 != 0) { $byte = '0' . $byte; } $result .= $byte; } return $result; } } ?>