1 // Written in the D programming language.
3 /** This module contains the $(LREF Complex) type, which is used to represent
4 complex numbers, along with related mathematical operations and functions.
6 $(LREF Complex) will eventually
7 $(DDLINK deprecate, Deprecated Features, replace)
8 the built-in types `cfloat`, `cdouble`, `creal`, `ifloat`,
9 `idouble`, and `ireal`.
12 TABLE_SV = <table border="1" cellpadding="4" cellspacing="0">
13 <caption>Special Values</caption>
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)
29 /** Helper function that returns a complex number with the specified
30 real and imaginary parts.
33 R = (template parameter) type of real part of complex number
34 I = (template parameter) type of imaginary part of complex number
36 re = real part of complex number to be constructed
37 im = (optional) imaginary part of complex number, 0 if omitted.
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)).
46 auto complex(R
)(const R re
) @safe pure nothrow @nogc
49 static if (isFloatingPoint
!R
)
50 return Complex
!R(re
, 0);
52 return Complex
!double(re
, 0);
56 auto complex(R
, I
)(const R re
, const I im
) @safe pure nothrow @nogc
57 if (is(R
: double) && is(I
: double))
59 static if (isFloatingPoint
!R || isFloatingPoint
!I
)
60 return Complex
!(CommonType
!(R
, I
))(re
, im
);
62 return Complex
!double(re
, im
);
66 @safe pure nothrow unittest
68 auto a
= complex(1.0);
69 static assert(is(typeof(a
) == Complex
!double));
73 auto b
= complex(2.0L);
74 static assert(is(typeof(b
) == Complex
!real));
78 auto c
= complex(1.0, 2.0);
79 static assert(is(typeof(c
) == Complex
!double));
83 auto d
= complex(3.0, 4.0L);
84 static assert(is(typeof(d
) == Complex
!real));
89 static assert(is(typeof(e
) == Complex
!double));
93 auto f
= complex(1L, 2);
94 static assert(is(typeof(f
) == Complex
!double));
98 auto g
= complex(3, 4.0L);
99 static assert(is(typeof(g
) == Complex
!real));
101 assert(g
.im
== 4.0L);
105 /** A complex number parametrised by a type `T`, which must be either
106 `float`, `double` or `real`.
109 if (isFloatingPoint
!T
)
111 import std
.format
.spec
: FormatSpec
;
112 import std
.range
.primitives
: isOutputRange
;
114 /** The real part of the number. */
117 /** The imaginary part of the number. */
120 /** Converts the complex number to a string representation.
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'.
126 See the $(MREF std, format) and $(REF format, std,string)
127 documentation for more information.
129 string
toString() const @safe /* TODO: pure nothrow */
131 import std
.exception
: assumeUnique
;
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
);
140 static if (is(T
== double))
144 auto c
= complex(1.2, 3.4);
146 // Vanilla toString formatting:
147 assert(c
.toString() == "1.2+3.4i");
149 // Formatting with std.string.format specs: the precision and width
150 // specifiers apply to both the real and imaginary parts of the
152 import std
.format
: format
;
153 assert(format("%.2f", c
) == "1.20+3.40i");
154 assert(format("%4.1f", c
) == " 1.2+ 3.4i");
158 void toString(Writer
, Char
)(scope Writer w
, scope const ref FormatSpec
!Char formatSpec
) const
159 if (isOutputRange
!(Writer
, const(Char
)[]))
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)
167 formatValue(w
, im
, formatSpec
);
171 @safe pure nothrow @nogc:
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
178 this(R
: T
)(Complex
!R z
)
185 this(Rx
: T
, Ry
: T
)(const Rx x
, const Ry y
)
192 this(R
: T
)(const R r
)
198 // ASSIGNMENT OPERATORS
201 ref Complex
opAssign(R
: T
)(Complex
!R z
)
209 ref Complex
opAssign(R
: T
)(const R r
)
216 // COMPARISON OPERATORS
219 bool opEquals(R
: T
)(Complex
!R z
) const
221 return re
== z
.re
&& im
== z
.im
;
225 bool opEquals(R
: T
)(const R r
) const
227 return re
== r
&& im
== 0;
233 Complex
opUnary(string op
)() const
240 Complex
opUnary(string op
)() const
243 return Complex(-re
, -im
);
248 // complex op complex
249 Complex
!(CommonType
!(T
,R
)) opBinary(string op
, R
)(Complex
!R z
) const
251 alias C
= typeof(return);
252 auto w
= C(this.re
, this.im
);
253 return w
.opOpAssign
!(op
)(z
);
256 // complex op numeric
257 Complex
!(CommonType
!(T
,R
)) opBinary(string op
, R
)(const R r
) const
260 alias C
= typeof(return);
261 auto w
= C(this.re
, this.im
);
262 return w
.opOpAssign
!(op
)(r
);
265 // numeric + complex, numeric * complex
266 Complex
!(CommonType
!(T
, R
)) opBinaryRight(string op
, R
)(const R r
) const
267 if ((op
== "+" || op
== "*") && (isNumeric
!R
))
269 return opBinary
!(op
)(r
);
273 Complex
!(CommonType
!(T
, R
)) opBinaryRight(string op
, R
)(const R r
) const
274 if (op
== "-" && isNumeric
!R
)
276 return Complex(r
- re
, -im
);
280 Complex
!(CommonType
!(T
, R
)) opBinaryRight(string op
, R
)(const R r
) const
281 if (op
== "/" && isNumeric
!R
)
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
;
298 import core
.math
: fabs;
299 typeof(return) w
= void;
300 if (fabs(re
) < fabs(im
))
302 immutable ratio
= re
/im
;
303 immutable rdivd
= r
/(re
*ratio
+ im
);
310 immutable ratio
= im
/re
;
311 immutable rdivd
= r
/(re
+ im
*ratio
);
321 // numeric ^^ complex
322 Complex
!(CommonType
!(T
, R
)) opBinaryRight(string op
, R
)(const R lhs
) const
323 if (op
== "^^" && isNumeric
!R
)
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;
335 ar
= log(lhs
) * this.im
;
341 ab
= (-lhs
) ^^
this.re
* exp(-PI
* this.im
);
342 ar
= PI
* this.re
+ log(-lhs
) * this.im
;
345 return typeof(return)(ab
* cos(ar
), ab
* sin(ar
));
348 // OP-ASSIGN OPERATORS
350 // complex += complex, complex -= complex
351 ref Complex
opOpAssign(string op
, C
)(const C z
)
352 if ((op
== "+" || op
== "-") && is(C R
== Complex
!R
))
354 mixin ("re "~op
~"= z.re;");
355 mixin ("im "~op
~"= z.im;");
359 // complex *= complex
360 ref Complex
opOpAssign(string op
, C
)(const C z
)
361 if (op
== "*" && is(C R
== Complex
!R
))
363 auto temp
= re
*z
.re
- im
*z
.im
;
364 im
= im
*z
.re
+ re
*z
.im
;
369 // complex /= complex
370 ref Complex
opOpAssign(string op
, C
)(const C z
)
371 if (op
== "/" && is(C R
== Complex
!R
))
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
387 import core
.math
: fabs;
388 if (fabs(z
.re
) < fabs(z
.im
))
390 immutable ratio
= z
.re
/z
.im
;
391 immutable denom
= z
.re
*ratio
+ z
.im
;
393 immutable temp
= (re
*ratio
+ im
)/denom
;
394 im
= (im
*ratio
- re
)/denom
;
399 immutable ratio
= z
.im
/z
.re
;
400 immutable denom
= z
.re
+ z
.im
*ratio
;
402 immutable temp
= (re
+ im
*ratio
)/denom
;
403 im
= (im
- re
*ratio
)/denom
;
410 // complex ^^= complex
411 ref Complex
opOpAssign(string op
, C
)(const C z
)
412 if (op
== "^^" && is(C R
== Complex
!R
))
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
;
426 // complex += numeric, complex -= numeric
427 ref Complex
opOpAssign(string op
, U
: T
)(const U a
)
428 if (op
== "+" || op
== "-")
430 mixin ("re "~op
~"= a;");
434 // complex *= numeric, complex /= numeric
435 ref Complex
opOpAssign(string op
, U
: T
)(const U a
)
436 if (op
== "*" || op
== "/")
438 mixin ("re "~op
~"= a;");
439 mixin ("im "~op
~"= a;");
444 ref Complex
opOpAssign(string op
, R
)(const R r
)
445 if (op
== "^^" && isFloatingPoint
!R
)
447 import core
.math
: cos
, sin
;
448 immutable ab
= abs(this)^^r
;
449 immutable ar
= arg(this)*r
;
456 ref Complex
opOpAssign(string op
, U
)(const U i
)
457 if (op
== "^^" && isIntegral
!U
)
466 // identity; do nothing
477 this ^^
= cast(real) i
;
482 /** Returns a complex number instance that correponds in size and in ABI
483 to the associated C compiler's `_Complex` type.
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
);
493 return c_complex_real(re
, im
);
497 @safe pure nothrow unittest
500 static import core
.math
;
503 enum EPS
= double.epsilon
;
504 auto c1
= complex(1.0, 1.0);
506 // Check unary operations.
507 auto c2
= Complex
!double(0.5, 2.0);
511 assert((-c2
).re
== -(c2
.re
));
512 assert((-c2
).im
== -(c2
.im
));
513 assert(c2
== -(-c2
));
515 // Check complex-complex operations.
517 assert(cpc
.re
== c1
.re
+ c2
.re
);
518 assert(cpc
.im
== c1
.im
+ c2
.im
);
521 assert(cmc.re
== c1
.re
- c2
.re
);
522 assert(cmc.im
== c1
.im
- c2
.im
);
525 assert(isClose(abs(ctc
), abs(c1
)*abs(c2
), EPS
));
526 assert(isClose(arg(ctc
), arg(c1
)+arg(c2
), EPS
));
529 assert(isClose(abs(cdc
), abs(c1
)/abs(c2
), EPS
));
530 assert(isClose(arg(cdc
), arg(c1
)-arg(c2
), EPS
));
533 assert(isClose(cec
.re
, 0.1152413197994, 1e-12));
534 assert(isClose(cec
.im
, 0.2187079045274, 1e-12));
536 // Check complex-real operations.
540 assert(cpr
.re
== c1
.re
+ a
);
541 assert(cpr
.im
== c1
.im
);
544 assert(cmr
.re
== c1
.re
- a
);
545 assert(cmr
.im
== c1
.im
);
548 assert(ctr
.re
== c1
.re
*a
);
549 assert(ctr
.im
== c1
.im
*a
);
552 assert(isClose(abs(cdr
), abs(c1
)/a
, EPS
));
553 assert(isClose(arg(cdr
), arg(c1
), EPS
));
556 assert(isClose(abs(cer
), abs(c1
)^^
3, EPS
));
557 assert(isClose(arg(cer
), arg(c1
)*3, EPS
));
563 assert(rmc
.re
== a
-c1
.re
);
564 assert(rmc
.im
== -c1
.im
);
570 assert(isClose(abs(rdc
), a
/abs(c1
), EPS
));
571 assert(isClose(arg(rdc
), -arg(c1
), EPS
));
574 assert(isClose(abs(rdc
), a
/abs(c2
), EPS
));
575 assert(isClose(arg(rdc
), -arg(c2
), EPS
));
577 auto rec1a
= 1.0 ^^ c1
;
578 assert(rec1a
.re
== 1.0);
579 assert(rec1a
.im
== 0.0);
581 auto rec2a
= 1.0 ^^ c2
;
582 assert(rec2a
.re
== 1.0);
583 assert(rec2a
.im
== 0.0);
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.
591 assert(isClose(arg1b
, PI
, EPS
) ||
isClose(arg1b
, -PI
, EPS
));
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
));
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));
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));
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);
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));
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
));
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);
632 // Check Complex-int operations.
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));
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
);
656 assert(isClose(c1c
.re
, 1.0, EPS
));
657 assert(isClose(c1c
.im
, 0.0, 0.0, EPS
));
661 assert(isClose(c1c
.re
, 0.5882352941177, 1e-12));
662 assert(isClose(c1c
.im
, -0.3529411764706, 1e-12));
665 assert(isClose(c2c
.re
, 1.25, EPS
));
666 assert(isClose(c2c
.im
, 0.75, EPS
));
670 assert(isClose(c2c
.re
, 1.0, EPS
));
671 assert(isClose(c2c
.im
, 0.0, 0.0, EPS
));
674 @safe pure nothrow unittest
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);
685 @safe pure nothrow unittest
687 // Assignments and comparisons
692 assert(z
.re
== 1.0 && z
.im
== 0.0);
696 assert(z
.re
== 2.0 && z
.im
== 0.0);
700 assert(z
.re
== 1.0 && z
.im
== 0.0);
702 auto w
= Complex
!real(1.0, 1.0);
705 assert(z
.re
== 1.0 && z
.im
== 1.0);
707 auto c
= Complex
!float(2.0, 2.0);
710 assert(z
.re
== 2.0 && z
.im
== 2.0);
714 /* Makes Complex!(Complex!T) fold to Complex!T.
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:
720 Complex!T addI(T)(T x)
722 return x + Complex!T(0.0, 1.0);
725 The above will work if T is both real and complex.
728 if (is(T R
== Complex
!R
))
733 @safe pure nothrow unittest
735 static assert(is(Complex
!(Complex
!real) == Complex
!real));
737 Complex
!T
addI(T
)(T x
)
739 return x
+ Complex
!T(0.0, 1.0);
743 assert(z1
.re
== 1.0 && z1
.im
== 1.0);
745 enum one
= Complex
!double(1.0, 0.0);
752 Params: z = A complex number.
753 Returns: The absolute value (or modulus) of `z`.
755 T
abs(T
)(Complex
!T z
) @safe pure nothrow @nogc
757 import std
.math
.algebraic
: hypot
;
758 return hypot(z
.re
, z
.im
);
762 @safe pure nothrow unittest
764 static import core
.math
;
765 assert(abs(complex(1.0)) == 1.0);
766 assert(abs(complex(0.0, 1.0)) == 1.0);
767 assert(abs(complex(1.0L, -2.0L)) == core
.math
.sqrt(5.0L));
770 @safe pure nothrow @nogc unittest
772 static import core
.math
;
773 assert(abs(complex(0.0L, -3.2L)) == 3.2L);
774 assert(abs(complex(0.0L, 71.6L)) == 71.6L);
775 assert(abs(complex(-1.0L, 1.0L)) == core
.math
.sqrt(2.0L));
778 @safe pure nothrow @nogc unittest
780 import std
.meta
: AliasSeq
;
781 static foreach (T
; AliasSeq
!(float, double, real))
783 static import std
.math
;
784 Complex
!T a
= complex(T(-12), T(3));
785 T b
= std
.math
.hypot(a
.re
, a
.im
);
786 assert(std
.math
.isClose(abs(a
), b
));
787 assert(std
.math
.isClose(abs(-a
), b
));
793 z = A complex number.
795 Returns: The squared modulus of `z`.
796 For genericity, if called on a real number, returns its square.
798 T
sqAbs(T
)(Complex
!T z
) @safe pure nothrow @nogc
800 return z
.re
*z
.re
+ z
.im
*z
.im
;
804 @safe pure nothrow unittest
806 import std
.math
.operations
: isClose
;
807 assert(sqAbs(complex(0.0)) == 0.0);
808 assert(sqAbs(complex(1.0)) == 1.0);
809 assert(sqAbs(complex(0.0, 1.0)) == 1.0);
810 assert(isClose(sqAbs(complex(1.0L, -2.0L)), 5.0L));
811 assert(isClose(sqAbs(complex(-3.0L, 1.0L)), 10.0L));
812 assert(isClose(sqAbs(complex(1.0f,-1.0f)), 2.0f));
816 T
sqAbs(T
)(const T x
) @safe pure nothrow @nogc
817 if (isFloatingPoint
!T
)
822 @safe pure nothrow unittest
824 import std
.math
.operations
: isClose
;
825 assert(sqAbs(0.0) == 0.0);
826 assert(sqAbs(-1.0) == 1.0);
827 assert(isClose(sqAbs(-3.0L), 9.0L));
828 assert(isClose(sqAbs(-5.0f), 25.0f));
833 Params: z = A complex number.
834 Returns: The argument (or phase) of `z`.
836 T
arg(T
)(Complex
!T z
) @safe pure nothrow @nogc
838 import std
.math
.trigonometry
: atan2
;
839 return atan2(z
.im
, z
.re
);
843 @safe pure nothrow unittest
845 import std
.math
.constants
: PI_2
, PI_4
;
846 assert(arg(complex(1.0)) == 0.0);
847 assert(arg(complex(0.0L, 1.0L)) == PI_2
);
848 assert(arg(complex(1.0L, 1.0L)) == PI_4
);
853 * Extracts the norm of a complex number.
855 * z = A complex number
857 * The squared magnitude of `z`.
859 T
norm(T
)(Complex
!T z
) @safe pure nothrow @nogc
861 return z
.re
* z
.re
+ z
.im
* z
.im
;
865 @safe pure nothrow @nogc unittest
867 import std
.math
.operations
: isClose
;
868 import std
.math
.constants
: PI
;
869 assert(norm(complex(3.0, 4.0)) == 25.0);
870 assert(norm(fromPolar(5.0, 0.0)) == 25.0);
871 assert(isClose(norm(fromPolar(5.0L, PI
/ 6)), 25.0L));
872 assert(isClose(norm(fromPolar(5.0L, 13 * PI
/ 6)), 25.0L));
877 Params: z = A complex number.
878 Returns: The complex conjugate of `z`.
880 Complex
!T
conj(T
)(Complex
!T z
) @safe pure nothrow @nogc
882 return Complex
!T(z
.re
, -z
.im
);
886 @safe pure nothrow unittest
888 assert(conj(complex(1.0)) == complex(1.0));
889 assert(conj(complex(1.0, 2.0)) == complex(1.0, -2.0));
892 @safe pure nothrow @nogc unittest
894 import std
.meta
: AliasSeq
;
895 static foreach (T
; AliasSeq
!(float, double, real))
897 auto c
= Complex
!T(7, 3L);
898 assert(conj(c
) == Complex
!T(7, -3L));
899 auto z
= Complex
!T(0, -3.2L);
900 assert(conj(z
) == -z
);
905 * Returns the projection of `z` onto the Riemann sphere.
907 * z = A complex number
909 * The projection of `z` onto the Riemann sphere.
911 Complex
!T
proj(T
)(Complex
!T z
)
913 static import std
.math
;
915 if (std
.math
.isInfinity(z
.re
) || std
.math
.isInfinity(z
.im
))
916 return Complex
!T(T
.infinity
, std
.math
.copysign(0.0, z
.im
));
922 @safe pure nothrow unittest
924 assert(proj(complex(1.0)) == complex(1.0));
925 assert(proj(complex(double.infinity
, 5.0)) == complex(double.infinity
, 0.0));
926 assert(proj(complex(5.0, -double.infinity
)) == complex(double.infinity
, -0.0));
931 Constructs a complex number given its absolute value and argument.
933 modulus = The modulus
934 argument = The argument
935 Returns: The complex number with the given modulus and argument.
937 Complex
!(CommonType
!(T
, U
)) fromPolar(T
, U
)(const T modulus
, const U argument
)
938 @safe pure nothrow @nogc
940 import core
.math
: sin
, cos
;
941 return Complex
!(CommonType
!(T
,U
))
942 (modulus
*cos(argument
), modulus
*sin(argument
));
946 @safe pure nothrow unittest
949 import std
.math
.operations
: isClose
;
950 import std
.math
.algebraic
: sqrt
;
951 import std
.math
.constants
: PI_4
;
952 auto z
= fromPolar(core
.math
.sqrt(2.0L), PI_4
);
953 assert(isClose(z
.re
, 1.0L));
954 assert(isClose(z
.im
, 1.0L));
957 version (StdUnittest
)
959 // Helper function for comparing two Complex numbers.
960 int ceqrel(T
)(const Complex
!T x
, const Complex
!T y
) @safe pure nothrow @nogc
962 import std
.math
.operations
: feqrel
;
963 const r
= feqrel(x
.re
, y
.re
);
964 const i
= feqrel(x
.im
, y
.im
);
965 return r
< i ? r
: i
;
970 Trigonometric functions on complex numbers.
972 Params: z = A complex number.
973 Returns: The sine, cosine and tangent of `z`, respectively.
975 Complex
!T
sin(T
)(Complex
!T z
) @safe pure nothrow @nogc
977 auto cs
= expi(z
.re
);
978 auto csh
= coshisinh(z
.im
);
979 return typeof(return)(cs
.im
* csh
.re
, cs
.re
* csh
.im
);
983 @safe pure nothrow unittest
985 static import core
.math
;
986 assert(sin(complex(0.0)) == 0.0);
987 assert(sin(complex(2.0, 0)) == core
.math
.sin(2.0));
990 @safe pure nothrow unittest
992 static import core
.math
;
993 assert(ceqrel(sin(complex(2.0L, 0)), complex(core
.math
.sin(2.0L))) >= real.mant_dig
- 1);
997 Complex
!T
cos(T
)(Complex
!T z
) @safe pure nothrow @nogc
999 auto cs
= expi(z
.re
);
1000 auto csh
= coshisinh(z
.im
);
1001 return typeof(return)(cs
.re
* csh
.re
, - cs
.im
* csh
.im
);
1005 @safe pure nothrow unittest
1007 static import core
.math
;
1008 static import std
.math
;
1009 assert(cos(complex(0.0)) == 1.0);
1010 assert(cos(complex(1.3, 0.0)) == core
.math
.cos(1.3));
1011 assert(cos(complex(0.0, 5.2)) == std
.math
.cosh(5.2));
1014 @safe pure nothrow unittest
1016 static import core
.math
;
1017 static import std
.math
;
1018 assert(ceqrel(cos(complex(0, 5.2L)), complex(std
.math
.cosh(5.2L), 0.0L)) >= real.mant_dig
- 1);
1019 assert(ceqrel(cos(complex(1.3L)), complex(core
.math
.cos(1.3L))) >= real.mant_dig
- 1);
1023 Complex
!T
tan(T
)(Complex
!T z
) @safe pure nothrow @nogc
1025 return sin(z
) / cos(z
);
1029 @safe pure nothrow @nogc unittest
1031 static import std
.math
;
1033 int ceqrel(T
)(const Complex
!T x
, const Complex
!T y
) @safe pure nothrow @nogc
1035 import std
.math
.operations
: feqrel
;
1036 const r
= feqrel(x
.re
, y
.re
);
1037 const i
= feqrel(x
.im
, y
.im
);
1038 return r
< i ? r
: i
;
1040 assert(ceqrel(tan(complex(1.0, 0.0)), complex(std
.math
.tan(1.0), 0.0)) >= double.mant_dig
- 2);
1041 assert(ceqrel(tan(complex(0.0, 1.0)), complex(0.0, std
.math
.tanh(1.0))) >= double.mant_dig
- 2);
1045 Inverse trigonometric functions on complex numbers.
1047 Params: z = A complex number.
1048 Returns: The arcsine, arccosine and arctangent of `z`, respectively.
1050 Complex
!T
asin(T
)(Complex
!T z
) @safe pure nothrow @nogc
1052 auto ash
= asinh(Complex
!T(-z
.im
, z
.re
));
1053 return Complex
!T(ash
.im
, -ash
.re
);
1057 @safe pure nothrow unittest
1059 import std
.math
.operations
: isClose
;
1060 import std
.math
.constants
: PI
;
1061 assert(asin(complex(0.0)) == 0.0);
1062 assert(isClose(asin(complex(0.5L)), PI
/ 6));
1065 @safe pure nothrow unittest
1067 import std
.math
.operations
: isClose
;
1068 import std
.math
.constants
: PI
;
1069 version (DigitalMars
) {} else // Disabled because of https://issues.dlang.org/show_bug.cgi?id=21376
1070 assert(isClose(asin(complex(0.5f)), float(PI
) / 6));
1074 Complex
!T
acos(T
)(Complex
!T z
) @safe pure nothrow @nogc
1076 static import std
.math
;
1078 return Complex
!T(T(std
.math
.PI_2
) - as
.re
, as
.im
);
1082 @safe pure nothrow unittest
1084 import std
.math
.operations
: isClose
;
1085 import std
.math
.constants
: PI
;
1086 import std
.math
.trigonometry
: std_math_acos
= acos
;
1087 assert(acos(complex(0.0)) == std_math_acos(0.0));
1088 assert(isClose(acos(complex(0.5L)), PI
/ 3));
1091 @safe pure nothrow unittest
1093 import std
.math
.operations
: isClose
;
1094 import std
.math
.constants
: PI
;
1095 version (DigitalMars
) {} else // Disabled because of https://issues.dlang.org/show_bug.cgi?id=21376
1096 assert(isClose(acos(complex(0.5f)), float(PI
) / 3));
1100 Complex
!T
atan(T
)(Complex
!T z
) @safe pure nothrow @nogc
1102 static import std
.math
;
1103 const T re2
= z
.re
* z
.re
;
1104 const T x
= 1 - re2
- z
.im
* z
.im
;
1109 num
= re2
+ num
* num
;
1110 den
= re2
+ den
* den
;
1112 return Complex
!T(T(0.5) * std
.math
.atan2(2 * z
.re
, x
),
1113 T(0.25) * std
.math
.log(num
/ den
));
1117 @safe pure nothrow @nogc unittest
1119 import std
.math
.operations
: isClose
;
1120 import std
.math
.constants
: PI
;
1121 assert(atan(complex(0.0)) == 0.0);
1122 assert(isClose(atan(sqrt(complex(3.0L))), PI
/ 3));
1123 assert(isClose(atan(sqrt(complex(3.0f))), float(PI
) / 3));
1127 Hyperbolic trigonometric functions on complex numbers.
1129 Params: z = A complex number.
1130 Returns: The hyperbolic sine, cosine and tangent of `z`, respectively.
1132 Complex
!T
sinh(T
)(Complex
!T z
) @safe pure nothrow @nogc
1134 static import core
.math
, std
.math
;
1135 return Complex
!T(std
.math
.sinh(z
.re
) * core
.math
.cos(z
.im
),
1136 std
.math
.cosh(z
.re
) * core
.math
.sin(z
.im
));
1140 @safe pure nothrow unittest
1142 static import std
.math
;
1143 assert(sinh(complex(0.0)) == 0.0);
1144 assert(sinh(complex(1.0L)) == std
.math
.sinh(1.0L));
1145 assert(sinh(complex(1.0f)) == std
.math
.sinh(1.0f));
1149 Complex
!T
cosh(T
)(Complex
!T z
) @safe pure nothrow @nogc
1151 static import core
.math
, std
.math
;
1152 return Complex
!T(std
.math
.cosh(z
.re
) * core
.math
.cos(z
.im
),
1153 std
.math
.sinh(z
.re
) * core
.math
.sin(z
.im
));
1157 @safe pure nothrow unittest
1159 static import std
.math
;
1160 assert(cosh(complex(0.0)) == 1.0);
1161 assert(cosh(complex(1.0L)) == std
.math
.cosh(1.0L));
1162 assert(cosh(complex(1.0f)) == std
.math
.cosh(1.0f));
1166 Complex
!T
tanh(T
)(Complex
!T z
) @safe pure nothrow @nogc
1168 return sinh(z
) / cosh(z
);
1172 @safe pure nothrow @nogc unittest
1174 import std
.math
.operations
: isClose
;
1175 import std
.math
.trigonometry
: std_math_tanh
= tanh
;
1176 assert(tanh(complex(0.0)) == 0.0);
1177 assert(isClose(tanh(complex(1.0L)), std_math_tanh(1.0L)));
1178 assert(isClose(tanh(complex(1.0f)), std_math_tanh(1.0f)));
1182 Inverse hyperbolic trigonometric functions on complex numbers.
1184 Params: z = A complex number.
1185 Returns: The hyperbolic arcsine, arccosine and arctangent of `z`, respectively.
1187 Complex
!T
asinh(T
)(Complex
!T z
) @safe pure nothrow @nogc
1189 auto t
= Complex
!T((z
.re
- z
.im
) * (z
.re
+ z
.im
) + 1, 2 * z
.re
* z
.im
);
1190 return log(sqrt(t
) + z
);
1194 @safe pure nothrow unittest
1196 import std
.math
.operations
: isClose
;
1197 import std
.math
.trigonometry
: std_math_asinh
= asinh
;
1198 assert(asinh(complex(0.0)) == 0.0);
1199 assert(isClose(asinh(complex(1.0L)), std_math_asinh(1.0L)));
1200 assert(isClose(asinh(complex(1.0f)), std_math_asinh(1.0f)));
1204 Complex
!T
acosh(T
)(Complex
!T z
) @safe pure nothrow @nogc
1206 return 2 * log(sqrt(T(0.5) * (z
+ 1)) + sqrt(T(0.5) * (z
- 1)));
1210 @safe pure nothrow unittest
1212 import std
.math
.operations
: isClose
;
1213 import std
.math
.trigonometry
: std_math_acosh
= acosh
;
1214 assert(acosh(complex(1.0)) == 0.0);
1215 assert(isClose(acosh(complex(3.0L)), std_math_acosh(3.0L)));
1216 assert(isClose(acosh(complex(3.0f)), std_math_acosh(3.0f)));
1220 Complex
!T
atanh(T
)(Complex
!T z
) @safe pure nothrow @nogc
1222 static import std
.math
;
1223 const T im2
= z
.im
* z
.im
;
1224 const T x
= 1 - im2
- z
.re
* z
.re
;
1229 num
= im2
+ num
* num
;
1230 den
= im2
+ den
* den
;
1232 return Complex
!T(T(0.25) * (std
.math
.log(num
) - std
.math
.log(den
)),
1233 T(0.5) * std
.math
.atan2(2 * z
.im
, x
));
1237 @safe pure nothrow @nogc unittest
1239 import std
.math
.operations
: isClose
;
1240 import std
.math
.trigonometry
: std_math_atanh
= atanh
;
1241 assert(atanh(complex(0.0)) == 0.0);
1242 assert(isClose(atanh(complex(0.5L)), std_math_atanh(0.5L)));
1243 assert(isClose(atanh(complex(0.5f)), std_math_atanh(0.5f)));
1247 Params: y = A real number.
1248 Returns: The value of cos(y) + i sin(y).
1251 `expi` is included here for convenience and for easy migration of code.
1253 Complex
!real expi(real y
) @trusted pure nothrow @nogc
1255 import core
.math
: cos
, sin
;
1256 return Complex
!real(cos(y
), sin(y
));
1260 @safe pure nothrow unittest
1262 import core
.math
: cos
, sin
;
1263 assert(expi(0.0L) == 1.0L);
1264 assert(expi(1.3e5L
) == complex(cos(1.3e5L
), sin(1.3e5L
)));
1268 Params: y = A real number.
1269 Returns: The value of cosh(y) + i sinh(y)
1272 `coshisinh` is included here for convenience and for easy migration of code.
1274 Complex
!real coshisinh(real y
) @safe pure nothrow @nogc
1276 static import core
.math
;
1277 static import std
.math
;
1278 if (core
.math
.fabs(y
) <= 0.5)
1279 return Complex
!real(std
.math
.cosh(y
), std
.math
.sinh(y
));
1282 auto z
= std
.math
.exp(y
);
1285 return Complex
!real(z
+ zi
, z
- zi
);
1290 @safe pure nothrow @nogc unittest
1292 import std
.math
.trigonometry
: cosh
, sinh
;
1293 assert(coshisinh(3.0L) == complex(cosh(3.0L), sinh(3.0L)));
1297 Params: z = A complex number.
1298 Returns: The square root of `z`.
1300 Complex
!T
sqrt(T
)(Complex
!T z
) @safe pure nothrow @nogc
1302 static import core
.math
;
1308 c
= typeof(return)(0, 0);
1315 x
= core
.math
.fabs(z_re
);
1316 y
= core
.math
.fabs(z_im
);
1320 w
= core
.math
.sqrt(x
)
1321 * core
.math
.sqrt(0.5 * (1 + core
.math
.sqrt(1 + r
* r
)));
1326 w
= core
.math
.sqrt(y
)
1327 * core
.math
.sqrt(0.5 * (r
+ core
.math
.sqrt(1 + r
* r
)));
1332 c
= typeof(return)(w
, z_im
/ (w
+ w
));
1338 c
= typeof(return)(z_im
/ (w
+ w
), w
);
1345 @safe pure nothrow unittest
1347 static import core
.math
;
1348 assert(sqrt(complex(0.0)) == 0.0);
1349 assert(sqrt(complex(1.0L, 0)) == core
.math
.sqrt(1.0L));
1350 assert(sqrt(complex(-1.0L, 0)) == complex(0, 1.0L));
1351 assert(sqrt(complex(-8.0, -6.0)) == complex(1.0, -3.0));
1354 @safe pure nothrow unittest
1356 import std
.math
.operations
: isClose
;
1358 auto c1
= complex(1.0, 1.0);
1359 auto c2
= Complex
!double(0.5, 2.0);
1361 auto c1s
= sqrt(c1
);
1362 assert(isClose(c1s
.re
, 1.09868411347));
1363 assert(isClose(c1s
.im
, 0.455089860562));
1365 auto c2s
= sqrt(c2
);
1366 assert(isClose(c2s
.re
, 1.13171392428));
1367 assert(isClose(c2s
.im
, 0.883615530876));
1370 // support %f formatting of complex numbers
1371 // https://issues.dlang.org/show_bug.cgi?id=10881
1374 import std
.format
: format
;
1376 auto x
= complex(1.2, 3.4);
1377 assert(format("%.2f", x
) == "1.20+3.40i");
1379 auto y
= complex(1.2, -3.4);
1380 assert(format("%.2f", y
) == "1.20-3.40i");
1385 // Test wide string formatting
1386 import std
.format
.write
: formattedWrite
;
1387 wstring
wformat(T
)(string format
, Complex
!T c
)
1389 import std
.array
: appender
;
1390 auto w
= appender
!wstring();
1391 auto n
= formattedWrite(w
, format
, c
);
1395 auto x
= complex(1.2, 3.4);
1396 assert(wformat("%.2f", x
) == "1.20+3.40i"w
);
1401 // Test ease of use (vanilla toString() should be supported)
1402 assert(complex(1.2, 3.4).toString() == "1.2+3.4i");
1405 @safe pure nothrow @nogc unittest
1407 auto c
= complex(3.0L, 4.0L);
1409 assert(c
.re
== 2.0L);
1410 assert(c
.im
== 1.0L);
1414 * Calculates e$(SUPERSCRIPT x).
1416 * x = A complex number
1418 * The complex base e exponential of `x`
1421 * $(TR $(TH x) $(TH exp(x)))
1422 * $(TR $(TD ($(PLUSMN)0, +0)) $(TD (1, +0)))
1423 * $(TR $(TD (any, +$(INFIN))) $(TD ($(NAN), $(NAN))))
1424 * $(TR $(TD (any, $(NAN)) $(TD ($(NAN), $(NAN)))))
1425 * $(TR $(TD (+$(INFIN), +0)) $(TD (+$(INFIN), +0)))
1426 * $(TR $(TD (-$(INFIN), any)) $(TD ($(PLUSMN)0, cis(x.im))))
1427 * $(TR $(TD (+$(INFIN), any)) $(TD ($(PLUSMN)$(INFIN), cis(x.im))))
1428 * $(TR $(TD (-$(INFIN), +$(INFIN))) $(TD ($(PLUSMN)0, $(PLUSMN)0)))
1429 * $(TR $(TD (+$(INFIN), +$(INFIN))) $(TD ($(PLUSMN)$(INFIN), $(NAN))))
1430 * $(TR $(TD (-$(INFIN), $(NAN))) $(TD ($(PLUSMN)0, $(PLUSMN)0)))
1431 * $(TR $(TD (+$(INFIN), $(NAN))) $(TD ($(PLUSMN)$(INFIN), $(NAN))))
1432 * $(TR $(TD ($(NAN), +0)) $(TD ($(NAN), +0)))
1433 * $(TR $(TD ($(NAN), any)) $(TD ($(NAN), $(NAN))))
1434 * $(TR $(TD ($(NAN), $(NAN))) $(TD ($(NAN), $(NAN))))
1437 Complex
!T
exp(T
)(Complex
!T x
) @trusted pure nothrow @nogc // TODO: @safe
1439 static import std
.math
;
1441 // Handle special cases explicitly here, as fromPolar will otherwise
1442 // cause them to return Complex!T(NaN, NaN), or with the wrong sign.
1443 if (std
.math
.isInfinity(x
.re
))
1445 if (std
.math
.isNaN(x
.im
))
1447 if (std
.math
.signbit(x
.re
))
1448 return Complex
!T(0, std
.math
.copysign(0, x
.im
));
1452 if (std
.math
.isInfinity(x
.im
))
1454 if (std
.math
.signbit(x
.re
))
1455 return Complex
!T(0, std
.math
.copysign(0, x
.im
));
1457 return Complex
!T(T
.infinity
, -T
.nan
);
1461 if (std
.math
.signbit(x
.re
))
1462 return Complex
!T(0.0);
1464 return Complex
!T(T
.infinity
);
1467 if (std
.math
.isNaN(x
.re
))
1469 if (std
.math
.isNaN(x
.im
) || std
.math
.isInfinity(x
.im
))
1470 return Complex
!T(T
.nan
, T
.nan
);
1476 if (std
.math
.isNaN(x
.im
) || std
.math
.isInfinity(x
.im
))
1477 return Complex
!T(T
.nan
, T
.nan
);
1479 return Complex
!T(1.0, 0.0);
1482 return fromPolar
!(T
, T
)(std
.math
.exp(x
.re
), x
.im
);
1486 @safe pure nothrow @nogc unittest
1488 import std
.math
.operations
: isClose
;
1489 import std
.math
.constants
: PI
;
1491 assert(exp(complex(0.0, 0.0)) == complex(1.0, 0.0));
1493 auto a
= complex(2.0, 1.0);
1494 assert(exp(conj(a
)) == conj(exp(a
)));
1496 auto b
= exp(complex(0.0L, 1.0L) * PI
);
1497 assert(isClose(b
, -1.0L, 0.0, 1e-15));
1500 @safe pure nothrow @nogc unittest
1502 import std
.math
.traits
: isNaN
, isInfinity
;
1504 auto a
= exp(complex(0.0, double.infinity
));
1505 assert(a
.re
.isNaN
&& a
.im
.isNaN
);
1506 auto b
= exp(complex(0.0, double.infinity
));
1507 assert(b
.re
.isNaN
&& b
.im
.isNaN
);
1508 auto c
= exp(complex(0.0, double.nan
));
1509 assert(c
.re
.isNaN
&& c
.im
.isNaN
);
1511 auto d
= exp(complex(+double.infinity
, 0.0));
1512 assert(d
== complex(double.infinity
, 0.0));
1513 auto e
= exp(complex(-double.infinity
, 0.0));
1514 assert(e
== complex(0.0));
1515 auto f
= exp(complex(-double.infinity
, 1.0));
1516 assert(f
== complex(0.0));
1517 auto g
= exp(complex(+double.infinity
, 1.0));
1518 assert(g
== complex(double.infinity
, double.infinity
));
1519 auto h
= exp(complex(-double.infinity
, +double.infinity
));
1520 assert(h
== complex(0.0));
1521 auto i
= exp(complex(+double.infinity
, +double.infinity
));
1522 assert(i
.re
.isInfinity
&& i
.im
.isNaN
);
1523 auto j
= exp(complex(-double.infinity
, double.nan
));
1524 assert(j
== complex(0.0));
1525 auto k
= exp(complex(+double.infinity
, double.nan
));
1526 assert(k
.re
.isInfinity
&& k
.im
.isNaN
);
1528 auto l
= exp(complex(double.nan
, 0));
1529 assert(l
.re
.isNaN
&& l
.im
== 0.0);
1530 auto m
= exp(complex(double.nan
, 1));
1531 assert(m
.re
.isNaN
&& m
.im
.isNaN
);
1532 auto n
= exp(complex(double.nan
, double.nan
));
1533 assert(n
.re
.isNaN
&& n
.im
.isNaN
);
1536 @safe pure nothrow @nogc unittest
1538 import std
.math
.constants
: PI
;
1539 import std
.math
.operations
: isClose
;
1541 auto a
= exp(complex(0.0, -PI
));
1542 assert(isClose(a
, -1.0, 0.0, 1e-15));
1544 auto b
= exp(complex(0.0, -2.0 * PI
/ 3.0));
1545 assert(isClose(b
, complex(-0.5L, -0.866025403784438646763L)));
1547 auto c
= exp(complex(0.0, PI
/ 3.0));
1548 assert(isClose(c
, complex(0.5L, 0.866025403784438646763L)));
1550 auto d
= exp(complex(0.0, 2.0 * PI
/ 3.0));
1551 assert(isClose(d
, complex(-0.5L, 0.866025403784438646763L)));
1553 auto e
= exp(complex(0.0, PI
));
1554 assert(isClose(e
, -1.0, 0.0, 1e-15));
1558 * Calculate the natural logarithm of x.
1559 * The branch cut is along the negative axis.
1561 * x = A complex number
1563 * The complex natural logarithm of `x`
1566 * $(TR $(TH x) $(TH log(x)))
1567 * $(TR $(TD (-0, +0)) $(TD (-$(INFIN), $(PI))))
1568 * $(TR $(TD (+0, +0)) $(TD (-$(INFIN), +0)))
1569 * $(TR $(TD (any, +$(INFIN))) $(TD (+$(INFIN), $(PI)/2)))
1570 * $(TR $(TD (any, $(NAN))) $(TD ($(NAN), $(NAN))))
1571 * $(TR $(TD (-$(INFIN), any)) $(TD (+$(INFIN), $(PI))))
1572 * $(TR $(TD (+$(INFIN), any)) $(TD (+$(INFIN), +0)))
1573 * $(TR $(TD (-$(INFIN), +$(INFIN))) $(TD (+$(INFIN), 3$(PI)/4)))
1574 * $(TR $(TD (+$(INFIN), +$(INFIN))) $(TD (+$(INFIN), $(PI)/4)))
1575 * $(TR $(TD ($(PLUSMN)$(INFIN), $(NAN))) $(TD (+$(INFIN), $(NAN))))
1576 * $(TR $(TD ($(NAN), any)) $(TD ($(NAN), $(NAN))))
1577 * $(TR $(TD ($(NAN), +$(INFIN))) $(TD (+$(INFIN), $(NAN))))
1578 * $(TR $(TD ($(NAN), $(NAN))) $(TD ($(NAN), $(NAN))))
1581 Complex
!T
log(T
)(Complex
!T x
) @safe pure nothrow @nogc
1583 static import std
.math
;
1585 // Handle special cases explicitly here for better accuracy.
1586 // The order here is important, so that the correct path is chosen.
1587 if (std
.math
.isNaN(x
.re
))
1589 if (std
.math
.isInfinity(x
.im
))
1590 return Complex
!T(T
.infinity
, T
.nan
);
1592 return Complex
!T(T
.nan
, T
.nan
);
1594 if (std
.math
.isInfinity(x
.re
))
1596 if (std
.math
.isNaN(x
.im
))
1597 return Complex
!T(T
.infinity
, T
.nan
);
1598 else if (std
.math
.isInfinity(x
.im
))
1600 if (std
.math
.signbit(x
.re
))
1601 return Complex
!T(T
.infinity
, std
.math
.copysign(3.0 * std
.math
.PI_4
, x
.im
));
1603 return Complex
!T(T
.infinity
, std
.math
.copysign(std
.math
.PI_4
, x
.im
));
1607 if (std
.math
.signbit(x
.re
))
1608 return Complex
!T(T
.infinity
, std
.math
.copysign(std
.math
.PI
, x
.im
));
1610 return Complex
!T(T
.infinity
, std
.math
.copysign(0.0, x
.im
));
1613 if (std
.math
.isNaN(x
.im
))
1614 return Complex
!T(T
.nan
, T
.nan
);
1615 if (std
.math
.isInfinity(x
.im
))
1616 return Complex
!T(T
.infinity
, std
.math
.copysign(std
.math
.PI_2
, x
.im
));
1617 if (x
.re
== 0.0 && x
.im
== 0.0)
1619 if (std
.math
.signbit(x
.re
))
1620 return Complex
!T(-T
.infinity
, std
.math
.copysign(std
.math
.PI
, x
.im
));
1622 return Complex
!T(-T
.infinity
, std
.math
.copysign(0.0, x
.im
));
1625 return Complex
!T(std
.math
.log(abs(x
)), arg(x
));
1629 @safe pure nothrow @nogc unittest
1631 import core
.math
: sqrt
;
1632 import std
.math
.constants
: PI
;
1633 import std
.math
.operations
: isClose
;
1635 auto a
= complex(2.0, 1.0);
1636 assert(log(conj(a
)) == conj(log(a
)));
1638 auto b
= 2.0 * log10(complex(0.0, 1.0));
1639 auto c
= 4.0 * log10(complex(sqrt(2.0) / 2, sqrt(2.0) / 2));
1640 assert(isClose(b
, c
, 0.0, 1e-15));
1642 assert(log(complex(-1.0L, 0.0L)) == complex(0.0L, PI
));
1643 assert(log(complex(-1.0L, -0.0L)) == complex(0.0L, -PI
));
1646 @safe pure nothrow @nogc unittest
1648 import std
.math
.traits
: isNaN
, isInfinity
;
1649 import std
.math
.constants
: PI
, PI_2
, PI_4
;
1651 auto a
= log(complex(-0.0L, 0.0L));
1652 assert(a
== complex(-real.infinity
, PI
));
1653 auto b
= log(complex(0.0L, 0.0L));
1654 assert(b
== complex(-real.infinity
, +0.0L));
1655 auto c
= log(complex(1.0L, real.infinity
));
1656 assert(c
== complex(real.infinity
, PI_2
));
1657 auto d
= log(complex(1.0L, real.nan
));
1658 assert(d
.re
.isNaN
&& d
.im
.isNaN
);
1660 auto e
= log(complex(-real.infinity
, 1.0L));
1661 assert(e
== complex(real.infinity
, PI
));
1662 auto f
= log(complex(real.infinity
, 1.0L));
1663 assert(f
== complex(real.infinity
, 0.0L));
1664 auto g
= log(complex(-real.infinity
, real.infinity
));
1665 assert(g
== complex(real.infinity
, 3.0 * PI_4
));
1666 auto h
= log(complex(real.infinity
, real.infinity
));
1667 assert(h
== complex(real.infinity
, PI_4
));
1668 auto i
= log(complex(real.infinity
, real.nan
));
1669 assert(i
.re
.isInfinity
&& i
.im
.isNaN
);
1671 auto j
= log(complex(real.nan
, 1.0L));
1672 assert(j
.re
.isNaN
&& j
.im
.isNaN
);
1673 auto k
= log(complex(real.nan
, real.infinity
));
1674 assert(k
.re
.isInfinity
&& k
.im
.isNaN
);
1675 auto l
= log(complex(real.nan
, real.nan
));
1676 assert(l
.re
.isNaN
&& l
.im
.isNaN
);
1679 @safe pure nothrow @nogc unittest
1681 import std
.math
.constants
: PI
;
1682 import std
.math
.operations
: isClose
;
1684 auto a
= log(fromPolar(1.0, PI
/ 6.0));
1685 assert(isClose(a
, complex(0.0L, 0.523598775598298873077L), 0.0, 1e-15));
1687 auto b
= log(fromPolar(1.0, PI
/ 3.0));
1688 assert(isClose(b
, complex(0.0L, 1.04719755119659774615L), 0.0, 1e-15));
1690 auto c
= log(fromPolar(1.0, PI
/ 2.0));
1691 assert(isClose(c
, complex(0.0L, 1.57079632679489661923L), 0.0, 1e-15));
1693 auto d
= log(fromPolar(1.0, 2.0 * PI
/ 3.0));
1694 assert(isClose(d
, complex(0.0L, 2.09439510239319549230L), 0.0, 1e-15));
1696 auto e
= log(fromPolar(1.0, 5.0 * PI
/ 6.0));
1697 assert(isClose(e
, complex(0.0L, 2.61799387799149436538L), 0.0, 1e-15));
1699 auto f
= log(complex(-1.0L, 0.0L));
1700 assert(isClose(f
, complex(0.0L, PI
), 0.0, 1e-15));
1704 * Calculate the base-10 logarithm of x.
1706 * x = A complex number
1708 * The complex base 10 logarithm of `x`
1710 Complex
!T
log10(T
)(Complex
!T x
) @safe pure nothrow @nogc
1712 import std
.math
.constants
: LN10
;
1714 return log(x
) / Complex
!T(LN10
);
1718 @safe pure nothrow @nogc unittest
1720 import core
.math
: sqrt
;
1721 import std
.math
.constants
: LN10
, PI
;
1722 import std
.math
.operations
: isClose
;
1724 auto a
= complex(2.0, 1.0);
1725 assert(log10(a
) == log(a
) / log(complex(10.0)));
1727 auto b
= log10(complex(0.0, 1.0)) * 2.0;
1728 auto c
= log10(complex(sqrt(2.0) / 2, sqrt(2.0) / 2)) * 4.0;
1729 assert(isClose(b
, c
, 0.0, 1e-15));
1732 @safe pure nothrow @nogc unittest
1734 import std
.math
.constants
: LN10
, PI
;
1735 import std
.math
.operations
: isClose
;
1737 auto a
= log10(fromPolar(1.0, PI
/ 6.0));
1738 assert(isClose(a
, complex(0.0L, 0.227396058973640224580L), 0.0, 1e-15));
1740 auto b
= log10(fromPolar(1.0, PI
/ 3.0));
1741 assert(isClose(b
, complex(0.0L, 0.454792117947280449161L), 0.0, 1e-15));
1743 auto c
= log10(fromPolar(1.0, PI
/ 2.0));
1744 assert(isClose(c
, complex(0.0L, 0.682188176920920673742L), 0.0, 1e-15));
1746 auto d
= log10(fromPolar(1.0, 2.0 * PI
/ 3.0));
1747 assert(isClose(d
, complex(0.0L, 0.909584235894560898323L), 0.0, 1e-15));
1749 auto e
= log10(fromPolar(1.0, 5.0 * PI
/ 6.0));
1750 assert(isClose(e
, complex(0.0L, 1.13698029486820112290L), 0.0, 1e-15));
1752 auto f
= log10(complex(-1.0L, 0.0L));
1753 assert(isClose(f
, complex(0.0L, 1.36437635384184134748L), 0.0, 1e-15));
1755 assert(ceqrel(log10(complex(-100.0L, 0.0L)), complex(2.0L, PI
/ LN10
)) >= real.mant_dig
- 1);
1756 assert(ceqrel(log10(complex(-100.0L, -0.0L)), complex(2.0L, -PI
/ LN10
)) >= real.mant_dig
- 1);
1760 * Calculates x$(SUPERSCRIPT n).
1761 * The branch cut is on the negative axis.
1766 * `x` raised to the power of `n`
1768 Complex
!T
pow(T
, Int
)(Complex
!T x
, const Int n
) @safe pure nothrow @nogc
1771 alias UInt
= Unsigned
!(Unqual
!Int
);
1773 UInt m
= (n
< 0) ?
-cast(UInt
) n
: n
;
1774 Complex
!T y
= (m
% 2) ? x
: Complex
!T(1);
1783 return (n
< 0) ? Complex
!T(1) / y
: y
;
1787 @safe pure nothrow @nogc unittest
1789 import std
.math
.operations
: isClose
;
1791 auto a
= complex(1.0, 2.0);
1792 assert(pow(a
, 2) == a
* a
);
1793 assert(pow(a
, 3) == a
* a
* a
);
1794 assert(pow(a
, -2) == 1.0 / (a
* a
));
1795 assert(isClose(pow(a
, -3), 1.0 / (a
* a
* a
)));
1799 Complex
!T
pow(T
)(Complex
!T x
, const T n
) @trusted pure nothrow @nogc
1801 static import std
.math
;
1804 return Complex
!T(0.0);
1806 if (x
.im
== 0 && x
.re
> 0.0)
1807 return Complex
!T(std
.math
.pow(x
.re
, n
));
1809 Complex
!T t
= log(x
);
1810 return fromPolar
!(T
, T
)(std
.math
.exp(n
* t
.re
), n
* t
.im
);
1814 @safe pure nothrow @nogc unittest
1816 import std
.math
.operations
: isClose
;
1817 assert(pow(complex(0.0), 2.0) == complex(0.0));
1818 assert(pow(complex(5.0), 2.0) == complex(25.0));
1820 auto a
= pow(complex(-1.0, 0.0), 0.5);
1821 assert(isClose(a
, complex(0.0, +1.0), 0.0, 1e-16));
1823 auto b
= pow(complex(-1.0, -0.0), 0.5);
1824 assert(isClose(b
, complex(0.0, -1.0), 0.0, 1e-16));
1828 Complex
!T
pow(T
)(Complex
!T x
, Complex
!T y
) @trusted pure nothrow @nogc
1830 return (x
== 0) ? Complex
!T(0) : exp(y
* log(x
));
1834 @safe pure nothrow @nogc unittest
1836 import std
.math
.operations
: isClose
;
1837 import std
.math
.exponential
: exp
;
1838 import std
.math
.constants
: PI
;
1839 auto a
= complex(0.0);
1840 auto b
= complex(2.0);
1841 assert(pow(a
, b
) == complex(0.0));
1843 auto c
= complex(0.0L, 1.0L);
1844 assert(isClose(pow(c
, c
), exp((-PI
) / 2)));
1848 Complex
!T
pow(T
)(const T x
, Complex
!T n
) @trusted pure nothrow @nogc
1850 static import std
.math
;
1853 ? fromPolar
!(T
, T
)(std
.math
.pow(x
, n
.re
), n
.im
* std
.math
.log(x
))
1854 : pow(Complex
!T(x
), n
);
1858 @safe pure nothrow @nogc unittest
1860 import std
.math
.operations
: isClose
;
1861 assert(pow(2.0, complex(0.0)) == complex(1.0));
1862 assert(pow(2.0, complex(5.0)) == complex(32.0));
1864 auto a
= pow(-2.0, complex(-1.0));
1865 assert(isClose(a
, complex(-0.5), 0.0, 1e-16));
1867 auto b
= pow(-0.5, complex(-1.0));
1868 assert(isClose(b
, complex(-2.0), 0.0, 1e-15));
1871 @safe pure nothrow @nogc unittest
1873 import std
.math
.constants
: PI
;
1874 import std
.math
.operations
: isClose
;
1876 auto a
= pow(complex(3.0, 4.0), 2);
1877 assert(isClose(a
, complex(-7.0, 24.0)));
1879 auto b
= pow(complex(3.0, 4.0), PI
);
1880 assert(ceqrel(b
, complex(-152.91512205297134, 35.547499631917738)) >= double.mant_dig
- 3);
1882 auto c
= pow(complex(3.0, 4.0), complex(-2.0, 1.0));
1883 assert(ceqrel(c
, complex(0.015351734187477306, -0.0038407695456661503)) >= double.mant_dig
- 3);
1885 auto d
= pow(PI
, complex(2.0, -1.0));
1886 assert(ceqrel(d
, complex(4.0790296880118296, -8.9872469554541869)) >= double.mant_dig
- 1);
1888 auto e
= complex(2.0);
1889 assert(ceqrel(pow(e
, 3), exp(3 * log(e
))) >= double.mant_dig
- 1);
1892 @safe pure nothrow @nogc unittest
1894 import std
.meta
: AliasSeq
;
1895 import std
.math
.traits
: floatTraits
, RealFormat
;
1896 static foreach (T
; AliasSeq
!(float, double, real))
1898 static if (floatTraits
!T
.realFormat
== RealFormat
.ibmExtended
)
1900 /* For IBM real, epsilon is too small (since 1.0 plus any double is
1901 representable) to be able to expect results within epsilon * 100. */
1905 T eps
= T
.epsilon
* 100;
1909 Complex
!T ref1
= pow(complex(a
), complex(b
));
1910 Complex
!T res1
= pow(a
, complex(b
));
1911 Complex
!T res2
= pow(complex(a
), b
);
1912 assert(abs(ref1
- res1
) < eps
);
1913 assert(abs(ref1
- res2
) < eps
);
1914 assert(abs(res1
- res2
) < eps
);
1918 Complex
!T ref2
= pow(complex(a
), complex(b
));
1919 Complex
!T res3
= pow(a
, complex(b
));
1920 Complex
!T res4
= pow(complex(a
), b
);
1921 assert(abs(ref2
- res3
) < eps
);
1922 assert(abs(ref2
- res4
) < eps
);
1923 assert(abs(res3
- res4
) < eps
);
1928 @safe pure nothrow @nogc unittest
1930 import std
.meta
: AliasSeq
;
1931 static foreach (T
; AliasSeq
!(float, double, real))
1933 auto c
= Complex
!T(123, 456);
1934 auto n
= c
.toNative();
1935 assert(c
.re
== n
.re
&& c
.im
== n
.im
);