GmpBigInteger.class.php

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