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 = ±
16 NAN = $(RED NAN)
17 INFIN = ∞
18 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 */
toString()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 {
version(FastMath)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 {
version(FastMath)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
483 @safe pure nothrow unittest
484 {
485 import std.complex;
486 static import core.math;
487 import std.math;
488
489 enum EPS = double.epsilon;
490 auto c1 = complex(1.0, 1.0);
491
492 // Check unary operations.
493 auto c2 = Complex!double(0.5, 2.0);
494
495 assert(c2 == +c2);
496
497 assert((-c2).re == -(c2.re));
498 assert((-c2).im == -(c2.im));
499 assert(c2 == -(-c2));
500
501 // Check complex-complex operations.
502 auto cpc = c1 + c2;
503 assert(cpc.re == c1.re + c2.re);
504 assert(cpc.im == c1.im + c2.im);
505
506 auto cmc = c1 - c2;
507 assert(cmc.re == c1.re - c2.re);
508 assert(cmc.im == c1.im - c2.im);
509
510 auto ctc = c1 * c2;
511 assert(isClose(abs(ctc), abs(c1)*abs(c2), EPS));
512 assert(isClose(arg(ctc), arg(c1)+arg(c2), EPS));
513
514 auto cdc = c1 / c2;
515 assert(isClose(abs(cdc), abs(c1)/abs(c2), EPS));
516 assert(isClose(arg(cdc), arg(c1)-arg(c2), EPS));
517
518 auto cec = c1^^c2;
519 assert(isClose(cec.re, 0.1152413197994, 1e-12));
520 assert(isClose(cec.im, 0.2187079045274, 1e-12));
521
522 // Check complex-real operations.
523 double a = 123.456;
524
525 auto cpr = c1 + a;
526 assert(cpr.re == c1.re + a);
527 assert(cpr.im == c1.im);
528
529 auto cmr = c1 - a;
530 assert(cmr.re == c1.re - a);
531 assert(cmr.im == c1.im);
532
533 auto ctr = c1 * a;
534 assert(ctr.re == c1.re*a);
535 assert(ctr.im == c1.im*a);
536
537 auto cdr = c1 / a;
538 assert(isClose(abs(cdr), abs(c1)/a, EPS));
539 assert(isClose(arg(cdr), arg(c1), EPS));
540
541 auto cer = c1^^3.0;
542 assert(isClose(abs(cer), abs(c1)^^3, EPS));
543 assert(isClose(arg(cer), arg(c1)*3, EPS));
544
545 auto rpc = a + c1;
546 assert(rpc == cpr);
547
548 auto rmc = a - c1;
549 assert(rmc.re == a-c1.re);
550 assert(rmc.im == -c1.im);
551
552 auto rtc = a * c1;
553 assert(rtc == ctr);
554
555 auto rdc = a / c1;
556 assert(isClose(abs(rdc), a/abs(c1), EPS));
557 assert(isClose(arg(rdc), -arg(c1), EPS));
558
559 rdc = a / c2;
560 assert(isClose(abs(rdc), a/abs(c2), EPS));
561 assert(isClose(arg(rdc), -arg(c2), EPS));
562
563 auto rec1a = 1.0 ^^ c1;
564 assert(rec1a.re == 1.0);
565 assert(rec1a.im == 0.0);
566
567 auto rec2a = 1.0 ^^ c2;
568 assert(rec2a.re == 1.0);
569 assert(rec2a.im == 0.0);
570
571 auto rec1b = (-1.0) ^^ c1;
572 assert(isClose(abs(rec1b), std.math.exp(-PI * c1.im), EPS));
573 auto arg1b = arg(rec1b);
574 /* The argument _should_ be PI, but floating-point rounding error
575 * means that in fact the imaginary part is very slightly negative.
576 */
577 assert(isClose(arg1b, PI, EPS) || isClose(arg1b, -PI, EPS));
578
579 auto rec2b = (-1.0) ^^ c2;
580 assert(isClose(abs(rec2b), std.math.exp(-2 * PI), EPS));
581 assert(isClose(arg(rec2b), PI_2, EPS));
582
583 auto rec3a = 0.79 ^^ complex(6.8, 5.7);
584 auto rec3b = complex(0.79, 0.0) ^^ complex(6.8, 5.7);
585 assert(isClose(rec3a.re, rec3b.re, 1e-14));
586 assert(isClose(rec3a.im, rec3b.im, 1e-14));
587
588 auto rec4a = (-0.79) ^^ complex(6.8, 5.7);
589 auto rec4b = complex(-0.79, 0.0) ^^ complex(6.8, 5.7);
590 assert(isClose(rec4a.re, rec4b.re, 1e-14));
591 assert(isClose(rec4a.im, rec4b.im, 1e-14));
592
593 auto rer = a ^^ complex(2.0, 0.0);
594 auto rcheck = a ^^ 2.0;
595 static assert(is(typeof(rcheck) == double));
596 assert(feqrel(rer.re, rcheck) == double.mant_dig);
597 assert(isIdentical(rer.re, rcheck));
598 assert(rer.im == 0.0);
599
600 auto rer2 = (-a) ^^ complex(2.0, 0.0);
601 rcheck = (-a) ^^ 2.0;
602 assert(feqrel(rer2.re, rcheck) == double.mant_dig);
603 assert(isIdentical(rer2.re, rcheck));
604 assert(isClose(rer2.im, 0.0, 0.0, 1e-10));
605
606 auto rer3 = (-a) ^^ complex(-2.0, 0.0);
607 rcheck = (-a) ^^ (-2.0);
608 assert(feqrel(rer3.re, rcheck) == double.mant_dig);
609 assert(isIdentical(rer3.re, rcheck));
610 assert(isClose(rer3.im, 0.0, 0.0, EPS));
611
612 auto rer4 = a ^^ complex(-2.0, 0.0);
613 rcheck = a ^^ (-2.0);
614 assert(feqrel(rer4.re, rcheck) == double.mant_dig);
615 assert(isIdentical(rer4.re, rcheck));
616 assert(rer4.im == 0.0);
617
618 // Check Complex-int operations.
619 foreach (i; 0 .. 6)
620 {
621 auto cei = c1^^i;
622 assert(isClose(abs(cei), abs(c1)^^i, 1e-14));
623 // Use cos() here to deal with arguments that go outside
624 // the (-pi,pi] interval (only an issue for i>3).
625 assert(isClose(core.math.cos(arg(cei)), core.math.cos(arg(c1)*i), 1e-14));
626 }
627
628 // Check operations between different complex types.
629 auto cf = Complex!float(1.0, 1.0);
630 auto cr = Complex!real(1.0, 1.0);
631 auto c1pcf = c1 + cf;
632 auto c1pcr = c1 + cr;
633 static assert(is(typeof(c1pcf) == Complex!double));
634 static assert(is(typeof(c1pcr) == Complex!real));
635 assert(c1pcf.re == c1pcr.re);
636 assert(c1pcf.im == c1pcr.im);
637
638 auto c1c = c1;
639 auto c2c = c2;
640
641 c1c /= c1;
642 assert(isClose(c1c.re, 1.0, EPS));
643 assert(isClose(c1c.im, 0.0, 0.0, EPS));
644
645 c1c = c1;
646 c1c /= c2;
647 assert(isClose(c1c.re, 0.5882352941177, 1e-12));
648 assert(isClose(c1c.im, -0.3529411764706, 1e-12));
649
650 c2c /= c1;
651 assert(isClose(c2c.re, 1.25, EPS));
652 assert(isClose(c2c.im, 0.75, EPS));
653
654 c2c = c2;
655 c2c /= c2;
656 assert(isClose(c2c.re, 1.0, EPS));
657 assert(isClose(c2c.im, 0.0, 0.0, EPS));
658 }
659
660 @safe pure nothrow unittest
661 {
662 // Initialization
663 Complex!double a = 1;
664 assert(a.re == 1 && a.im == 0);
665 Complex!double b = 1.0;
666 assert(b.re == 1.0 && b.im == 0);
667 Complex!double c = Complex!real(1.0, 2);
668 assert(c.re == 1.0 && c.im == 2);
669 }
670
671 @safe pure nothrow unittest
672 {
673 // Assignments and comparisons
674 Complex!double z;
675
676 z = 1;
677 assert(z == 1);
678 assert(z.re == 1.0 && z.im == 0.0);
679
680 z = 2.0;
681 assert(z == 2.0);
682 assert(z.re == 2.0 && z.im == 0.0);
683
684 z = 1.0L;
685 assert(z == 1.0L);
686 assert(z.re == 1.0 && z.im == 0.0);
687
688 auto w = Complex!real(1.0, 1.0);
689 z = w;
690 assert(z == w);
691 assert(z.re == 1.0 && z.im == 1.0);
692
693 auto c = Complex!float(2.0, 2.0);
694 z = c;
695 assert(z == c);
696 assert(z.re == 2.0 && z.im == 2.0);
697 }
698
699
700 /* Makes Complex!(Complex!T) fold to Complex!T.
701
702 The rationale for this is that just like the real line is a
703 subspace of the complex plane, the complex plane is a subspace
704 of itself. Example of usage:
705 ---
706 Complex!T addI(T)(T x)
707 {
708 return x + Complex!T(0.0, 1.0);
709 }
710 ---
711 The above will work if T is both real and complex.
712 */
713 template Complex(T)
714 if (is(T R == Complex!R))
715 {
716 alias Complex = T;
717 }
718
719 @safe pure nothrow unittest
720 {
721 static assert(is(Complex!(Complex!real) == Complex!real));
722
723 Complex!T addI(T)(T x)
724 {
725 return x + Complex!T(0.0, 1.0);
726 }
727
728 auto z1 = addI(1.0);
729 assert(z1.re == 1.0 && z1.im == 1.0);
730
731 enum one = Complex!double(1.0, 0.0);
732 auto z2 = addI(one);
733 assert(z1 == z2);
734 }
735
736
737 /**
738 Params: z = A complex number.
739 Returns: The absolute value (or modulus) of `z`.
740 */
abs(T)741 T abs(T)(Complex!T z) @safe pure nothrow @nogc
742 {
743 import std.math.algebraic : hypot;
744 return hypot(z.re, z.im);
745 }
746
747 ///
748 @safe pure nothrow unittest
749 {
750 static import core.math;
751 assert(abs(complex(1.0)) == 1.0);
752 assert(abs(complex(0.0, 1.0)) == 1.0);
753 assert(abs(complex(1.0L, -2.0L)) == core.math.sqrt(5.0L));
754 }
755
756 @safe pure nothrow @nogc unittest
757 {
758 static import core.math;
759 assert(abs(complex(0.0L, -3.2L)) == 3.2L);
760 assert(abs(complex(0.0L, 71.6L)) == 71.6L);
761 assert(abs(complex(-1.0L, 1.0L)) == core.math.sqrt(2.0L));
762 }
763
764 @safe pure nothrow @nogc unittest
765 {
766 import std.meta : AliasSeq;
767 static foreach (T; AliasSeq!(float, double, real))
768 {{
769 static import std.math;
770 Complex!T a = complex(T(-12), T(3));
771 T b = std.math.hypot(a.re, a.im);
772 assert(std.math.isClose(abs(a), b));
773 assert(std.math.isClose(abs(-a), b));
774 }}
775 }
776
777 /++
778 Params:
779 z = A complex number.
780 x = A real number.
781 Returns: The squared modulus of `z`.
782 For genericity, if called on a real number, returns its square.
783 +/
sqAbs(T)784 T sqAbs(T)(Complex!T z) @safe pure nothrow @nogc
785 {
786 return z.re*z.re + z.im*z.im;
787 }
788
789 ///
790 @safe pure nothrow unittest
791 {
792 import std.math.operations : isClose;
793 assert(sqAbs(complex(0.0)) == 0.0);
794 assert(sqAbs(complex(1.0)) == 1.0);
795 assert(sqAbs(complex(0.0, 1.0)) == 1.0);
796 assert(isClose(sqAbs(complex(1.0L, -2.0L)), 5.0L));
797 assert(isClose(sqAbs(complex(-3.0L, 1.0L)), 10.0L));
798 assert(isClose(sqAbs(complex(1.0f,-1.0f)), 2.0f));
799 }
800
801 /// ditto
802 T sqAbs(T)(const T x) @safe pure nothrow @nogc
803 if (isFloatingPoint!T)
804 {
805 return x*x;
806 }
807
808 @safe pure nothrow unittest
809 {
810 import std.math.operations : isClose;
811 assert(sqAbs(0.0) == 0.0);
812 assert(sqAbs(-1.0) == 1.0);
813 assert(isClose(sqAbs(-3.0L), 9.0L));
814 assert(isClose(sqAbs(-5.0f), 25.0f));
815 }
816
817
818 /**
819 Params: z = A complex number.
820 Returns: The argument (or phase) of `z`.
821 */
arg(T)822 T arg(T)(Complex!T z) @safe pure nothrow @nogc
823 {
824 import std.math.trigonometry : atan2;
825 return atan2(z.im, z.re);
826 }
827
828 ///
829 @safe pure nothrow unittest
830 {
831 import std.math.constants : PI_2, PI_4;
832 assert(arg(complex(1.0)) == 0.0);
833 assert(arg(complex(0.0L, 1.0L)) == PI_2);
834 assert(arg(complex(1.0L, 1.0L)) == PI_4);
835 }
836
837
838 /**
839 * Extracts the norm of a complex number.
840 * Params:
841 * z = A complex number
842 * Returns:
843 * The squared magnitude of `z`.
844 */
norm(T)845 T norm(T)(Complex!T z) @safe pure nothrow @nogc
846 {
847 return z.re * z.re + z.im * z.im;
848 }
849
850 ///
851 @safe pure nothrow @nogc unittest
852 {
853 import std.math.operations : isClose;
854 import std.math.constants : PI;
855 assert(norm(complex(3.0, 4.0)) == 25.0);
856 assert(norm(fromPolar(5.0, 0.0)) == 25.0);
857 assert(isClose(norm(fromPolar(5.0L, PI / 6)), 25.0L));
858 assert(isClose(norm(fromPolar(5.0L, 13 * PI / 6)), 25.0L));
859 }
860
861
862 /**
863 Params: z = A complex number.
864 Returns: The complex conjugate of `z`.
865 */
866 Complex!T conj(T)(Complex!T z) @safe pure nothrow @nogc
867 {
868 return Complex!T(z.re, -z.im);
869 }
870
871 ///
872 @safe pure nothrow unittest
873 {
874 assert(conj(complex(1.0)) == complex(1.0));
875 assert(conj(complex(1.0, 2.0)) == complex(1.0, -2.0));
876 }
877
878 @safe pure nothrow @nogc unittest
879 {
880 import std.meta : AliasSeq;
881 static foreach (T; AliasSeq!(float, double, real))
882 {{
883 auto c = Complex!T(7, 3L);
884 assert(conj(c) == Complex!T(7, -3L));
885 auto z = Complex!T(0, -3.2L);
886 assert(conj(z) == -z);
887 }}
888 }
889
890 /**
891 * Returns the projection of `z` onto the Riemann sphere.
892 * Params:
893 * z = A complex number
894 * Returns:
895 * The projection of `z` onto the Riemann sphere.
896 */
897 Complex!T proj(T)(Complex!T z)
898 {
899 static import std.math;
900
901 if (std.math.isInfinity(z.re) || std.math.isInfinity(z.im))
902 return Complex!T(T.infinity, std.math.copysign(0.0, z.im));
903
904 return z;
905 }
906
907 ///
908 @safe pure nothrow unittest
909 {
910 assert(proj(complex(1.0)) == complex(1.0));
911 assert(proj(complex(double.infinity, 5.0)) == complex(double.infinity, 0.0));
912 assert(proj(complex(5.0, -double.infinity)) == complex(double.infinity, -0.0));
913 }
914
915
916 /**
917 Constructs a complex number given its absolute value and argument.
918 Params:
919 modulus = The modulus
920 argument = The argument
921 Returns: The complex number with the given modulus and argument.
922 */
923 Complex!(CommonType!(T, U)) fromPolar(T, U)(const T modulus, const U argument)
924 @safe pure nothrow @nogc
925 {
926 import core.math : sin, cos;
927 return Complex!(CommonType!(T,U))
928 (modulus*cos(argument), modulus*sin(argument));
929 }
930
931 ///
932 @safe pure nothrow unittest
933 {
934 import core.math;
935 import std.math.operations : isClose;
936 import std.math.algebraic : sqrt;
937 import std.math.constants : PI_4;
938 auto z = fromPolar(core.math.sqrt(2.0), PI_4);
939 assert(isClose(z.re, 1.0L));
940 assert(isClose(z.im, 1.0L));
941 }
942
version(StdUnittest)943 version (StdUnittest)
944 {
945 // Helper function for comparing two Complex numbers.
946 int ceqrel(T)(const Complex!T x, const Complex!T y) @safe pure nothrow @nogc
947 {
948 import std.math.operations : feqrel;
949 const r = feqrel(x.re, y.re);
950 const i = feqrel(x.im, y.im);
951 return r < i ? r : i;
952 }
953 }
954
955 /**
956 Trigonometric functions on complex numbers.
957
958 Params: z = A complex number.
959 Returns: The sine, cosine and tangent of `z`, respectively.
960 */
961 Complex!T sin(T)(Complex!T z) @safe pure nothrow @nogc
962 {
963 auto cs = expi(z.re);
964 auto csh = coshisinh(z.im);
965 return typeof(return)(cs.im * csh.re, cs.re * csh.im);
966 }
967
968 ///
969 @safe pure nothrow unittest
970 {
971 static import core.math;
972 assert(sin(complex(0.0)) == 0.0);
973 assert(sin(complex(2.0, 0)) == core.math.sin(2.0));
974 }
975
976 @safe pure nothrow unittest
977 {
978 static import core.math;
979 assert(ceqrel(sin(complex(2.0L, 0)), complex(core.math.sin(2.0L))) >= real.mant_dig - 1);
980 }
981
982 /// ditto
983 Complex!T cos(T)(Complex!T z) @safe pure nothrow @nogc
984 {
985 auto cs = expi(z.re);
986 auto csh = coshisinh(z.im);
987 return typeof(return)(cs.re * csh.re, - cs.im * csh.im);
988 }
989
990 ///
991 @safe pure nothrow unittest
992 {
993 static import core.math;
994 static import std.math;
995 assert(cos(complex(0.0)) == 1.0);
996 assert(cos(complex(1.3, 0.0)) == core.math.cos(1.3));
997 assert(cos(complex(0.0, 5.2)) == std.math.cosh(5.2));
998 }
999
1000 @safe pure nothrow unittest
1001 {
1002 static import core.math;
1003 static import std.math;
1004 assert(ceqrel(cos(complex(0, 5.2L)), complex(std.math.cosh(5.2L), 0.0L)) >= real.mant_dig - 1);
1005 assert(ceqrel(cos(complex(1.3L)), complex(core.math.cos(1.3L))) >= real.mant_dig - 1);
1006 }
1007
1008 /// ditto
1009 Complex!T tan(T)(Complex!T z) @safe pure nothrow @nogc
1010 {
1011 return sin(z) / cos(z);
1012 }
1013
1014 ///
1015 @safe pure nothrow @nogc unittest
1016 {
1017 static import std.math;
1018
ceqrel(T)1019 int ceqrel(T)(const Complex!T x, const Complex!T y) @safe pure nothrow @nogc
1020 {
1021 import std.math.operations : feqrel;
1022 const r = feqrel(x.re, y.re);
1023 const i = feqrel(x.im, y.im);
1024 return r < i ? r : i;
1025 }
1026 assert(ceqrel(tan(complex(1.0, 0.0)), complex(std.math.tan(1.0), 0.0)) >= double.mant_dig - 2);
1027 assert(ceqrel(tan(complex(0.0, 1.0)), complex(0.0, std.math.tanh(1.0))) >= double.mant_dig - 2);
1028 }
1029
1030 /**
1031 Inverse trigonometric functions on complex numbers.
1032
1033 Params: z = A complex number.
1034 Returns: The arcsine, arccosine and arctangent of `z`, respectively.
1035 */
1036 Complex!T asin(T)(Complex!T z) @safe pure nothrow @nogc
1037 {
1038 auto ash = asinh(Complex!T(-z.im, z.re));
1039 return Complex!T(ash.im, -ash.re);
1040 }
1041
1042 ///
1043 @safe pure nothrow unittest
1044 {
1045 import std.math.operations : isClose;
1046 import std.math.constants : PI;
1047 assert(asin(complex(0.0)) == 0.0);
1048 assert(isClose(asin(complex(0.5L)), PI / 6));
1049 }
1050
1051 @safe pure nothrow unittest
1052 {
1053 import std.math.operations : isClose;
1054 import std.math.constants : PI;
version(DigitalMars)1055 version (DigitalMars) {} else // Disabled because of issue 21376
1056 assert(isClose(asin(complex(0.5f)), float(PI) / 6));
1057 }
1058
1059 /// ditto
1060 Complex!T acos(T)(Complex!T z) @safe pure nothrow @nogc
1061 {
1062 static import std.math;
1063 auto as = asin(z);
1064 return Complex!T(T(std.math.PI_2) - as.re, as.im);
1065 }
1066
1067 ///
1068 @safe pure nothrow unittest
1069 {
1070 import std.math.operations : isClose;
1071 import std.math.constants : PI;
1072 import std.math.trigonometry : std_math_acos = acos;
1073 assert(acos(complex(0.0)) == std_math_acos(0.0));
1074 assert(isClose(acos(complex(0.5L)), PI / 3));
1075 }
1076
1077 @safe pure nothrow unittest
1078 {
1079 import std.math.operations : isClose;
1080 import std.math.constants : PI;
version(DigitalMars)1081 version (DigitalMars) {} else // Disabled because of issue 21376
1082 assert(isClose(acos(complex(0.5f)), float(PI) / 3));
1083 }
1084
1085 /// ditto
1086 Complex!T atan(T)(Complex!T z) @safe pure nothrow @nogc
1087 {
1088 static import std.math;
1089 const T re2 = z.re * z.re;
1090 const T x = 1 - re2 - z.im * z.im;
1091
1092 T num = z.im + 1;
1093 T den = z.im - 1;
1094
1095 num = re2 + num * num;
1096 den = re2 + den * den;
1097
1098 return Complex!T(T(0.5) * std.math.atan2(2 * z.re, x),
1099 T(0.25) * std.math.log(num / den));
1100 }
1101
1102 ///
1103 @safe pure nothrow @nogc unittest
1104 {
1105 import std.math.operations : isClose;
1106 import std.math.constants : PI;
1107 assert(atan(complex(0.0)) == 0.0);
1108 assert(isClose(atan(sqrt(complex(3.0L))), PI / 3));
1109 assert(isClose(atan(sqrt(complex(3.0f))), float(PI) / 3));
1110 }
1111
1112 /**
1113 Hyperbolic trigonometric functions on complex numbers.
1114
1115 Params: z = A complex number.
1116 Returns: The hyperbolic sine, cosine and tangent of `z`, respectively.
1117 */
1118 Complex!T sinh(T)(Complex!T z) @safe pure nothrow @nogc
1119 {
1120 static import core.math, std.math;
1121 return Complex!T(std.math.sinh(z.re) * core.math.cos(z.im),
1122 std.math.cosh(z.re) * core.math.sin(z.im));
1123 }
1124
1125 ///
1126 @safe pure nothrow unittest
1127 {
1128 static import std.math;
1129 assert(sinh(complex(0.0)) == 0.0);
1130 assert(sinh(complex(1.0L)) == std.math.sinh(1.0L));
1131 assert(sinh(complex(1.0f)) == std.math.sinh(1.0f));
1132 }
1133
1134 /// ditto
1135 Complex!T cosh(T)(Complex!T z) @safe pure nothrow @nogc
1136 {
1137 static import core.math, std.math;
1138 return Complex!T(std.math.cosh(z.re) * core.math.cos(z.im),
1139 std.math.sinh(z.re) * core.math.sin(z.im));
1140 }
1141
1142 ///
1143 @safe pure nothrow unittest
1144 {
1145 static import std.math;
1146 assert(cosh(complex(0.0)) == 1.0);
1147 assert(cosh(complex(1.0L)) == std.math.cosh(1.0L));
1148 assert(cosh(complex(1.0f)) == std.math.cosh(1.0f));
1149 }
1150
1151 /// ditto
1152 Complex!T tanh(T)(Complex!T z) @safe pure nothrow @nogc
1153 {
1154 return sinh(z) / cosh(z);
1155 }
1156
1157 ///
1158 @safe pure nothrow @nogc unittest
1159 {
1160 import std.math.operations : isClose;
1161 import std.math.trigonometry : std_math_tanh = tanh;
1162 assert(tanh(complex(0.0)) == 0.0);
1163 assert(isClose(tanh(complex(1.0L)), std_math_tanh(1.0L)));
1164 assert(isClose(tanh(complex(1.0f)), std_math_tanh(1.0f)));
1165 }
1166
1167 /**
1168 Inverse hyperbolic trigonometric functions on complex numbers.
1169
1170 Params: z = A complex number.
1171 Returns: The hyperbolic arcsine, arccosine and arctangent of `z`, respectively.
1172 */
1173 Complex!T asinh(T)(Complex!T z) @safe pure nothrow @nogc
1174 {
1175 auto t = Complex!T((z.re - z.im) * (z.re + z.im) + 1, 2 * z.re * z.im);
1176 return log(sqrt(t) + z);
1177 }
1178
1179 ///
1180 @safe pure nothrow unittest
1181 {
1182 import std.math.operations : isClose;
1183 import std.math.trigonometry : std_math_asinh = asinh;
1184 assert(asinh(complex(0.0)) == 0.0);
1185 assert(isClose(asinh(complex(1.0L)), std_math_asinh(1.0L)));
1186 assert(isClose(asinh(complex(1.0f)), std_math_asinh(1.0f)));
1187 }
1188
1189 /// ditto
1190 Complex!T acosh(T)(Complex!T z) @safe pure nothrow @nogc
1191 {
1192 return 2 * log(sqrt(T(0.5) * (z + 1)) + sqrt(T(0.5) * (z - 1)));
1193 }
1194
1195 ///
1196 @safe pure nothrow unittest
1197 {
1198 import std.math.operations : isClose;
1199 import std.math.trigonometry : std_math_acosh = acosh;
1200 assert(acosh(complex(1.0)) == 0.0);
1201 assert(isClose(acosh(complex(3.0L)), std_math_acosh(3.0L)));
1202 assert(isClose(acosh(complex(3.0f)), std_math_acosh(3.0f)));
1203 }
1204
1205 /// ditto
1206 Complex!T atanh(T)(Complex!T z) @safe pure nothrow @nogc
1207 {
1208 static import std.math;
1209 const T im2 = z.im * z.im;
1210 const T x = 1 - im2 - z.re * z.re;
1211
1212 T num = 1 + z.re;
1213 T den = 1 - z.re;
1214
1215 num = im2 + num * num;
1216 den = im2 + den * den;
1217
1218 return Complex!T(T(0.25) * (std.math.log(num) - std.math.log(den)),
1219 T(0.5) * std.math.atan2(2 * z.im, x));
1220 }
1221
1222 ///
1223 @safe pure nothrow @nogc unittest
1224 {
1225 import std.math.operations : isClose;
1226 import std.math.trigonometry : std_math_atanh = atanh;
1227 assert(atanh(complex(0.0)) == 0.0);
1228 assert(isClose(atanh(complex(0.5L)), std_math_atanh(0.5L)));
1229 assert(isClose(atanh(complex(0.5f)), std_math_atanh(0.5f)));
1230 }
1231
1232 /**
1233 Params: y = A real number.
1234 Returns: The value of cos(y) + i sin(y).
1235
1236 Note:
1237 `expi` is included here for convenience and for easy migration of code.
1238 */
1239 Complex!real expi(real y) @trusted pure nothrow @nogc
1240 {
1241 import core.math : cos, sin;
1242 return Complex!real(cos(y), sin(y));
1243 }
1244
1245 ///
1246 @safe pure nothrow unittest
1247 {
1248 import core.math : cos, sin;
1249 assert(expi(0.0L) == 1.0L);
1250 assert(expi(1.3e5L) == complex(cos(1.3e5L), sin(1.3e5L)));
1251 }
1252
1253 /**
1254 Params: y = A real number.
1255 Returns: The value of cosh(y) + i sinh(y)
1256
1257 Note:
1258 `coshisinh` is included here for convenience and for easy migration of code.
1259 */
1260 Complex!real coshisinh(real y) @safe pure nothrow @nogc
1261 {
1262 static import core.math;
1263 static import std.math;
1264 if (core.math.fabs(y) <= 0.5)
1265 return Complex!real(std.math.cosh(y), std.math.sinh(y));
1266 else
1267 {
1268 auto z = std.math.exp(y);
1269 auto zi = 0.5 / z;
1270 z = 0.5 * z;
1271 return Complex!real(z + zi, z - zi);
1272 }
1273 }
1274
1275 ///
1276 @safe pure nothrow @nogc unittest
1277 {
1278 import std.math.trigonometry : cosh, sinh;
1279 assert(coshisinh(3.0L) == complex(cosh(3.0L), sinh(3.0L)));
1280 }
1281
1282 /**
1283 Params: z = A complex number.
1284 Returns: The square root of `z`.
1285 */
1286 Complex!T sqrt(T)(Complex!T z) @safe pure nothrow @nogc
1287 {
1288 static import core.math;
1289 typeof(return) c;
1290 real x,y,w,r;
1291
1292 if (z == 0)
1293 {
1294 c = typeof(return)(0, 0);
1295 }
1296 else
1297 {
1298 real z_re = z.re;
1299 real z_im = z.im;
1300
1301 x = core.math.fabs(z_re);
1302 y = core.math.fabs(z_im);
1303 if (x >= y)
1304 {
1305 r = y / x;
1306 w = core.math.sqrt(x)
1307 * core.math.sqrt(0.5 * (1 + core.math.sqrt(1 + r * r)));
1308 }
1309 else
1310 {
1311 r = x / y;
1312 w = core.math.sqrt(y)
1313 * core.math.sqrt(0.5 * (r + core.math.sqrt(1 + r * r)));
1314 }
1315
1316 if (z_re >= 0)
1317 {
1318 c = typeof(return)(w, z_im / (w + w));
1319 }
1320 else
1321 {
1322 if (z_im < 0)
1323 w = -w;
1324 c = typeof(return)(z_im / (w + w), w);
1325 }
1326 }
1327 return c;
1328 }
1329
1330 ///
1331 @safe pure nothrow unittest
1332 {
1333 static import core.math;
1334 assert(sqrt(complex(0.0)) == 0.0);
1335 assert(sqrt(complex(1.0L, 0)) == core.math.sqrt(1.0L));
1336 assert(sqrt(complex(-1.0L, 0)) == complex(0, 1.0L));
1337 assert(sqrt(complex(-8.0, -6.0)) == complex(1.0, -3.0));
1338 }
1339
1340 @safe pure nothrow unittest
1341 {
1342 import std.math.operations : isClose;
1343
1344 auto c1 = complex(1.0, 1.0);
1345 auto c2 = Complex!double(0.5, 2.0);
1346
1347 auto c1s = sqrt(c1);
1348 assert(isClose(c1s.re, 1.09868411347));
1349 assert(isClose(c1s.im, 0.455089860562));
1350
1351 auto c2s = sqrt(c2);
1352 assert(isClose(c2s.re, 1.13171392428));
1353 assert(isClose(c2s.im, 0.883615530876));
1354 }
1355
1356 // support %f formatting of complex numbers
1357 // https://issues.dlang.org/show_bug.cgi?id=10881
1358 @safe unittest
1359 {
1360 import std.format : format;
1361
1362 auto x = complex(1.2, 3.4);
1363 assert(format("%.2f", x) == "1.20+3.40i");
1364
1365 auto y = complex(1.2, -3.4);
1366 assert(format("%.2f", y) == "1.20-3.40i");
1367 }
1368
1369 @safe unittest
1370 {
1371 // Test wide string formatting
1372 import std.format.write : formattedWrite;
wformat(T)1373 wstring wformat(T)(string format, Complex!T c)
1374 {
1375 import std.array : appender;
1376 auto w = appender!wstring();
1377 auto n = formattedWrite(w, format, c);
1378 return w.data;
1379 }
1380
1381 auto x = complex(1.2, 3.4);
1382 assert(wformat("%.2f", x) == "1.20+3.40i"w);
1383 }
1384
1385 @safe unittest
1386 {
1387 // Test ease of use (vanilla toString() should be supported)
1388 assert(complex(1.2, 3.4).toString() == "1.2+3.4i");
1389 }
1390
1391 @safe pure nothrow @nogc unittest
1392 {
1393 auto c = complex(3.0L, 4.0L);
1394 c = sqrt(c);
1395 assert(c.re == 2.0L);
1396 assert(c.im == 1.0L);
1397 }
1398
1399 /**
1400 * Calculates e$(SUPERSCRIPT x).
1401 * Params:
1402 * x = A complex number
1403 * Returns:
1404 * The complex base e exponential of `x`
1405 *
1406 * $(TABLE_SV
1407 * $(TR $(TH x) $(TH exp(x)))
1408 * $(TR $(TD ($(PLUSMN)0, +0)) $(TD (1, +0)))
1409 * $(TR $(TD (any, +$(INFIN))) $(TD ($(NAN), $(NAN))))
1410 * $(TR $(TD (any, $(NAN)) $(TD ($(NAN), $(NAN)))))
1411 * $(TR $(TD (+$(INFIN), +0)) $(TD (+$(INFIN), +0)))
1412 * $(TR $(TD (-$(INFIN), any)) $(TD ($(PLUSMN)0, cis(x.im))))
1413 * $(TR $(TD (+$(INFIN), any)) $(TD ($(PLUSMN)$(INFIN), cis(x.im))))
1414 * $(TR $(TD (-$(INFIN), +$(INFIN))) $(TD ($(PLUSMN)0, $(PLUSMN)0)))
1415 * $(TR $(TD (+$(INFIN), +$(INFIN))) $(TD ($(PLUSMN)$(INFIN), $(NAN))))
1416 * $(TR $(TD (-$(INFIN), $(NAN))) $(TD ($(PLUSMN)0, $(PLUSMN)0)))
1417 * $(TR $(TD (+$(INFIN), $(NAN))) $(TD ($(PLUSMN)$(INFIN), $(NAN))))
1418 * $(TR $(TD ($(NAN), +0)) $(TD ($(NAN), +0)))
1419 * $(TR $(TD ($(NAN), any)) $(TD ($(NAN), $(NAN))))
1420 * $(TR $(TD ($(NAN), $(NAN))) $(TD ($(NAN), $(NAN))))
1421 * )
1422 */
1423 Complex!T exp(T)(Complex!T x) @trusted pure nothrow @nogc // TODO: @safe
1424 {
1425 static import std.math;
1426
1427 // Handle special cases explicitly here, as fromPolar will otherwise
1428 // cause them to return Complex!T(NaN, NaN), or with the wrong sign.
1429 if (std.math.isInfinity(x.re))
1430 {
1431 if (std.math.isNaN(x.im))
1432 {
1433 if (std.math.signbit(x.re))
1434 return Complex!T(0, std.math.copysign(0, x.im));
1435 else
1436 return x;
1437 }
1438 if (std.math.isInfinity(x.im))
1439 {
1440 if (std.math.signbit(x.re))
1441 return Complex!T(0, std.math.copysign(0, x.im));
1442 else
1443 return Complex!T(T.infinity, -T.nan);
1444 }
1445 if (x.im == 0.0)
1446 {
1447 if (std.math.signbit(x.re))
1448 return Complex!T(0.0);
1449 else
1450 return Complex!T(T.infinity);
1451 }
1452 }
1453 if (std.math.isNaN(x.re))
1454 {
1455 if (std.math.isNaN(x.im) || std.math.isInfinity(x.im))
1456 return Complex!T(T.nan, T.nan);
1457 if (x.im == 0.0)
1458 return x;
1459 }
1460 if (x.re == 0.0)
1461 {
1462 if (std.math.isNaN(x.im) || std.math.isInfinity(x.im))
1463 return Complex!T(T.nan, T.nan);
1464 if (x.im == 0.0)
1465 return Complex!T(1.0, 0.0);
1466 }
1467
1468 return fromPolar!(T, T)(std.math.exp(x.re), x.im);
1469 }
1470
1471 ///
1472 @safe pure nothrow @nogc unittest
1473 {
1474 import std.math.operations : isClose;
1475 import std.math.constants : PI;
1476
1477 assert(exp(complex(0.0, 0.0)) == complex(1.0, 0.0));
1478
1479 auto a = complex(2.0, 1.0);
1480 assert(exp(conj(a)) == conj(exp(a)));
1481
1482 auto b = exp(complex(0.0L, 1.0L) * PI);
1483 assert(isClose(b, -1.0L, 0.0, 1e-15));
1484 }
1485
1486 @safe pure nothrow @nogc unittest
1487 {
1488 import std.math.traits : isNaN, isInfinity;
1489
1490 auto a = exp(complex(0.0, double.infinity));
1491 assert(a.re.isNaN && a.im.isNaN);
1492 auto b = exp(complex(0.0, double.infinity));
1493 assert(b.re.isNaN && b.im.isNaN);
1494 auto c = exp(complex(0.0, double.nan));
1495 assert(c.re.isNaN && c.im.isNaN);
1496
1497 auto d = exp(complex(+double.infinity, 0.0));
1498 assert(d == complex(double.infinity, 0.0));
1499 auto e = exp(complex(-double.infinity, 0.0));
1500 assert(e == complex(0.0));
1501 auto f = exp(complex(-double.infinity, 1.0));
1502 assert(f == complex(0.0));
1503 auto g = exp(complex(+double.infinity, 1.0));
1504 assert(g == complex(double.infinity, double.infinity));
1505 auto h = exp(complex(-double.infinity, +double.infinity));
1506 assert(h == complex(0.0));
1507 auto i = exp(complex(+double.infinity, +double.infinity));
1508 assert(i.re.isInfinity && i.im.isNaN);
1509 auto j = exp(complex(-double.infinity, double.nan));
1510 assert(j == complex(0.0));
1511 auto k = exp(complex(+double.infinity, double.nan));
1512 assert(k.re.isInfinity && k.im.isNaN);
1513
1514 auto l = exp(complex(double.nan, 0));
1515 assert(l.re.isNaN && l.im == 0.0);
1516 auto m = exp(complex(double.nan, 1));
1517 assert(m.re.isNaN && m.im.isNaN);
1518 auto n = exp(complex(double.nan, double.nan));
1519 assert(n.re.isNaN && n.im.isNaN);
1520 }
1521
1522 @safe pure nothrow @nogc unittest
1523 {
1524 import std.math.constants : PI;
1525 import std.math.operations : isClose;
1526
1527 auto a = exp(complex(0.0, -PI));
1528 assert(isClose(a, -1.0, 0.0, 1e-15));
1529
1530 auto b = exp(complex(0.0, -2.0 * PI / 3.0));
1531 assert(isClose(b, complex(-0.5L, -0.866025403784438646763L)));
1532
1533 auto c = exp(complex(0.0, PI / 3.0));
1534 assert(isClose(c, complex(0.5L, 0.866025403784438646763L)));
1535
1536 auto d = exp(complex(0.0, 2.0 * PI / 3.0));
1537 assert(isClose(d, complex(-0.5L, 0.866025403784438646763L)));
1538
1539 auto e = exp(complex(0.0, PI));
1540 assert(isClose(e, -1.0, 0.0, 1e-15));
1541 }
1542
1543 /**
1544 * Calculate the natural logarithm of x.
1545 * The branch cut is along the negative axis.
1546 * Params:
1547 * x = A complex number
1548 * Returns:
1549 * The complex natural logarithm of `x`
1550 *
1551 * $(TABLE_SV
1552 * $(TR $(TH x) $(TH log(x)))
1553 * $(TR $(TD (-0, +0)) $(TD (-$(INFIN), $(PI))))
1554 * $(TR $(TD (+0, +0)) $(TD (-$(INFIN), +0)))
1555 * $(TR $(TD (any, +$(INFIN))) $(TD (+$(INFIN), $(PI)/2)))
1556 * $(TR $(TD (any, $(NAN))) $(TD ($(NAN), $(NAN))))
1557 * $(TR $(TD (-$(INFIN), any)) $(TD (+$(INFIN), $(PI))))
1558 * $(TR $(TD (+$(INFIN), any)) $(TD (+$(INFIN), +0)))
1559 * $(TR $(TD (-$(INFIN), +$(INFIN))) $(TD (+$(INFIN), 3$(PI)/4)))
1560 * $(TR $(TD (+$(INFIN), +$(INFIN))) $(TD (+$(INFIN), $(PI)/4)))
1561 * $(TR $(TD ($(PLUSMN)$(INFIN), $(NAN))) $(TD (+$(INFIN), $(NAN))))
1562 * $(TR $(TD ($(NAN), any)) $(TD ($(NAN), $(NAN))))
1563 * $(TR $(TD ($(NAN), +$(INFIN))) $(TD (+$(INFIN), $(NAN))))
1564 * $(TR $(TD ($(NAN), $(NAN))) $(TD ($(NAN), $(NAN))))
1565 * )
1566 */
1567 Complex!T log(T)(Complex!T x) @safe pure nothrow @nogc
1568 {
1569 static import std.math;
1570
1571 // Handle special cases explicitly here for better accuracy.
1572 // The order here is important, so that the correct path is chosen.
1573 if (std.math.isNaN(x.re))
1574 {
1575 if (std.math.isInfinity(x.im))
1576 return Complex!T(T.infinity, T.nan);
1577 else
1578 return Complex!T(T.nan, T.nan);
1579 }
1580 if (std.math.isInfinity(x.re))
1581 {
1582 if (std.math.isNaN(x.im))
1583 return Complex!T(T.infinity, T.nan);
1584 else if (std.math.isInfinity(x.im))
1585 {
1586 if (std.math.signbit(x.re))
1587 return Complex!T(T.infinity, std.math.copysign(3.0 * std.math.PI_4, x.im));
1588 else
1589 return Complex!T(T.infinity, std.math.copysign(std.math.PI_4, x.im));
1590 }
1591 else
1592 {
1593 if (std.math.signbit(x.re))
1594 return Complex!T(T.infinity, std.math.copysign(std.math.PI, x.im));
1595 else
1596 return Complex!T(T.infinity, std.math.copysign(0.0, x.im));
1597 }
1598 }
1599 if (std.math.isNaN(x.im))
1600 return Complex!T(T.nan, T.nan);
1601 if (std.math.isInfinity(x.im))
1602 return Complex!T(T.infinity, std.math.copysign(std.math.PI_2, x.im));
1603 if (x.re == 0.0 && x.im == 0.0)
1604 {
1605 if (std.math.signbit(x.re))
1606 return Complex!T(-T.infinity, std.math.copysign(std.math.PI, x.im));
1607 else
1608 return Complex!T(-T.infinity, std.math.copysign(0.0, x.im));
1609 }
1610
1611 return Complex!T(std.math.log(abs(x)), arg(x));
1612 }
1613
1614 ///
1615 @safe pure nothrow @nogc unittest
1616 {
1617 import core.math : sqrt;
1618 import std.math.constants : PI;
1619 import std.math.operations : isClose;
1620
1621 auto a = complex(2.0, 1.0);
1622 assert(log(conj(a)) == conj(log(a)));
1623
1624 auto b = 2.0 * log10(complex(0.0, 1.0));
1625 auto c = 4.0 * log10(complex(sqrt(2.0) / 2, sqrt(2.0) / 2));
1626 assert(isClose(b, c, 0.0, 1e-15));
1627
1628 assert(log(complex(-1.0L, 0.0L)) == complex(0.0L, PI));
1629 assert(log(complex(-1.0L, -0.0L)) == complex(0.0L, -PI));
1630 }
1631
1632 @safe pure nothrow @nogc unittest
1633 {
1634 import std.math.traits : isNaN, isInfinity;
1635 import std.math.constants : PI, PI_2, PI_4;
1636
1637 auto a = log(complex(-0.0L, 0.0L));
1638 assert(a == complex(-real.infinity, PI));
1639 auto b = log(complex(0.0L, 0.0L));
1640 assert(b == complex(-real.infinity, +0.0L));
1641 auto c = log(complex(1.0L, real.infinity));
1642 assert(c == complex(real.infinity, PI_2));
1643 auto d = log(complex(1.0L, real.nan));
1644 assert(d.re.isNaN && d.im.isNaN);
1645
1646 auto e = log(complex(-real.infinity, 1.0L));
1647 assert(e == complex(real.infinity, PI));
1648 auto f = log(complex(real.infinity, 1.0L));
1649 assert(f == complex(real.infinity, 0.0L));
1650 auto g = log(complex(-real.infinity, real.infinity));
1651 assert(g == complex(real.infinity, 3.0 * PI_4));
1652 auto h = log(complex(real.infinity, real.infinity));
1653 assert(h == complex(real.infinity, PI_4));
1654 auto i = log(complex(real.infinity, real.nan));
1655 assert(i.re.isInfinity && i.im.isNaN);
1656
1657 auto j = log(complex(real.nan, 1.0L));
1658 assert(j.re.isNaN && j.im.isNaN);
1659 auto k = log(complex(real.nan, real.infinity));
1660 assert(k.re.isInfinity && k.im.isNaN);
1661 auto l = log(complex(real.nan, real.nan));
1662 assert(l.re.isNaN && l.im.isNaN);
1663 }
1664
1665 @safe pure nothrow @nogc unittest
1666 {
1667 import std.math.constants : PI;
1668 import std.math.operations : isClose;
1669
1670 auto a = log(fromPolar(1.0, PI / 6.0));
1671 assert(isClose(a, complex(0.0L, 0.523598775598298873077L), 0.0, 1e-15));
1672
1673 auto b = log(fromPolar(1.0, PI / 3.0));
1674 assert(isClose(b, complex(0.0L, 1.04719755119659774615L), 0.0, 1e-15));
1675
1676 auto c = log(fromPolar(1.0, PI / 2.0));
1677 assert(isClose(c, complex(0.0L, 1.57079632679489661923L), 0.0, 1e-15));
1678
1679 auto d = log(fromPolar(1.0, 2.0 * PI / 3.0));
1680 assert(isClose(d, complex(0.0L, 2.09439510239319549230L), 0.0, 1e-15));
1681
1682 auto e = log(fromPolar(1.0, 5.0 * PI / 6.0));
1683 assert(isClose(e, complex(0.0L, 2.61799387799149436538L), 0.0, 1e-15));
1684
1685 auto f = log(complex(-1.0L, 0.0L));
1686 assert(isClose(f, complex(0.0L, PI), 0.0, 1e-15));
1687 }
1688
1689 /**
1690 * Calculate the base-10 logarithm of x.
1691 * Params:
1692 * x = A complex number
1693 * Returns:
1694 * The complex base 10 logarithm of `x`
1695 */
1696 Complex!T log10(T)(Complex!T x) @safe pure nothrow @nogc
1697 {
1698 static import std.math;
1699
1700 return log(x) / Complex!T(std.math.log(10.0));
1701 }
1702
1703 ///
1704 @safe pure nothrow @nogc unittest
1705 {
1706 import core.math : sqrt;
1707 import std.math.constants : LN10, PI;
1708 import std.math.operations : isClose;
1709
1710 auto a = complex(2.0, 1.0);
1711 assert(log10(a) == log(a) / log(complex(10.0)));
1712
1713 auto b = log10(complex(0.0, 1.0)) * 2.0;
1714 auto c = log10(complex(sqrt(2.0) / 2, sqrt(2.0) / 2)) * 4.0;
1715 assert(isClose(b, c, 0.0, 1e-15));
1716 }
1717
1718 @safe pure nothrow @nogc unittest
1719 {
1720 import std.math.constants : LN10, PI;
1721 import std.math.operations : isClose;
1722
1723 auto a = log10(fromPolar(1.0, PI / 6.0));
1724 assert(isClose(a, complex(0.0L, 0.227396058973640224580L), 0.0, 1e-15));
1725
1726 auto b = log10(fromPolar(1.0, PI / 3.0));
1727 assert(isClose(b, complex(0.0L, 0.454792117947280449161L), 0.0, 1e-15));
1728
1729 auto c = log10(fromPolar(1.0, PI / 2.0));
1730 assert(isClose(c, complex(0.0L, 0.682188176920920673742L), 0.0, 1e-15));
1731
1732 auto d = log10(fromPolar(1.0, 2.0 * PI / 3.0));
1733 assert(isClose(d, complex(0.0L, 0.909584235894560898323L), 0.0, 1e-15));
1734
1735 auto e = log10(fromPolar(1.0, 5.0 * PI / 6.0));
1736 assert(isClose(e, complex(0.0L, 1.13698029486820112290L), 0.0, 1e-15));
1737
1738 auto f = log10(complex(-1.0L, 0.0L));
1739 assert(isClose(f, complex(0.0L, 1.36437635384184134748L), 0.0, 1e-15));
1740
1741 assert(ceqrel(log10(complex(-100.0L, 0.0L)), complex(2.0L, PI / LN10)) >= real.mant_dig - 1);
1742 assert(ceqrel(log10(complex(-100.0L, -0.0L)), complex(2.0L, -PI / LN10)) >= real.mant_dig - 1);
1743 }
1744
1745 /**
1746 * Calculates x$(SUPERSCRIPT n).
1747 * The branch cut is on the negative axis.
1748 * Params:
1749 * x = base
1750 * n = exponent
1751 * Returns:
1752 * `x` raised to the power of `n`
1753 */
1754 Complex!T pow(T, Int)(Complex!T x, const Int n) @safe pure nothrow @nogc
1755 if (isIntegral!Int)
1756 {
1757 alias UInt = Unsigned!(Unqual!Int);
1758
1759 UInt m = (n < 0) ? -cast(UInt) n : n;
1760 Complex!T y = (m % 2) ? x : Complex!T(1);
1761
1762 while (m >>= 1)
1763 {
1764 x *= x;
1765 if (m % 2)
1766 y *= x;
1767 }
1768
1769 return (n < 0) ? Complex!T(1) / y : y;
1770 }
1771
1772 ///
1773 @safe pure nothrow @nogc unittest
1774 {
1775 import std.math.operations : isClose;
1776
1777 auto a = complex(1.0, 2.0);
1778 assert(pow(a, 2) == a * a);
1779 assert(pow(a, 3) == a * a * a);
1780 assert(pow(a, -2) == 1.0 / (a * a));
1781 assert(isClose(pow(a, -3), 1.0 / (a * a * a)));
1782 }
1783
1784 /// ditto
1785 Complex!T pow(T)(Complex!T x, const T n) @trusted pure nothrow @nogc
1786 {
1787 static import std.math;
1788
1789 if (x == 0.0)
1790 return Complex!T(0.0);
1791
1792 if (x.im == 0 && x.re > 0.0)
1793 return Complex!T(std.math.pow(x.re, n));
1794
1795 Complex!T t = log(x);
1796 return fromPolar!(T, T)(std.math.exp(n * t.re), n * t.im);
1797 }
1798
1799 ///
1800 @safe pure nothrow @nogc unittest
1801 {
1802 import std.math.operations : isClose;
1803 assert(pow(complex(0.0), 2.0) == complex(0.0));
1804 assert(pow(complex(5.0), 2.0) == complex(25.0));
1805
1806 auto a = pow(complex(-1.0, 0.0), 0.5);
1807 assert(isClose(a, complex(0.0, +1.0), 0.0, 1e-16));
1808
1809 auto b = pow(complex(-1.0, -0.0), 0.5);
1810 assert(isClose(b, complex(0.0, -1.0), 0.0, 1e-16));
1811 }
1812
1813 /// ditto
1814 Complex!T pow(T)(Complex!T x, Complex!T y) @trusted pure nothrow @nogc
1815 {
1816 return (x == 0) ? Complex!T(0) : exp(y * log(x));
1817 }
1818
1819 ///
1820 @safe pure nothrow @nogc unittest
1821 {
1822 import std.math.operations : isClose;
1823 import std.math.exponential : exp;
1824 import std.math.constants : PI;
1825 auto a = complex(0.0);
1826 auto b = complex(2.0);
1827 assert(pow(a, b) == complex(0.0));
1828
1829 auto c = complex(0.0L, 1.0L);
1830 assert(isClose(pow(c, c), exp((-PI) / 2)));
1831 }
1832
1833 /// ditto
1834 Complex!T pow(T)(const T x, Complex!T n) @trusted pure nothrow @nogc
1835 {
1836 static import std.math;
1837
1838 return (x > 0.0)
1839 ? fromPolar!(T, T)(std.math.pow(x, n.re), n.im * std.math.log(x))
1840 : pow(Complex!T(x), n);
1841 }
1842
1843 ///
1844 @safe pure nothrow @nogc unittest
1845 {
1846 import std.math.operations : isClose;
1847 assert(pow(2.0, complex(0.0)) == complex(1.0));
1848 assert(pow(2.0, complex(5.0)) == complex(32.0));
1849
1850 auto a = pow(-2.0, complex(-1.0));
1851 assert(isClose(a, complex(-0.5), 0.0, 1e-16));
1852
1853 auto b = pow(-0.5, complex(-1.0));
1854 assert(isClose(b, complex(-2.0), 0.0, 1e-15));
1855 }
1856
1857 @safe pure nothrow @nogc unittest
1858 {
1859 import std.math.constants : PI;
1860 import std.math.operations : isClose;
1861
1862 auto a = pow(complex(3.0, 4.0), 2);
1863 assert(isClose(a, complex(-7.0, 24.0)));
1864
1865 auto b = pow(complex(3.0, 4.0), PI);
1866 assert(ceqrel(b, complex(-152.91512205297134, 35.547499631917738)) >= double.mant_dig - 3);
1867
1868 auto c = pow(complex(3.0, 4.0), complex(-2.0, 1.0));
1869 assert(ceqrel(c, complex(0.015351734187477306, -0.0038407695456661503)) >= double.mant_dig - 3);
1870
1871 auto d = pow(PI, complex(2.0, -1.0));
1872 assert(ceqrel(d, complex(4.0790296880118296, -8.9872469554541869)) >= double.mant_dig - 1);
1873
1874 auto e = complex(2.0);
1875 assert(ceqrel(pow(e, 3), exp(3 * log(e))) >= double.mant_dig - 1);
1876 }
1877
1878 @safe pure nothrow @nogc unittest
1879 {
1880 import std.meta : AliasSeq;
1881 import std.math : RealFormat, floatTraits;
1882 static foreach (T; AliasSeq!(float, double, real))
1883 {{
1884 static if (floatTraits!T.realFormat == RealFormat.ibmExtended)
1885 {
1886 /* For IBM real, epsilon is too small (since 1.0 plus any double is
1887 representable) to be able to expect results within epsilon * 100. */
1888 }
1889 else
1890 {
1891 T eps = T.epsilon * 100;
1892
1893 T a = -1.0;
1894 T b = 0.5;
1895 Complex!T ref1 = pow(complex(a), complex(b));
1896 Complex!T res1 = pow(a, complex(b));
1897 Complex!T res2 = pow(complex(a), b);
1898 assert(abs(ref1 - res1) < eps);
1899 assert(abs(ref1 - res2) < eps);
1900 assert(abs(res1 - res2) < eps);
1901
1902 T c = -3.2;
1903 T d = 1.4;
1904 Complex!T ref2 = pow(complex(a), complex(b));
1905 Complex!T res3 = pow(a, complex(b));
1906 Complex!T res4 = pow(complex(a), b);
1907 assert(abs(ref2 - res3) < eps);
1908 assert(abs(ref2 - res4) < eps);
1909 assert(abs(res3 - res4) < eps);
1910 }
1911 }}
1912 }
1913