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 $(D cfloat), $(D cdouble), $(D creal), $(D ifloat),
9 $(D idouble), and $(D ireal).
11 Authors: Lars Tandle Kyllingstad, Don Clugston
12 Copyright: Copyright (c) 2010, Lars T. Kyllingstad.
13 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0)
14 Source: $(PHOBOSSRC std/_complex.d)
20 /** Helper function that returns a _complex number with the specified
21 real and imaginary parts.
24 R = (template parameter) type of real part of complex number
25 I = (template parameter) type of imaginary part of complex number
27 re = real part of complex number to be constructed
28 im = (optional) imaginary part of complex number, 0 if omitted.
31 $(D Complex) instance with real and imaginary parts set
32 to the values provided as input. If neither $(D re) nor
33 $(D im) are floating-point numbers, the return type will
34 be $(D Complex!double). Otherwise, the return type is
35 deduced using $(D std.traits.CommonType!(R, I)).
37 auto complex(R
)(R re
) @safe pure nothrow @nogc
40 static if (isFloatingPoint
!R
)
41 return Complex
!R(re
, 0);
43 return Complex
!double(re
, 0);
47 auto complex(R
, I
)(R re
, I im
) @safe pure nothrow @nogc
48 if (is(R
: double) && is(I
: double))
50 static if (isFloatingPoint
!R || isFloatingPoint
!I
)
51 return Complex
!(CommonType
!(R
, I
))(re
, im
);
53 return Complex
!double(re
, im
);
57 @safe pure nothrow unittest
59 auto a
= complex(1.0);
60 static assert(is(typeof(a
) == Complex
!double));
64 auto b
= complex(2.0L);
65 static assert(is(typeof(b
) == Complex
!real));
69 auto c
= complex(1.0, 2.0);
70 static assert(is(typeof(c
) == Complex
!double));
74 auto d
= complex(3.0, 4.0L);
75 static assert(is(typeof(d
) == Complex
!real));
80 static assert(is(typeof(e
) == Complex
!double));
84 auto f
= complex(1L, 2);
85 static assert(is(typeof(f
) == Complex
!double));
89 auto g
= complex(3, 4.0L);
90 static assert(is(typeof(g
) == Complex
!real));
96 /** A complex number parametrised by a type $(D T), which must be either
97 $(D float), $(D double) or $(D real).
100 if (isFloatingPoint
!T
)
102 import std
.format
: FormatSpec
;
103 import std
.range
.primitives
: isOutputRange
;
105 /** The real part of the number. */
108 /** The imaginary part of the number. */
111 /** Converts the complex number to a string representation.
113 The second form of this function is usually not called directly;
114 instead, it is used via $(REF format, std,string), as shown in the examples
115 below. Supported format characters are 'e', 'f', 'g', 'a', and 's'.
117 See the $(MREF std, format) and $(REF format, std,string)
118 documentation for more information.
120 string
toString() const @safe /* TODO: pure nothrow */
122 import std
.exception
: assumeUnique
;
125 auto fmt
= FormatSpec
!char("%s");
126 toString((const(char)[] s
) { buf
~= s
; }, fmt
);
127 static trustedAssumeUnique(T
)(T t
) @trusted { return assumeUnique(t
); }
128 return trustedAssumeUnique(buf
);
131 static if (is(T
== double))
135 auto c
= complex(1.2, 3.4);
137 // Vanilla toString formatting:
138 assert(c
.toString() == "1.2+3.4i");
140 // Formatting with std.string.format specs: the precision and width
141 // specifiers apply to both the real and imaginary parts of the
143 import std
.format
: format
;
144 assert(format("%.2f", c
) == "1.20+3.40i");
145 assert(format("%4.1f", c
) == " 1.2+ 3.4i");
149 void toString(Writer
, Char
)(scope Writer w
,
150 FormatSpec
!Char formatSpec
) const
151 if (isOutputRange
!(Writer
, const(Char
)[]))
153 import std
.format
: formatValue
;
154 import std
.math
: signbit
;
155 import std
.range
.primitives
: put
;
156 formatValue(w
, re
, formatSpec
);
157 if (signbit(im
) == 0)
159 formatValue(w
, im
, formatSpec
);
163 @safe pure nothrow @nogc:
165 /** Construct a complex number with the specified real and
166 imaginary parts. In the case where a single argument is passed
167 that is not complex, the imaginary part of the result will be
170 this(R
: T
)(Complex
!R z
)
177 this(Rx
: T
, Ry
: T
)(Rx x
, Ry y
)
190 // ASSIGNMENT OPERATORS
193 ref Complex
opAssign(R
: T
)(Complex
!R z
)
201 ref Complex
opAssign(R
: T
)(R r
)
208 // COMPARISON OPERATORS
211 bool opEquals(R
: T
)(Complex
!R z
) const
213 return re
== z
.re
&& im
== z
.im
;
217 bool opEquals(R
: T
)(R r
) const
219 return re
== r
&& im
== 0;
225 Complex
opUnary(string op
)() const
232 Complex
opUnary(string op
)() const
235 return Complex(-re
, -im
);
240 // complex op complex
241 Complex
!(CommonType
!(T
,R
)) opBinary(string op
, R
)(Complex
!R z
) const
243 alias C
= typeof(return);
244 auto w
= C(this.re
, this.im
);
245 return w
.opOpAssign
!(op
)(z
);
248 // complex op numeric
249 Complex
!(CommonType
!(T
,R
)) opBinary(string op
, R
)(R r
) const
252 alias C
= typeof(return);
253 auto w
= C(this.re
, this.im
);
254 return w
.opOpAssign
!(op
)(r
);
257 // numeric + complex, numeric * complex
258 Complex
!(CommonType
!(T
, R
)) opBinaryRight(string op
, R
)(R r
) const
259 if ((op
== "+" || op
== "*") && (isNumeric
!R
))
261 return opBinary
!(op
)(r
);
265 Complex
!(CommonType
!(T
, R
)) opBinaryRight(string op
, R
)(R r
) const
266 if (op
== "-" && isNumeric
!R
)
268 return Complex(r
- re
, -im
);
272 Complex
!(CommonType
!(T
, R
)) opBinaryRight(string op
, R
)(R r
) const
273 if (op
== "/" && isNumeric
!R
)
275 import std
.math
: fabs;
276 typeof(return) w
= void;
277 if (fabs(re
) < fabs(im
))
279 immutable ratio
= re
/im
;
280 immutable rdivd
= r
/(re
*ratio
+ im
);
287 immutable ratio
= im
/re
;
288 immutable rdivd
= r
/(re
+ im
*ratio
);
297 // numeric ^^ complex
298 Complex
!(CommonType
!(T
, R
)) opBinaryRight(string op
, R
)(R lhs
) const
299 if (op
== "^^" && isNumeric
!R
)
301 import std
.math
: cos
, exp
, log
, sin
, PI
;
302 Unqual
!(CommonType
!(T
, R
)) ab
= void, ar
= void;
309 ar
= log(lhs
) * this.im
;
315 ab
= (-lhs
) ^^
this.re
* exp(-PI
* this.im
);
316 ar
= PI
* this.re
+ log(-lhs
) * this.im
;
319 return typeof(return)(ab
* cos(ar
), ab
* sin(ar
));
322 // OP-ASSIGN OPERATORS
324 // complex += complex, complex -= complex
325 ref Complex
opOpAssign(string op
, C
)(C z
)
326 if ((op
== "+" || op
== "-") && is(C R
== Complex
!R
))
328 mixin ("re "~op
~"= z.re;");
329 mixin ("im "~op
~"= z.im;");
333 // complex *= complex
334 ref Complex
opOpAssign(string op
, C
)(C z
)
335 if (op
== "*" && is(C R
== Complex
!R
))
337 auto temp
= re
*z
.re
- im
*z
.im
;
338 im
= im
*z
.re
+ re
*z
.im
;
343 // complex /= complex
344 ref Complex
opOpAssign(string op
, C
)(C z
)
345 if (op
== "/" && is(C R
== Complex
!R
))
347 import std
.math
: fabs;
348 if (fabs(z
.re
) < fabs(z
.im
))
350 immutable ratio
= z
.re
/z
.im
;
351 immutable denom
= z
.re
*ratio
+ z
.im
;
353 immutable temp
= (re
*ratio
+ im
)/denom
;
354 im
= (im
*ratio
- re
)/denom
;
359 immutable ratio
= z
.im
/z
.re
;
360 immutable denom
= z
.re
+ z
.im
*ratio
;
362 immutable temp
= (re
+ im
*ratio
)/denom
;
363 im
= (im
- re
*ratio
)/denom
;
369 // complex ^^= complex
370 ref Complex
opOpAssign(string op
, C
)(C z
)
371 if (op
== "^^" && is(C R
== Complex
!R
))
373 import std
.math
: exp
, log
, cos
, sin
;
374 immutable r
= abs(this);
375 immutable t
= arg(this);
376 immutable ab
= r^^z
.re
* exp(-t
*z
.im
);
377 immutable ar
= t
*z
.re
+ log(r
)*z
.im
;
384 // complex += numeric, complex -= numeric
385 ref Complex
opOpAssign(string op
, U
: T
)(U a
)
386 if (op
== "+" || op
== "-")
388 mixin ("re "~op
~"= a;");
392 // complex *= numeric, complex /= numeric
393 ref Complex
opOpAssign(string op
, U
: T
)(U a
)
394 if (op
== "*" || op
== "/")
396 mixin ("re "~op
~"= a;");
397 mixin ("im "~op
~"= a;");
402 ref Complex
opOpAssign(string op
, R
)(R r
)
403 if (op
== "^^" && isFloatingPoint
!R
)
405 import std
.math
: cos
, sin
;
406 immutable ab
= abs(this)^^r
;
407 immutable ar
= arg(this)*r
;
414 ref Complex
opOpAssign(string op
, U
)(U i
)
415 if (op
== "^^" && isIntegral
!U
)
424 // identity; do nothing
435 this ^^
= cast(real) i
;
441 @safe pure nothrow unittest
446 enum EPS
= double.epsilon
;
447 auto c1
= complex(1.0, 1.0);
449 // Check unary operations.
450 auto c2
= Complex
!double(0.5, 2.0);
454 assert((-c2
).re
== -(c2
.re
));
455 assert((-c2
).im
== -(c2
.im
));
456 assert(c2
== -(-c2
));
458 // Check complex-complex operations.
460 assert(cpc
.re
== c1
.re
+ c2
.re
);
461 assert(cpc
.im
== c1
.im
+ c2
.im
);
464 assert(cmc.re
== c1
.re
- c2
.re
);
465 assert(cmc.im
== c1
.im
- c2
.im
);
468 assert(approxEqual(abs(ctc
), abs(c1
)*abs(c2
), EPS
));
469 assert(approxEqual(arg(ctc
), arg(c1
)+arg(c2
), EPS
));
472 assert(approxEqual(abs(cdc
), abs(c1
)/abs(c2
), EPS
));
473 assert(approxEqual(arg(cdc
), arg(c1
)-arg(c2
), EPS
));
476 assert(approxEqual(cec
.re
, 0.11524131979943839881, EPS
));
477 assert(approxEqual(cec
.im
, 0.21870790452746026696, EPS
));
479 // Check complex-real operations.
483 assert(cpr
.re
== c1
.re
+ a
);
484 assert(cpr
.im
== c1
.im
);
487 assert(cmr
.re
== c1
.re
- a
);
488 assert(cmr
.im
== c1
.im
);
491 assert(ctr
.re
== c1
.re
*a
);
492 assert(ctr
.im
== c1
.im
*a
);
495 assert(approxEqual(abs(cdr
), abs(c1
)/a
, EPS
));
496 assert(approxEqual(arg(cdr
), arg(c1
), EPS
));
499 assert(approxEqual(abs(cer
), abs(c1
)^^
3, EPS
));
500 assert(approxEqual(arg(cer
), arg(c1
)*3, EPS
));
506 assert(rmc
.re
== a
-c1
.re
);
507 assert(rmc
.im
== -c1
.im
);
513 assert(approxEqual(abs(rdc
), a
/abs(c1
), EPS
));
514 assert(approxEqual(arg(rdc
), -arg(c1
), EPS
));
517 assert(approxEqual(abs(rdc
), a
/abs(c2
), EPS
));
518 assert(approxEqual(arg(rdc
), -arg(c2
), EPS
));
520 auto rec1a
= 1.0 ^^ c1
;
521 assert(rec1a
.re
== 1.0);
522 assert(rec1a
.im
== 0.0);
524 auto rec2a
= 1.0 ^^ c2
;
525 assert(rec2a
.re
== 1.0);
526 assert(rec2a
.im
== 0.0);
528 auto rec1b
= (-1.0) ^^ c1
;
529 assert(approxEqual(abs(rec1b
), std
.math
.exp(-PI
* c1
.im
), EPS
));
530 auto arg1b
= arg(rec1b
);
531 /* The argument _should_ be PI, but floating-point rounding error
532 * means that in fact the imaginary part is very slightly negative.
534 assert(approxEqual(arg1b
, PI
, EPS
) ||
approxEqual(arg1b
, -PI
, EPS
));
536 auto rec2b
= (-1.0) ^^ c2
;
537 assert(approxEqual(abs(rec2b
), std
.math
.exp(-2 * PI
), EPS
));
538 assert(approxEqual(arg(rec2b
), PI_2
, EPS
));
540 auto rec3a
= 0.79 ^^
complex(6.8, 5.7);
541 auto rec3b
= complex(0.79, 0.0) ^^
complex(6.8, 5.7);
542 assert(approxEqual(rec3a
.re
, rec3b
.re
, EPS
));
543 assert(approxEqual(rec3a
.im
, rec3b
.im
, EPS
));
545 auto rec4a
= (-0.79) ^^
complex(6.8, 5.7);
546 auto rec4b
= complex(-0.79, 0.0) ^^
complex(6.8, 5.7);
547 assert(approxEqual(rec4a
.re
, rec4b
.re
, EPS
));
548 assert(approxEqual(rec4a
.im
, rec4b
.im
, EPS
));
550 auto rer
= a ^^
complex(2.0, 0.0);
551 auto rcheck
= a ^^
2.0;
552 static assert(is(typeof(rcheck
) == double));
553 assert(feqrel(rer
.re
, rcheck
) == double.mant_dig
);
554 assert(isIdentical(rer
.re
, rcheck
));
555 assert(rer
.im
== 0.0);
557 auto rer2
= (-a
) ^^
complex(2.0, 0.0);
558 rcheck
= (-a
) ^^
2.0;
559 assert(feqrel(rer2
.re
, rcheck
) == double.mant_dig
);
560 assert(isIdentical(rer2
.re
, rcheck
));
561 assert(approxEqual(rer2
.im
, 0.0, EPS
));
563 auto rer3
= (-a
) ^^
complex(-2.0, 0.0);
564 rcheck
= (-a
) ^^
(-2.0);
565 assert(feqrel(rer3
.re
, rcheck
) == double.mant_dig
);
566 assert(isIdentical(rer3
.re
, rcheck
));
567 assert(approxEqual(rer3
.im
, 0.0, EPS
));
569 auto rer4
= a ^^
complex(-2.0, 0.0);
570 rcheck
= a ^^
(-2.0);
571 assert(feqrel(rer4
.re
, rcheck
) == double.mant_dig
);
572 assert(isIdentical(rer4
.re
, rcheck
));
573 assert(rer4
.im
== 0.0);
575 // Check Complex-int operations.
579 assert(approxEqual(abs(cei
), abs(c1
)^^i
, EPS
));
580 // Use cos() here to deal with arguments that go outside
581 // the (-pi,pi] interval (only an issue for i>3).
582 assert(approxEqual(std
.math
.cos(arg(cei
)), std
.math
.cos(arg(c1
)*i
), EPS
));
585 // Check operations between different complex types.
586 auto cf
= Complex
!float(1.0, 1.0);
587 auto cr
= Complex
!real(1.0, 1.0);
588 auto c1pcf
= c1
+ cf
;
589 auto c1pcr
= c1
+ cr
;
590 static assert(is(typeof(c1pcf
) == Complex
!double));
591 static assert(is(typeof(c1pcr
) == Complex
!real));
592 assert(c1pcf
.re
== c1pcr
.re
);
593 assert(c1pcf
.im
== c1pcr
.im
);
599 assert(approxEqual(c1c
.re
, 1.0, EPS
));
600 assert(approxEqual(c1c
.im
, 0.0, EPS
));
604 assert(approxEqual(c1c
.re
, 0.588235, EPS
));
605 assert(approxEqual(c1c
.im
, -0.352941, EPS
));
608 assert(approxEqual(c2c
.re
, 1.25, EPS
));
609 assert(approxEqual(c2c
.im
, 0.75, EPS
));
613 assert(approxEqual(c2c
.re
, 1.0, EPS
));
614 assert(approxEqual(c2c
.im
, 0.0, EPS
));
617 @safe pure nothrow unittest
620 Complex
!double a
= 1;
621 assert(a
.re
== 1 && a
.im
== 0);
622 Complex
!double b
= 1.0;
623 assert(b
.re
== 1.0 && b
.im
== 0);
624 Complex
!double c
= Complex
!real(1.0, 2);
625 assert(c
.re
== 1.0 && c
.im
== 2);
628 @safe pure nothrow unittest
630 // Assignments and comparisons
635 assert(z
.re
== 1.0 && z
.im
== 0.0);
639 assert(z
.re
== 2.0 && z
.im
== 0.0);
643 assert(z
.re
== 1.0 && z
.im
== 0.0);
645 auto w
= Complex
!real(1.0, 1.0);
648 assert(z
.re
== 1.0 && z
.im
== 1.0);
650 auto c
= Complex
!float(2.0, 2.0);
653 assert(z
.re
== 2.0 && z
.im
== 2.0);
657 /* Makes Complex!(Complex!T) fold to Complex!T.
659 The rationale for this is that just like the real line is a
660 subspace of the complex plane, the complex plane is a subspace
661 of itself. Example of usage:
663 Complex!T addI(T)(T x)
665 return x + Complex!T(0.0, 1.0);
668 The above will work if T is both real and complex.
671 if (is(T R
== Complex
!R
))
676 @safe pure nothrow unittest
678 static assert(is(Complex
!(Complex
!real) == Complex
!real));
680 Complex
!T
addI(T
)(T x
)
682 return x
+ Complex
!T(0.0, 1.0);
686 assert(z1
.re
== 1.0 && z1
.im
== 1.0);
688 enum one
= Complex
!double(1.0, 0.0);
695 Params: z = A complex number.
696 Returns: The absolute value (or modulus) of `z`.
698 T
abs(T
)(Complex
!T z
) @safe pure nothrow @nogc
700 import std
.math
: hypot
;
701 return hypot(z
.re
, z
.im
);
705 @safe pure nothrow unittest
707 static import std
.math
;
708 assert(abs(complex(1.0)) == 1.0);
709 assert(abs(complex(0.0, 1.0)) == 1.0);
710 assert(abs(complex(1.0L, -2.0L)) == std
.math
.sqrt(5.0L));
716 z = A complex number.
718 Returns: The squared modulus of `z`.
719 For genericity, if called on a real number, returns its square.
721 T
sqAbs(T
)(Complex
!T z
) @safe pure nothrow @nogc
723 return z
.re
*z
.re
+ z
.im
*z
.im
;
727 @safe pure nothrow unittest
730 assert(sqAbs(complex(0.0)) == 0.0);
731 assert(sqAbs(complex(1.0)) == 1.0);
732 assert(sqAbs(complex(0.0, 1.0)) == 1.0);
733 assert(approxEqual(sqAbs(complex(1.0L, -2.0L)), 5.0L));
734 assert(approxEqual(sqAbs(complex(-3.0L, 1.0L)), 10.0L));
735 assert(approxEqual(sqAbs(complex(1.0f,-1.0f)), 2.0f));
739 T
sqAbs(T
)(T x
) @safe pure nothrow @nogc
740 if (isFloatingPoint
!T
)
745 @safe pure nothrow unittest
748 assert(sqAbs(0.0) == 0.0);
749 assert(sqAbs(-1.0) == 1.0);
750 assert(approxEqual(sqAbs(-3.0L), 9.0L));
751 assert(approxEqual(sqAbs(-5.0f), 25.0f));
756 Params: z = A complex number.
757 Returns: The argument (or phase) of `z`.
759 T
arg(T
)(Complex
!T z
) @safe pure nothrow @nogc
761 import std
.math
: atan2
;
762 return atan2(z
.im
, z
.re
);
766 @safe pure nothrow unittest
769 assert(arg(complex(1.0)) == 0.0);
770 assert(arg(complex(0.0L, 1.0L)) == PI_2
);
771 assert(arg(complex(1.0L, 1.0L)) == PI_4
);
776 Params: z = A complex number.
777 Returns: The complex conjugate of `z`.
779 Complex
!T
conj(T
)(Complex
!T z
) @safe pure nothrow @nogc
781 return Complex
!T(z
.re
, -z
.im
);
785 @safe pure nothrow unittest
787 assert(conj(complex(1.0)) == complex(1.0));
788 assert(conj(complex(1.0, 2.0)) == complex(1.0, -2.0));
793 Constructs a complex number given its absolute value and argument.
795 modulus = The modulus
796 argument = The argument
797 Returns: The complex number with the given modulus and argument.
799 Complex
!(CommonType
!(T
, U
)) fromPolar(T
, U
)(T modulus
, U argument
)
800 @safe pure nothrow @nogc
802 import std
.math
: sin
, cos
;
803 return Complex
!(CommonType
!(T
,U
))
804 (modulus
*cos(argument
), modulus
*sin(argument
));
808 @safe pure nothrow unittest
811 auto z
= fromPolar(std
.math
.sqrt(2.0), PI_4
);
812 assert(approxEqual(z
.re
, 1.0L, real.epsilon
));
813 assert(approxEqual(z
.im
, 1.0L, real.epsilon
));
818 Trigonometric functions on complex numbers.
820 Params: z = A complex number.
821 Returns: The sine and cosine of `z`, respectively.
823 Complex
!T
sin(T
)(Complex
!T z
) @safe pure nothrow @nogc
825 import std
.math
: expi
, coshisinh
;
826 auto cs
= expi(z
.re
);
827 auto csh
= coshisinh(z
.im
);
828 return typeof(return)(cs
.im
* csh
.re
, cs
.re
* csh
.im
);
832 @safe pure nothrow unittest
834 static import std
.math
;
835 import std
.math
: feqrel
;
836 assert(sin(complex(0.0)) == 0.0);
837 assert(sin(complex(2.0, 0)) == std
.math
.sin(2.0));
838 auto c1
= sin(complex(2.0L, 0));
839 auto c2
= complex(std
.math
.sin(2.0L), 0);
840 assert(feqrel(c1
.re
, c2
.re
) >= real.mant_dig
- 1 &&
841 feqrel(c1
.im
, c2
.im
) >= real.mant_dig
- 1);
846 Complex
!T
cos(T
)(Complex
!T z
) @safe pure nothrow @nogc
848 import std
.math
: expi
, coshisinh
;
849 auto cs
= expi(z
.re
);
850 auto csh
= coshisinh(z
.im
);
851 return typeof(return)(cs
.re
* csh
.re
, - cs
.im
* csh
.im
);
855 @safe pure nothrow unittest
857 static import std
.math
;
858 import std
.math
: feqrel
;
859 assert(cos(complex(0.0)) == 1.0);
860 assert(cos(complex(1.3)) == std
.math
.cos(1.3));
861 auto c1
= cos(complex(0, 5.2L));
862 auto c2
= complex(std
.math
.cosh(5.2L), 0.0L);
863 assert(feqrel(c1
.re
, c2
.re
) >= real.mant_dig
- 1 &&
864 feqrel(c1
.im
, c2
.im
) >= real.mant_dig
- 1);
865 auto c3
= cos(complex(1.3L));
866 auto c4
= complex(std
.math
.cos(1.3L), 0.0L);
867 assert(feqrel(c3
.re
, c4
.re
) >= real.mant_dig
- 1 &&
868 feqrel(c3
.im
, c4
.im
) >= real.mant_dig
- 1);
872 Params: y = A real number.
873 Returns: The value of cos(y) + i sin(y).
876 $(D expi) is included here for convenience and for easy migration of code
877 that uses $(REF _expi, std,math). Unlike $(REF _expi, std,math), which uses the
878 x87 $(I fsincos) instruction when possible, this function is no faster
879 than calculating cos(y) and sin(y) separately.
881 Complex
!real expi(real y
) @trusted pure nothrow @nogc
883 import std
.math
: cos
, sin
;
884 return Complex
!real(cos(y
), sin(y
));
888 @safe pure nothrow unittest
890 static import std
.math
;
892 assert(expi(1.3e5L
) == complex(std
.math
.cos(1.3e5L
), std
.math
.sin(1.3e5L
)));
893 assert(expi(0.0L) == 1.0L);
894 auto z1
= expi(1.234);
895 auto z2
= std
.math
.expi(1.234);
896 assert(z1
.re
== z2
.re
&& z1
.im
== z2
.im
);
901 Params: z = A complex number.
902 Returns: The square root of `z`.
904 Complex
!T
sqrt(T
)(Complex
!T z
) @safe pure nothrow @nogc
906 static import std
.math
;
912 c
= typeof(return)(0, 0);
919 x
= std
.math
.fabs(z_re
);
920 y
= std
.math
.fabs(z_im
);
925 * std
.math
.sqrt(0.5 * (1 + std
.math
.sqrt(1 + r
* r
)));
931 * std
.math
.sqrt(0.5 * (r
+ std
.math
.sqrt(1 + r
* r
)));
936 c
= typeof(return)(w
, z_im
/ (w
+ w
));
942 c
= typeof(return)(z_im
/ (w
+ w
), w
);
949 @safe pure nothrow unittest
951 static import std
.math
;
952 assert(sqrt(complex(0.0)) == 0.0);
953 assert(sqrt(complex(1.0L, 0)) == std
.math
.sqrt(1.0L));
954 assert(sqrt(complex(-1.0L, 0)) == complex(0, 1.0L));
957 @safe pure nothrow unittest
959 import std
.math
: approxEqual
;
961 auto c1
= complex(1.0, 1.0);
962 auto c2
= Complex
!double(0.5, 2.0);
965 assert(approxEqual(c1s
.re
, 1.09868411));
966 assert(approxEqual(c1s
.im
, 0.45508986));
969 assert(approxEqual(c2s
.re
, 1.1317134));
970 assert(approxEqual(c2s
.im
, 0.8836155));
973 // Issue 10881: support %f formatting of complex numbers
976 import std
.format
: format
;
978 auto x
= complex(1.2, 3.4);
979 assert(format("%.2f", x
) == "1.20+3.40i");
981 auto y
= complex(1.2, -3.4);
982 assert(format("%.2f", y
) == "1.20-3.40i");
987 // Test wide string formatting
989 wstring
wformat(T
)(string format
, Complex
!T c
)
991 import std
.array
: appender
;
992 auto w
= appender
!wstring();
993 auto n
= formattedWrite(w
, format
, c
);
997 auto x
= complex(1.2, 3.4);
998 assert(wformat("%.2f", x
) == "1.20+3.40i"w
);
1003 // Test ease of use (vanilla toString() should be supported)
1004 assert(complex(1.2, 3.4).toString() == "1.2+3.4i");