Overview

Namespaces

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

Classes

  • AbstractComplexType
  • ComplexType
  • ComplexTypeFactory
  • GMPComplexType
  • 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\Complex;
 12: 
 13: use chippyash\Type\Number\Rational\RationalType;
 14: use chippyash\Type\Number\Rational\GMPRationalType;
 15: use chippyash\Type\Number\Rational\RationalTypeFactory;
 16: use chippyash\Type\Exceptions\NotRealComplexException;
 17: use chippyash\Type\Interfaces\GMPInterface;
 18: use chippyash\Type\Number\GMPIntType;
 19: use chippyash\Type\Number\FloatType;
 20: use chippyash\Type\TypeFactory;
 21: 
 22: /**
 23:  * A complex number - algabraic form - GMP version
 24:  *
 25:  * A complex number is a number that can be expressed in the form a + bi,
 26:  * where a and b are real numbers and i is the imaginary unit,
 27:  * which satisfies the equation i² = −1
 28:  *
 29:  * Complex numbers use real numbers expressed as a GMPRationalType.  This allows
 30:  * for greater arithmetic stability
 31:  *
 32:  * @link http://en.wikipedia.org/wiki/Complex_number
 33:  */
 34: class GMPComplexType extends AbstractComplexType implements GMPInterface
 35: {
 36: 
 37:     /**
 38:      * Map of values for this type
 39:      * @var array
 40:      */
 41:     protected $valueMap = array(
 42:         0 => array(
 43:             'name' => 'real',
 44:             'class' => 'chippyash\Type\Number\Rational\GMPRationalType'
 45:         ),
 46:         1 => array(
 47:             'name' => 'imaginary',
 48:             'class' => 'chippyash\Type\Number\Rational\GMPRationalType'
 49:         )
 50:     );
 51: 
 52:     /**
 53:      * Constructor
 54:      *
 55:      * @param GMPRationalType $real
 56:      * @param GMPRationalType $imaginary
 57:      */
 58:     public function __construct(GMPRationalType $real, GMPRationalType $imaginary)
 59:     {
 60:         $this->setFromTypes(array($real, $imaginary));
 61:     }
 62: 
 63:     /**
 64:      * Return the modulus, also known as absolute value or magnitude of this number
 65:      * = sqrt(r^2 + i^2);
 66:      *
 67:      * @return \chippyash\Type\Number\Rational\GMPRationalType
 68:      */
 69:     public function modulus()
 70:     {
 71:         if ($this->isReal()) {
 72:             //sqrt(r^2 + 0^2) = sqrt(r^2) = abs(r)
 73:             /** @noinspection PhpUndefinedMethodInspection */
 74:             return $this->value['real']->abs();
 75:         }
 76:         //get r^2 and i^2
 77:         $sqrR = array(
 78:             'n' => gmp_pow($this->value['real']->numerator()->gmp(), 2),
 79:             'd' => gmp_pow($this->value['real']->denominator()->gmp(), 2)
 80:         );
 81:         $sqrI = array(
 82:             'n' => gmp_pow($this->value['imaginary']->numerator()->gmp(), 2),
 83:             'd' => gmp_pow($this->value['imaginary']->denominator()->gmp(), 2)
 84:         );
 85:         //r^2 + i^2
 86:         $den = $this->lcm($sqrR['d'], $sqrI['d']);
 87:         $numRaw = gmp_strval(
 88:             gmp_add(
 89:                 gmp_div_q(gmp_mul($sqrR['n'], $den), $sqrR['d']),
 90:                 gmp_div_q(gmp_mul($sqrI['n'], $den), $sqrI['d'])
 91:             )
 92:         );
 93:         $num = TypeFactory::createInt($numRaw);
 94: 
 95:         //sqrt(num/den) = sqrt(num)/sqrt(den)
 96:         //now this a fudge - we ought to be able to get a proper square root using
 97:         //factors etc but what we do instead is to do an approximation by converting
 98:         //to intermediate rationals using as much precision as we can i.e.
 99:         // rNum = GMPRationaType(sqrt(num))
100:         // rDen = GMPRationalType(sqrt(den))
101:         // mod = rN/1 * 1/rD
102:         $rNum = RationalTypeFactory::fromFloat(sqrt($num()));
103:         $rDen = RationalTypeFactory::fromFloat(sqrt(gmp_strval($den)));
104:         $modN = gmp_mul($rNum->numerator()->gmp(), $rDen->denominator()->gmp());
105:         $modD = gmp_mul($rNum->denominator()->gmp(), $rDen->numerator()->gmp());
106: 
107:         return RationalTypeFactory::create(
108:             (int) gmp_strval($modN),
109:             (int) gmp_strval($modD)
110:         );
111:     }
112: 
113:     /**
114:      * Return the angle (sometimes known as the argument) of the number
115:      * when expressed in polar notation
116:      * 
117:      * The return value is a rational expressing theta as radians
118:      *
119:      * @todo implement gmp atan2 method
120:      *
121:      * @return \chippyash\Type\Number\Rational\GMPRationalType
122:      */
123:     public function theta()
124:     {
125:         return RationalTypeFactory::fromFloat(
126:             atan2(
127:                 $this->value['imaginary']->asFloatType()->get(),
128:                 $this->value['real']->asFloatType()->get()
129:             )
130:         );
131:     }
132:     
133:     /**
134:      * Return the value of number array of gmp resources|objects
135:      *
136:      * @return \GMP|\resource array [[num,den],[num,den]]
137:      */
138:     public function gmp()
139:     {
140:         return array($this->value['real']->gmp(), $this->value['imaginary']->gmp());
141:     }
142: 
143:     /**
144:      * Return number as GMPIntType number.
145:      * If number isReal() will return floor(r())
146:      *
147:      * @return \chippyash\Type\Number\GMPIntType
148:      * @throws NotRealComplexException
149:      */
150:     public function asGMPIntType()
151:     {
152:         if ($this->isReal()) {
153:             return new GMPIntType(floor($this->value['real']->get()));
154:         } else {
155:             throw new NotRealComplexException();
156:         }
157:     }
158:     
159:     /**
160:      * Return the number as a GMPComplex number i.e. a+bi
161:      * Clones self
162:      * 
163:      * @return \chippyash\Type\Number\Complex\GMPComplexType
164:      */
165:     public function asGMPComplex()
166:     {
167:         return clone $this;
168:     }
169:     
170:     /**
171:      * Return the number as a Complex number i.e. n+0i
172:      * 
173:      * @return \chippyash\Type\Number\Complex\ComplexType
174:      */
175:     public function asComplex()
176:     {
177:         return new ComplexType($this->r()->asRational(), $this->i()->asRational());
178:     }
179:     
180:     /**
181:      * Return number as GMPRational number.
182:      * If number isReal() will return GMPRationalType
183:      * NB, numerator and denominator will be caste as GMPIntTypes
184:      *
185:      * @return \chippyash\Type\Number\Rational\GMPRationalType
186:      * @throws NotRealComplexException
187:      */
188:     public function asGMPRational()
189:     {
190:         if ($this->isReal()) {
191:             return clone $this->value['real'];
192:         } else {
193:             throw new NotRealComplexException();
194:         }
195:     }
196:     
197:     /**
198:      * Return number as Rational number.
199:      * NB, numerator and denominator will be caste as IntTypes
200:      *
201:      * @return \chippyash\Type\Number\Rational\RationalType
202:      *
203:      * @throws NotRealComplexException
204:      */
205:     public function asRational()
206:     {
207:         if ($this->isReal()) {
208:             return new RationalType(
209:                 $this->value['real']->numerator()->asIntType(),
210:                 $this->value['real']->denominator()->asIntType()
211:             );
212:         } else {
213:             throw new NotRealComplexException();
214:         }
215:     }
216:     
217:     /**
218:      * Return number as a FloatType number.
219:      *
220:      * @return \chippyash\Type\Number\FloatType
221:      * @throws NotRealComplexException
222:      */
223:     public function asFloatType()
224:     {
225:         if ($this->isReal()) {
226:             return new FloatType($this->value['real']->get());
227:         } else {
228:             throw new NotRealComplexException();
229:         }
230:     }
231:     
232:     /**
233:      * Return Least Common Multiple of two numbers
234:      * @param int $a
235:      * @param int $b
236:      * @return int
237:      */
238:     private function lcm($a, $b)
239:     {
240:         return gmp_abs(gmp_div_q(gmp_mul($a, $b), gmp_gcd($a, $b)));
241:     }
242: }
243: 
Chippyash Strong Types API documentation generated by ApiGen 2.8.0