Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

std.complex update: added expi() and moved some functions to module level #559

Merged
merged 5 commits into from almost 2 years ago

3 participants

Lars T. Kyllingstad Don Clugston David Nadlinger
Lars T. Kyllingstad
Collaborator

I have just copied the implementation of std.math.expi() more or less verbatim. I don't know any assembler, so someone should check that the implementation is still valid when the function returns a struct as opposed to a built-in creal. I can't see why it shouldn't be, but you never know... Since there are several functions in std.complex now that are basically ripped from std.math, I have added Don as module author.

Furthermore, I have moved abs(), arg() and conj() down to module level. (They were previously properties of Complex.) This is mainly for consistency with std.math. Backwards compatibility is preserved thanks to the magic of UFCS. (Not that there is much compatibility to worry about; it doesn't seem like too many people are using this module yet.)

added some commits May 01, 2012
Lars T. Kyllingstad std.complex: Moved abs, arg & conj to module level
Backwards compatibility is preserved through the magic of UFCS.
5b4351d
Lars T. Kyllingstad std.complex: Cleanup
Moved some stuff around, removed some extraneous whitespace, made
function documentation more consistent.
34bc329
Lars T. Kyllingstad Added std.complex.expi()
Also added Don as author, since there are several functions in
std.complex, including expi(), that are copied more or less verbatim
from std.math.
03295d1
Lars T. Kyllingstad std.complex: Minor doc improvement c80bb85
Lars T. Kyllingstad
Collaborator

Don, I just noticed there is an "assign" feature on GitHub pull requests now. You are probably the one who should review this request, that is why I assigned it to you. (Please let me know if you'd rather I'd not do that in the future.)

Don Clugston
Collaborator
donc commented May 11, 2012

I don't know any assembler, so someone should check that the implementation is still valid when the function returns a struct as opposed to a built-in creal. I can't see why it shouldn't be, but you never know...

Unfortunately, it isn't valid. The ABI says that creals are returned on the top two elements of the x87 stack. There is no other type which does that. In fact this instruction is the only example of built-in complex type on any architecture that I know of...
They will have to be returned in a struct. Not worth using the asm at all, just use a separate sin() and cos() function. We can maybe try to get the backend to recognize and create an fsincos at some point, but I doubt this function is really performance critical anyway.

Lars T. Kyllingstad
Collaborator

Too bad. That means the only reason to have this function in std.complex is to preserve backwards compatibility when the built-in types are deprecated. I'll fix it later today.

Lars T. Kyllingstad
Collaborator

Done.

Don Clugston donc merged commit 944987d into from June 21, 2012
Don Clugston donc closed this June 21, 2012
David Nadlinger
Collaborator

It probably really doesn't matter much at this point, but I just wanted to note that this is a breaking change, even with UFCS in place – D doesn't have ADL.

Lars T. Kyllingstad
Collaborator

Please explain? (Or perhaps give an example of where it will fail.)

David Nadlinger
Collaborator
import std.complex : complex;

auto c = complex(2.0);
c.abs();

Alternatively, consider that a module doesn't import std.complex at all, for example because Complex is merely passed as a template parameter (this is arguably not so likely with Complex, but it could well happen in similar other cases).

Lars T. Kyllingstad
Collaborator

Ok, I see. Good point. I don't think there will be too many cases of this happening, but maybe I should reinstate the struct methods (only deprecated and written in terms of the module-level functions), just in case.

Deleted user Unknown referenced this pull request from a commit December 24, 2013
Commit has since been removed from the repository and is no longer available.
Deleted user Unknown referenced this pull request from a commit December 25, 2013
Commit has since been removed from the repository and is no longer available.
Deleted user Unknown referenced this pull request from a commit December 25, 2013
Commit has since been removed from the repository and is no longer available.
Deleted user Unknown referenced this pull request from a commit December 25, 2013
Commit has since been removed from the repository and is no longer available.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 5 unique commits by 1 author.

May 01, 2012
Lars T. Kyllingstad std.complex: Moved abs, arg & conj to module level
Backwards compatibility is preserved through the magic of UFCS.
5b4351d
Lars T. Kyllingstad std.complex: Cleanup
Moved some stuff around, removed some extraneous whitespace, made
function documentation more consistent.
34bc329
Lars T. Kyllingstad Added std.complex.expi()
Also added Don as author, since there are several functions in
std.complex, including expi(), that are copied more or less verbatim
from std.math.
03295d1
Lars T. Kyllingstad std.complex: Minor doc improvement c80bb85
May 11, 2012
Lars T. Kyllingstad Removed asm code from std.complex.expi() 029440c
This page is out of date. Refresh to see the latest.

Showing 1 changed file with 119 additions and 135 deletions. Show diff stats Hide diff stats

  1. 254  std/complex.d
254  std/complex.d
... ...
@@ -1,9 +1,13 @@
1 1
 // Written in the D programming language.
2 2
 
3  
-/** Module that will replace the built-in types $(D cfloat), $(D cdouble),
4  
-    $(D creal), $(D ifloat), $(D idouble), and $(D ireal).
  3
+/** This module contains the $(LREF Complex) type, which is used to represent
  4
+    _complex numbers, along with related mathematical operations and functions.
5 5
 
6  
-    Authors:    Lars Tandle Kyllingstad
  6
+    $(LREF Complex) will eventually $(LINK2 ../deprecate.html, replace)
  7
+    the built-in types $(D cfloat), $(D cdouble), $(D creal), $(D ifloat),
  8
+    $(D idouble), and $(D ireal).
  9
+
  10
+    Authors:    Lars Tandle Kyllingstad, Don Clugston
7 11
     Copyright:  Copyright (c) 2010, Lars T. Kyllingstad.
8 12
     License:    $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0)
9 13
     Source:     $(PHOBOSSRC std/_complex.d)
@@ -17,8 +21,6 @@ import std.numeric;
17 21
 import std.traits;
18 22
 
19 23
 
20  
-
21  
-
22 24
 /** Helper function that returns a _complex number with the specified
23 25
     real and imaginary parts.
24 26
 
@@ -61,7 +63,6 @@ auto complex(R, I)(R re, I im)  @safe pure nothrow
61 63
         return Complex!double(re, im);
62 64
 }
63 65
 
64  
-
65 66
 unittest
66 67
 {
67 68
     auto a = complex(1.0);
@@ -101,8 +102,6 @@ unittest
101 102
 }
102 103
 
103 104
 
104  
-
105  
-
106 105
 /** A complex number parametrised by a type $(D T), which must be either
107 106
     $(D float), $(D double) or $(D real).
108 107
 */
@@ -114,38 +113,45 @@ struct Complex(T)  if (isFloatingPoint!T)
114 113
     /** The imaginary part of the number. */
115 114
     T im;
116 115
 
  116
+    /** Converts the complex number to a string representation.
117 117
 
118  
-@safe pure nothrow  // The following functions depend only on std.math.
119  
-{
120  
-
121  
-    /** Calculate the absolute value (or modulus) of the number. */
122  
-    @property T abs() const
123  
-    {
124  
-        return hypot(re, im);
125  
-    }
  118
+        If a $(D sink) delegate is specified, the string is passed to it
  119
+        and this function returns $(D null).  Otherwise, this function
  120
+        returns the string representation directly.
126 121
 
  122
+        The output format is controlled via $(D formatSpec), which should consist
  123
+        of a single POSIX format specifier, including the percent (%) character.
  124
+        Note that complex numbers are floating point numbers, so the only
  125
+        valid format characters are 'e', 'f', 'g', 'a', and 's', where 's'
  126
+        gives the default behaviour. Positional parameters are not valid
  127
+        in this context.
127 128
 
128  
-    /** Calculate the argument (or phase) of the number. */
129  
-    @property T arg() const
  129
+        See the $(LINK2 std_format.html, std.format documentation) for
  130
+        more information.
  131
+    */
  132
+    string toString(scope void delegate(const(char)[]) sink = null,
  133
+                    string formatSpec = "%s")
  134
+        const
130 135
     {
131  
-        return atan2(im, re);
132  
-    }
133  
-
  136
+        if (sink == null)
  137
+        {
  138
+            char[] buf;
  139
+            buf.reserve(100);
  140
+            toString((const(char)[] s) { buf ~= s; }, formatSpec);
  141
+            return cast(string) buf;
  142
+        }
134 143
 
135  
-    /** Return the complex conjugate of the number. */
136  
-    @property Complex conj() const
137  
-    {
138  
-        return Complex(re, -im);
  144
+        formattedWrite(sink, formatSpec, re);
  145
+        if (signbit(im) == 0)  sink("+");
  146
+        formattedWrite(sink, formatSpec, im);
  147
+        sink("i");
  148
+        return null;
139 149
     }
140 150
 
141  
-
142  
-
  151
+@safe pure nothrow:
143 152
 
144 153
     // ASSIGNMENT OPERATORS
145 154
 
146  
-    // TODO: Make operators return by ref when DMD bug 2460 is fixed.
147  
-
148  
-
149 155
     // this = complex
150 156
     ref Complex opAssign(R : T)(Complex!R z)
151 157
     {
@@ -154,7 +160,6 @@ struct Complex(T)  if (isFloatingPoint!T)
154 160
         return this;
155 161
     }
156 162
 
157  
-
158 163
     // this = numeric
159 164
     ref Complex opAssign(R : T)(R r)
160 165
     {
@@ -163,30 +168,22 @@ struct Complex(T)  if (isFloatingPoint!T)
163 168
         return this;
164 169
     }
165 170
 
166  
-
167  
-
168  
-
169 171
     // COMPARISON OPERATORS
170 172
 
171  
-
172 173
     // this == complex
173 174
     bool opEquals(R : T)(Complex!R z) const
174 175
     {
175 176
         return re == z.re && im == z.im;
176 177
     }
177 178
 
178  
-
179 179
     // this == numeric
180 180
     bool opEquals(R : T)(R r) const
181 181
     {
182 182
         return re == r && im == 0;
183 183
     }
184 184
 
185  
-
186  
-
187 185
     // UNARY OPERATORS
188 186
 
189  
-
190 187
     // +complex
191 188
     Complex opUnary(string op)() const
192 189
         if (op == "+")
@@ -194,7 +191,6 @@ struct Complex(T)  if (isFloatingPoint!T)
194 191
         return this;
195 192
     }
196 193
 
197  
-
198 194
     // -complex
199 195
     Complex opUnary(string op)() const
200 196
         if (op == "-")
@@ -202,11 +198,8 @@ struct Complex(T)  if (isFloatingPoint!T)
202 198
         return Complex(-re, -im);
203 199
     }
204 200
 
205  
-
206  
-
207 201
     // BINARY OPERATORS
208 202
 
209  
-
210 203
     // complex op complex
211 204
     Complex!(CommonType!(T,R)) opBinary(string op, R)(Complex!R z) const
212 205
     {
@@ -215,7 +208,6 @@ struct Complex(T)  if (isFloatingPoint!T)
215 208
         return w.opOpAssign!(op)(z);
216 209
     }
217 210
 
218  
-
219 211
     // complex op numeric
220 212
     Complex!(CommonType!(T,R)) opBinary(string op, R)(R r) const
221 213
         if (isNumeric!R)
@@ -225,7 +217,6 @@ struct Complex(T)  if (isFloatingPoint!T)
225 217
         return w.opOpAssign!(op)(r);
226 218
     }
227 219
 
228  
-
229 220
     // numeric + complex,  numeric * complex
230 221
     Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(R r) const
231 222
         if ((op == "+" || op == "*") && (isNumeric!R))
@@ -233,7 +224,6 @@ struct Complex(T)  if (isFloatingPoint!T)
233 224
         return opBinary!(op)(r);
234 225
     }
235 226
 
236  
-
237 227
     // numeric - complex
238 228
     Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(R r) const
239 229
         if (op == "-" && isNumeric!R)
@@ -241,7 +231,6 @@ struct Complex(T)  if (isFloatingPoint!T)
241 231
         return Complex(r - re, -im);
242 232
     }
243 233
 
244  
-
245 234
     // numeric / complex
246 235
     Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(R r) const
247 236
         if (op == "/" && isNumeric!R)
@@ -269,10 +258,7 @@ struct Complex(T)  if (isFloatingPoint!T)
269 258
         return w;
270 259
     }
271 260
 
272  
-
273  
-
274  
-    // OPASSIGN OPERATORS
275  
-
  261
+    // OP-ASSIGN OPERATORS
276 262
 
277 263
     // complex += complex,  complex -= complex
278 264
     ref Complex opOpAssign(string op, C)(C z)
@@ -283,7 +269,6 @@ struct Complex(T)  if (isFloatingPoint!T)
283 269
         return this;
284 270
     }
285 271
 
286  
-
287 272
     // complex *= complex
288 273
     ref Complex opOpAssign(string op, C)(C z)
289 274
         if (op == "*" && is(C R == Complex!R))
@@ -294,7 +279,6 @@ struct Complex(T)  if (isFloatingPoint!T)
294 279
         return this;
295 280
     }
296 281
 
297  
-
298 282
     // complex /= complex
299 283
     ref Complex opOpAssign(string op, C)(C z)
300 284
         if (op == "/" && is(C R == Complex!R))
@@ -320,13 +304,12 @@ struct Complex(T)  if (isFloatingPoint!T)
320 304
         return this;
321 305
     }
322 306
 
323  
-
324 307
     // complex ^^= complex
325 308
     ref Complex opOpAssign(string op, C)(C z)
326 309
         if (op == "^^" && is(C R == Complex!R))
327 310
     {
328  
-        FPTemporary!T r = abs;
329  
-        FPTemporary!T t = arg;
  311
+        FPTemporary!T r = abs(this);
  312
+        FPTemporary!T t = arg(this);
330 313
         FPTemporary!T ab = r^^z.re * exp(-t*z.im);
331 314
         FPTemporary!T ar = t*z.re + log(r)*z.im;
332 315
 
@@ -335,7 +318,6 @@ struct Complex(T)  if (isFloatingPoint!T)
335 318
         return this;
336 319
     }
337 320
 
338  
-
339 321
     // complex += numeric,  complex -= numeric
340 322
     ref Complex opOpAssign(string op, U : T)(U a)
341 323
         if (op == "+" || op == "-")
@@ -344,7 +326,6 @@ struct Complex(T)  if (isFloatingPoint!T)
344 326
         return this;
345 327
     }
346 328
 
347  
-
348 329
     // complex *= numeric,  complex /= numeric
349 330
     ref Complex opOpAssign(string op, U : T)(U a)
350 331
         if (op == "*" || op == "/")
@@ -354,19 +335,17 @@ struct Complex(T)  if (isFloatingPoint!T)
354 335
         return this;
355 336
     }
356 337
 
357  
-
358 338
     // complex ^^= real
359 339
     ref Complex opOpAssign(string op, R)(R r)
360 340
         if (op == "^^" && isFloatingPoint!R)
361 341
     {
362  
-        FPTemporary!T ab = abs^^r;
363  
-        FPTemporary!T ar = arg*r;
  342
+        FPTemporary!T ab = abs(this)^^r;
  343
+        FPTemporary!T ar = arg(this)*r;
364 344
         re = ab*std.math.cos(ar);
365 345
         im = ab*std.math.sin(ar);
366 346
         return this;
367 347
     }
368 348
 
369  
-
370 349
     // complex ^^= int
371 350
     ref Complex opOpAssign(string op, U)(U i)
372 351
         if (op == "^^" && isIntegral!U)
@@ -393,60 +372,12 @@ struct Complex(T)  if (isFloatingPoint!T)
393 372
         }
394 373
         return this;
395 374
     }
396  
-
397  
-} // @safe pure nothrow
398  
-
399  
-
400  
-
401  
-    /** Convert the complex number to a string representation.
402  
-
403  
-        If a $(D sink) delegate is specified, the string is passed to it
404  
-        and this function returns $(D null).  Otherwise, this function
405  
-        returns the string representation directly.
406  
-
407  
-        The output format is controlled via $(D formatSpec), which should consist
408  
-        of a single POSIX format specifier, including the percent (%) character.
409  
-        Note that complex numbers are floating point numbers, so the only
410  
-        valid format characters are 'e', 'f', 'g', 'a', and 's', where 's'
411  
-        gives the default behaviour. Positional parameters are not valid
412  
-        in this context.
413  
-
414  
-        See the $(LINK2 std_format.html, std.format documentation) for
415  
-        more information.
416  
-    */
417  
-    string toString
418  
-        (scope void delegate(const(char)[]) sink = null, string formatSpec = "%s")
419  
-        const
420  
-    {
421  
-        if (sink == null)
422  
-        {
423  
-            char[] buf;
424  
-            buf.reserve(100);
425  
-            toString((const(char)[] s) { buf ~= s; }, formatSpec);
426  
-            return cast(string) buf;
427  
-        }
428  
-
429  
-        formattedWrite(sink, formatSpec, re);
430  
-        if (signbit(im) == 0)  sink("+");
431  
-        formattedWrite(sink, formatSpec, im);
432  
-        sink("i");
433  
-        return null;
434  
-    }
435 375
 }
436 376
 
437  
-
438 377
 unittest
439 378
 {
440 379
     enum EPS = double.epsilon;
441  
-
442  
-    // Check abs() and arg()
443  
-    auto c1 = Complex!double(1.0, 1.0);
444  
-    assert (approxEqual(c1.abs, std.math.sqrt(2.0), EPS));
445  
-    assert (approxEqual(c1.arg, PI_4, EPS));
446  
-
447  
-    auto c1c = c1.conj;
448  
-    assert (c1c.re == 1.0 && c1c.im == -1.0);
449  
-
  380
+    auto c1 = complex(1.0, 1.0);
450 381
 
451 382
     // Check unary operations.
452 383
     auto c2 = Complex!double(0.5, 2.0);
@@ -457,7 +388,6 @@ unittest
457 388
     assert ((-c2).im == -(c2.im));
458 389
     assert (c2 == -(-c2));
459 390
 
460  
-
461 391
     // Check complex-complex operations.
462 392
     auto cpc = c1 + c2;
463 393
     assert (cpc.re == c1.re + c2.re);
@@ -468,18 +398,17 @@ unittest
468 398
     assert (cmc.im == c1.im - c2.im);
469 399
 
470 400
     auto ctc = c1 * c2;
471  
-    assert (approxEqual(ctc.abs, c1.abs*c2.abs, EPS));
472  
-    assert (approxEqual(ctc.arg, c1.arg+c2.arg, EPS));
  401
+    assert (approxEqual(abs(ctc), abs(c1)*abs(c2), EPS));
  402
+    assert (approxEqual(arg(ctc), arg(c1)+arg(c2), EPS));
473 403
 
474 404
     auto cdc = c1 / c2;
475  
-    assert (approxEqual(cdc.abs, c1.abs/c2.abs, EPS));
476  
-    assert (approxEqual(cdc.arg, c1.arg-c2.arg, EPS));
  405
+    assert (approxEqual(abs(cdc), abs(c1)/abs(c2), EPS));
  406
+    assert (approxEqual(arg(cdc), arg(c1)-arg(c2), EPS));
477 407
 
478 408
     auto cec = c1^^c2;
479 409
     assert (approxEqual(cec.re, 0.11524131979943839881, EPS));
480 410
     assert (approxEqual(cec.im, 0.21870790452746026696, EPS));
481 411
 
482  
-
483 412
     // Check complex-real operations.
484 413
     double a = 123.456;
485 414
 
@@ -496,8 +425,8 @@ unittest
496 425
     assert (ctr.im == c1.im*a);
497 426
 
498 427
     auto cdr = c1 / a;
499  
-    assert (approxEqual(cdr.abs, c1.abs/a, EPS));
500  
-    assert (approxEqual(cdr.arg, c1.arg, EPS));
  428
+    assert (approxEqual(abs(cdr), abs(c1)/a, EPS));
  429
+    assert (approxEqual(arg(cdr), arg(c1), EPS));
501 430
 
502 431
     auto rpc = a + c1;
503 432
     assert (rpc == cpr);
@@ -510,25 +439,23 @@ unittest
510 439
     assert (rtc == ctr);
511 440
 
512 441
     auto rdc = a / c1;
513  
-    assert (approxEqual(rdc.abs, a/c1.abs, EPS));
514  
-    assert (approxEqual(rdc.arg, -c1.arg, EPS));
  442
+    assert (approxEqual(abs(rdc), a/abs(c1), EPS));
  443
+    assert (approxEqual(arg(rdc), -arg(c1), EPS));
515 444
 
516 445
     auto cer = c1^^3.0;
517  
-    assert (approxEqual(cer.abs, c1.abs^^3, EPS));
518  
-    assert (approxEqual(cer.arg, c1.arg*3, EPS));
519  
-
  446
+    assert (approxEqual(abs(cer), abs(c1)^^3, EPS));
  447
+    assert (approxEqual(arg(cer), arg(c1)*3, EPS));
520 448
 
521 449
     // Check Complex-int operations.
522 450
     foreach (i; 0..6)
523 451
     {
524 452
         auto cei = c1^^i;
525  
-        assert (approxEqual(cei.abs, c1.abs^^i, EPS));
  453
+        assert (approxEqual(abs(cei), abs(c1)^^i, EPS));
526 454
         // Use cos() here to deal with arguments that go outside
527 455
         // the (-pi,pi] interval (only an issue for i>3).
528  
-        assert (approxEqual(std.math.cos(cei.arg), std.math.cos(c1.arg*i), EPS));
  456
+        assert (approxEqual(std.math.cos(arg(cei)), std.math.cos(arg(c1)*i), EPS));
529 457
     }
530 458
 
531  
-
532 459
     // Check operations between different complex types.
533 460
     auto cf = Complex!float(1.0, 1.0);
534 461
     auto cr = Complex!real(1.0, 1.0);
@@ -557,7 +484,6 @@ unittest
557 484
     assert (z == 1.0L);
558 485
     assert (z.re == 1.0  &&  z.im == 0.0);
559 486
 
560  
-
561 487
     auto w = Complex!real(1.0, 1.0);
562 488
     z = w;
563 489
     assert (z == w);
@@ -581,7 +507,7 @@ unittest
581 507
     assert (s1 == z1.toString());
582 508
 
583 509
     // Using custom format specifier
584  
-    auto z2 = z1.conj;
  510
+    auto z2 = conj(z1);
585 511
     char[] s2;
586 512
     z2.toString((const(char)[] c) { s2 ~= c; }, "%.8e");
587 513
     assert (s2 == "1.23456789e-01-1.23456789e-01i");
@@ -589,9 +515,7 @@ unittest
589 515
 }
590 516
 
591 517
 
592  
-
593  
-
594  
-/*  Fold Complex!(Complex!T) to Complex!T.
  518
+/*  Makes Complex!(Complex!T) fold to Complex!T.
595 519
 
596 520
     The rationale for this is that just like the real line is a
597 521
     subspace of the complex plane, the complex plane is a subspace
@@ -627,9 +551,48 @@ unittest
627 551
 }
628 552
 
629 553
 
  554
+/** Calculates the absolute value (or modulus) of a complex number. */
  555
+T abs(T)(Complex!T z) @safe pure nothrow
  556
+{
  557
+    return hypot(z.re, z.im);
  558
+}
  559
+
  560
+unittest
  561
+{
  562
+    assert (abs(complex(1.0)) == 1.0);
  563
+    assert (abs(complex(0.0, 1.0)) == 1.0);
  564
+    assert (abs(complex(1.0L, -2.0L)) == std.math.sqrt(5.0L));
  565
+}
630 566
 
631 567
 
632  
-/** Construct a complex number given its absolute value and argument. */
  568
+/** Calculates the argument (or phase) of a complex number. */
  569
+T arg(T)(Complex!T z) @safe pure nothrow
  570
+{
  571
+    return atan2(z.im, z.re);
  572
+}
  573
+
  574
+unittest
  575
+{
  576
+    assert (arg(complex(1.0)) == 0.0);
  577
+    assert (arg(complex(0.0L, 1.0L)) == PI_2);
  578
+    assert (arg(complex(1.0L, 1.0L)) == PI_4);
  579
+}
  580
+
  581
+
  582
+/** Returns the complex conjugate of a complex number. */
  583
+Complex!T conj(T)(Complex!T z) @safe pure nothrow
  584
+{
  585
+    return Complex!T(z.re, -z.im);
  586
+}
  587
+
  588
+unittest
  589
+{
  590
+    assert (conj(complex(1.0)) == complex(1.0));
  591
+    assert (conj(complex(1.0, 2.0)) == complex(1.0, -2.0));
  592
+}
  593
+
  594
+
  595
+/** Constructs a complex number given its absolute value and argument. */
633 596
 Complex!(CommonType!(T, U)) fromPolar(T, U)(T modulus, U argument)
634 597
     @safe pure nothrow
635 598
 {
@@ -645,8 +608,6 @@ unittest
645 608
 }
646 609
 
647 610
 
648  
-
649  
-
650 611
 /** Trigonometric functions. */
651 612
 Complex!T sin(T)(Complex!T z)  @safe pure nothrow
652 613
 {
@@ -677,6 +638,29 @@ unittest{
677 638
 }
678 639
 
679 640
 
  641
+/** Calculates cos(y) + i sin(y).
  642
+
  643
+    Note:
  644
+    $(D expi) is included here for convenience and for easy migration of code
  645
+    that uses $(XREF math,_expi).  Unlike $(XREF math,_expi), which uses the
  646
+    x87 $(I fsincos) instruction when possible, this function is no faster
  647
+    than calculating cos(y) and sin(y) separately.
  648
+*/
  649
+Complex!real expi(real y)  @trusted pure nothrow
  650
+{
  651
+    return Complex!real(std.math.cos(y), std.math.sin(y));
  652
+}
  653
+
  654
+unittest
  655
+{
  656
+    assert(expi(1.3e5L) == complex(std.math.cos(1.3e5L), std.math.sin(1.3e5L)));
  657
+    assert(expi(0.0L) == 1.0L);
  658
+    auto z1 = expi(1.234);
  659
+    auto z2 = std.math.expi(1.234);
  660
+    assert(z1.re == z2.re && z1.im == z2.im);
  661
+}
  662
+
  663
+
680 664
 /** Square root. */
681 665
 Complex!T sqrt(T)(Complex!T z)  @safe pure nothrow
682 666
 {
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.