1 // Written in the D programming language.
2 
3 /** This module contains the $(LREF Complex) type, which is used to represent
4     complex numbers, along with related mathematical operations and functions.
5 
6     $(LREF Complex) will eventually
7     $(DDLINK deprecate, Deprecated Features, replace)
8     the built-in types `cfloat`, `cdouble`, `creal`, `ifloat`,
9     `idouble`, and `ireal`.
10 
11     Macros:
12         TABLE_SV = <table border="1" cellpadding="4" cellspacing="0">
13                 <caption>Special Values</caption>
14                 $0</table>
15         PLUSMN = &plusmn;
16         NAN = $(RED NAN)
17         INFIN = &infin;
18         PI = &pi;
19 
20     Authors:    Lars Tandle Kyllingstad, Don Clugston
21     Copyright:  Copyright (c) 2010, Lars T. Kyllingstad.
22     License:    $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0)
23     Source:     $(PHOBOSSRC std/complex.d)
24 */
25 module std.complex;
26 
27 import std.traits;
28 
29 /** Helper function that returns a complex number with the specified
30     real and imaginary parts.
31 
32     Params:
33         R = (template parameter) type of real part of complex number
34         I = (template parameter) type of imaginary part of complex number
35 
36         re = real part of complex number to be constructed
37         im = (optional) imaginary part of complex number, 0 if omitted.
38 
39     Returns:
40         `Complex` instance with real and imaginary parts set
41         to the values provided as input.  If neither `re` nor
42         `im` are floating-point numbers, the return type will
43         be `Complex!double`.  Otherwise, the return type is
44         deduced using $(D std.traits.CommonType!(R, I)).
45 */
46 auto complex(R)(const R re)  @safe pure nothrow @nogc
47 if (is(R : double))
48 {
49     static if (isFloatingPoint!R)
50         return Complex!R(re, 0);
51     else
52         return Complex!double(re, 0);
53 }
54 
55 /// ditto
56 auto complex(R, I)(const R re, const I im)  @safe pure nothrow @nogc
57 if (is(R : double) && is(I : double))
58 {
59     static if (isFloatingPoint!R || isFloatingPoint!I)
60         return Complex!(CommonType!(R, I))(re, im);
61     else
62         return Complex!double(re, im);
63 }
64 
65 ///
66 @safe pure nothrow unittest
67 {
68     auto a = complex(1.0);
69     static assert(is(typeof(a) == Complex!double));
70     assert(a.re == 1.0);
71     assert(a.im == 0.0);
72 
73     auto b = complex(2.0L);
74     static assert(is(typeof(b) == Complex!real));
75     assert(b.re == 2.0L);
76     assert(b.im == 0.0L);
77 
78     auto c = complex(1.0, 2.0);
79     static assert(is(typeof(c) == Complex!double));
80     assert(c.re == 1.0);
81     assert(c.im == 2.0);
82 
83     auto d = complex(3.0, 4.0L);
84     static assert(is(typeof(d) == Complex!real));
85     assert(d.re == 3.0);
86     assert(d.im == 4.0L);
87 
88     auto e = complex(1);
89     static assert(is(typeof(e) == Complex!double));
90     assert(e.re == 1);
91     assert(e.im == 0);
92 
93     auto f = complex(1L, 2);
94     static assert(is(typeof(f) == Complex!double));
95     assert(f.re == 1L);
96     assert(f.im == 2);
97 
98     auto g = complex(3, 4.0L);
99     static assert(is(typeof(g) == Complex!real));
100     assert(g.re == 3);
101     assert(g.im == 4.0L);
102 }
103 
104 
105 /** A complex number parametrised by a type `T`, which must be either
106     `float`, `double` or `real`.
107 */
108 struct Complex(T)
109 if (isFloatingPoint!T)
110 {
111     import std.format.spec : FormatSpec;
112     import std.range.primitives : isOutputRange;
113 
114     /** The real part of the number. */
115     T re;
116 
117     /** The imaginary part of the number. */
118     T im;
119 
120     /** Converts the complex number to a string representation.
121 
122     The second form of this function is usually not called directly;
123     instead, it is used via $(REF format, std,string), as shown in the examples
124     below.  Supported format characters are 'e', 'f', 'g', 'a', and 's'.
125 
126     See the $(MREF std, format) and $(REF format, std,string)
127     documentation for more information.
128     */
129     string toString() const @safe /* TODO: pure nothrow */
130     {
131         import std.exception : assumeUnique;
132         char[] buf;
133         buf.reserve(100);
134         auto fmt = FormatSpec!char("%s");
135         toString((const(char)[] s) { buf ~= s; }, fmt);
136         static trustedAssumeUnique(T)(T t) @trusted { return assumeUnique(t); }
137         return trustedAssumeUnique(buf);
138     }
139 
140     static if (is(T == double))
141     ///
142     @safe unittest
143     {
144         auto c = complex(1.2, 3.4);
145 
146         // Vanilla toString formatting:
147         assert(c.toString() == "1.2+3.4i");
148 
149         // Formatting with std.string.format specs: the precision and width
150         // specifiers apply to both the real and imaginary parts of the
151         // complex number.
152         import std.format : format;
153         assert(format("%.2f", c)  == "1.20+3.40i");
154         assert(format("%4.1f", c) == " 1.2+ 3.4i");
155     }
156 
157     /// ditto
158     void toString(Writer, Char)(scope Writer w, scope const ref FormatSpec!Char formatSpec) const
159     if (isOutputRange!(Writer, const(Char)[]))
160     {
161         import std.format.write : formatValue;
162         import std.math.traits : signbit;
163         import std.range.primitives : put;
164         formatValue(w, re, formatSpec);
165         if (signbit(im) == 0)
166            put(w, "+");
167         formatValue(w, im, formatSpec);
168         put(w, "i");
169     }
170 
171 @safe pure nothrow @nogc:
172 
173     /** Construct a complex number with the specified real and
174     imaginary parts. In the case where a single argument is passed
175     that is not complex, the imaginary part of the result will be
176     zero.
177     */
178     this(R : T)(Complex!R z)
179     {
180         re = z.re;
181         im = z.im;
182     }
183 
184     /// ditto
185     this(Rx : T, Ry : T)(const Rx x, const Ry y)
186     {
187         re = x;
188         im = y;
189     }
190 
191     /// ditto
192     this(R : T)(const R r)
193     {
194         re = r;
195         im = 0;
196     }
197 
198     // ASSIGNMENT OPERATORS
199 
200     // this = complex
201     ref Complex opAssign(R : T)(Complex!R z)
202     {
203         re = z.re;
204         im = z.im;
205         return this;
206     }
207 
208     // this = numeric
209     ref Complex opAssign(R : T)(const R r)
210     {
211         re = r;
212         im = 0;
213         return this;
214     }
215 
216     // COMPARISON OPERATORS
217 
218     // this == complex
219     bool opEquals(R : T)(Complex!R z) const
220     {
221         return re == z.re && im == z.im;
222     }
223 
224     // this == numeric
225     bool opEquals(R : T)(const R r) const
226     {
227         return re == r && im == 0;
228     }
229 
230     // UNARY OPERATORS
231 
232     // +complex
233     Complex opUnary(string op)() const
234     if (op == "+")
235     {
236         return this;
237     }
238 
239     // -complex
240     Complex opUnary(string op)() const
241     if (op == "-")
242     {
243         return Complex(-re, -im);
244     }
245 
246     // BINARY OPERATORS
247 
248     // complex op complex
249     Complex!(CommonType!(T,R)) opBinary(string op, R)(Complex!R z) const
250     {
251         alias C = typeof(return);
252         auto w = C(this.re, this.im);
253         return w.opOpAssign!(op)(z);
254     }
255 
256     // complex op numeric
257     Complex!(CommonType!(T,R)) opBinary(string op, R)(const R r) const
258     if (isNumeric!R)
259     {
260         alias C = typeof(return);
261         auto w = C(this.re, this.im);
262         return w.opOpAssign!(op)(r);
263     }
264 
265     // numeric + complex,  numeric * complex
266     Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(const R r) const
267     if ((op == "+" || op == "*") && (isNumeric!R))
268     {
269         return opBinary!(op)(r);
270     }
271 
272     // numeric - complex
273     Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(const R r) const
274     if (op == "-" && isNumeric!R)
275     {
276         return Complex(r - re, -im);
277     }
278 
279     // numeric / complex
280     Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(const R r) const
281     if (op == "/" && isNumeric!R)
282     {
283         version (FastMath)
284         {
285             // Compute norm(this)
286             immutable norm = re * re + im * im;
287             // Compute r * conj(this)
288             immutable prod_re = r * re;
289             immutable prod_im = r * -im;
290             // Divide the product by the norm
291             typeof(return) w = void;
292             w.re = prod_re / norm;
293             w.im = prod_im / norm;
294             return w;
295         }
296         else
297         {
298             import core.math : fabs;
299             typeof(return) w = void;
300             if (fabs(re) < fabs(im))
301             {
302                 immutable ratio = re/im;
303                 immutable rdivd = r/(re*ratio + im);
304 
305                 w.re = rdivd*ratio;
306                 w.im = -rdivd;
307             }
308             else
309             {
310                 immutable ratio = im/re;
311                 immutable rdivd = r/(re + im*ratio);
312 
313                 w.re = rdivd;
314                 w.im = -rdivd*ratio;
315             }
316 
317             return w;
318         }
319     }
320 
321     // numeric ^^ complex
322     Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(const R lhs) const
323     if (op == "^^" && isNumeric!R)
324     {
325         import core.math : cos, sin;
326         import std.math.exponential : exp, log;
327         import std.math.constants : PI;
328         Unqual!(CommonType!(T, R)) ab = void, ar = void;
329 
330         if (lhs >= 0)
331         {
332             // r = lhs
333             // theta = 0
334             ab = lhs ^^ this.re;
335             ar = log(lhs) * this.im;
336         }
337         else
338         {
339             // r = -lhs
340             // theta = PI
341             ab = (-lhs) ^^ this.re * exp(-PI * this.im);
342             ar = PI * this.re + log(-lhs) * this.im;
343         }
344 
345         return typeof(return)(ab * cos(ar), ab * sin(ar));
346     }
347 
348     // OP-ASSIGN OPERATORS
349 
350     // complex += complex,  complex -= complex
351     ref Complex opOpAssign(string op, C)(const C z)
352     if ((op == "+" || op == "-") && is(C R == Complex!R))
353     {
354         mixin ("re "~op~"= z.re;");
355         mixin ("im "~op~"= z.im;");
356         return this;
357     }
358 
359     // complex *= complex
360     ref Complex opOpAssign(string op, C)(const C z)
361     if (op == "*" && is(C R == Complex!R))
362     {
363         auto temp = re*z.re - im*z.im;
364         im = im*z.re + re*z.im;
365         re = temp;
366         return this;
367     }
368 
369     // complex /= complex
370     ref Complex opOpAssign(string op, C)(const C z)
371     if (op == "/" && is(C R == Complex!R))
372     {
373         version (FastMath)
374         {
375             // Compute norm(z)
376             immutable norm = z.re * z.re + z.im * z.im;
377             // Compute this * conj(z)
378             immutable prod_re = re * z.re - im * -z.im;
379             immutable prod_im = im * z.re + re * -z.im;
380             // Divide the product by the norm
381             re = prod_re / norm;
382             im = prod_im / norm;
383             return this;
384         }
385         else
386         {
387             import core.math : fabs;
388             if (fabs(z.re) < fabs(z.im))
389             {
390                 immutable ratio = z.re/z.im;
391                 immutable denom = z.re*ratio + z.im;
392 
393                 immutable temp = (re*ratio + im)/denom;
394                 im = (im*ratio - re)/denom;
395                 re = temp;
396             }
397             else
398             {
399                 immutable ratio = z.im/z.re;
400                 immutable denom = z.re + z.im*ratio;
401 
402                 immutable temp = (re + im*ratio)/denom;
403                 im = (im - re*ratio)/denom;
404                 re = temp;
405             }
406             return this;
407         }
408     }
409 
410     // complex ^^= complex
411     ref Complex opOpAssign(string op, C)(const C z)
412     if (op == "^^" && is(C R == Complex!R))
413     {
414         import core.math : cos, sin;
415         import std.math.exponential : exp, log;
416         immutable r = abs(this);
417         immutable t = arg(this);
418         immutable ab = r^^z.re * exp(-t*z.im);
419         immutable ar = t*z.re + log(r)*z.im;
420 
421         re = ab*cos(ar);
422         im = ab*sin(ar);
423         return this;
424     }
425 
426     // complex += numeric,  complex -= numeric
427     ref Complex opOpAssign(string op, U : T)(const U a)
428     if (op == "+" || op == "-")
429     {
430         mixin ("re "~op~"= a;");
431         return this;
432     }
433 
434     // complex *= numeric,  complex /= numeric
435     ref Complex opOpAssign(string op, U : T)(const U a)
436     if (op == "*" || op == "/")
437     {
438         mixin ("re "~op~"= a;");
439         mixin ("im "~op~"= a;");
440         return this;
441     }
442 
443     // complex ^^= real
444     ref Complex opOpAssign(string op, R)(const R r)
445     if (op == "^^" && isFloatingPoint!R)
446     {
447         import core.math : cos, sin;
448         immutable ab = abs(this)^^r;
449         immutable ar = arg(this)*r;
450         re = ab*cos(ar);
451         im = ab*sin(ar);
452         return this;
453     }
454 
455     // complex ^^= int
456     ref Complex opOpAssign(string op, U)(const U i)
457     if (op == "^^" && isIntegral!U)
458     {
459         switch (i)
460         {
461         case 0:
462             re = 1.0;
463             im = 0.0;
464             break;
465         case 1:
466             // identity; do nothing
467             break;
468         case 2:
469             this *= this;
470             break;
471         case 3:
472             auto z = this;
473             this *= z;
474             this *= z;
475             break;
476         default:
477             this ^^= cast(real) i;
478         }
479         return this;
480     }
481 
482     /** Returns a complex number instance that correponds in size and in ABI
483         to the associated C compiler's `_Complex` type.
484      */
485     auto toNative()
486     {
487         import core.stdc.config : c_complex_float, c_complex_double, c_complex_real;
488         static if (is(T == float))
489             return c_complex_float(re, im);
490         else static if (is(T == double))
491             return c_complex_double(re, im);
492         else
493             return c_complex_real(re, im);
494     }
495 }
496 
497 @safe pure nothrow unittest
498 {
499     import std.complex;
500     static import core.math;
501     import std.math;
502 
503     enum EPS = double.epsilon;
504     auto c1 = complex(1.0, 1.0);
505 
506     // Check unary operations.
507     auto c2 = Complex!double(0.5, 2.0);
508 
509     assert(c2 == +c2);
510 
511     assert((-c2).re == -(c2.re));
512     assert((-c2).im == -(c2.im));
513     assert(c2 == -(-c2));
514 
515     // Check complex-complex operations.
516     auto cpc = c1 + c2;
517     assert(cpc.re == c1.re + c2.re);
518     assert(cpc.im == c1.im + c2.im);
519 
520     auto cmc = c1 - c2;
521     assert(cmc.re == c1.re - c2.re);
522     assert(cmc.im == c1.im - c2.im);
523 
524     auto ctc = c1 * c2;
525     assert(isClose(abs(ctc), abs(c1)*abs(c2), EPS));
526     assert(isClose(arg(ctc), arg(c1)+arg(c2), EPS));
527 
528     auto cdc = c1 / c2;
529     assert(isClose(abs(cdc), abs(c1)/abs(c2), EPS));
530     assert(isClose(arg(cdc), arg(c1)-arg(c2), EPS));
531 
532     auto cec = c1^^c2;
533     assert(isClose(cec.re, 0.1152413197994, 1e-12));
534     assert(isClose(cec.im, 0.2187079045274, 1e-12));
535 
536     // Check complex-real operations.
537     double a = 123.456;
538 
539     auto cpr = c1 + a;
540     assert(cpr.re == c1.re + a);
541     assert(cpr.im == c1.im);
542 
543     auto cmr = c1 - a;
544     assert(cmr.re == c1.re - a);
545     assert(cmr.im == c1.im);
546 
547     auto ctr = c1 * a;
548     assert(ctr.re == c1.re*a);
549     assert(ctr.im == c1.im*a);
550 
551     auto cdr = c1 / a;
552     assert(isClose(abs(cdr), abs(c1)/a, EPS));
553     assert(isClose(arg(cdr), arg(c1), EPS));
554 
555     auto cer = c1^^3.0;
556     assert(isClose(abs(cer), abs(c1)^^3, EPS));
557     assert(isClose(arg(cer), arg(c1)*3, EPS));
558 
559     auto rpc = a + c1;
560     assert(rpc == cpr);
561 
562     auto rmc = a - c1;
563     assert(rmc.re == a-c1.re);
564     assert(rmc.im == -c1.im);
565 
566     auto rtc = a * c1;
567     assert(rtc == ctr);
568 
569     auto rdc = a / c1;
570     assert(isClose(abs(rdc), a/abs(c1), EPS));
571     assert(isClose(arg(rdc), -arg(c1), EPS));
572 
573     rdc = a / c2;
574     assert(isClose(abs(rdc), a/abs(c2), EPS));
575     assert(isClose(arg(rdc), -arg(c2), EPS));
576 
577     auto rec1a = 1.0 ^^ c1;
578     assert(rec1a.re == 1.0);
579     assert(rec1a.im == 0.0);
580 
581     auto rec2a = 1.0 ^^ c2;
582     assert(rec2a.re == 1.0);
583     assert(rec2a.im == 0.0);
584 
585     auto rec1b = (-1.0) ^^ c1;
586     assert(isClose(abs(rec1b), std.math.exp(-PI * c1.im), EPS));
587     auto arg1b = arg(rec1b);
588     /* The argument _should_ be PI, but floating-point rounding error
589      * means that in fact the imaginary part is very slightly negative.
590      */
591     assert(isClose(arg1b, PI, EPS) || isClose(arg1b, -PI, EPS));
592 
593     auto rec2b = (-1.0) ^^ c2;
594     assert(isClose(abs(rec2b), std.math.exp(-2 * PI), EPS));
595     assert(isClose(arg(rec2b), PI_2, EPS));
596 
597     auto rec3a = 0.79 ^^ complex(6.8, 5.7);
598     auto rec3b = complex(0.79, 0.0) ^^ complex(6.8, 5.7);
599     assert(isClose(rec3a.re, rec3b.re, 1e-14));
600     assert(isClose(rec3a.im, rec3b.im, 1e-14));
601 
602     auto rec4a = (-0.79) ^^ complex(6.8, 5.7);
603     auto rec4b = complex(-0.79, 0.0) ^^ complex(6.8, 5.7);
604     assert(isClose(rec4a.re, rec4b.re, 1e-14));
605     assert(isClose(rec4a.im, rec4b.im, 1e-14));
606 
607     auto rer = a ^^ complex(2.0, 0.0);
608     auto rcheck = a ^^ 2.0;
609     static assert(is(typeof(rcheck) == double));
610     assert(feqrel(rer.re, rcheck) == double.mant_dig);
611     assert(isIdentical(rer.re, rcheck));
612     assert(rer.im == 0.0);
613 
614     auto rer2 = (-a) ^^ complex(2.0, 0.0);
615     rcheck = (-a) ^^ 2.0;
616     assert(feqrel(rer2.re, rcheck) == double.mant_dig);
617     assert(isIdentical(rer2.re, rcheck));
618     assert(isClose(rer2.im, 0.0, 0.0, 1e-10));
619 
620     auto rer3 = (-a) ^^ complex(-2.0, 0.0);
621     rcheck = (-a) ^^ (-2.0);
622     assert(feqrel(rer3.re, rcheck) == double.mant_dig);
623     assert(isIdentical(rer3.re, rcheck));
624     assert(isClose(rer3.im, 0.0, 0.0, EPS));
625 
626     auto rer4 = a ^^ complex(-2.0, 0.0);
627     rcheck = a ^^ (-2.0);
628     assert(feqrel(rer4.re, rcheck) == double.mant_dig);
629     assert(isIdentical(rer4.re, rcheck));
630     assert(rer4.im == 0.0);
631 
632     // Check Complex-int operations.
633     foreach (i; 0 .. 6)
634     {
635         auto cei = c1^^i;
636         assert(isClose(abs(cei), abs(c1)^^i, 1e-14));
637         // Use cos() here to deal with arguments that go outside
638         // the (-pi,pi] interval (only an issue for i>3).
639         assert(isClose(core.math.cos(arg(cei)), core.math.cos(arg(c1)*i), 1e-14));
640     }
641 
642     // Check operations between different complex types.
643     auto cf = Complex!float(1.0, 1.0);
644     auto cr = Complex!real(1.0, 1.0);
645     auto c1pcf = c1 + cf;
646     auto c1pcr = c1 + cr;
647     static assert(is(typeof(c1pcf) == Complex!double));
648     static assert(is(typeof(c1pcr) == Complex!real));
649     assert(c1pcf.re == c1pcr.re);
650     assert(c1pcf.im == c1pcr.im);
651 
652     auto c1c = c1;
653     auto c2c = c2;
654 
655     c1c /= c1;
656     assert(isClose(c1c.re, 1.0, EPS));
657     assert(isClose(c1c.im, 0.0, 0.0, EPS));
658 
659     c1c = c1;
660     c1c /= c2;
661     assert(isClose(c1c.re, 0.5882352941177, 1e-12));
662     assert(isClose(c1c.im, -0.3529411764706, 1e-12));
663 
664     c2c /= c1;
665     assert(isClose(c2c.re, 1.25, EPS));
666     assert(isClose(c2c.im, 0.75, EPS));
667 
668     c2c = c2;
669     c2c /= c2;
670     assert(isClose(c2c.re, 1.0, EPS));
671     assert(isClose(c2c.im, 0.0, 0.0, EPS));
672 }
673 
674 @safe pure nothrow unittest
675 {
676     // Initialization
677     Complex!double a = 1;
678     assert(a.re == 1 && a.im == 0);
679     Complex!double b = 1.0;
680     assert(b.re == 1.0 && b.im == 0);
681     Complex!double c = Complex!real(1.0, 2);
682     assert(c.re == 1.0 && c.im == 2);
683 }
684 
685 @safe pure nothrow unittest
686 {
687     // Assignments and comparisons
688     Complex!double z;
689 
690     z = 1;
691     assert(z == 1);
692     assert(z.re == 1.0  &&  z.im == 0.0);
693 
694     z = 2.0;
695     assert(z == 2.0);
696     assert(z.re == 2.0  &&  z.im == 0.0);
697 
698     z = 1.0L;
699     assert(z == 1.0L);
700     assert(z.re == 1.0  &&  z.im == 0.0);
701 
702     auto w = Complex!real(1.0, 1.0);
703     z = w;
704     assert(z == w);
705     assert(z.re == 1.0  &&  z.im == 1.0);
706 
707     auto c = Complex!float(2.0, 2.0);
708     z = c;
709     assert(z == c);
710     assert(z.re == 2.0  &&  z.im == 2.0);
711 }
712 
713 
714 /*  Makes Complex!(Complex!T) fold to Complex!T.
715 
716     The rationale for this is that just like the real line is a
717     subspace of the complex plane, the complex plane is a subspace
718     of itself.  Example of usage:
719     ---
720     Complex!T addI(T)(T x)
721     {
722         return x + Complex!T(0.0, 1.0);
723     }
724     ---
725     The above will work if T is both real and complex.
726 */
727 template Complex(T)
728 if (is(T R == Complex!R))
729 {
730     alias Complex = T;
731 }
732 
733 @safe pure nothrow unittest
734 {
735     static assert(is(Complex!(Complex!real) == Complex!real));
736 
737     Complex!T addI(T)(T x)
738     {
739         return x + Complex!T(0.0, 1.0);
740     }
741 
742     auto z1 = addI(1.0);
743     assert(z1.re == 1.0 && z1.im == 1.0);
744 
745     enum one = Complex!double(1.0, 0.0);
746     auto z2 = addI(one);
747     assert(z1 == z2);
748 }
749 
750 
751 /**
752  * Calculates the absolute value (or modulus) of a complex number.
753  *
754  *      $(TABLE_SV
755  *      $(TR $(TH $(I z))                          $(TH abs(z))             $(TH Notes))
756  *      $(TR $(TD (0, 0))                          $(TD 0)                  $(TD ))
757  *      $(TR $(TD (NaN, any) or (any, NaN))        $(TD NaN)                $(TD ))
758  *      $(TR $(TD (Inf, any) or (any, Inf))        $(TD Inf)                $(TD ))
759  *      $(TR $(TD (a, b)) normal case              $(TD hypot(a, b))      $(TD Uses algorithm to prevent overflow/underflow ))
760  *      )
761  *
762  * Params:
763  *      z = A complex number of type Complex!T
764  *
765  * Returns:
766  *      The absolute value (modulus) of `z`
767  */
768 T abs(T)(Complex!T z) @safe pure nothrow @nogc
769 {
770     import std.math.algebraic : hypot;
771     return hypot(z.re, z.im);
772 }
773 
774 ///
775 @safe pure nothrow unittest
776 {
777     static import core.math;
778     assert(abs(complex(1.0)) == 1.0);
779     assert(abs(complex(0.0, 1.0)) == 1.0);
780     assert(abs(complex(1.0L, -2.0L)) == core.math.sqrt(5.0L));
781 }
782 
783 @safe pure nothrow unittest
784 {
785     {
786         auto x = Complex!float(-5.016556e-20, 0);
787         assert(x.abs == 5.016556e-20f);
788         auto x1 = Complex!float(-5.016556e-20f, 0);
789         assert(x1.abs == 5.016556e-20f);
790         auto x2 = Complex!float(5.016556e-20f, 0);
791         assert(x2.abs == 5.016556e-20f);
792     }
793     {
794         import std.math.traits : isNaN, isInfinity;
795         assert(Complex!double(double.nan, 0).abs.isNaN);
796         assert(Complex!double(double.nan, double.nan).abs.isNaN);
797         assert(Complex!double(double.infinity, 0).abs.isInfinity);
798         assert(Complex!double(0, double.infinity).abs.isInfinity);
799         assert(Complex!double(0, 0).abs == 0);
800     }
801 }
802 
803 @safe pure nothrow @nogc unittest
804 {
805     static import core.math;
806     assert(abs(complex(0.0L, -3.2L)) == 3.2L);
807     assert(abs(complex(0.0L, 71.6L)) == 71.6L);
808     assert(abs(complex(-1.0L, 1.0L)) == core.math.sqrt(2.0L));
809 }
810 
811 @safe pure nothrow @nogc unittest
812 {
813     import std.meta : AliasSeq;
814     static foreach (T; AliasSeq!(float, double, real))
815     {{
816         static import std.math;
817         Complex!T a = complex(T(-12), T(3));
818         T b = std.math.hypot(a.re, a.im);
819         assert(std.math.isClose(abs(a), b));
820         assert(std.math.isClose(abs(-a), b));
821     }}
822 }
823 
824 
825 /++
826    Params:
827     z = A complex number.
828     x = A real number.
829    Returns: The squared modulus of `z`.
830    For genericity, if called on a real number, returns its square.
831 +/
832 T sqAbs(T)(Complex!T z) @safe pure nothrow @nogc
833 {
834     return z.re*z.re + z.im*z.im;
835 }
836 
837 ///
838 @safe pure nothrow unittest
839 {
840     import std.math.operations : isClose;
841     assert(sqAbs(complex(0.0)) == 0.0);
842     assert(sqAbs(complex(1.0)) == 1.0);
843     assert(sqAbs(complex(0.0, 1.0)) == 1.0);
844     assert(isClose(sqAbs(complex(1.0L, -2.0L)), 5.0L));
845     assert(isClose(sqAbs(complex(-3.0L, 1.0L)), 10.0L));
846     assert(isClose(sqAbs(complex(1.0f,-1.0f)), 2.0f));
847 }
848 
849 
850 /// ditto
851 T sqAbs(T)(const T x) @safe pure nothrow @nogc
852 if (isFloatingPoint!T)
853 {
854     return x*x;
855 }
856 
857 @safe pure nothrow unittest
858 {
859     import std.math.operations : isClose;
860     assert(sqAbs(0.0) == 0.0);
861     assert(sqAbs(-1.0) == 1.0);
862     assert(isClose(sqAbs(-3.0L), 9.0L));
863     assert(isClose(sqAbs(-5.0f), 25.0f));
864 }
865 
866 
867 /**
868  Params: z = A complex number.
869  Returns: The argument (or phase) of `z`.
870  */
871 T arg(T)(Complex!T z) @safe pure nothrow @nogc
872 {
873     import std.math.trigonometry : atan2;
874     return atan2(z.im, z.re);
875 }
876 
877 ///
878 @safe pure nothrow unittest
879 {
880     import std.math.constants : PI_2, PI_4;
881     assert(arg(complex(1.0)) == 0.0);
882     assert(arg(complex(0.0L, 1.0L)) == PI_2);
883     assert(arg(complex(1.0L, 1.0L)) == PI_4);
884 }
885 
886 
887 /**
888  * Extracts the norm of a complex number.
889  * Params:
890  *      z = A complex number
891  * Returns:
892  *      The squared magnitude of `z`.
893  */
894 T norm(T)(Complex!T z) @safe pure nothrow @nogc
895 {
896     return z.re * z.re + z.im * z.im;
897 }
898 
899 ///
900 @safe pure nothrow @nogc unittest
901 {
902     import std.math.operations : isClose;
903     import std.math.constants : PI;
904     assert(norm(complex(3.0, 4.0)) == 25.0);
905     assert(norm(fromPolar(5.0, 0.0)) == 25.0);
906     assert(isClose(norm(fromPolar(5.0L, PI / 6)), 25.0L));
907     assert(isClose(norm(fromPolar(5.0L, 13 * PI / 6)), 25.0L));
908 }
909 
910 
911 /**
912   Params: z = A complex number.
913   Returns: The complex conjugate of `z`.
914 */
915 Complex!T conj(T)(Complex!T z) @safe pure nothrow @nogc
916 {
917     return Complex!T(z.re, -z.im);
918 }
919 
920 ///
921 @safe pure nothrow unittest
922 {
923     assert(conj(complex(1.0)) == complex(1.0));
924     assert(conj(complex(1.0, 2.0)) == complex(1.0, -2.0));
925 }
926 
927 @safe pure nothrow @nogc unittest
928 {
929     import std.meta : AliasSeq;
930     static foreach (T; AliasSeq!(float, double, real))
931     {{
932          auto c = Complex!T(7, 3L);
933          assert(conj(c) == Complex!T(7, -3L));
934          auto z = Complex!T(0, -3.2L);
935          assert(conj(z) == -z);
936     }}
937 }
938 
939 /**
940  * Returns the projection of `z` onto the Riemann sphere.
941  * Params:
942  *      z = A complex number
943  * Returns:
944  *      The projection of `z` onto the Riemann sphere.
945  */
946 Complex!T proj(T)(Complex!T z)
947 {
948     static import std.math;
949 
950     if (std.math.isInfinity(z.re) || std.math.isInfinity(z.im))
951         return Complex!T(T.infinity, std.math.copysign(0.0, z.im));
952 
953     return z;
954 }
955 
956 ///
957 @safe pure nothrow unittest
958 {
959     assert(proj(complex(1.0)) == complex(1.0));
960     assert(proj(complex(double.infinity, 5.0)) == complex(double.infinity, 0.0));
961     assert(proj(complex(5.0, -double.infinity)) == complex(double.infinity, -0.0));
962 }
963 
964 
965 /**
966   Constructs a complex number given its absolute value and argument.
967   Params:
968     modulus = The modulus
969     argument = The argument
970   Returns: The complex number with the given modulus and argument.
971 */
972 Complex!(CommonType!(T, U)) fromPolar(T, U)(const T modulus, const U argument)
973     @safe pure nothrow @nogc
974 {
975     import core.math : sin, cos;
976     return Complex!(CommonType!(T,U))
977         (modulus*cos(argument), modulus*sin(argument));
978 }
979 
980 ///
981 @safe pure nothrow unittest
982 {
983     import core.math;
984     import std.math.operations : isClose;
985     import std.math.algebraic : sqrt;
986     import std.math.constants : PI_4;
987     auto z = fromPolar(core.math.sqrt(2.0L), PI_4);
988     assert(isClose(z.re, 1.0L));
989     assert(isClose(z.im, 1.0L));
990 }
991 
992 version (StdUnittest)
993 {
994     // Helper function for comparing two Complex numbers.
995     int ceqrel(T)(const Complex!T x, const Complex!T y) @safe pure nothrow @nogc
996     {
997         import std.math.operations : feqrel;
998         const r = feqrel(x.re, y.re);
999         const i = feqrel(x.im, y.im);
1000         return r < i ? r : i;
1001     }
1002 }
1003 
1004 /**
1005     Trigonometric functions on complex numbers.
1006 
1007     Params: z = A complex number.
1008     Returns: The sine, cosine and tangent of `z`, respectively.
1009 */
1010 Complex!T sin(T)(Complex!T z)  @safe pure nothrow @nogc
1011 {
1012     auto cs = expi(z.re);
1013     auto csh = coshisinh(z.im);
1014     return typeof(return)(cs.im * csh.re, cs.re * csh.im);
1015 }
1016 
1017 ///
1018 @safe pure nothrow unittest
1019 {
1020     static import core.math;
1021     assert(sin(complex(0.0)) == 0.0);
1022     assert(sin(complex(2.0, 0)) == core.math.sin(2.0));
1023 }
1024 
1025 @safe pure nothrow unittest
1026 {
1027     static import core.math;
1028     assert(ceqrel(sin(complex(2.0L, 0)), complex(core.math.sin(2.0L))) >= real.mant_dig - 1);
1029 }
1030 
1031 /// ditto
1032 Complex!T cos(T)(Complex!T z)  @safe pure nothrow @nogc
1033 {
1034     auto cs = expi(z.re);
1035     auto csh = coshisinh(z.im);
1036     return typeof(return)(cs.re * csh.re, - cs.im * csh.im);
1037 }
1038 
1039 ///
1040 @safe pure nothrow unittest
1041 {
1042     static import core.math;
1043     static import std.math;
1044     assert(cos(complex(0.0)) == 1.0);
1045     assert(cos(complex(1.3, 0.0)) == core.math.cos(1.3));
1046     assert(cos(complex(0.0, 5.2)) == std.math.cosh(5.2));
1047 }
1048 
1049 @safe pure nothrow unittest
1050 {
1051     static import core.math;
1052     static import std.math;
1053     assert(ceqrel(cos(complex(0, 5.2L)), complex(std.math.cosh(5.2L), 0.0L)) >= real.mant_dig - 1);
1054     assert(ceqrel(cos(complex(1.3L)), complex(core.math.cos(1.3L))) >= real.mant_dig - 1);
1055 }
1056 
1057 /// ditto
1058 Complex!T tan(T)(Complex!T z) @safe pure nothrow @nogc
1059 {
1060     return sin(z) / cos(z);
1061 }
1062 
1063 ///
1064 @safe pure nothrow @nogc unittest
1065 {
1066     static import std.math;
1067 
1068     int ceqrel(T)(const Complex!T x, const Complex!T y) @safe pure nothrow @nogc
1069     {
1070         import std.math.operations : feqrel;
1071         const r = feqrel(x.re, y.re);
1072         const i = feqrel(x.im, y.im);
1073         return r < i ? r : i;
1074     }
1075     assert(ceqrel(tan(complex(1.0, 0.0)), complex(std.math.tan(1.0), 0.0)) >= double.mant_dig - 2);
1076     assert(ceqrel(tan(complex(0.0, 1.0)), complex(0.0, std.math.tanh(1.0))) >= double.mant_dig - 2);
1077 }
1078 
1079 /**
1080     Inverse trigonometric functions on complex numbers.
1081 
1082     Params: z = A complex number.
1083     Returns: The arcsine, arccosine and arctangent of `z`, respectively.
1084 */
1085 Complex!T asin(T)(Complex!T z)  @safe pure nothrow @nogc
1086 {
1087     auto ash = asinh(Complex!T(-z.im, z.re));
1088     return Complex!T(ash.im, -ash.re);
1089 }
1090 
1091 ///
1092 @safe pure nothrow unittest
1093 {
1094     import std.math.operations : isClose;
1095     import std.math.constants : PI;
1096     assert(asin(complex(0.0)) == 0.0);
1097     assert(isClose(asin(complex(0.5L)), PI / 6));
1098 }
1099 
1100 @safe pure nothrow unittest
1101 {
1102     import std.math.operations : isClose;
1103     import std.math.constants : PI;
1104     version (DigitalMars) {} else // Disabled because of https://issues.dlang.org/show_bug.cgi?id=21376
1105     assert(isClose(asin(complex(0.5f)), float(PI) / 6));
1106 }
1107 
1108 /// ditto
1109 Complex!T acos(T)(Complex!T z)  @safe pure nothrow @nogc
1110 {
1111     static import std.math;
1112     auto as = asin(z);
1113     return Complex!T(T(std.math.PI_2) - as.re, as.im);
1114 }
1115 
1116 ///
1117 @safe pure nothrow unittest
1118 {
1119     import std.math.operations : isClose;
1120     import std.math.constants : PI;
1121     import std.math.trigonometry : std_math_acos = acos;
1122     assert(acos(complex(0.0)) == std_math_acos(0.0));
1123     assert(isClose(acos(complex(0.5L)), PI / 3));
1124 }
1125 
1126 @safe pure nothrow unittest
1127 {
1128     import std.math.operations : isClose;
1129     import std.math.constants : PI;
1130     version (DigitalMars) {} else // Disabled because of https://issues.dlang.org/show_bug.cgi?id=21376
1131     assert(isClose(acos(complex(0.5f)), float(PI) / 3));
1132 }
1133 
1134 /// ditto
1135 Complex!T atan(T)(Complex!T z) @safe pure nothrow @nogc
1136 {
1137     static import std.math;
1138     const T re2 = z.re * z.re;
1139     const T x = 1 - re2 - z.im * z.im;
1140 
1141     T num = z.im + 1;
1142     T den = z.im - 1;
1143 
1144     num = re2 + num * num;
1145     den = re2 + den * den;
1146 
1147     return Complex!T(T(0.5) * std.math.atan2(2 * z.re, x),
1148                      T(0.25) * std.math.log(num / den));
1149 }
1150 
1151 ///
1152 @safe pure nothrow @nogc unittest
1153 {
1154     import std.math.operations : isClose;
1155     import std.math.constants : PI;
1156     assert(atan(complex(0.0)) == 0.0);
1157     assert(isClose(atan(sqrt(complex(3.0L))), PI / 3));
1158     assert(isClose(atan(sqrt(complex(3.0f))), float(PI) / 3));
1159 }
1160 
1161 /**
1162     Hyperbolic trigonometric functions on complex numbers.
1163 
1164     Params: z = A complex number.
1165     Returns: The hyperbolic sine, cosine and tangent of `z`, respectively.
1166 */
1167 Complex!T sinh(T)(Complex!T z)  @safe pure nothrow @nogc
1168 {
1169     static import core.math, std.math;
1170     return Complex!T(std.math.sinh(z.re) * core.math.cos(z.im),
1171                      std.math.cosh(z.re) * core.math.sin(z.im));
1172 }
1173 
1174 ///
1175 @safe pure nothrow unittest
1176 {
1177     static import std.math;
1178     assert(sinh(complex(0.0)) == 0.0);
1179     assert(sinh(complex(1.0L)) == std.math.sinh(1.0L));
1180     assert(sinh(complex(1.0f)) == std.math.sinh(1.0f));
1181 }
1182 
1183 /// ditto
1184 Complex!T cosh(T)(Complex!T z)  @safe pure nothrow @nogc
1185 {
1186     static import core.math, std.math;
1187     return Complex!T(std.math.cosh(z.re) * core.math.cos(z.im),
1188                      std.math.sinh(z.re) * core.math.sin(z.im));
1189 }
1190 
1191 ///
1192 @safe pure nothrow unittest
1193 {
1194     static import std.math;
1195     assert(cosh(complex(0.0)) == 1.0);
1196     assert(cosh(complex(1.0L)) == std.math.cosh(1.0L));
1197     assert(cosh(complex(1.0f)) == std.math.cosh(1.0f));
1198 }
1199 
1200 /// ditto
1201 Complex!T tanh(T)(Complex!T z) @safe pure nothrow @nogc
1202 {
1203     return sinh(z) / cosh(z);
1204 }
1205 
1206 ///
1207 @safe pure nothrow @nogc unittest
1208 {
1209     import std.math.operations : isClose;
1210     import std.math.trigonometry : std_math_tanh = tanh;
1211     assert(tanh(complex(0.0)) == 0.0);
1212     assert(isClose(tanh(complex(1.0L)), std_math_tanh(1.0L)));
1213     assert(isClose(tanh(complex(1.0f)), std_math_tanh(1.0f)));
1214 }
1215 
1216 /**
1217     Inverse hyperbolic trigonometric functions on complex numbers.
1218 
1219     Params: z = A complex number.
1220     Returns: The hyperbolic arcsine, arccosine and arctangent of `z`, respectively.
1221 */
1222 Complex!T asinh(T)(Complex!T z)  @safe pure nothrow @nogc
1223 {
1224     auto t = Complex!T((z.re - z.im) * (z.re + z.im) + 1, 2 * z.re * z.im);
1225     return log(sqrt(t) + z);
1226 }
1227 
1228 ///
1229 @safe pure nothrow unittest
1230 {
1231     import std.math.operations : isClose;
1232     import std.math.trigonometry : std_math_asinh = asinh;
1233     assert(asinh(complex(0.0)) == 0.0);
1234     assert(isClose(asinh(complex(1.0L)), std_math_asinh(1.0L)));
1235     assert(isClose(asinh(complex(1.0f)), std_math_asinh(1.0f)));
1236 }
1237 
1238 /// ditto
1239 Complex!T acosh(T)(Complex!T z)  @safe pure nothrow @nogc
1240 {
1241     return 2 * log(sqrt(T(0.5) * (z + 1)) + sqrt(T(0.5) * (z - 1)));
1242 }
1243 
1244 ///
1245 @safe pure nothrow unittest
1246 {
1247     import std.math.operations : isClose;
1248     import std.math.trigonometry : std_math_acosh = acosh;
1249     assert(acosh(complex(1.0)) == 0.0);
1250     assert(isClose(acosh(complex(3.0L)), std_math_acosh(3.0L)));
1251     assert(isClose(acosh(complex(3.0f)), std_math_acosh(3.0f)));
1252 }
1253 
1254 /// ditto
1255 Complex!T atanh(T)(Complex!T z) @safe pure nothrow @nogc
1256 {
1257     static import std.math;
1258     const T im2 = z.im * z.im;
1259     const T x = 1 - im2 - z.re * z.re;
1260 
1261     T num = 1 + z.re;
1262     T den = 1 - z.re;
1263 
1264     num = im2 + num * num;
1265     den = im2 + den * den;
1266 
1267     return Complex!T(T(0.25) * (std.math.log(num) - std.math.log(den)),
1268                      T(0.5) * std.math.atan2(2 * z.im, x));
1269 }
1270 
1271 ///
1272 @safe pure nothrow @nogc unittest
1273 {
1274     import std.math.operations : isClose;
1275     import std.math.trigonometry : std_math_atanh = atanh;
1276     assert(atanh(complex(0.0)) == 0.0);
1277     assert(isClose(atanh(complex(0.5L)), std_math_atanh(0.5L)));
1278     assert(isClose(atanh(complex(0.5f)), std_math_atanh(0.5f)));
1279 }
1280 
1281 /**
1282     Params: y = A real number.
1283     Returns: The value of cos(y) + i sin(y).
1284 
1285     Note:
1286     `expi` is included here for convenience and for easy migration of code.
1287 */
1288 Complex!real expi(real y)  @trusted pure nothrow @nogc
1289 {
1290     import core.math : cos, sin;
1291     return Complex!real(cos(y), sin(y));
1292 }
1293 
1294 ///
1295 @safe pure nothrow unittest
1296 {
1297     import core.math : cos, sin;
1298     assert(expi(0.0L) == 1.0L);
1299     assert(expi(1.3e5L) == complex(cos(1.3e5L), sin(1.3e5L)));
1300 }
1301 
1302 /**
1303     Params: y = A real number.
1304     Returns: The value of cosh(y) + i sinh(y)
1305 
1306     Note:
1307     `coshisinh` is included here for convenience and for easy migration of code.
1308 */
1309 Complex!real coshisinh(real y) @safe pure nothrow @nogc
1310 {
1311     static import core.math;
1312     static import std.math;
1313     if (core.math.fabs(y) <= 0.5)
1314         return Complex!real(std.math.cosh(y), std.math.sinh(y));
1315     else
1316     {
1317         auto z = std.math.exp(y);
1318         auto zi = 0.5 / z;
1319         z = 0.5 * z;
1320         return Complex!real(z + zi, z - zi);
1321     }
1322 }
1323 
1324 ///
1325 @safe pure nothrow @nogc unittest
1326 {
1327     import std.math.trigonometry : cosh, sinh;
1328     assert(coshisinh(3.0L) == complex(cosh(3.0L), sinh(3.0L)));
1329 }
1330 
1331 /**
1332     Params: z = A complex number.
1333     Returns: The square root of `z`.
1334 */
1335 Complex!T sqrt(T)(Complex!T z)  @safe pure nothrow @nogc
1336 {
1337     static import core.math;
1338     typeof(return) c;
1339     real x,y,w,r;
1340 
1341     if (z == 0)
1342     {
1343         c = typeof(return)(0, 0);
1344     }
1345     else
1346     {
1347         real z_re = z.re;
1348         real z_im = z.im;
1349 
1350         x = core.math.fabs(z_re);
1351         y = core.math.fabs(z_im);
1352         if (x >= y)
1353         {
1354             r = y / x;
1355             w = core.math.sqrt(x)
1356                 * core.math.sqrt(0.5 * (1 + core.math.sqrt(1 + r * r)));
1357         }
1358         else
1359         {
1360             r = x / y;
1361             w = core.math.sqrt(y)
1362                 * core.math.sqrt(0.5 * (r + core.math.sqrt(1 + r * r)));
1363         }
1364 
1365         if (z_re >= 0)
1366         {
1367             c = typeof(return)(w, z_im / (w + w));
1368         }
1369         else
1370         {
1371             if (z_im < 0)
1372                 w = -w;
1373             c = typeof(return)(z_im / (w + w), w);
1374         }
1375     }
1376     return c;
1377 }
1378 
1379 ///
1380 @safe pure nothrow unittest
1381 {
1382     static import core.math;
1383     assert(sqrt(complex(0.0)) == 0.0);
1384     assert(sqrt(complex(1.0L, 0)) == core.math.sqrt(1.0L));
1385     assert(sqrt(complex(-1.0L, 0)) == complex(0, 1.0L));
1386     assert(sqrt(complex(-8.0, -6.0)) == complex(1.0, -3.0));
1387 }
1388 
1389 @safe pure nothrow unittest
1390 {
1391     import std.math.operations : isClose;
1392 
1393     auto c1 = complex(1.0, 1.0);
1394     auto c2 = Complex!double(0.5, 2.0);
1395 
1396     auto c1s = sqrt(c1);
1397     assert(isClose(c1s.re, 1.09868411347));
1398     assert(isClose(c1s.im, 0.455089860562));
1399 
1400     auto c2s = sqrt(c2);
1401     assert(isClose(c2s.re, 1.13171392428));
1402     assert(isClose(c2s.im, 0.883615530876));
1403 }
1404 
1405 // support %f formatting of complex numbers
1406 // https://issues.dlang.org/show_bug.cgi?id=10881
1407 @safe unittest
1408 {
1409     import std.format : format;
1410 
1411     auto x = complex(1.2, 3.4);
1412     assert(format("%.2f", x) == "1.20+3.40i");
1413 
1414     auto y = complex(1.2, -3.4);
1415     assert(format("%.2f", y) == "1.20-3.40i");
1416 }
1417 
1418 @safe unittest
1419 {
1420     // Test wide string formatting
1421     import std.format.write : formattedWrite;
1422     wstring wformat(T)(string format, Complex!T c)
1423     {
1424         import std.array : appender;
1425         auto w = appender!wstring();
1426         auto n = formattedWrite(w, format, c);
1427         return w.data;
1428     }
1429 
1430     auto x = complex(1.2, 3.4);
1431     assert(wformat("%.2f", x) == "1.20+3.40i"w);
1432 }
1433 
1434 @safe unittest
1435 {
1436     // Test ease of use (vanilla toString() should be supported)
1437     assert(complex(1.2, 3.4).toString() == "1.2+3.4i");
1438 }
1439 
1440 @safe pure nothrow @nogc unittest
1441 {
1442     auto c = complex(3.0L, 4.0L);
1443     c = sqrt(c);
1444     assert(c.re == 2.0L);
1445     assert(c.im == 1.0L);
1446 }
1447 
1448 /**
1449  * Calculates e$(SUPERSCRIPT x).
1450  * Params:
1451  *      x = A complex number
1452  * Returns:
1453  *      The complex base e exponential of `x`
1454  *
1455  *      $(TABLE_SV
1456  *      $(TR $(TH x)                           $(TH exp(x)))
1457  *      $(TR $(TD ($(PLUSMN)0, +0))            $(TD (1, +0)))
1458  *      $(TR $(TD (any, +$(INFIN)))            $(TD ($(NAN), $(NAN))))
1459  *      $(TR $(TD (any, $(NAN))                $(TD ($(NAN), $(NAN)))))
1460  *      $(TR $(TD (+$(INFIN), +0))             $(TD (+$(INFIN), +0)))
1461  *      $(TR $(TD (-$(INFIN), any))            $(TD ($(PLUSMN)0, cis(x.im))))
1462  *      $(TR $(TD (+$(INFIN), any))            $(TD ($(PLUSMN)$(INFIN), cis(x.im))))
1463  *      $(TR $(TD (-$(INFIN), +$(INFIN)))      $(TD ($(PLUSMN)0, $(PLUSMN)0)))
1464  *      $(TR $(TD (+$(INFIN), +$(INFIN)))      $(TD ($(PLUSMN)$(INFIN), $(NAN))))
1465  *      $(TR $(TD (-$(INFIN), $(NAN)))         $(TD ($(PLUSMN)0, $(PLUSMN)0)))
1466  *      $(TR $(TD (+$(INFIN), $(NAN)))         $(TD ($(PLUSMN)$(INFIN), $(NAN))))
1467  *      $(TR $(TD ($(NAN), +0))                $(TD ($(NAN), +0)))
1468  *      $(TR $(TD ($(NAN), any))               $(TD ($(NAN), $(NAN))))
1469  *      $(TR $(TD ($(NAN), $(NAN)))            $(TD ($(NAN), $(NAN))))
1470  *      )
1471  */
1472 Complex!T exp(T)(Complex!T x) @trusted pure nothrow @nogc // TODO: @safe
1473 {
1474     static import std.math;
1475 
1476     // Handle special cases explicitly here, as fromPolar will otherwise
1477     // cause them to return Complex!T(NaN, NaN), or with the wrong sign.
1478     if (std.math.isInfinity(x.re))
1479     {
1480         if (std.math.isNaN(x.im))
1481         {
1482             if (std.math.signbit(x.re))
1483                 return Complex!T(0, std.math.copysign(0, x.im));
1484             else
1485                 return x;
1486         }
1487         if (std.math.isInfinity(x.im))
1488         {
1489             if (std.math.signbit(x.re))
1490                 return Complex!T(0, std.math.copysign(0, x.im));
1491             else
1492                 return Complex!T(T.infinity, -T.nan);
1493         }
1494         if (x.im == 0.0)
1495         {
1496             if (std.math.signbit(x.re))
1497                 return Complex!T(0.0);
1498             else
1499                 return Complex!T(T.infinity);
1500         }
1501     }
1502     if (std.math.isNaN(x.re))
1503     {
1504         if (std.math.isNaN(x.im) || std.math.isInfinity(x.im))
1505             return Complex!T(T.nan, T.nan);
1506         if (x.im == 0.0)
1507             return x;
1508     }
1509     if (x.re == 0.0)
1510     {
1511         if (std.math.isNaN(x.im) || std.math.isInfinity(x.im))
1512             return Complex!T(T.nan, T.nan);
1513         if (x.im == 0.0)
1514             return Complex!T(1.0, 0.0);
1515     }
1516 
1517     return fromPolar!(T, T)(std.math.exp(x.re), x.im);
1518 }
1519 
1520 ///
1521 @safe pure nothrow @nogc unittest
1522 {
1523     import std.math.operations : isClose;
1524     import std.math.constants : PI;
1525 
1526     assert(exp(complex(0.0, 0.0)) == complex(1.0, 0.0));
1527 
1528     auto a = complex(2.0, 1.0);
1529     assert(exp(conj(a)) == conj(exp(a)));
1530 
1531     auto b = exp(complex(0.0L, 1.0L) * PI);
1532     assert(isClose(b, -1.0L, 0.0, 1e-15));
1533 }
1534 
1535 @safe pure nothrow @nogc unittest
1536 {
1537     import std.math.traits : isNaN, isInfinity;
1538 
1539     auto a = exp(complex(0.0, double.infinity));
1540     assert(a.re.isNaN && a.im.isNaN);
1541     auto b = exp(complex(0.0, double.infinity));
1542     assert(b.re.isNaN && b.im.isNaN);
1543     auto c = exp(complex(0.0, double.nan));
1544     assert(c.re.isNaN && c.im.isNaN);
1545 
1546     auto d = exp(complex(+double.infinity, 0.0));
1547     assert(d == complex(double.infinity, 0.0));
1548     auto e = exp(complex(-double.infinity, 0.0));
1549     assert(e == complex(0.0));
1550     auto f = exp(complex(-double.infinity, 1.0));
1551     assert(f == complex(0.0));
1552     auto g = exp(complex(+double.infinity, 1.0));
1553     assert(g == complex(double.infinity, double.infinity));
1554     auto h = exp(complex(-double.infinity, +double.infinity));
1555     assert(h == complex(0.0));
1556     auto i = exp(complex(+double.infinity, +double.infinity));
1557     assert(i.re.isInfinity && i.im.isNaN);
1558     auto j = exp(complex(-double.infinity, double.nan));
1559     assert(j == complex(0.0));
1560     auto k = exp(complex(+double.infinity, double.nan));
1561     assert(k.re.isInfinity && k.im.isNaN);
1562 
1563     auto l = exp(complex(double.nan, 0));
1564     assert(l.re.isNaN && l.im == 0.0);
1565     auto m = exp(complex(double.nan, 1));
1566     assert(m.re.isNaN && m.im.isNaN);
1567     auto n = exp(complex(double.nan, double.nan));
1568     assert(n.re.isNaN && n.im.isNaN);
1569 }
1570 
1571 @safe pure nothrow @nogc unittest
1572 {
1573     import std.math.constants : PI;
1574     import std.math.operations : isClose;
1575 
1576     auto a = exp(complex(0.0, -PI));
1577     assert(isClose(a, -1.0, 0.0, 1e-15));
1578 
1579     auto b = exp(complex(0.0, -2.0 * PI / 3.0));
1580     assert(isClose(b, complex(-0.5L, -0.866025403784438646763L)));
1581 
1582     auto c = exp(complex(0.0, PI / 3.0));
1583     assert(isClose(c, complex(0.5L, 0.866025403784438646763L)));
1584 
1585     auto d = exp(complex(0.0, 2.0 * PI / 3.0));
1586     assert(isClose(d, complex(-0.5L, 0.866025403784438646763L)));
1587 
1588     auto e = exp(complex(0.0, PI));
1589     assert(isClose(e, -1.0, 0.0, 1e-15));
1590 }
1591 
1592 /**
1593  * Calculate the natural logarithm of x.
1594  * The branch cut is along the negative axis.
1595  * Params:
1596  *      x = A complex number
1597  * Returns:
1598  *      The complex natural logarithm of `x`
1599  *
1600  *      $(TABLE_SV
1601  *      $(TR $(TH x)                           $(TH log(x)))
1602  *      $(TR $(TD (-0, +0))                    $(TD (-$(INFIN), $(PI))))
1603  *      $(TR $(TD (+0, +0))                    $(TD (-$(INFIN), +0)))
1604  *      $(TR $(TD (any, +$(INFIN)))            $(TD (+$(INFIN), $(PI)/2)))
1605  *      $(TR $(TD (any, $(NAN)))               $(TD ($(NAN), $(NAN))))
1606  *      $(TR $(TD (-$(INFIN), any))            $(TD (+$(INFIN), $(PI))))
1607  *      $(TR $(TD (+$(INFIN), any))            $(TD (+$(INFIN), +0)))
1608  *      $(TR $(TD (-$(INFIN), +$(INFIN)))      $(TD (+$(INFIN), 3$(PI)/4)))
1609  *      $(TR $(TD (+$(INFIN), +$(INFIN)))      $(TD (+$(INFIN), $(PI)/4)))
1610  *      $(TR $(TD ($(PLUSMN)$(INFIN), $(NAN))) $(TD (+$(INFIN), $(NAN))))
1611  *      $(TR $(TD ($(NAN), any))               $(TD ($(NAN), $(NAN))))
1612  *      $(TR $(TD ($(NAN), +$(INFIN)))         $(TD (+$(INFIN), $(NAN))))
1613  *      $(TR $(TD ($(NAN), $(NAN)))            $(TD ($(NAN), $(NAN))))
1614  *      )
1615  */
1616 Complex!T log(T)(Complex!T x) @safe pure nothrow @nogc
1617 {
1618     static import std.math;
1619 
1620     // Handle special cases explicitly here for better accuracy.
1621     // The order here is important, so that the correct path is chosen.
1622     if (std.math.isNaN(x.re))
1623     {
1624         if (std.math.isInfinity(x.im))
1625             return Complex!T(T.infinity, T.nan);
1626         else
1627             return Complex!T(T.nan, T.nan);
1628     }
1629     if (std.math.isInfinity(x.re))
1630     {
1631         if (std.math.isNaN(x.im))
1632             return Complex!T(T.infinity, T.nan);
1633         else if (std.math.isInfinity(x.im))
1634         {
1635             if (std.math.signbit(x.re))
1636                 return Complex!T(T.infinity, std.math.copysign(3.0 * std.math.PI_4, x.im));
1637             else
1638                 return Complex!T(T.infinity, std.math.copysign(std.math.PI_4, x.im));
1639         }
1640         else
1641         {
1642             if (std.math.signbit(x.re))
1643                 return Complex!T(T.infinity, std.math.copysign(std.math.PI, x.im));
1644             else
1645                 return Complex!T(T.infinity, std.math.copysign(0.0, x.im));
1646         }
1647     }
1648     if (std.math.isNaN(x.im))
1649         return Complex!T(T.nan, T.nan);
1650     if (std.math.isInfinity(x.im))
1651         return Complex!T(T.infinity, std.math.copysign(std.math.PI_2, x.im));
1652     if (x.re == 0.0 && x.im == 0.0)
1653     {
1654         if (std.math.signbit(x.re))
1655             return Complex!T(-T.infinity, std.math.copysign(std.math.PI, x.im));
1656         else
1657             return Complex!T(-T.infinity, std.math.copysign(0.0, x.im));
1658     }
1659 
1660     return Complex!T(std.math.log(abs(x)), arg(x));
1661 }
1662 
1663 ///
1664 @safe pure nothrow @nogc unittest
1665 {
1666     import core.math : sqrt;
1667     import std.math.constants : PI;
1668     import std.math.operations : isClose;
1669 
1670     auto a = complex(2.0, 1.0);
1671     assert(log(conj(a)) == conj(log(a)));
1672 
1673     auto b = 2.0 * log10(complex(0.0, 1.0));
1674     auto c = 4.0 * log10(complex(sqrt(2.0) / 2, sqrt(2.0) / 2));
1675     assert(isClose(b, c, 0.0, 1e-15));
1676 
1677     assert(log(complex(-1.0L, 0.0L)) == complex(0.0L, PI));
1678     assert(log(complex(-1.0L, -0.0L)) == complex(0.0L, -PI));
1679 }
1680 
1681 @safe pure nothrow @nogc unittest
1682 {
1683     import std.math.traits : isNaN, isInfinity;
1684     import std.math.constants : PI, PI_2, PI_4;
1685 
1686     auto a = log(complex(-0.0L, 0.0L));
1687     assert(a == complex(-real.infinity, PI));
1688     auto b = log(complex(0.0L, 0.0L));
1689     assert(b == complex(-real.infinity, +0.0L));
1690     auto c = log(complex(1.0L, real.infinity));
1691     assert(c == complex(real.infinity, PI_2));
1692     auto d = log(complex(1.0L, real.nan));
1693     assert(d.re.isNaN && d.im.isNaN);
1694 
1695     auto e = log(complex(-real.infinity, 1.0L));
1696     assert(e == complex(real.infinity, PI));
1697     auto f = log(complex(real.infinity, 1.0L));
1698     assert(f == complex(real.infinity, 0.0L));
1699     auto g = log(complex(-real.infinity, real.infinity));
1700     assert(g == complex(real.infinity, 3.0 * PI_4));
1701     auto h = log(complex(real.infinity, real.infinity));
1702     assert(h == complex(real.infinity, PI_4));
1703     auto i = log(complex(real.infinity, real.nan));
1704     assert(i.re.isInfinity && i.im.isNaN);
1705 
1706     auto j = log(complex(real.nan, 1.0L));
1707     assert(j.re.isNaN && j.im.isNaN);
1708     auto k = log(complex(real.nan, real.infinity));
1709     assert(k.re.isInfinity && k.im.isNaN);
1710     auto l = log(complex(real.nan, real.nan));
1711     assert(l.re.isNaN && l.im.isNaN);
1712 }
1713 
1714 @safe pure nothrow @nogc unittest
1715 {
1716     import std.math.constants : PI;
1717     import std.math.operations : isClose;
1718 
1719     auto a = log(fromPolar(1.0, PI / 6.0));
1720     assert(isClose(a, complex(0.0L, 0.523598775598298873077L), 0.0, 1e-15));
1721 
1722     auto b = log(fromPolar(1.0, PI / 3.0));
1723     assert(isClose(b, complex(0.0L, 1.04719755119659774615L), 0.0, 1e-15));
1724 
1725     auto c = log(fromPolar(1.0, PI / 2.0));
1726     assert(isClose(c, complex(0.0L, 1.57079632679489661923L), 0.0, 1e-15));
1727 
1728     auto d = log(fromPolar(1.0, 2.0 * PI / 3.0));
1729     assert(isClose(d, complex(0.0L, 2.09439510239319549230L), 0.0, 1e-15));
1730 
1731     auto e = log(fromPolar(1.0, 5.0 * PI / 6.0));
1732     assert(isClose(e, complex(0.0L, 2.61799387799149436538L), 0.0, 1e-15));
1733 
1734     auto f = log(complex(-1.0L, 0.0L));
1735     assert(isClose(f, complex(0.0L, PI), 0.0, 1e-15));
1736 }
1737 
1738 /**
1739  * Calculate the base-10 logarithm of x.
1740  * Params:
1741  *      x = A complex number
1742  * Returns:
1743  *      The complex base 10 logarithm of `x`
1744  */
1745 Complex!T log10(T)(Complex!T x) @safe pure nothrow @nogc
1746 {
1747     import std.math.constants : LN10;
1748 
1749     return log(x) / Complex!T(LN10);
1750 }
1751 
1752 ///
1753 @safe pure nothrow @nogc unittest
1754 {
1755     import core.math : sqrt;
1756     import std.math.constants : LN10, PI;
1757     import std.math.operations : isClose;
1758 
1759     auto a = complex(2.0, 1.0);
1760     assert(log10(a) == log(a) / log(complex(10.0)));
1761 
1762     auto b = log10(complex(0.0, 1.0)) * 2.0;
1763     auto c = log10(complex(sqrt(2.0) / 2, sqrt(2.0) / 2)) * 4.0;
1764     assert(isClose(b, c, 0.0, 1e-15));
1765 }
1766 
1767 @safe pure nothrow @nogc unittest
1768 {
1769     import std.math.constants : LN10, PI;
1770     import std.math.operations : isClose;
1771 
1772     auto a = log10(fromPolar(1.0, PI / 6.0));
1773     assert(isClose(a, complex(0.0L, 0.227396058973640224580L), 0.0, 1e-15));
1774 
1775     auto b = log10(fromPolar(1.0, PI / 3.0));
1776     assert(isClose(b, complex(0.0L, 0.454792117947280449161L), 0.0, 1e-15));
1777 
1778     auto c = log10(fromPolar(1.0, PI / 2.0));
1779     assert(isClose(c, complex(0.0L, 0.682188176920920673742L), 0.0, 1e-15));
1780 
1781     auto d = log10(fromPolar(1.0, 2.0 * PI / 3.0));
1782     assert(isClose(d, complex(0.0L, 0.909584235894560898323L), 0.0, 1e-15));
1783 
1784     auto e = log10(fromPolar(1.0, 5.0 * PI / 6.0));
1785     assert(isClose(e, complex(0.0L, 1.13698029486820112290L), 0.0, 1e-15));
1786 
1787     auto f = log10(complex(-1.0L, 0.0L));
1788     assert(isClose(f, complex(0.0L, 1.36437635384184134748L), 0.0, 1e-15));
1789 
1790     assert(ceqrel(log10(complex(-100.0L, 0.0L)), complex(2.0L, PI / LN10)) >= real.mant_dig - 1);
1791     assert(ceqrel(log10(complex(-100.0L, -0.0L)), complex(2.0L, -PI / LN10)) >= real.mant_dig - 1);
1792 }
1793 
1794 /**
1795  * Calculates x$(SUPERSCRIPT n).
1796  * The branch cut is on the negative axis.
1797  * Params:
1798  *      x = base
1799  *      n = exponent
1800  * Returns:
1801  *      `x` raised to the power of `n`
1802  */
1803 Complex!T pow(T, Int)(Complex!T x, const Int n) @safe pure nothrow @nogc
1804 if (isIntegral!Int)
1805 {
1806     alias UInt = Unsigned!(Unqual!Int);
1807 
1808     UInt m = (n < 0) ? -cast(UInt) n : n;
1809     Complex!T y = (m % 2) ? x : Complex!T(1);
1810 
1811     while (m >>= 1)
1812     {
1813         x *= x;
1814         if (m % 2)
1815             y *= x;
1816     }
1817 
1818     return (n < 0) ? Complex!T(1) / y : y;
1819 }
1820 
1821 ///
1822 @safe pure nothrow @nogc unittest
1823 {
1824     import std.math.operations : isClose;
1825 
1826     auto a = complex(1.0, 2.0);
1827     assert(pow(a, 2) == a * a);
1828     assert(pow(a, 3) == a * a * a);
1829     assert(pow(a, -2) == 1.0 / (a * a));
1830     assert(isClose(pow(a, -3), 1.0 / (a * a * a)));
1831 }
1832 
1833 /// ditto
1834 Complex!T pow(T)(Complex!T x, const T n) @trusted pure nothrow @nogc
1835 {
1836     static import std.math;
1837 
1838     if (x == 0.0)
1839         return Complex!T(0.0);
1840 
1841     if (x.im == 0 && x.re > 0.0)
1842         return Complex!T(std.math.pow(x.re, n));
1843 
1844     Complex!T t = log(x);
1845     return fromPolar!(T, T)(std.math.exp(n * t.re), n * t.im);
1846 }
1847 
1848 ///
1849 @safe pure nothrow @nogc unittest
1850 {
1851     import std.math.operations : isClose;
1852     assert(pow(complex(0.0), 2.0) == complex(0.0));
1853     assert(pow(complex(5.0), 2.0) == complex(25.0));
1854 
1855     auto a = pow(complex(-1.0, 0.0), 0.5);
1856     assert(isClose(a, complex(0.0, +1.0), 0.0, 1e-16));
1857 
1858     auto b = pow(complex(-1.0, -0.0), 0.5);
1859     assert(isClose(b, complex(0.0, -1.0), 0.0, 1e-16));
1860 }
1861 
1862 /// ditto
1863 Complex!T pow(T)(Complex!T x, Complex!T y) @trusted pure nothrow @nogc
1864 {
1865     return (x == 0) ? Complex!T(0) : exp(y * log(x));
1866 }
1867 
1868 ///
1869 @safe pure nothrow @nogc unittest
1870 {
1871     import std.math.operations : isClose;
1872     import std.math.exponential : exp;
1873     import std.math.constants : PI;
1874     auto a = complex(0.0);
1875     auto b = complex(2.0);
1876     assert(pow(a, b) == complex(0.0));
1877 
1878     auto c = complex(0.0L, 1.0L);
1879     assert(isClose(pow(c, c), exp((-PI) / 2)));
1880 }
1881 
1882 /// ditto
1883 Complex!T pow(T)(const T x, Complex!T n) @trusted pure nothrow @nogc
1884 {
1885     static import std.math;
1886 
1887     return (x > 0.0)
1888         ? fromPolar!(T, T)(std.math.pow(x, n.re), n.im * std.math.log(x))
1889         : pow(Complex!T(x), n);
1890 }
1891 
1892 ///
1893 @safe pure nothrow @nogc unittest
1894 {
1895     import std.math.operations : isClose;
1896     assert(pow(2.0, complex(0.0)) == complex(1.0));
1897     assert(pow(2.0, complex(5.0)) == complex(32.0));
1898 
1899     auto a = pow(-2.0, complex(-1.0));
1900     assert(isClose(a, complex(-0.5), 0.0, 1e-16));
1901 
1902     auto b = pow(-0.5, complex(-1.0));
1903     assert(isClose(b, complex(-2.0), 0.0, 1e-15));
1904 }
1905 
1906 @safe pure nothrow @nogc unittest
1907 {
1908     import std.math.constants : PI;
1909     import std.math.operations : isClose;
1910 
1911     auto a = pow(complex(3.0, 4.0), 2);
1912     assert(isClose(a, complex(-7.0, 24.0)));
1913 
1914     auto b = pow(complex(3.0, 4.0), PI);
1915     assert(ceqrel(b, complex(-152.91512205297134, 35.547499631917738)) >= double.mant_dig - 3);
1916 
1917     auto c = pow(complex(3.0, 4.0), complex(-2.0, 1.0));
1918     assert(ceqrel(c, complex(0.015351734187477306, -0.0038407695456661503)) >= double.mant_dig - 3);
1919 
1920     auto d = pow(PI, complex(2.0, -1.0));
1921     assert(ceqrel(d, complex(4.0790296880118296, -8.9872469554541869)) >= double.mant_dig - 1);
1922 
1923     auto e = complex(2.0);
1924     assert(ceqrel(pow(e, 3), exp(3 * log(e))) >= double.mant_dig - 1);
1925 }
1926 
1927 @safe pure nothrow @nogc unittest
1928 {
1929     import std.meta : AliasSeq;
1930     import std.math.traits : floatTraits, RealFormat;
1931     static foreach (T; AliasSeq!(float, double, real))
1932     {{
1933          static if (floatTraits!T.realFormat == RealFormat.ibmExtended)
1934          {
1935              /* For IBM real, epsilon is too small (since 1.0 plus any double is
1936                 representable) to be able to expect results within epsilon * 100.  */
1937          }
1938          else
1939          {
1940              T eps = T.epsilon * 100;
1941 
1942              T a = -1.0;
1943              T b = 0.5;
1944              Complex!T ref1 = pow(complex(a), complex(b));
1945              Complex!T res1 = pow(a, complex(b));
1946              Complex!T res2 = pow(complex(a), b);
1947              assert(abs(ref1 - res1) < eps);
1948              assert(abs(ref1 - res2) < eps);
1949              assert(abs(res1 - res2) < eps);
1950 
1951              T c = -3.2;
1952              T d = 1.4;
1953              Complex!T ref2 = pow(complex(a), complex(b));
1954              Complex!T res3 = pow(a, complex(b));
1955              Complex!T res4 = pow(complex(a), b);
1956              assert(abs(ref2 - res3) < eps);
1957              assert(abs(ref2 - res4) < eps);
1958              assert(abs(res3 - res4) < eps);
1959          }
1960     }}
1961 }
1962 
1963 @safe pure nothrow @nogc unittest
1964 {
1965     import std.meta : AliasSeq;
1966     static foreach (T; AliasSeq!(float, double, real))
1967     {{
1968          auto c = Complex!T(123, 456);
1969          auto n = c.toNative();
1970          assert(c.re == n.re && c.im == n.im);
1971     }}
1972 }