1*627f7eb2Smrg // Written in the D programming language.
2*627f7eb2Smrg
3*627f7eb2Smrg /** This module contains the $(LREF Complex) type, which is used to represent
4*627f7eb2Smrg _complex numbers, along with related mathematical operations and functions.
5*627f7eb2Smrg
6*627f7eb2Smrg $(LREF Complex) will eventually
7*627f7eb2Smrg $(DDLINK deprecate, Deprecated Features, replace)
8*627f7eb2Smrg the built-in types $(D cfloat), $(D cdouble), $(D creal), $(D ifloat),
9*627f7eb2Smrg $(D idouble), and $(D ireal).
10*627f7eb2Smrg
11*627f7eb2Smrg Authors: Lars Tandle Kyllingstad, Don Clugston
12*627f7eb2Smrg Copyright: Copyright (c) 2010, Lars T. Kyllingstad.
13*627f7eb2Smrg License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0)
14*627f7eb2Smrg Source: $(PHOBOSSRC std/_complex.d)
15*627f7eb2Smrg */
16*627f7eb2Smrg module std.complex;
17*627f7eb2Smrg
18*627f7eb2Smrg import std.traits;
19*627f7eb2Smrg
20*627f7eb2Smrg /** Helper function that returns a _complex number with the specified
21*627f7eb2Smrg real and imaginary parts.
22*627f7eb2Smrg
23*627f7eb2Smrg Params:
24*627f7eb2Smrg R = (template parameter) type of real part of complex number
25*627f7eb2Smrg I = (template parameter) type of imaginary part of complex number
26*627f7eb2Smrg
27*627f7eb2Smrg re = real part of complex number to be constructed
28*627f7eb2Smrg im = (optional) imaginary part of complex number, 0 if omitted.
29*627f7eb2Smrg
30*627f7eb2Smrg Returns:
31*627f7eb2Smrg $(D Complex) instance with real and imaginary parts set
32*627f7eb2Smrg to the values provided as input. If neither $(D re) nor
33*627f7eb2Smrg $(D im) are floating-point numbers, the return type will
34*627f7eb2Smrg be $(D Complex!double). Otherwise, the return type is
35*627f7eb2Smrg deduced using $(D std.traits.CommonType!(R, I)).
36*627f7eb2Smrg */
37*627f7eb2Smrg auto complex(R)(R re) @safe pure nothrow @nogc
38*627f7eb2Smrg if (is(R : double))
39*627f7eb2Smrg {
40*627f7eb2Smrg static if (isFloatingPoint!R)
41*627f7eb2Smrg return Complex!R(re, 0);
42*627f7eb2Smrg else
43*627f7eb2Smrg return Complex!double(re, 0);
44*627f7eb2Smrg }
45*627f7eb2Smrg
46*627f7eb2Smrg /// ditto
47*627f7eb2Smrg auto complex(R, I)(R re, I im) @safe pure nothrow @nogc
48*627f7eb2Smrg if (is(R : double) && is(I : double))
49*627f7eb2Smrg {
50*627f7eb2Smrg static if (isFloatingPoint!R || isFloatingPoint!I)
51*627f7eb2Smrg return Complex!(CommonType!(R, I))(re, im);
52*627f7eb2Smrg else
53*627f7eb2Smrg return Complex!double(re, im);
54*627f7eb2Smrg }
55*627f7eb2Smrg
56*627f7eb2Smrg ///
57*627f7eb2Smrg @safe pure nothrow unittest
58*627f7eb2Smrg {
59*627f7eb2Smrg auto a = complex(1.0);
60*627f7eb2Smrg static assert(is(typeof(a) == Complex!double));
61*627f7eb2Smrg assert(a.re == 1.0);
62*627f7eb2Smrg assert(a.im == 0.0);
63*627f7eb2Smrg
64*627f7eb2Smrg auto b = complex(2.0L);
65*627f7eb2Smrg static assert(is(typeof(b) == Complex!real));
66*627f7eb2Smrg assert(b.re == 2.0L);
67*627f7eb2Smrg assert(b.im == 0.0L);
68*627f7eb2Smrg
69*627f7eb2Smrg auto c = complex(1.0, 2.0);
70*627f7eb2Smrg static assert(is(typeof(c) == Complex!double));
71*627f7eb2Smrg assert(c.re == 1.0);
72*627f7eb2Smrg assert(c.im == 2.0);
73*627f7eb2Smrg
74*627f7eb2Smrg auto d = complex(3.0, 4.0L);
75*627f7eb2Smrg static assert(is(typeof(d) == Complex!real));
76*627f7eb2Smrg assert(d.re == 3.0);
77*627f7eb2Smrg assert(d.im == 4.0L);
78*627f7eb2Smrg
79*627f7eb2Smrg auto e = complex(1);
80*627f7eb2Smrg static assert(is(typeof(e) == Complex!double));
81*627f7eb2Smrg assert(e.re == 1);
82*627f7eb2Smrg assert(e.im == 0);
83*627f7eb2Smrg
84*627f7eb2Smrg auto f = complex(1L, 2);
85*627f7eb2Smrg static assert(is(typeof(f) == Complex!double));
86*627f7eb2Smrg assert(f.re == 1L);
87*627f7eb2Smrg assert(f.im == 2);
88*627f7eb2Smrg
89*627f7eb2Smrg auto g = complex(3, 4.0L);
90*627f7eb2Smrg static assert(is(typeof(g) == Complex!real));
91*627f7eb2Smrg assert(g.re == 3);
92*627f7eb2Smrg assert(g.im == 4.0L);
93*627f7eb2Smrg }
94*627f7eb2Smrg
95*627f7eb2Smrg
96*627f7eb2Smrg /** A complex number parametrised by a type $(D T), which must be either
97*627f7eb2Smrg $(D float), $(D double) or $(D real).
98*627f7eb2Smrg */
99*627f7eb2Smrg struct Complex(T)
100*627f7eb2Smrg if (isFloatingPoint!T)
101*627f7eb2Smrg {
102*627f7eb2Smrg import std.format : FormatSpec;
103*627f7eb2Smrg import std.range.primitives : isOutputRange;
104*627f7eb2Smrg
105*627f7eb2Smrg /** The real part of the number. */
106*627f7eb2Smrg T re;
107*627f7eb2Smrg
108*627f7eb2Smrg /** The imaginary part of the number. */
109*627f7eb2Smrg T im;
110*627f7eb2Smrg
111*627f7eb2Smrg /** Converts the complex number to a string representation.
112*627f7eb2Smrg
113*627f7eb2Smrg The second form of this function is usually not called directly;
114*627f7eb2Smrg instead, it is used via $(REF format, std,string), as shown in the examples
115*627f7eb2Smrg below. Supported format characters are 'e', 'f', 'g', 'a', and 's'.
116*627f7eb2Smrg
117*627f7eb2Smrg See the $(MREF std, format) and $(REF format, std,string)
118*627f7eb2Smrg documentation for more information.
119*627f7eb2Smrg */
toString()120*627f7eb2Smrg string toString() const @safe /* TODO: pure nothrow */
121*627f7eb2Smrg {
122*627f7eb2Smrg import std.exception : assumeUnique;
123*627f7eb2Smrg char[] buf;
124*627f7eb2Smrg buf.reserve(100);
125*627f7eb2Smrg auto fmt = FormatSpec!char("%s");
126*627f7eb2Smrg toString((const(char)[] s) { buf ~= s; }, fmt);
127*627f7eb2Smrg static trustedAssumeUnique(T)(T t) @trusted { return assumeUnique(t); }
128*627f7eb2Smrg return trustedAssumeUnique(buf);
129*627f7eb2Smrg }
130*627f7eb2Smrg
131*627f7eb2Smrg static if (is(T == double))
132*627f7eb2Smrg ///
133*627f7eb2Smrg @safe unittest
134*627f7eb2Smrg {
135*627f7eb2Smrg auto c = complex(1.2, 3.4);
136*627f7eb2Smrg
137*627f7eb2Smrg // Vanilla toString formatting:
138*627f7eb2Smrg assert(c.toString() == "1.2+3.4i");
139*627f7eb2Smrg
140*627f7eb2Smrg // Formatting with std.string.format specs: the precision and width
141*627f7eb2Smrg // specifiers apply to both the real and imaginary parts of the
142*627f7eb2Smrg // complex number.
143*627f7eb2Smrg import std.format : format;
144*627f7eb2Smrg assert(format("%.2f", c) == "1.20+3.40i");
145*627f7eb2Smrg assert(format("%4.1f", c) == " 1.2+ 3.4i");
146*627f7eb2Smrg }
147*627f7eb2Smrg
148*627f7eb2Smrg /// ditto
149*627f7eb2Smrg void toString(Writer, Char)(scope Writer w,
150*627f7eb2Smrg FormatSpec!Char formatSpec) const
151*627f7eb2Smrg if (isOutputRange!(Writer, const(Char)[]))
152*627f7eb2Smrg {
153*627f7eb2Smrg import std.format : formatValue;
154*627f7eb2Smrg import std.math : signbit;
155*627f7eb2Smrg import std.range.primitives : put;
156*627f7eb2Smrg formatValue(w, re, formatSpec);
157*627f7eb2Smrg if (signbit(im) == 0)
158*627f7eb2Smrg put(w, "+");
159*627f7eb2Smrg formatValue(w, im, formatSpec);
160*627f7eb2Smrg put(w, "i");
161*627f7eb2Smrg }
162*627f7eb2Smrg
163*627f7eb2Smrg @safe pure nothrow @nogc:
164*627f7eb2Smrg
165*627f7eb2Smrg /** Construct a complex number with the specified real and
166*627f7eb2Smrg imaginary parts. In the case where a single argument is passed
167*627f7eb2Smrg that is not complex, the imaginary part of the result will be
168*627f7eb2Smrg zero.
169*627f7eb2Smrg */
170*627f7eb2Smrg this(R : T)(Complex!R z)
171*627f7eb2Smrg {
172*627f7eb2Smrg re = z.re;
173*627f7eb2Smrg im = z.im;
174*627f7eb2Smrg }
175*627f7eb2Smrg
176*627f7eb2Smrg /// ditto
177*627f7eb2Smrg this(Rx : T, Ry : T)(Rx x, Ry y)
178*627f7eb2Smrg {
179*627f7eb2Smrg re = x;
180*627f7eb2Smrg im = y;
181*627f7eb2Smrg }
182*627f7eb2Smrg
183*627f7eb2Smrg /// ditto
184*627f7eb2Smrg this(R : T)(R r)
185*627f7eb2Smrg {
186*627f7eb2Smrg re = r;
187*627f7eb2Smrg im = 0;
188*627f7eb2Smrg }
189*627f7eb2Smrg
190*627f7eb2Smrg // ASSIGNMENT OPERATORS
191*627f7eb2Smrg
192*627f7eb2Smrg // this = complex
193*627f7eb2Smrg ref Complex opAssign(R : T)(Complex!R z)
194*627f7eb2Smrg {
195*627f7eb2Smrg re = z.re;
196*627f7eb2Smrg im = z.im;
197*627f7eb2Smrg return this;
198*627f7eb2Smrg }
199*627f7eb2Smrg
200*627f7eb2Smrg // this = numeric
201*627f7eb2Smrg ref Complex opAssign(R : T)(R r)
202*627f7eb2Smrg {
203*627f7eb2Smrg re = r;
204*627f7eb2Smrg im = 0;
205*627f7eb2Smrg return this;
206*627f7eb2Smrg }
207*627f7eb2Smrg
208*627f7eb2Smrg // COMPARISON OPERATORS
209*627f7eb2Smrg
210*627f7eb2Smrg // this == complex
211*627f7eb2Smrg bool opEquals(R : T)(Complex!R z) const
212*627f7eb2Smrg {
213*627f7eb2Smrg return re == z.re && im == z.im;
214*627f7eb2Smrg }
215*627f7eb2Smrg
216*627f7eb2Smrg // this == numeric
217*627f7eb2Smrg bool opEquals(R : T)(R r) const
218*627f7eb2Smrg {
219*627f7eb2Smrg return re == r && im == 0;
220*627f7eb2Smrg }
221*627f7eb2Smrg
222*627f7eb2Smrg // UNARY OPERATORS
223*627f7eb2Smrg
224*627f7eb2Smrg // +complex
225*627f7eb2Smrg Complex opUnary(string op)() const
226*627f7eb2Smrg if (op == "+")
227*627f7eb2Smrg {
228*627f7eb2Smrg return this;
229*627f7eb2Smrg }
230*627f7eb2Smrg
231*627f7eb2Smrg // -complex
232*627f7eb2Smrg Complex opUnary(string op)() const
233*627f7eb2Smrg if (op == "-")
234*627f7eb2Smrg {
235*627f7eb2Smrg return Complex(-re, -im);
236*627f7eb2Smrg }
237*627f7eb2Smrg
238*627f7eb2Smrg // BINARY OPERATORS
239*627f7eb2Smrg
240*627f7eb2Smrg // complex op complex
241*627f7eb2Smrg Complex!(CommonType!(T,R)) opBinary(string op, R)(Complex!R z) const
242*627f7eb2Smrg {
243*627f7eb2Smrg alias C = typeof(return);
244*627f7eb2Smrg auto w = C(this.re, this.im);
245*627f7eb2Smrg return w.opOpAssign!(op)(z);
246*627f7eb2Smrg }
247*627f7eb2Smrg
248*627f7eb2Smrg // complex op numeric
249*627f7eb2Smrg Complex!(CommonType!(T,R)) opBinary(string op, R)(R r) const
250*627f7eb2Smrg if (isNumeric!R)
251*627f7eb2Smrg {
252*627f7eb2Smrg alias C = typeof(return);
253*627f7eb2Smrg auto w = C(this.re, this.im);
254*627f7eb2Smrg return w.opOpAssign!(op)(r);
255*627f7eb2Smrg }
256*627f7eb2Smrg
257*627f7eb2Smrg // numeric + complex, numeric * complex
258*627f7eb2Smrg Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(R r) const
259*627f7eb2Smrg if ((op == "+" || op == "*") && (isNumeric!R))
260*627f7eb2Smrg {
261*627f7eb2Smrg return opBinary!(op)(r);
262*627f7eb2Smrg }
263*627f7eb2Smrg
264*627f7eb2Smrg // numeric - complex
265*627f7eb2Smrg Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(R r) const
266*627f7eb2Smrg if (op == "-" && isNumeric!R)
267*627f7eb2Smrg {
268*627f7eb2Smrg return Complex(r - re, -im);
269*627f7eb2Smrg }
270*627f7eb2Smrg
271*627f7eb2Smrg // numeric / complex
272*627f7eb2Smrg Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(R r) const
273*627f7eb2Smrg if (op == "/" && isNumeric!R)
274*627f7eb2Smrg {
275*627f7eb2Smrg import std.math : fabs;
276*627f7eb2Smrg typeof(return) w = void;
277*627f7eb2Smrg if (fabs(re) < fabs(im))
278*627f7eb2Smrg {
279*627f7eb2Smrg immutable ratio = re/im;
280*627f7eb2Smrg immutable rdivd = r/(re*ratio + im);
281*627f7eb2Smrg
282*627f7eb2Smrg w.re = rdivd*ratio;
283*627f7eb2Smrg w.im = -rdivd;
284*627f7eb2Smrg }
285*627f7eb2Smrg else
286*627f7eb2Smrg {
287*627f7eb2Smrg immutable ratio = im/re;
288*627f7eb2Smrg immutable rdivd = r/(re + im*ratio);
289*627f7eb2Smrg
290*627f7eb2Smrg w.re = rdivd;
291*627f7eb2Smrg w.im = -rdivd*ratio;
292*627f7eb2Smrg }
293*627f7eb2Smrg
294*627f7eb2Smrg return w;
295*627f7eb2Smrg }
296*627f7eb2Smrg
297*627f7eb2Smrg // numeric ^^ complex
298*627f7eb2Smrg Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(R lhs) const
299*627f7eb2Smrg if (op == "^^" && isNumeric!R)
300*627f7eb2Smrg {
301*627f7eb2Smrg import std.math : cos, exp, log, sin, PI;
302*627f7eb2Smrg Unqual!(CommonType!(T, R)) ab = void, ar = void;
303*627f7eb2Smrg
304*627f7eb2Smrg if (lhs >= 0)
305*627f7eb2Smrg {
306*627f7eb2Smrg // r = lhs
307*627f7eb2Smrg // theta = 0
308*627f7eb2Smrg ab = lhs ^^ this.re;
309*627f7eb2Smrg ar = log(lhs) * this.im;
310*627f7eb2Smrg }
311*627f7eb2Smrg else
312*627f7eb2Smrg {
313*627f7eb2Smrg // r = -lhs
314*627f7eb2Smrg // theta = PI
315*627f7eb2Smrg ab = (-lhs) ^^ this.re * exp(-PI * this.im);
316*627f7eb2Smrg ar = PI * this.re + log(-lhs) * this.im;
317*627f7eb2Smrg }
318*627f7eb2Smrg
319*627f7eb2Smrg return typeof(return)(ab * cos(ar), ab * sin(ar));
320*627f7eb2Smrg }
321*627f7eb2Smrg
322*627f7eb2Smrg // OP-ASSIGN OPERATORS
323*627f7eb2Smrg
324*627f7eb2Smrg // complex += complex, complex -= complex
325*627f7eb2Smrg ref Complex opOpAssign(string op, C)(C z)
326*627f7eb2Smrg if ((op == "+" || op == "-") && is(C R == Complex!R))
327*627f7eb2Smrg {
328*627f7eb2Smrg mixin ("re "~op~"= z.re;");
329*627f7eb2Smrg mixin ("im "~op~"= z.im;");
330*627f7eb2Smrg return this;
331*627f7eb2Smrg }
332*627f7eb2Smrg
333*627f7eb2Smrg // complex *= complex
334*627f7eb2Smrg ref Complex opOpAssign(string op, C)(C z)
335*627f7eb2Smrg if (op == "*" && is(C R == Complex!R))
336*627f7eb2Smrg {
337*627f7eb2Smrg auto temp = re*z.re - im*z.im;
338*627f7eb2Smrg im = im*z.re + re*z.im;
339*627f7eb2Smrg re = temp;
340*627f7eb2Smrg return this;
341*627f7eb2Smrg }
342*627f7eb2Smrg
343*627f7eb2Smrg // complex /= complex
344*627f7eb2Smrg ref Complex opOpAssign(string op, C)(C z)
345*627f7eb2Smrg if (op == "/" && is(C R == Complex!R))
346*627f7eb2Smrg {
347*627f7eb2Smrg import std.math : fabs;
348*627f7eb2Smrg if (fabs(z.re) < fabs(z.im))
349*627f7eb2Smrg {
350*627f7eb2Smrg immutable ratio = z.re/z.im;
351*627f7eb2Smrg immutable denom = z.re*ratio + z.im;
352*627f7eb2Smrg
353*627f7eb2Smrg immutable temp = (re*ratio + im)/denom;
354*627f7eb2Smrg im = (im*ratio - re)/denom;
355*627f7eb2Smrg re = temp;
356*627f7eb2Smrg }
357*627f7eb2Smrg else
358*627f7eb2Smrg {
359*627f7eb2Smrg immutable ratio = z.im/z.re;
360*627f7eb2Smrg immutable denom = z.re + z.im*ratio;
361*627f7eb2Smrg
362*627f7eb2Smrg immutable temp = (re + im*ratio)/denom;
363*627f7eb2Smrg im = (im - re*ratio)/denom;
364*627f7eb2Smrg re = temp;
365*627f7eb2Smrg }
366*627f7eb2Smrg return this;
367*627f7eb2Smrg }
368*627f7eb2Smrg
369*627f7eb2Smrg // complex ^^= complex
370*627f7eb2Smrg ref Complex opOpAssign(string op, C)(C z)
371*627f7eb2Smrg if (op == "^^" && is(C R == Complex!R))
372*627f7eb2Smrg {
373*627f7eb2Smrg import std.math : exp, log, cos, sin;
374*627f7eb2Smrg immutable r = abs(this);
375*627f7eb2Smrg immutable t = arg(this);
376*627f7eb2Smrg immutable ab = r^^z.re * exp(-t*z.im);
377*627f7eb2Smrg immutable ar = t*z.re + log(r)*z.im;
378*627f7eb2Smrg
379*627f7eb2Smrg re = ab*cos(ar);
380*627f7eb2Smrg im = ab*sin(ar);
381*627f7eb2Smrg return this;
382*627f7eb2Smrg }
383*627f7eb2Smrg
384*627f7eb2Smrg // complex += numeric, complex -= numeric
385*627f7eb2Smrg ref Complex opOpAssign(string op, U : T)(U a)
386*627f7eb2Smrg if (op == "+" || op == "-")
387*627f7eb2Smrg {
388*627f7eb2Smrg mixin ("re "~op~"= a;");
389*627f7eb2Smrg return this;
390*627f7eb2Smrg }
391*627f7eb2Smrg
392*627f7eb2Smrg // complex *= numeric, complex /= numeric
393*627f7eb2Smrg ref Complex opOpAssign(string op, U : T)(U a)
394*627f7eb2Smrg if (op == "*" || op == "/")
395*627f7eb2Smrg {
396*627f7eb2Smrg mixin ("re "~op~"= a;");
397*627f7eb2Smrg mixin ("im "~op~"= a;");
398*627f7eb2Smrg return this;
399*627f7eb2Smrg }
400*627f7eb2Smrg
401*627f7eb2Smrg // complex ^^= real
402*627f7eb2Smrg ref Complex opOpAssign(string op, R)(R r)
403*627f7eb2Smrg if (op == "^^" && isFloatingPoint!R)
404*627f7eb2Smrg {
405*627f7eb2Smrg import std.math : cos, sin;
406*627f7eb2Smrg immutable ab = abs(this)^^r;
407*627f7eb2Smrg immutable ar = arg(this)*r;
408*627f7eb2Smrg re = ab*cos(ar);
409*627f7eb2Smrg im = ab*sin(ar);
410*627f7eb2Smrg return this;
411*627f7eb2Smrg }
412*627f7eb2Smrg
413*627f7eb2Smrg // complex ^^= int
414*627f7eb2Smrg ref Complex opOpAssign(string op, U)(U i)
415*627f7eb2Smrg if (op == "^^" && isIntegral!U)
416*627f7eb2Smrg {
417*627f7eb2Smrg switch (i)
418*627f7eb2Smrg {
419*627f7eb2Smrg case 0:
420*627f7eb2Smrg re = 1.0;
421*627f7eb2Smrg im = 0.0;
422*627f7eb2Smrg break;
423*627f7eb2Smrg case 1:
424*627f7eb2Smrg // identity; do nothing
425*627f7eb2Smrg break;
426*627f7eb2Smrg case 2:
427*627f7eb2Smrg this *= this;
428*627f7eb2Smrg break;
429*627f7eb2Smrg case 3:
430*627f7eb2Smrg auto z = this;
431*627f7eb2Smrg this *= z;
432*627f7eb2Smrg this *= z;
433*627f7eb2Smrg break;
434*627f7eb2Smrg default:
435*627f7eb2Smrg this ^^= cast(real) i;
436*627f7eb2Smrg }
437*627f7eb2Smrg return this;
438*627f7eb2Smrg }
439*627f7eb2Smrg }
440*627f7eb2Smrg
441*627f7eb2Smrg @safe pure nothrow unittest
442*627f7eb2Smrg {
443*627f7eb2Smrg import std.complex;
444*627f7eb2Smrg import std.math;
445*627f7eb2Smrg
446*627f7eb2Smrg enum EPS = double.epsilon;
447*627f7eb2Smrg auto c1 = complex(1.0, 1.0);
448*627f7eb2Smrg
449*627f7eb2Smrg // Check unary operations.
450*627f7eb2Smrg auto c2 = Complex!double(0.5, 2.0);
451*627f7eb2Smrg
452*627f7eb2Smrg assert(c2 == +c2);
453*627f7eb2Smrg
454*627f7eb2Smrg assert((-c2).re == -(c2.re));
455*627f7eb2Smrg assert((-c2).im == -(c2.im));
456*627f7eb2Smrg assert(c2 == -(-c2));
457*627f7eb2Smrg
458*627f7eb2Smrg // Check complex-complex operations.
459*627f7eb2Smrg auto cpc = c1 + c2;
460*627f7eb2Smrg assert(cpc.re == c1.re + c2.re);
461*627f7eb2Smrg assert(cpc.im == c1.im + c2.im);
462*627f7eb2Smrg
463*627f7eb2Smrg auto cmc = c1 - c2;
464*627f7eb2Smrg assert(cmc.re == c1.re - c2.re);
465*627f7eb2Smrg assert(cmc.im == c1.im - c2.im);
466*627f7eb2Smrg
467*627f7eb2Smrg auto ctc = c1 * c2;
468*627f7eb2Smrg assert(approxEqual(abs(ctc), abs(c1)*abs(c2), EPS));
469*627f7eb2Smrg assert(approxEqual(arg(ctc), arg(c1)+arg(c2), EPS));
470*627f7eb2Smrg
471*627f7eb2Smrg auto cdc = c1 / c2;
472*627f7eb2Smrg assert(approxEqual(abs(cdc), abs(c1)/abs(c2), EPS));
473*627f7eb2Smrg assert(approxEqual(arg(cdc), arg(c1)-arg(c2), EPS));
474*627f7eb2Smrg
475*627f7eb2Smrg auto cec = c1^^c2;
476*627f7eb2Smrg assert(approxEqual(cec.re, 0.11524131979943839881, EPS));
477*627f7eb2Smrg assert(approxEqual(cec.im, 0.21870790452746026696, EPS));
478*627f7eb2Smrg
479*627f7eb2Smrg // Check complex-real operations.
480*627f7eb2Smrg double a = 123.456;
481*627f7eb2Smrg
482*627f7eb2Smrg auto cpr = c1 + a;
483*627f7eb2Smrg assert(cpr.re == c1.re + a);
484*627f7eb2Smrg assert(cpr.im == c1.im);
485*627f7eb2Smrg
486*627f7eb2Smrg auto cmr = c1 - a;
487*627f7eb2Smrg assert(cmr.re == c1.re - a);
488*627f7eb2Smrg assert(cmr.im == c1.im);
489*627f7eb2Smrg
490*627f7eb2Smrg auto ctr = c1 * a;
491*627f7eb2Smrg assert(ctr.re == c1.re*a);
492*627f7eb2Smrg assert(ctr.im == c1.im*a);
493*627f7eb2Smrg
494*627f7eb2Smrg auto cdr = c1 / a;
495*627f7eb2Smrg assert(approxEqual(abs(cdr), abs(c1)/a, EPS));
496*627f7eb2Smrg assert(approxEqual(arg(cdr), arg(c1), EPS));
497*627f7eb2Smrg
498*627f7eb2Smrg auto cer = c1^^3.0;
499*627f7eb2Smrg assert(approxEqual(abs(cer), abs(c1)^^3, EPS));
500*627f7eb2Smrg assert(approxEqual(arg(cer), arg(c1)*3, EPS));
501*627f7eb2Smrg
502*627f7eb2Smrg auto rpc = a + c1;
503*627f7eb2Smrg assert(rpc == cpr);
504*627f7eb2Smrg
505*627f7eb2Smrg auto rmc = a - c1;
506*627f7eb2Smrg assert(rmc.re == a-c1.re);
507*627f7eb2Smrg assert(rmc.im == -c1.im);
508*627f7eb2Smrg
509*627f7eb2Smrg auto rtc = a * c1;
510*627f7eb2Smrg assert(rtc == ctr);
511*627f7eb2Smrg
512*627f7eb2Smrg auto rdc = a / c1;
513*627f7eb2Smrg assert(approxEqual(abs(rdc), a/abs(c1), EPS));
514*627f7eb2Smrg assert(approxEqual(arg(rdc), -arg(c1), EPS));
515*627f7eb2Smrg
516*627f7eb2Smrg rdc = a / c2;
517*627f7eb2Smrg assert(approxEqual(abs(rdc), a/abs(c2), EPS));
518*627f7eb2Smrg assert(approxEqual(arg(rdc), -arg(c2), EPS));
519*627f7eb2Smrg
520*627f7eb2Smrg auto rec1a = 1.0 ^^ c1;
521*627f7eb2Smrg assert(rec1a.re == 1.0);
522*627f7eb2Smrg assert(rec1a.im == 0.0);
523*627f7eb2Smrg
524*627f7eb2Smrg auto rec2a = 1.0 ^^ c2;
525*627f7eb2Smrg assert(rec2a.re == 1.0);
526*627f7eb2Smrg assert(rec2a.im == 0.0);
527*627f7eb2Smrg
528*627f7eb2Smrg auto rec1b = (-1.0) ^^ c1;
529*627f7eb2Smrg assert(approxEqual(abs(rec1b), std.math.exp(-PI * c1.im), EPS));
530*627f7eb2Smrg auto arg1b = arg(rec1b);
531*627f7eb2Smrg /* The argument _should_ be PI, but floating-point rounding error
532*627f7eb2Smrg * means that in fact the imaginary part is very slightly negative.
533*627f7eb2Smrg */
534*627f7eb2Smrg assert(approxEqual(arg1b, PI, EPS) || approxEqual(arg1b, -PI, EPS));
535*627f7eb2Smrg
536*627f7eb2Smrg auto rec2b = (-1.0) ^^ c2;
537*627f7eb2Smrg assert(approxEqual(abs(rec2b), std.math.exp(-2 * PI), EPS));
538*627f7eb2Smrg assert(approxEqual(arg(rec2b), PI_2, EPS));
539*627f7eb2Smrg
540*627f7eb2Smrg auto rec3a = 0.79 ^^ complex(6.8, 5.7);
541*627f7eb2Smrg auto rec3b = complex(0.79, 0.0) ^^ complex(6.8, 5.7);
542*627f7eb2Smrg assert(approxEqual(rec3a.re, rec3b.re, EPS));
543*627f7eb2Smrg assert(approxEqual(rec3a.im, rec3b.im, EPS));
544*627f7eb2Smrg
545*627f7eb2Smrg auto rec4a = (-0.79) ^^ complex(6.8, 5.7);
546*627f7eb2Smrg auto rec4b = complex(-0.79, 0.0) ^^ complex(6.8, 5.7);
547*627f7eb2Smrg assert(approxEqual(rec4a.re, rec4b.re, EPS));
548*627f7eb2Smrg assert(approxEqual(rec4a.im, rec4b.im, EPS));
549*627f7eb2Smrg
550*627f7eb2Smrg auto rer = a ^^ complex(2.0, 0.0);
551*627f7eb2Smrg auto rcheck = a ^^ 2.0;
552*627f7eb2Smrg static assert(is(typeof(rcheck) == double));
553*627f7eb2Smrg assert(feqrel(rer.re, rcheck) == double.mant_dig);
554*627f7eb2Smrg assert(isIdentical(rer.re, rcheck));
555*627f7eb2Smrg assert(rer.im == 0.0);
556*627f7eb2Smrg
557*627f7eb2Smrg auto rer2 = (-a) ^^ complex(2.0, 0.0);
558*627f7eb2Smrg rcheck = (-a) ^^ 2.0;
559*627f7eb2Smrg assert(feqrel(rer2.re, rcheck) == double.mant_dig);
560*627f7eb2Smrg assert(isIdentical(rer2.re, rcheck));
561*627f7eb2Smrg assert(approxEqual(rer2.im, 0.0, EPS));
562*627f7eb2Smrg
563*627f7eb2Smrg auto rer3 = (-a) ^^ complex(-2.0, 0.0);
564*627f7eb2Smrg rcheck = (-a) ^^ (-2.0);
565*627f7eb2Smrg assert(feqrel(rer3.re, rcheck) == double.mant_dig);
566*627f7eb2Smrg assert(isIdentical(rer3.re, rcheck));
567*627f7eb2Smrg assert(approxEqual(rer3.im, 0.0, EPS));
568*627f7eb2Smrg
569*627f7eb2Smrg auto rer4 = a ^^ complex(-2.0, 0.0);
570*627f7eb2Smrg rcheck = a ^^ (-2.0);
571*627f7eb2Smrg assert(feqrel(rer4.re, rcheck) == double.mant_dig);
572*627f7eb2Smrg assert(isIdentical(rer4.re, rcheck));
573*627f7eb2Smrg assert(rer4.im == 0.0);
574*627f7eb2Smrg
575*627f7eb2Smrg // Check Complex-int operations.
576*627f7eb2Smrg foreach (i; 0 .. 6)
577*627f7eb2Smrg {
578*627f7eb2Smrg auto cei = c1^^i;
579*627f7eb2Smrg assert(approxEqual(abs(cei), abs(c1)^^i, EPS));
580*627f7eb2Smrg // Use cos() here to deal with arguments that go outside
581*627f7eb2Smrg // the (-pi,pi] interval (only an issue for i>3).
582*627f7eb2Smrg assert(approxEqual(std.math.cos(arg(cei)), std.math.cos(arg(c1)*i), EPS));
583*627f7eb2Smrg }
584*627f7eb2Smrg
585*627f7eb2Smrg // Check operations between different complex types.
586*627f7eb2Smrg auto cf = Complex!float(1.0, 1.0);
587*627f7eb2Smrg auto cr = Complex!real(1.0, 1.0);
588*627f7eb2Smrg auto c1pcf = c1 + cf;
589*627f7eb2Smrg auto c1pcr = c1 + cr;
590*627f7eb2Smrg static assert(is(typeof(c1pcf) == Complex!double));
591*627f7eb2Smrg static assert(is(typeof(c1pcr) == Complex!real));
592*627f7eb2Smrg assert(c1pcf.re == c1pcr.re);
593*627f7eb2Smrg assert(c1pcf.im == c1pcr.im);
594*627f7eb2Smrg
595*627f7eb2Smrg auto c1c = c1;
596*627f7eb2Smrg auto c2c = c2;
597*627f7eb2Smrg
598*627f7eb2Smrg c1c /= c1;
599*627f7eb2Smrg assert(approxEqual(c1c.re, 1.0, EPS));
600*627f7eb2Smrg assert(approxEqual(c1c.im, 0.0, EPS));
601*627f7eb2Smrg
602*627f7eb2Smrg c1c = c1;
603*627f7eb2Smrg c1c /= c2;
604*627f7eb2Smrg assert(approxEqual(c1c.re, 0.588235, EPS));
605*627f7eb2Smrg assert(approxEqual(c1c.im, -0.352941, EPS));
606*627f7eb2Smrg
607*627f7eb2Smrg c2c /= c1;
608*627f7eb2Smrg assert(approxEqual(c2c.re, 1.25, EPS));
609*627f7eb2Smrg assert(approxEqual(c2c.im, 0.75, EPS));
610*627f7eb2Smrg
611*627f7eb2Smrg c2c = c2;
612*627f7eb2Smrg c2c /= c2;
613*627f7eb2Smrg assert(approxEqual(c2c.re, 1.0, EPS));
614*627f7eb2Smrg assert(approxEqual(c2c.im, 0.0, EPS));
615*627f7eb2Smrg }
616*627f7eb2Smrg
617*627f7eb2Smrg @safe pure nothrow unittest
618*627f7eb2Smrg {
619*627f7eb2Smrg // Initialization
620*627f7eb2Smrg Complex!double a = 1;
621*627f7eb2Smrg assert(a.re == 1 && a.im == 0);
622*627f7eb2Smrg Complex!double b = 1.0;
623*627f7eb2Smrg assert(b.re == 1.0 && b.im == 0);
624*627f7eb2Smrg Complex!double c = Complex!real(1.0, 2);
625*627f7eb2Smrg assert(c.re == 1.0 && c.im == 2);
626*627f7eb2Smrg }
627*627f7eb2Smrg
628*627f7eb2Smrg @safe pure nothrow unittest
629*627f7eb2Smrg {
630*627f7eb2Smrg // Assignments and comparisons
631*627f7eb2Smrg Complex!double z;
632*627f7eb2Smrg
633*627f7eb2Smrg z = 1;
634*627f7eb2Smrg assert(z == 1);
635*627f7eb2Smrg assert(z.re == 1.0 && z.im == 0.0);
636*627f7eb2Smrg
637*627f7eb2Smrg z = 2.0;
638*627f7eb2Smrg assert(z == 2.0);
639*627f7eb2Smrg assert(z.re == 2.0 && z.im == 0.0);
640*627f7eb2Smrg
641*627f7eb2Smrg z = 1.0L;
642*627f7eb2Smrg assert(z == 1.0L);
643*627f7eb2Smrg assert(z.re == 1.0 && z.im == 0.0);
644*627f7eb2Smrg
645*627f7eb2Smrg auto w = Complex!real(1.0, 1.0);
646*627f7eb2Smrg z = w;
647*627f7eb2Smrg assert(z == w);
648*627f7eb2Smrg assert(z.re == 1.0 && z.im == 1.0);
649*627f7eb2Smrg
650*627f7eb2Smrg auto c = Complex!float(2.0, 2.0);
651*627f7eb2Smrg z = c;
652*627f7eb2Smrg assert(z == c);
653*627f7eb2Smrg assert(z.re == 2.0 && z.im == 2.0);
654*627f7eb2Smrg }
655*627f7eb2Smrg
656*627f7eb2Smrg
657*627f7eb2Smrg /* Makes Complex!(Complex!T) fold to Complex!T.
658*627f7eb2Smrg
659*627f7eb2Smrg The rationale for this is that just like the real line is a
660*627f7eb2Smrg subspace of the complex plane, the complex plane is a subspace
661*627f7eb2Smrg of itself. Example of usage:
662*627f7eb2Smrg ---
663*627f7eb2Smrg Complex!T addI(T)(T x)
664*627f7eb2Smrg {
665*627f7eb2Smrg return x + Complex!T(0.0, 1.0);
666*627f7eb2Smrg }
667*627f7eb2Smrg ---
668*627f7eb2Smrg The above will work if T is both real and complex.
669*627f7eb2Smrg */
670*627f7eb2Smrg template Complex(T)
671*627f7eb2Smrg if (is(T R == Complex!R))
672*627f7eb2Smrg {
673*627f7eb2Smrg alias Complex = T;
674*627f7eb2Smrg }
675*627f7eb2Smrg
676*627f7eb2Smrg @safe pure nothrow unittest
677*627f7eb2Smrg {
678*627f7eb2Smrg static assert(is(Complex!(Complex!real) == Complex!real));
679*627f7eb2Smrg
680*627f7eb2Smrg Complex!T addI(T)(T x)
681*627f7eb2Smrg {
682*627f7eb2Smrg return x + Complex!T(0.0, 1.0);
683*627f7eb2Smrg }
684*627f7eb2Smrg
685*627f7eb2Smrg auto z1 = addI(1.0);
686*627f7eb2Smrg assert(z1.re == 1.0 && z1.im == 1.0);
687*627f7eb2Smrg
688*627f7eb2Smrg enum one = Complex!double(1.0, 0.0);
689*627f7eb2Smrg auto z2 = addI(one);
690*627f7eb2Smrg assert(z1 == z2);
691*627f7eb2Smrg }
692*627f7eb2Smrg
693*627f7eb2Smrg
694*627f7eb2Smrg /**
695*627f7eb2Smrg Params: z = A complex number.
696*627f7eb2Smrg Returns: The absolute value (or modulus) of `z`.
697*627f7eb2Smrg */
abs(T)698*627f7eb2Smrg T abs(T)(Complex!T z) @safe pure nothrow @nogc
699*627f7eb2Smrg {
700*627f7eb2Smrg import std.math : hypot;
701*627f7eb2Smrg return hypot(z.re, z.im);
702*627f7eb2Smrg }
703*627f7eb2Smrg
704*627f7eb2Smrg ///
705*627f7eb2Smrg @safe pure nothrow unittest
706*627f7eb2Smrg {
707*627f7eb2Smrg static import std.math;
708*627f7eb2Smrg assert(abs(complex(1.0)) == 1.0);
709*627f7eb2Smrg assert(abs(complex(0.0, 1.0)) == 1.0);
710*627f7eb2Smrg assert(abs(complex(1.0L, -2.0L)) == std.math.sqrt(5.0L));
711*627f7eb2Smrg }
712*627f7eb2Smrg
713*627f7eb2Smrg
714*627f7eb2Smrg /++
715*627f7eb2Smrg Params:
716*627f7eb2Smrg z = A complex number.
717*627f7eb2Smrg x = A real number.
718*627f7eb2Smrg Returns: The squared modulus of `z`.
719*627f7eb2Smrg For genericity, if called on a real number, returns its square.
720*627f7eb2Smrg +/
sqAbs(T)721*627f7eb2Smrg T sqAbs(T)(Complex!T z) @safe pure nothrow @nogc
722*627f7eb2Smrg {
723*627f7eb2Smrg return z.re*z.re + z.im*z.im;
724*627f7eb2Smrg }
725*627f7eb2Smrg
726*627f7eb2Smrg ///
727*627f7eb2Smrg @safe pure nothrow unittest
728*627f7eb2Smrg {
729*627f7eb2Smrg import std.math;
730*627f7eb2Smrg assert(sqAbs(complex(0.0)) == 0.0);
731*627f7eb2Smrg assert(sqAbs(complex(1.0)) == 1.0);
732*627f7eb2Smrg assert(sqAbs(complex(0.0, 1.0)) == 1.0);
733*627f7eb2Smrg assert(approxEqual(sqAbs(complex(1.0L, -2.0L)), 5.0L));
734*627f7eb2Smrg assert(approxEqual(sqAbs(complex(-3.0L, 1.0L)), 10.0L));
735*627f7eb2Smrg assert(approxEqual(sqAbs(complex(1.0f,-1.0f)), 2.0f));
736*627f7eb2Smrg }
737*627f7eb2Smrg
738*627f7eb2Smrg /// ditto
739*627f7eb2Smrg T sqAbs(T)(T x) @safe pure nothrow @nogc
740*627f7eb2Smrg if (isFloatingPoint!T)
741*627f7eb2Smrg {
742*627f7eb2Smrg return x*x;
743*627f7eb2Smrg }
744*627f7eb2Smrg
745*627f7eb2Smrg @safe pure nothrow unittest
746*627f7eb2Smrg {
747*627f7eb2Smrg import std.math;
748*627f7eb2Smrg assert(sqAbs(0.0) == 0.0);
749*627f7eb2Smrg assert(sqAbs(-1.0) == 1.0);
750*627f7eb2Smrg assert(approxEqual(sqAbs(-3.0L), 9.0L));
751*627f7eb2Smrg assert(approxEqual(sqAbs(-5.0f), 25.0f));
752*627f7eb2Smrg }
753*627f7eb2Smrg
754*627f7eb2Smrg
755*627f7eb2Smrg /**
756*627f7eb2Smrg Params: z = A complex number.
757*627f7eb2Smrg Returns: The argument (or phase) of `z`.
758*627f7eb2Smrg */
arg(T)759*627f7eb2Smrg T arg(T)(Complex!T z) @safe pure nothrow @nogc
760*627f7eb2Smrg {
761*627f7eb2Smrg import std.math : atan2;
762*627f7eb2Smrg return atan2(z.im, z.re);
763*627f7eb2Smrg }
764*627f7eb2Smrg
765*627f7eb2Smrg ///
766*627f7eb2Smrg @safe pure nothrow unittest
767*627f7eb2Smrg {
768*627f7eb2Smrg import std.math;
769*627f7eb2Smrg assert(arg(complex(1.0)) == 0.0);
770*627f7eb2Smrg assert(arg(complex(0.0L, 1.0L)) == PI_2);
771*627f7eb2Smrg assert(arg(complex(1.0L, 1.0L)) == PI_4);
772*627f7eb2Smrg }
773*627f7eb2Smrg
774*627f7eb2Smrg
775*627f7eb2Smrg /**
776*627f7eb2Smrg Params: z = A complex number.
777*627f7eb2Smrg Returns: The complex conjugate of `z`.
778*627f7eb2Smrg */
779*627f7eb2Smrg Complex!T conj(T)(Complex!T z) @safe pure nothrow @nogc
780*627f7eb2Smrg {
781*627f7eb2Smrg return Complex!T(z.re, -z.im);
782*627f7eb2Smrg }
783*627f7eb2Smrg
784*627f7eb2Smrg ///
785*627f7eb2Smrg @safe pure nothrow unittest
786*627f7eb2Smrg {
787*627f7eb2Smrg assert(conj(complex(1.0)) == complex(1.0));
788*627f7eb2Smrg assert(conj(complex(1.0, 2.0)) == complex(1.0, -2.0));
789*627f7eb2Smrg }
790*627f7eb2Smrg
791*627f7eb2Smrg
792*627f7eb2Smrg /**
793*627f7eb2Smrg Constructs a complex number given its absolute value and argument.
794*627f7eb2Smrg Params:
795*627f7eb2Smrg modulus = The modulus
796*627f7eb2Smrg argument = The argument
797*627f7eb2Smrg Returns: The complex number with the given modulus and argument.
798*627f7eb2Smrg */
799*627f7eb2Smrg Complex!(CommonType!(T, U)) fromPolar(T, U)(T modulus, U argument)
800*627f7eb2Smrg @safe pure nothrow @nogc
801*627f7eb2Smrg {
802*627f7eb2Smrg import std.math : sin, cos;
803*627f7eb2Smrg return Complex!(CommonType!(T,U))
804*627f7eb2Smrg (modulus*cos(argument), modulus*sin(argument));
805*627f7eb2Smrg }
806*627f7eb2Smrg
807*627f7eb2Smrg ///
808*627f7eb2Smrg @safe pure nothrow unittest
809*627f7eb2Smrg {
810*627f7eb2Smrg import std.math;
811*627f7eb2Smrg auto z = fromPolar(std.math.sqrt(2.0), PI_4);
812*627f7eb2Smrg assert(approxEqual(z.re, 1.0L, real.epsilon));
813*627f7eb2Smrg assert(approxEqual(z.im, 1.0L, real.epsilon));
814*627f7eb2Smrg }
815*627f7eb2Smrg
816*627f7eb2Smrg
817*627f7eb2Smrg /**
818*627f7eb2Smrg Trigonometric functions on complex numbers.
819*627f7eb2Smrg
820*627f7eb2Smrg Params: z = A complex number.
821*627f7eb2Smrg Returns: The sine and cosine of `z`, respectively.
822*627f7eb2Smrg */
823*627f7eb2Smrg Complex!T sin(T)(Complex!T z) @safe pure nothrow @nogc
824*627f7eb2Smrg {
825*627f7eb2Smrg import std.math : expi, coshisinh;
826*627f7eb2Smrg auto cs = expi(z.re);
827*627f7eb2Smrg auto csh = coshisinh(z.im);
828*627f7eb2Smrg return typeof(return)(cs.im * csh.re, cs.re * csh.im);
829*627f7eb2Smrg }
830*627f7eb2Smrg
831*627f7eb2Smrg ///
832*627f7eb2Smrg @safe pure nothrow unittest
833*627f7eb2Smrg {
834*627f7eb2Smrg static import std.math;
835*627f7eb2Smrg assert(sin(complex(0.0)) == 0.0);
836*627f7eb2Smrg assert(sin(complex(2.0L, 0)) == std.math.sin(2.0L));
837*627f7eb2Smrg }
838*627f7eb2Smrg
839*627f7eb2Smrg
840*627f7eb2Smrg /// ditto
841*627f7eb2Smrg Complex!T cos(T)(Complex!T z) @safe pure nothrow @nogc
842*627f7eb2Smrg {
843*627f7eb2Smrg import std.math : expi, coshisinh;
844*627f7eb2Smrg auto cs = expi(z.re);
845*627f7eb2Smrg auto csh = coshisinh(z.im);
846*627f7eb2Smrg return typeof(return)(cs.re * csh.re, - cs.im * csh.im);
847*627f7eb2Smrg }
848*627f7eb2Smrg
849*627f7eb2Smrg ///
850*627f7eb2Smrg @safe pure nothrow unittest
851*627f7eb2Smrg {
852*627f7eb2Smrg import std.complex;
853*627f7eb2Smrg import std.math;
854*627f7eb2Smrg assert(cos(complex(0.0)) == 1.0);
855*627f7eb2Smrg assert(cos(complex(1.3L)) == std.math.cos(1.3L));
856*627f7eb2Smrg auto c1 = cos(complex(0, 5.2L));
857*627f7eb2Smrg auto c2 = cosh(5.2L);
858*627f7eb2Smrg assert(feqrel(c1.re, c2.re) >= real.mant_dig - 1 &&
859*627f7eb2Smrg feqrel(c1.im, c2.im) >= real.mant_dig - 1);
860*627f7eb2Smrg }
861*627f7eb2Smrg
862*627f7eb2Smrg
863*627f7eb2Smrg /**
864*627f7eb2Smrg Params: y = A real number.
865*627f7eb2Smrg Returns: The value of cos(y) + i sin(y).
866*627f7eb2Smrg
867*627f7eb2Smrg Note:
868*627f7eb2Smrg $(D expi) is included here for convenience and for easy migration of code
869*627f7eb2Smrg that uses $(REF _expi, std,math). Unlike $(REF _expi, std,math), which uses the
870*627f7eb2Smrg x87 $(I fsincos) instruction when possible, this function is no faster
871*627f7eb2Smrg than calculating cos(y) and sin(y) separately.
872*627f7eb2Smrg */
873*627f7eb2Smrg Complex!real expi(real y) @trusted pure nothrow @nogc
874*627f7eb2Smrg {
875*627f7eb2Smrg import std.math : cos, sin;
876*627f7eb2Smrg return Complex!real(cos(y), sin(y));
877*627f7eb2Smrg }
878*627f7eb2Smrg
879*627f7eb2Smrg ///
880*627f7eb2Smrg @safe pure nothrow unittest
881*627f7eb2Smrg {
882*627f7eb2Smrg static import std.math;
883*627f7eb2Smrg
884*627f7eb2Smrg assert(expi(1.3e5L) == complex(std.math.cos(1.3e5L), std.math.sin(1.3e5L)));
885*627f7eb2Smrg assert(expi(0.0L) == 1.0L);
886*627f7eb2Smrg auto z1 = expi(1.234);
887*627f7eb2Smrg auto z2 = std.math.expi(1.234);
888*627f7eb2Smrg assert(z1.re == z2.re && z1.im == z2.im);
889*627f7eb2Smrg }
890*627f7eb2Smrg
891*627f7eb2Smrg
892*627f7eb2Smrg /**
893*627f7eb2Smrg Params: z = A complex number.
894*627f7eb2Smrg Returns: The square root of `z`.
895*627f7eb2Smrg */
896*627f7eb2Smrg Complex!T sqrt(T)(Complex!T z) @safe pure nothrow @nogc
897*627f7eb2Smrg {
898*627f7eb2Smrg static import std.math;
899*627f7eb2Smrg typeof(return) c;
900*627f7eb2Smrg real x,y,w,r;
901*627f7eb2Smrg
902*627f7eb2Smrg if (z == 0)
903*627f7eb2Smrg {
904*627f7eb2Smrg c = typeof(return)(0, 0);
905*627f7eb2Smrg }
906*627f7eb2Smrg else
907*627f7eb2Smrg {
908*627f7eb2Smrg real z_re = z.re;
909*627f7eb2Smrg real z_im = z.im;
910*627f7eb2Smrg
911*627f7eb2Smrg x = std.math.fabs(z_re);
912*627f7eb2Smrg y = std.math.fabs(z_im);
913*627f7eb2Smrg if (x >= y)
914*627f7eb2Smrg {
915*627f7eb2Smrg r = y / x;
916*627f7eb2Smrg w = std.math.sqrt(x)
917*627f7eb2Smrg * std.math.sqrt(0.5 * (1 + std.math.sqrt(1 + r * r)));
918*627f7eb2Smrg }
919*627f7eb2Smrg else
920*627f7eb2Smrg {
921*627f7eb2Smrg r = x / y;
922*627f7eb2Smrg w = std.math.sqrt(y)
923*627f7eb2Smrg * std.math.sqrt(0.5 * (r + std.math.sqrt(1 + r * r)));
924*627f7eb2Smrg }
925*627f7eb2Smrg
926*627f7eb2Smrg if (z_re >= 0)
927*627f7eb2Smrg {
928*627f7eb2Smrg c = typeof(return)(w, z_im / (w + w));
929*627f7eb2Smrg }
930*627f7eb2Smrg else
931*627f7eb2Smrg {
932*627f7eb2Smrg if (z_im < 0)
933*627f7eb2Smrg w = -w;
934*627f7eb2Smrg c = typeof(return)(z_im / (w + w), w);
935*627f7eb2Smrg }
936*627f7eb2Smrg }
937*627f7eb2Smrg return c;
938*627f7eb2Smrg }
939*627f7eb2Smrg
940*627f7eb2Smrg ///
941*627f7eb2Smrg @safe pure nothrow unittest
942*627f7eb2Smrg {
943*627f7eb2Smrg static import std.math;
944*627f7eb2Smrg assert(sqrt(complex(0.0)) == 0.0);
945*627f7eb2Smrg assert(sqrt(complex(1.0L, 0)) == std.math.sqrt(1.0L));
946*627f7eb2Smrg assert(sqrt(complex(-1.0L, 0)) == complex(0, 1.0L));
947*627f7eb2Smrg }
948*627f7eb2Smrg
949*627f7eb2Smrg @safe pure nothrow unittest
950*627f7eb2Smrg {
951*627f7eb2Smrg import std.math : approxEqual;
952*627f7eb2Smrg
953*627f7eb2Smrg auto c1 = complex(1.0, 1.0);
954*627f7eb2Smrg auto c2 = Complex!double(0.5, 2.0);
955*627f7eb2Smrg
956*627f7eb2Smrg auto c1s = sqrt(c1);
957*627f7eb2Smrg assert(approxEqual(c1s.re, 1.09868411));
958*627f7eb2Smrg assert(approxEqual(c1s.im, 0.45508986));
959*627f7eb2Smrg
960*627f7eb2Smrg auto c2s = sqrt(c2);
961*627f7eb2Smrg assert(approxEqual(c2s.re, 1.1317134));
962*627f7eb2Smrg assert(approxEqual(c2s.im, 0.8836155));
963*627f7eb2Smrg }
964*627f7eb2Smrg
965*627f7eb2Smrg // Issue 10881: support %f formatting of complex numbers
966*627f7eb2Smrg @safe unittest
967*627f7eb2Smrg {
968*627f7eb2Smrg import std.format : format;
969*627f7eb2Smrg
970*627f7eb2Smrg auto x = complex(1.2, 3.4);
971*627f7eb2Smrg assert(format("%.2f", x) == "1.20+3.40i");
972*627f7eb2Smrg
973*627f7eb2Smrg auto y = complex(1.2, -3.4);
974*627f7eb2Smrg assert(format("%.2f", y) == "1.20-3.40i");
975*627f7eb2Smrg }
976*627f7eb2Smrg
977*627f7eb2Smrg @safe unittest
978*627f7eb2Smrg {
979*627f7eb2Smrg // Test wide string formatting
980*627f7eb2Smrg import std.format;
wformat(T)981*627f7eb2Smrg wstring wformat(T)(string format, Complex!T c)
982*627f7eb2Smrg {
983*627f7eb2Smrg import std.array : appender;
984*627f7eb2Smrg auto w = appender!wstring();
985*627f7eb2Smrg auto n = formattedWrite(w, format, c);
986*627f7eb2Smrg return w.data;
987*627f7eb2Smrg }
988*627f7eb2Smrg
989*627f7eb2Smrg auto x = complex(1.2, 3.4);
990*627f7eb2Smrg assert(wformat("%.2f", x) == "1.20+3.40i"w);
991*627f7eb2Smrg }
992*627f7eb2Smrg
993*627f7eb2Smrg @safe unittest
994*627f7eb2Smrg {
995*627f7eb2Smrg // Test ease of use (vanilla toString() should be supported)
996*627f7eb2Smrg assert(complex(1.2, 3.4).toString() == "1.2+3.4i");
997*627f7eb2Smrg }
998