Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
90.32% covered (success)
90.32%
56 / 62
84.62% covered (warning)
84.62%
22 / 26
CRAP
0.00% covered (danger)
0.00%
0 / 1
Complex
90.32% covered (success)
90.32%
56 / 62
84.62% covered (warning)
84.62%
22 / 26
44.68
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 re
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 im
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 conjugate
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 reciprocal
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 sqrt
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 abs
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 square
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 pow
40.00% covered (danger)
40.00%
2 / 5
0.00% covered (danger)
0.00%
0 / 1
4.94
 powComplex
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 powInteger
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 powScalar
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 add
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 addComplex
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 addScalar
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 sub
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 subComplex
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 subScalar
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 mult
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 multComplex
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 multScalar
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 magnitued
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 div
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 divComplex
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 divScalar
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 render
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
10
1<?php
2/**
3 * Jingga
4 *
5 * PHP Version 8.1
6 *
7 * @package   phpOMS\Math\Number
8 * @copyright Dennis Eichhorn
9 * @license   OMS License 2.0
10 * @version   1.0.0
11 * @link      https://jingga.app
12 */
13declare(strict_types=1);
14
15namespace phpOMS\Math\Number;
16
17/**
18 * Complex number class.
19 *
20 * @package phpOMS\Math\Number
21 * @license OMS License 2.0
22 * @link    https://jingga.app
23 * @since   1.0.0
24 */
25final class Complex
26{
27    /**
28     * Real part.
29     *
30     * @var int|float
31     * @since 1.0.0
32     */
33    private $re;
34
35    /**
36     * Imaginary part.
37     *
38     * @var int|float
39     * @since 1.0.0
40     */
41    private $im;
42
43    /**
44     * Constructor.
45     *
46     * @param int|float $re Real part
47     * @param int|float $im Imaginary part
48     *
49     * @since 1.0.0
50     */
51    public function __construct(int | float $re = 0, int | float $im = 0)
52    {
53        $this->re = $re;
54        $this->im = $im;
55    }
56
57    /**
58     * Get real part
59     *
60     * @return int|float
61     *
62     * @since 1.0.0
63     */
64    public function re() : int | float
65    {
66        return $this->re;
67    }
68
69    /**
70     * Get imaginary part
71     *
72     * @return int|float
73     *
74     * @since 1.0.0
75     */
76    public function im() : int | float
77    {
78        return $this->im;
79    }
80
81    /**
82     * Conjugate
83     *
84     * @latex z = a - b*i
85     *
86     * @return Complex
87     *
88     * @since 1.0.0
89     */
90    public function conjugate() : self
91    {
92        return new self($this->re, -$this->im);
93    }
94
95    /**
96     * Reciprocal
97     *
98     * @return Complex
99     *
100     * @since 1.0.0
101     */
102    public function reciprocal() : self
103    {
104        return new self(
105            $this->re / ($this->re ** 2 + $this->im ** 2),
106            -$this->im / ($this->re ** 2 + $this->im ** 2)
107        );
108    }
109
110    /**
111     * Square root
112     *
113     * @return Complex
114     *
115     * @since 1.0.0
116     */
117    public function sqrt() : self
118    {
119        return new self(
120            \sqrt(($this->re + \sqrt($this->re ** 2 + $this->im ** 2)) / 2),
121            ($this->im <=> 0) * \sqrt((-$this->re + \sqrt($this->re ** 2 + $this->im ** 2)) / 2)
122        );
123    }
124
125    /**
126     * Absolute
127     *
128     * @return int|float
129     *
130     * @since 1.0.0
131     */
132    public function abs() : int | float
133    {
134        return \sqrt($this->re ** 2 + $this->im ** 2);
135    }
136
137    /**
138     * Square
139     *
140     * @return Complex
141     *
142     * @since 1.0.0
143     */
144    public function square() : self
145    {
146        return $this->multComplex($this);
147    }
148
149    /**
150     * Pow opperator
151     *
152     * @param int|float|self $value Value to pow
153     *
154     * @return Complex
155     *
156     * @since 1.0.0
157     */
158    public function pow(int | float | self $value) : self
159    {
160        if (\is_int($value)) {
161            return $this->powInteger($value);
162        } elseif (\is_float($value)) {
163            return $this->powScalar($value);
164        }
165
166        return $this->powComplex($value);
167    }
168
169    /**
170     * Power with complex number
171     *
172     * @param Complex $value Power
173     *
174     * @return Complex
175     *
176     * @since 1.0.0
177     */
178    public function powComplex(self $value) : self
179    {
180        return $this;
181    }
182
183    /**
184     * Power with integer
185     *
186     * @param int $value Power
187     *
188     * @return Complex
189     *
190     * @since 1.0.0
191     */
192    public function powInteger(int $value) : self
193    {
194        if ($value === 0) {
195            return new self(1, 0);
196        } elseif ($value === 1) {
197            return $this;
198        }
199
200        return $this->multComplex($this->powInteger(--$value));
201    }
202
203    /**
204     * Power with scalar
205     *
206     * @param int|float $value Power
207     *
208     * @return Complex
209     *
210     * @since 1.0.0
211     */
212    public function powScalar(int | float $value) : self
213    {
214        return $this;
215    }
216
217    /**
218     * Add opperator
219     *
220     * @param int|float|self $value Value to add
221     *
222     * @return Complex
223     *
224     * @since 1.0.0
225     */
226    public function add(int | float | self $value) : self
227    {
228        if (\is_numeric($value)) {
229            return $this->addScalar($value);
230        }
231
232        return $this->addComplex($value);
233    }
234
235    /**
236     * Add opperator
237     *
238     * @param Complex $cpl Value to add
239     *
240     * @return Complex
241     *
242     * @since 1.0.0
243     */
244    private function addComplex(self $cpl) : self
245    {
246        return new self($this->re + $cpl->re(), $this->im + $cpl->im());
247    }
248
249    /**
250     * Add opperator
251     *
252     * @param int|float $val Value to add
253     *
254     * @return Complex
255     *
256     * @since 1.0.0
257     */
258    private function addScalar(int | float $val) : self
259    {
260        return new self($this->re + $val, $this->im);
261    }
262
263    /**
264     * Sub opperator
265     *
266     * @param int|float|self $value Value to sub
267     *
268     * @return Complex
269     *
270     * @since 1.0.0
271     */
272    public function sub(int | float | self $value) : self
273    {
274        if (\is_numeric($value)) {
275            return $this->subScalar($value);
276        }
277
278        return $this->subComplex($value);
279    }
280
281    /**
282     * Sub opperator
283     *
284     * @param Complex $cpl Value to sub
285     *
286     * @return Complex
287     *
288     * @since 1.0.0
289     */
290    private function subComplex(self $cpl) : self
291    {
292        return new self($this->re - $cpl->re(), $this->im - $cpl->im());
293    }
294
295    /**
296     * Sub opperator
297     *
298     * @param int|float $val Value to sub
299     *
300     * @return Complex
301     *
302     * @since 1.0.0
303     */
304    private function subScalar(int | float $val) : self
305    {
306        return new self($this->re - $val, $this->im);
307    }
308
309    /**
310     * Mult opperator
311     *
312     * @param int|float|self $value Value to mult
313     *
314     * @return Complex
315     *
316     * @since 1.0.0
317     */
318    public function mult(int | float | self $value) : self
319    {
320        if (\is_numeric($value)) {
321            return $this->multScalar($value);
322        }
323
324        return $this->multComplex($value);
325    }
326
327    /**
328     * Mult opperator
329     *
330     * @param Complex $cpl Value to mult
331     *
332     * @return Complex
333     *
334     * @since 1.0.0
335     */
336    private function multComplex(self $cpl) : self
337    {
338        return new self(
339            $this->re * $cpl->re() - $this->im * $cpl->im(),
340            $this->re * $cpl->im() + $this->im * $cpl->re()
341        );
342    }
343
344    /**
345     * Mult opperator
346     *
347     * @param int|float $val Value to mult
348     *
349     * @return Complex
350     *
351     * @since 1.0.0
352     */
353    private function multScalar(int | float $val) : self
354    {
355        return new self($this->re * $val, $this->im * $val);
356    }
357
358    /**
359     * Calculate the magnitude of the complex number
360     *
361     * @param int $power Power
362     *
363     * @return int|float
364     *
365     * @since 1.0.0
366     */
367    public function magnitued(int $power = 2) : int | float
368    {
369        return \pow($this->re, $power) + \pow($this->im, $power);
370    }
371
372    /**
373     * Div opperator
374     *
375     * @param int|float|self $value Value to div
376     *
377     * @return Complex
378     *
379     * @since 1.0.0
380     */
381    public function div(int | float | self $value) : self
382    {
383        if (\is_numeric($value)) {
384            return $this->divScalar($value);
385        }
386
387        return $this->divComplex($value);
388    }
389
390    /**
391     * Div opperator
392     *
393     * @param Complex $cpl Value to div
394     *
395     * @return Complex
396     *
397     * @since 1.0.0
398     */
399    private function divComplex(self $cpl) : self
400    {
401        return new self(
402            ($this->re * $cpl->re() + $this->im * $cpl->im()) / ($cpl->re() ** 2 + $cpl->im() ** 2),
403            ($this->im * $cpl->re() - $this->re * $cpl->im()) / ($cpl->re() ** 2 + $cpl->im() ** 2)
404        );
405    }
406
407    /**
408     * Div opperator
409     *
410     * @param int|float $val Value to div
411     *
412     * @return Complex
413     *
414     * @since 1.0.0
415     */
416    private function divScalar(int | float $val) : self
417    {
418        return new self($this->re / $val, $this->im / $val);
419    }
420
421    /**
422     * Render complex number
423     *
424     * @param int $precision Output precision
425     *
426     * @return string
427     *
428     * @since 1.0.0
429     */
430    public function render(int $precision = 2) : string
431    {
432        return ($this->re !== 0 ? \number_format($this->re, $precision) : '')
433        . ($this->im > 0 && $this->re !== 0 ? ' +' : '')
434        . ($this->im < 0 && $this->re !== 0 ? ' -' : '')
435        . ($this->im !== 0 ? (
436            ($this->re !== 0 ? ' ' : '') . \number_format(
437                ($this->im < 0 && $this->re === 0 ? $this->im : \abs($this->im)), $precision
438                ) . 'i'
439            ) : '');
440    }
441}