1: <?php
2: 3: 4: 5: 6: 7: 8: 9:
10: namespace chippyash\Type\Number\Complex;
11:
12: use chippyash\Type\AbstractMultiValueType;
13: use chippyash\Type\TypeFactory;
14: use chippyash\Type\Interfaces\ComplexTypeInterface;
15: use chippyash\Type\Interfaces\NumericTypeInterface;
16: use chippyash\Type\Number\Rational\RationalType;
17: use chippyash\Type\Exceptions\NotRealComplexException;
18:
19: 20: 21:
22: abstract class AbstractComplexType extends AbstractMultiValueType implements ComplexTypeInterface, NumericTypeInterface
23: {
24: 25: 26: 27:
28: protected $valueMap = array(
29: 0 => array(
30: 'name' => 'real',
31: 'class' => 'chippyash\Type\Interfaces\NumericTypeInterface'
32: ),
33: 1 => array(
34: 'name' => 'imaginary',
35: 'class' => 'chippyash\Type\Interfaces\NumericTypeInterface'
36: )
37: );
38:
39: 40: 41: 42: 43: 44:
45: abstract public function modulus();
46:
47: 48: 49: 50: 51: 52: 53: 54:
55: abstract public function theta();
56:
57: 58: 59: 60: 61:
62: abstract public function asComplex();
63:
64: 65: 66: 67: 68: 69: 70: 71:
72: abstract public function asRational();
73:
74: 75: 76: 77: 78: 79:
80: public function polarString()
81: {
82: if ($this->isZero()) {
83: return '0';
84: }
85:
86: $rho = $this->checkIntType($this->radius()->asFloatType()->get());
87: $theta = $this->checkIntType($this->theta()->asFloatType()->get());
88: if (is_int($theta)) {
89: $tpattern = 'cos %1$d + i⋅sin %1$d';
90: } else {
91: $tpattern = 'cos %1$f + i⋅sin %1$f';
92: }
93: if ($rho == 1) {
94: return sprintf($tpattern, $theta);
95: }
96: if (is_int($rho)) {
97: $rpattern = '%2$d';
98: } else {
99: $rpattern = '%2$f';
100: }
101: $pattern = "{$rpattern}({$tpattern})";
102: return sprintf($pattern, $theta, $rho);
103: }
104:
105: 106: 107: 108: 109: 110: 111:
112: public function asIntType()
113: {
114: if ($this->isReal()) {
115:
116: return TypeFactory::create('int', floor($this->value['real']->get()));
117: } else {
118: throw new NotRealComplexException();
119: }
120: }
121:
122: 123: 124: 125: 126: 127:
128: public function asFloatType()
129: {
130: if ($this->isReal()) {
131: return TypeFactory::create('float', $this->value['real']->get());
132: } else {
133: throw new NotRealComplexException();
134: }
135: }
136:
137: 138: 139: 140: 141: 142: 143: 144:
145: public function toFloat()
146: {
147: if ($this->isReal()) {
148: return $this->value['real']->get();
149: } else {
150: throw new NotRealComplexException();
151: }
152: }
153:
154: 155: 156: 157: 158: 159: 160:
161: public function abs()
162: {
163: return $this->modulus();
164: }
165:
166:
167: 168: 169: 170: 171:
172: public function negate()
173: {
174: $this->value['real']->negate();
175: $this->value['imaginary']->negate();
176:
177: return $this;
178: }
179:
180: 181: 182: 183:
184: public function r()
185: {
186: return $this->value['real'];
187: }
188:
189: 190: 191: 192: 193:
194: public function i()
195: {
196: return $this->value['imaginary'];
197: }
198:
199: 200: 201: 202:
203: public function isZero()
204: {
205: return ($this->value['real']->get() == 0 && $this->value['imaginary']->get() == 0);
206: }
207:
208: 209: 210: 211: 212:
213: public function isReal()
214: {
215: return ($this->value['imaginary']->numerator()->get() == 0);
216: }
217:
218: 219: 220: 221: 222: 223:
224: public function isGaussian()
225: {
226: return ($this->value['real']->denominator()->get() == 1 &&
227: $this->value['imaginary']->denominator()->get() == 1);
228: }
229:
230: 231: 232: 233:
234: public function conjugate()
235: {
236: $imaginary = clone $this->value['imaginary'];
237: return new static(clone $this->value['real'], $imaginary->negate());
238: }
239:
240: 241: 242: 243: 244: 245:
246: public function radius()
247: {
248: return $this->modulus();
249: }
250:
251: 252: 253: 254: 255: 256: 257: 258:
259: public function asPolar()
260: {
261: return array('radius'=>$this->modulus(), 'theta'=>$this->theta());
262: }
263:
264: 265: 266: 267: 268: 269:
270: public function polarQuadrant()
271: {
272: $signR = ($this->value['real']->numerator()->get() > 0 ? '+' : '-');
273: $signI = ($this->value['imaginary']->numerator()->get() > 0 ? '+' : '-');
274: $ret = 0;
275: switch ("{$signR}{$signI}") {
276: case '++':
277: $ret = 1;
278: break;
279: case '-+':
280: $ret = 2;
281: break;
282: case '--':
283: $ret = 3;
284: break;
285: case '+-':
286: $ret = 4;
287: break;
288: }
289:
290: return $ret;
291: }
292:
293: 294: 295: 296: 297: 298: 299:
300: public function __toString()
301: {
302: if ($this->isZero()) {
303: return '0';
304: }
305:
306: $real = (string) $this->value['real'];
307:
308: if ($this->isReal()) {
309: return $real;
310: }
311:
312: $imaginary = (string) $this->value['imaginary'];
313: if ($imaginary[0] != '-') {
314: $imaginary = '+' . $imaginary;
315: }
316: return "{$real}{$imaginary}i";
317: }
318:
319: 320: 321: 322: 323: 324:
325: public function __clone()
326: {
327: $this->value['real'] = clone $this->value['real'];
328: $this->value['imaginary'] = clone $this->value['imaginary'];
329: }
330:
331: 332: 333: 334: 335:
336: public function __invoke()
337: {
338: return $this->get();
339: }
340:
341: 342: 343: 344: 345:
346: protected function getAsNativeType()
347: {
348: if ($this->isZero()) {
349: return 0;
350: }
351: if ($this->isReal()) {
352: return $this->value['real']->get();
353: }
354:
355: return (string) $this;
356: }
357:
358: 359: 360: 361:
362: protected function checkIntType($value)
363: {
364: $test = intval($value);
365: if (($value - $test) == 0) {
366: return $test;
367: }
368:
369: return $value;
370: }
371: }
372: