00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00016 final class GmpBigInteger implements BigInteger
00017 {
00018 private $resource = null;
00019
00023 public static function make($number, $base = 10)
00024 {
00025 Assert::isTrue(is_numeric($number));
00026
00027 $result = new self;
00028 $result->resource = gmp_init($number, $base);
00029
00030 return $result;
00031 }
00032
00036 public static function getFactory()
00037 {
00038 return GmpBigIntegerFactory::me();
00039 }
00040
00044 public static function makeFromBinary($binary)
00045 {
00046 if ($binary === null || $binary === '')
00047 throw new WrongArgumentException(
00048 'can\'t make number from emptyness'
00049 );
00050
00051 if (ord($binary) > 127)
00052 throw new WrongArgumentException('only positive numbers allowed');
00053
00054 $number = self::make(0);
00055
00056 $length = strlen($binary);
00057 for ($i = 0; $i < $length; ++$i) {
00058 $number = $number->
00059 mul(self::make(256))->
00060 add(self::make(ord($binary)));
00061
00062 $binary = substr($binary, 1);
00063 }
00064
00065 return $number;
00066 }
00067
00071 public function add(BigInteger $x)
00072 {
00073 $result = new self;
00074 $result->resource = gmp_add($this->resource, $x->resource);
00075 return $result;
00076 }
00077
00078 public function compareTo(BigInteger $x)
00079 {
00080 $out = gmp_cmp($this->resource, $x->resource);
00081
00082 if ($out == 0)
00083 return 0;
00084 elseif ($out > 0)
00085 return 1;
00086 else
00087 return -1;
00088 }
00089
00093 public function mod(BigInteger $mod)
00094 {
00095 $result = new self;
00096 $result->resource = gmp_mod($this->resource, $mod->resource);
00097 return $result;
00098 }
00099
00103 public function pow(BigInteger $exp)
00104 {
00105 $result = new self;
00106 $result->resource = gmp_pow($this->resource, $exp->intValue());
00107 return $result;
00108 }
00109
00113 public function modPow(BigInteger $exp, BigInteger $mod)
00114 {
00115 $result = new self;
00116 $result->resource = gmp_powm(
00117 $this->resource,
00118 $exp->resource,
00119 $mod->resource
00120 );
00121 return $result;
00122 }
00123
00127 public function subtract(BigInteger $x)
00128 {
00129 $result = new self;
00130 $result->resource = gmp_sub($this->resource, $x->resource);
00131 return $result;
00132 }
00133
00137 public function mul(BigInteger $x)
00138 {
00139 $result = new self;
00140 $result->resource = gmp_mul($this->resource, $x->resource);
00141 return $result;
00142 }
00143
00147 public function div(BigInteger $x)
00148 {
00149 $result = new self;
00150 $result->resource = gmp_div($this->resource, $x->resource);
00151 return $result;
00152 }
00153
00154 public function toString()
00155 {
00156 return gmp_strval($this->resource);
00157 }
00158
00159 public function toBinary()
00160 {
00161 $withZero = gmp_cmp($this->resource, 0);
00162
00163 if ($withZero < 0)
00164 throw new WrongArgumentException('only positive integers allowed');
00165 elseif ($withZero === 0)
00166 return "\x00";
00167
00168 $bytes = array();
00169
00170 $dividend = $this->resource;
00171 while (gmp_cmp($dividend, 0) > 0) {
00172 list ($dividend, $reminder) = gmp_div_qr($dividend, 256);
00173 array_unshift($bytes, gmp_intval($reminder));
00174 }
00175
00176 if ($bytes[0] > 127) {
00177 array_unshift($bytes, 0);
00178 }
00179
00180 $binary = null;
00181 foreach ($bytes as $byte) {
00182 $binary .= pack('C', $byte);
00183 }
00184
00185 return $binary;
00186 }
00187
00188 public function intValue()
00189 {
00190 $intValue = gmp_intval($this->resource);
00191
00192 if ((string) $intValue !== gmp_strval($this->resource))
00193 throw new WrongArgumentException(
00194 'can\'t represent itself by integer'
00195 );
00196
00197 return $intValue;
00198 }
00199
00200 public function floatValue()
00201 {
00202 $stringValue = gmp_strval($this->resource);
00203 $floatValue = floatval($stringValue);
00204
00205 if (
00206 is_int($floatValue)
00207 && (string)$floatValue !== $stringValue
00208 || ! is_float($floatValue)
00209 ) {
00210 throw new WrongArgumentException('can\'t convert to float');
00211
00212 } else {
00213
00214 $absValue = abs($floatValue);
00215 $exponent = floor($absValue == 0 ? 0 : log10($absValue));
00216 $mantiss = (int) floor($floatValue * pow(10, -$exponent));
00217
00218 if (
00219 gmp_cmp(
00220 gmp_abs($this->resource),
00221 gmp_abs(
00222 gmp_sub(
00223 gmp_abs($this->resource),
00224 gmp_mul($mantiss, gmp_pow(10, $exponent))
00225 )
00226 )
00227 ) < 0
00228 )
00229 throw new WrongArgumentException('can\'t convert to float');
00230 }
00231
00232 return $floatValue;
00233 }
00234 }
00235 ?>