Overview

Namespaces

  • chippyash
    • Type
      • Exceptions
      • Interfaces
      • Number
        • Complex
        • Rational
      • String

Classes

  • FloatType
  • GMPIntType
  • IntType
  • NaturalIntType
  • WholeIntType
  • Overview
  • Namespace
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * Hard type support
  4:  * For when you absolutely want to know what you are getting
  5:  *
  6:  * @author Ashley Kitson <akitson@zf4.biz>
  7:  * @copyright Ashley Kitson, UK, 2014
  8:  * @licence GPL V3 or later : http://www.gnu.org/licenses/gpl.html
  9:  */
 10: 
 11: namespace chippyash\Type\Number;
 12: 
 13: use chippyash\Type\Interfaces\GMPInterface;
 14: use chippyash\Type\Number\Complex\GMPComplexType;
 15: use chippyash\Type\Number\Rational\GMPRationalType;
 16: use chippyash\Type\Exceptions\GmpNotSupportedException;
 17: 
 18: /**
 19:  * Integer Type - for use with GMP extension
 20:  */
 21: class GMPIntType extends IntType implements GMPInterface
 22: {
 23:     protected static $gmpInstalled;
 24:     
 25:     /**
 26:      * Constructor - check for gmp support
 27:      *
 28:      * @param mixed $value
 29:      * @throws GmpNotSupportedException
 30:      */
 31:     public function __construct($value)
 32:     {
 33:         if (empty(self::$gmpInstalled) || $this->checkGmpInstalled()) {
 34:             self::$gmpInstalled = true;
 35:         } else {
 36:             throw new GmpNotSupportedException();
 37:         }
 38:         parent::__construct($value);
 39:     }
 40: 
 41:     /**
 42:      * Negates the number
 43:      *
 44:      * @return \chippyash\Type\Number\GMPIntType Fluent Interface
 45:      */
 46:     public function negate()
 47:     {
 48:         $this->value = gmp_neg($this->value);
 49: 
 50:         return $this;
 51:     }
 52: 
 53:     /**
 54:      * Return the number as a GMPComplex number i.e. n+0i
 55:      *
 56:      * @return \chippyash\Type\Number\Complex\GMPComplexType
 57:      */
 58:     public function asComplex()
 59:     {
 60:         return new GMPComplexType(
 61:             new GMPRationalType(clone $this, new self(1)),
 62:             new GMPRationalType(new self(0), new self(1))
 63:         );
 64:     }
 65: 
 66:     /**
 67:      * Return number as GMPRational number.
 68:      * NB, numerator and denominator will be caste as GMPIntTypes
 69:      *
 70:      * @return \chippyash\Type\Number\Rational\GMPRationalType
 71:      */
 72:     public function asRational()
 73:     {
 74:         return new GMPRationalType(clone $this, new self(1));
 75:     }
 76: 
 77:     /**
 78:      * Return number as a FloatType number.
 79:      *
 80:      * @return \chippyash\Type\Number\FloatType
 81:      */
 82:     public function asFloatType()
 83:     {
 84:         return new FloatType(gmp_strval($this->value));
 85:     }
 86: 
 87:     /**
 88:      * Return the absolute value of the number
 89:      *
 90:      * @return \chippyash\Type\Number\GMPIntType
 91:      */
 92:     public function abs()
 93:     {
 94:         return new self(gmp_abs($this->value));
 95:     }
 96: 
 97:     /**
 98:      * Return all factors of this number (sorted)
 99:      * Returned factors are strings
100:      *
101:      * @return array [factor,factor, ...]
102:      */
103:     public function factors()
104:     {
105:         $num = $this->cloneValue();
106:         $limit = gmp_sqrt($num);
107:         $zero = gmp_init(0);
108:         $one = gmp_init(1);
109:         $ret = array();
110:         for ($x = gmp_init(1); gmp_cmp($x, $limit) <= 0; $x = gmp_add($x, $one)) {
111:             if (gmp_cmp(gmp_mod($num, $x), $zero) == 0) {
112:                 $xAsInt = gmp_strval($x);
113:                 $other = gmp_strval(gmp_div_q($num, $x));
114:                 $ret[$xAsInt] = $xAsInt;
115:                 $ret[$other] = $other;
116:             }
117:         }
118:         ksort($ret, SORT_NUMERIC);
119:         return array_values($ret);
120:     }
121: 
122:     /**
123:      * Return all prime factors of this number
124:      *
125:      * The keys (prime factors) will be strings
126:      * The values (exponents will be integers
127:      *
128:      * Adapted from http://www.thatsgeeky.com/2011/03/prime-factoring-with-php/
129:      *
130:      * @return array [primeFactor => exponent,...]
131:      */
132:     public function primeFactors()
133:     {
134:         $number = $this->cloneValue();
135:         $divisor = 2;
136:         $zero = gmp_init(0);
137:         $one = gmp_init(1);
138:         $dmax = gmp_sqrt($number);
139:         $factors = array();
140:         $sieve = array_fill(1, intval(gmp_strval($dmax)), 1);
141:         do {
142:             $rFlag = false;
143:             while (gmp_cmp(gmp_mod($number, $divisor), $zero) == 0) {
144:                 $factors[$divisor] = (isset($factors[$divisor]) ? $factors[$divisor] + 1 : 1);
145:                 $number = gmp_div_q($number, $divisor);
146:                 $rFlag = true;
147:             }
148:             if ($rFlag) {
149:                 $dmax = gmp_sqrt($number);
150:             }
151:             if (gmp_cmp($number, $one) > 0) {
152:                 for ($i = $divisor; gmp_cmp($i, $dmax) <= 0; $i += $divisor) {
153:                     $sieve[$i] = 0;
154:                 }
155:                 do {
156:                     $divisor ++;
157:                 } while (gmp_cmp($divisor, $dmax) < 0 && $sieve[$divisor] != 1 );
158:                 if (gmp_cmp($divisor, $dmax) > 0) {
159:                     $key = gmp_strval($number);
160:                     $factors[$key] = (isset($factors[$key]) ? $factors[$key] + 1 : 1);
161:                 }
162:             }
163:         } while (gmp_cmp($number, $one) > 0 && gmp_cmp($divisor, $dmax) <= 0);
164: 
165:         return $factors;
166:     }
167: 
168:     /**
169:      * Magic method - convert to string
170:      *
171:      * @return string
172:      */
173:     public function __toString()
174:     {
175:         return gmp_strval($this->value);
176:     }
177: 
178:     /**
179:      * Get the value of the object typed properly
180:      * as a PHP Native type
181:      *
182:      * @return integer
183:      */
184:     public function get()
185:     {
186:         return intval(gmp_strval($this->value));
187:     }
188: 
189:     /**
190:      * Return the value of number as a gmp resource or object
191:      *
192:      * @return \GMP|\resource resource|gmp object
193:      */
194:     public function gmp()
195:     {
196:         return $this->value;
197:     }
198: 
199:     /**
200:      * Return number as GMPIntType number.
201:      *
202:      * @return \chippyash\Type\Number\GMPIntType
203:      */
204:     public function asGMPIntType()
205:     {
206:         return clone $this;
207:     }
208:     
209:     /**
210:      * Return number as IntType
211:      * 
212:      * @return \chippyash\Type\Number\IntType
213:      */
214:     public function asIntType()
215:     {
216:         return new IntType($this->get());
217:     }
218:     
219:     /**
220:      * Return the number as a GMPComplex number i.e. n+0i
221:      * 
222:      * @return \chippyash\Type\Number\Complex\GMPComplexType
223:      */
224:     public function asGMPComplex()
225:     {
226:         return new GMPComplexType(
227:             new GMPRationalType(new GMPIntType($this->get()), new GMPIntType(1)),
228:             new GMPRationalType(new GMPIntType(0), new GMPIntType(1))
229:         );
230:     }
231:     
232:     /**
233:      * Return number as GMPRational number.
234:      * NB, numerator and denominator will be caste as GMPIntTypes
235:      *
236:      * @return \chippyash\Type\Number\Rational\GMPRationalType
237:      */
238:     public function asGMPRational()
239:     {
240:         return new GMPRationalType(new GMPIntType($this->get()), new GMPIntType(1));
241:     }
242: 
243:     /**
244:      * Return correctly typed value for this type
245:      *
246:      * @param mixed $value
247:      *
248:      * @return \GMP|\resource
249:      */
250:     protected function typeOf($value)
251:     {
252:         if ($this->gmpTypeCheck($value)) {
253:             return $value;
254:         } else {
255:             return gmp_init(intval($value));
256:         }
257:     }
258: 
259:     /**
260:      * @return \GMP|\resource
261:      */
262:     protected function cloneValue()
263:     {
264:         if (version_compare(PHP_VERSION, '5.6.0') < 0) {
265:             //it's a resource so can be copied
266:             return $this->value;
267:         }
268:         //it's an object so clone
269:         return clone $this->value;
270:     }
271: 
272: 
273:     /**
274:      * Check gmp type depending on PHP version
275:      *
276:      * @param mixed $value value to check type of
277:      * @return boolean true if gmp number else false
278:      */
279:     protected function gmpTypeCheck($value)
280:     {
281:         if (version_compare(PHP_VERSION, '5.6.0') < 0) {
282:             return is_resource($value) && get_resource_type($value) == 'GMP integer';
283:         }
284: 
285:         return ($value instanceof \GMP);
286:     }
287: 
288:     /**
289:      * Is gmp installed?
290:      *
291:      * @return boolean
292:      */
293:     protected function checkGmpInstalled()
294:     {
295:         return extension_loaded('gmp');
296:     }
297: }
298: 
Chippyash Strong Types API documentation generated by ApiGen 2.8.0