1 // Written in the D programming language. 2 3 /** This module contains the $(LREF Complex) type, which is used to represent 4 complex numbers, along with related mathematical operations and functions. 5 6 $(LREF Complex) will eventually 7 $(DDLINK deprecate, Deprecated Features, replace) 8 the built-in types `cfloat`, `cdouble`, `creal`, `ifloat`, 9 `idouble`, and `ireal`. 10 11 Macros: 12 TABLE_SV = <table border="1" cellpadding="4" cellspacing="0"> 13 <caption>Special Values</caption> 14 $0</table> 15 PLUSMN = ± 16 NAN = $(RED NAN) 17 INFIN = ∞ 18 PI = π 19 20 Authors: Lars Tandle Kyllingstad, Don Clugston 21 Copyright: Copyright (c) 2010, Lars T. Kyllingstad. 22 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0) 23 Source: $(PHOBOSSRC std/complex.d) 24 */ 25 module std.complex; 26 27 import std.traits; 28 29 /** Helper function that returns a complex number with the specified 30 real and imaginary parts. 31 32 Params: 33 R = (template parameter) type of real part of complex number 34 I = (template parameter) type of imaginary part of complex number 35 36 re = real part of complex number to be constructed 37 im = (optional) imaginary part of complex number, 0 if omitted. 38 39 Returns: 40 `Complex` instance with real and imaginary parts set 41 to the values provided as input. If neither `re` nor 42 `im` are floating-point numbers, the return type will 43 be `Complex!double`. Otherwise, the return type is 44 deduced using $(D std.traits.CommonType!(R, I)). 45 */ 46 auto complex(R)(const R re) @safe pure nothrow @nogc 47 if (is(R : double)) 48 { 49 static if (isFloatingPoint!R) 50 return Complex!R(re, 0); 51 else 52 return Complex!double(re, 0); 53 } 54 55 /// ditto 56 auto complex(R, I)(const R re, const I im) @safe pure nothrow @nogc 57 if (is(R : double) && is(I : double)) 58 { 59 static if (isFloatingPoint!R || isFloatingPoint!I) 60 return Complex!(CommonType!(R, I))(re, im); 61 else 62 return Complex!double(re, im); 63 } 64 65 /// 66 @safe pure nothrow unittest 67 { 68 auto a = complex(1.0); 69 static assert(is(typeof(a) == Complex!double)); 70 assert(a.re == 1.0); 71 assert(a.im == 0.0); 72 73 auto b = complex(2.0L); 74 static assert(is(typeof(b) == Complex!real)); 75 assert(b.re == 2.0L); 76 assert(b.im == 0.0L); 77 78 auto c = complex(1.0, 2.0); 79 static assert(is(typeof(c) == Complex!double)); 80 assert(c.re == 1.0); 81 assert(c.im == 2.0); 82 83 auto d = complex(3.0, 4.0L); 84 static assert(is(typeof(d) == Complex!real)); 85 assert(d.re == 3.0); 86 assert(d.im == 4.0L); 87 88 auto e = complex(1); 89 static assert(is(typeof(e) == Complex!double)); 90 assert(e.re == 1); 91 assert(e.im == 0); 92 93 auto f = complex(1L, 2); 94 static assert(is(typeof(f) == Complex!double)); 95 assert(f.re == 1L); 96 assert(f.im == 2); 97 98 auto g = complex(3, 4.0L); 99 static assert(is(typeof(g) == Complex!real)); 100 assert(g.re == 3); 101 assert(g.im == 4.0L); 102 } 103 104 105 /** A complex number parametrised by a type `T`, which must be either 106 `float`, `double` or `real`. 107 */ 108 struct Complex(T) 109 if (isFloatingPoint!T) 110 { 111 import std.format.spec : FormatSpec; 112 import std.range.primitives : isOutputRange; 113 114 /** The real part of the number. */ 115 T re; 116 117 /** The imaginary part of the number. */ 118 T im; 119 120 /** Converts the complex number to a string representation. 121 122 The second form of this function is usually not called directly; 123 instead, it is used via $(REF format, std,string), as shown in the examples 124 below. Supported format characters are 'e', 'f', 'g', 'a', and 's'. 125 126 See the $(MREF std, format) and $(REF format, std,string) 127 documentation for more information. 128 */ 129 string toString() const @safe /* TODO: pure nothrow */ 130 { 131 import std.exception : assumeUnique; 132 char[] buf; 133 buf.reserve(100); 134 auto fmt = FormatSpec!char("%s"); 135 toString((const(char)[] s) { buf ~= s; }, fmt); 136 static trustedAssumeUnique(T)(T t) @trusted { return assumeUnique(t); } 137 return trustedAssumeUnique(buf); 138 } 139 140 static if (is(T == double)) 141 /// 142 @safe unittest 143 { 144 auto c = complex(1.2, 3.4); 145 146 // Vanilla toString formatting: 147 assert(c.toString() == "1.2+3.4i"); 148 149 // Formatting with std.string.format specs: the precision and width 150 // specifiers apply to both the real and imaginary parts of the 151 // complex number. 152 import std.format : format; 153 assert(format("%.2f", c) == "1.20+3.40i"); 154 assert(format("%4.1f", c) == " 1.2+ 3.4i"); 155 } 156 157 /// ditto 158 void toString(Writer, Char)(scope Writer w, scope const ref FormatSpec!Char formatSpec) const 159 if (isOutputRange!(Writer, const(Char)[])) 160 { 161 import std.format.write : formatValue; 162 import std.math.traits : signbit; 163 import std.range.primitives : put; 164 formatValue(w, re, formatSpec); 165 if (signbit(im) == 0) 166 put(w, "+"); 167 formatValue(w, im, formatSpec); 168 put(w, "i"); 169 } 170 171 @safe pure nothrow @nogc: 172 173 /** Construct a complex number with the specified real and 174 imaginary parts. In the case where a single argument is passed 175 that is not complex, the imaginary part of the result will be 176 zero. 177 */ 178 this(R : T)(Complex!R z) 179 { 180 re = z.re; 181 im = z.im; 182 } 183 184 /// ditto 185 this(Rx : T, Ry : T)(const Rx x, const Ry y) 186 { 187 re = x; 188 im = y; 189 } 190 191 /// ditto 192 this(R : T)(const R r) 193 { 194 re = r; 195 im = 0; 196 } 197 198 // ASSIGNMENT OPERATORS 199 200 // this = complex 201 ref Complex opAssign(R : T)(Complex!R z) 202 { 203 re = z.re; 204 im = z.im; 205 return this; 206 } 207 208 // this = numeric 209 ref Complex opAssign(R : T)(const R r) 210 { 211 re = r; 212 im = 0; 213 return this; 214 } 215 216 // COMPARISON OPERATORS 217 218 // this == complex 219 bool opEquals(R : T)(Complex!R z) const 220 { 221 return re == z.re && im == z.im; 222 } 223 224 // this == numeric 225 bool opEquals(R : T)(const R r) const 226 { 227 return re == r && im == 0; 228 } 229 230 // UNARY OPERATORS 231 232 // +complex 233 Complex opUnary(string op)() const 234 if (op == "+") 235 { 236 return this; 237 } 238 239 // -complex 240 Complex opUnary(string op)() const 241 if (op == "-") 242 { 243 return Complex(-re, -im); 244 } 245 246 // BINARY OPERATORS 247 248 // complex op complex 249 Complex!(CommonType!(T,R)) opBinary(string op, R)(Complex!R z) const 250 { 251 alias C = typeof(return); 252 auto w = C(this.re, this.im); 253 return w.opOpAssign!(op)(z); 254 } 255 256 // complex op numeric 257 Complex!(CommonType!(T,R)) opBinary(string op, R)(const R r) const 258 if (isNumeric!R) 259 { 260 alias C = typeof(return); 261 auto w = C(this.re, this.im); 262 return w.opOpAssign!(op)(r); 263 } 264 265 // numeric + complex, numeric * complex 266 Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(const R r) const 267 if ((op == "+" || op == "*") && (isNumeric!R)) 268 { 269 return opBinary!(op)(r); 270 } 271 272 // numeric - complex 273 Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(const R r) const 274 if (op == "-" && isNumeric!R) 275 { 276 return Complex(r - re, -im); 277 } 278 279 // numeric / complex 280 Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(const R r) const 281 if (op == "/" && isNumeric!R) 282 { 283 version (FastMath) 284 { 285 // Compute norm(this) 286 immutable norm = re * re + im * im; 287 // Compute r * conj(this) 288 immutable prod_re = r * re; 289 immutable prod_im = r * -im; 290 // Divide the product by the norm 291 typeof(return) w = void; 292 w.re = prod_re / norm; 293 w.im = prod_im / norm; 294 return w; 295 } 296 else 297 { 298 import core.math : fabs; 299 typeof(return) w = void; 300 if (fabs(re) < fabs(im)) 301 { 302 immutable ratio = re/im; 303 immutable rdivd = r/(re*ratio + im); 304 305 w.re = rdivd*ratio; 306 w.im = -rdivd; 307 } 308 else 309 { 310 immutable ratio = im/re; 311 immutable rdivd = r/(re + im*ratio); 312 313 w.re = rdivd; 314 w.im = -rdivd*ratio; 315 } 316 317 return w; 318 } 319 } 320 321 // numeric ^^ complex 322 Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(const R lhs) const 323 if (op == "^^" && isNumeric!R) 324 { 325 import core.math : cos, sin; 326 import std.math.exponential : exp, log; 327 import std.math.constants : PI; 328 Unqual!(CommonType!(T, R)) ab = void, ar = void; 329 330 if (lhs >= 0) 331 { 332 // r = lhs 333 // theta = 0 334 ab = lhs ^^ this.re; 335 ar = log(lhs) * this.im; 336 } 337 else 338 { 339 // r = -lhs 340 // theta = PI 341 ab = (-lhs) ^^ this.re * exp(-PI * this.im); 342 ar = PI * this.re + log(-lhs) * this.im; 343 } 344 345 return typeof(return)(ab * cos(ar), ab * sin(ar)); 346 } 347 348 // OP-ASSIGN OPERATORS 349 350 // complex += complex, complex -= complex 351 ref Complex opOpAssign(string op, C)(const C z) 352 if ((op == "+" || op == "-") && is(C R == Complex!R)) 353 { 354 mixin ("re "~op~"= z.re;"); 355 mixin ("im "~op~"= z.im;"); 356 return this; 357 } 358 359 // complex *= complex 360 ref Complex opOpAssign(string op, C)(const C z) 361 if (op == "*" && is(C R == Complex!R)) 362 { 363 auto temp = re*z.re - im*z.im; 364 im = im*z.re + re*z.im; 365 re = temp; 366 return this; 367 } 368 369 // complex /= complex 370 ref Complex opOpAssign(string op, C)(const C z) 371 if (op == "/" && is(C R == Complex!R)) 372 { 373 version (FastMath) 374 { 375 // Compute norm(z) 376 immutable norm = z.re * z.re + z.im * z.im; 377 // Compute this * conj(z) 378 immutable prod_re = re * z.re - im * -z.im; 379 immutable prod_im = im * z.re + re * -z.im; 380 // Divide the product by the norm 381 re = prod_re / norm; 382 im = prod_im / norm; 383 return this; 384 } 385 else 386 { 387 import core.math : fabs; 388 if (fabs(z.re) < fabs(z.im)) 389 { 390 immutable ratio = z.re/z.im; 391 immutable denom = z.re*ratio + z.im; 392 393 immutable temp = (re*ratio + im)/denom; 394 im = (im*ratio - re)/denom; 395 re = temp; 396 } 397 else 398 { 399 immutable ratio = z.im/z.re; 400 immutable denom = z.re + z.im*ratio; 401 402 immutable temp = (re + im*ratio)/denom; 403 im = (im - re*ratio)/denom; 404 re = temp; 405 } 406 return this; 407 } 408 } 409 410 // complex ^^= complex 411 ref Complex opOpAssign(string op, C)(const C z) 412 if (op == "^^" && is(C R == Complex!R)) 413 { 414 import core.math : cos, sin; 415 import std.math.exponential : exp, log; 416 immutable r = abs(this); 417 immutable t = arg(this); 418 immutable ab = r^^z.re * exp(-t*z.im); 419 immutable ar = t*z.re + log(r)*z.im; 420 421 re = ab*cos(ar); 422 im = ab*sin(ar); 423 return this; 424 } 425 426 // complex += numeric, complex -= numeric 427 ref Complex opOpAssign(string op, U : T)(const U a) 428 if (op == "+" || op == "-") 429 { 430 mixin ("re "~op~"= a;"); 431 return this; 432 } 433 434 // complex *= numeric, complex /= numeric 435 ref Complex opOpAssign(string op, U : T)(const U a) 436 if (op == "*" || op == "/") 437 { 438 mixin ("re "~op~"= a;"); 439 mixin ("im "~op~"= a;"); 440 return this; 441 } 442 443 // complex ^^= real 444 ref Complex opOpAssign(string op, R)(const R r) 445 if (op == "^^" && isFloatingPoint!R) 446 { 447 import core.math : cos, sin; 448 immutable ab = abs(this)^^r; 449 immutable ar = arg(this)*r; 450 re = ab*cos(ar); 451 im = ab*sin(ar); 452 return this; 453 } 454 455 // complex ^^= int 456 ref Complex opOpAssign(string op, U)(const U i) 457 if (op == "^^" && isIntegral!U) 458 { 459 switch (i) 460 { 461 case 0: 462 re = 1.0; 463 im = 0.0; 464 break; 465 case 1: 466 // identity; do nothing 467 break; 468 case 2: 469 this *= this; 470 break; 471 case 3: 472 auto z = this; 473 this *= z; 474 this *= z; 475 break; 476 default: 477 this ^^= cast(real) i; 478 } 479 return this; 480 } 481 482 /** Returns a complex number instance that correponds in size and in ABI 483 to the associated C compiler's `_Complex` type. 484 */ 485 auto toNative() 486 { 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); 492 else 493 return c_complex_real(re, im); 494 } 495 } 496 497 @safe pure nothrow unittest 498 { 499 import std.complex; 500 static import core.math; 501 import std.math; 502 503 enum EPS = double.epsilon; 504 auto c1 = complex(1.0, 1.0); 505 506 // Check unary operations. 507 auto c2 = Complex!double(0.5, 2.0); 508 509 assert(c2 == +c2); 510 511 assert((-c2).re == -(c2.re)); 512 assert((-c2).im == -(c2.im)); 513 assert(c2 == -(-c2)); 514 515 // Check complex-complex operations. 516 auto cpc = c1 + c2; 517 assert(cpc.re == c1.re + c2.re); 518 assert(cpc.im == c1.im + c2.im); 519 520 auto cmc = c1 - c2; 521 assert(cmc.re == c1.re - c2.re); 522 assert(cmc.im == c1.im - c2.im); 523 524 auto ctc = c1 * c2; 525 assert(isClose(abs(ctc), abs(c1)*abs(c2), EPS)); 526 assert(isClose(arg(ctc), arg(c1)+arg(c2), EPS)); 527 528 auto cdc = c1 / c2; 529 assert(isClose(abs(cdc), abs(c1)/abs(c2), EPS)); 530 assert(isClose(arg(cdc), arg(c1)-arg(c2), EPS)); 531 532 auto cec = c1^^c2; 533 assert(isClose(cec.re, 0.1152413197994, 1e-12)); 534 assert(isClose(cec.im, 0.2187079045274, 1e-12)); 535 536 // Check complex-real operations. 537 double a = 123.456; 538 539 auto cpr = c1 + a; 540 assert(cpr.re == c1.re + a); 541 assert(cpr.im == c1.im); 542 543 auto cmr = c1 - a; 544 assert(cmr.re == c1.re - a); 545 assert(cmr.im == c1.im); 546 547 auto ctr = c1 * a; 548 assert(ctr.re == c1.re*a); 549 assert(ctr.im == c1.im*a); 550 551 auto cdr = c1 / a; 552 assert(isClose(abs(cdr), abs(c1)/a, EPS)); 553 assert(isClose(arg(cdr), arg(c1), EPS)); 554 555 auto cer = c1^^3.0; 556 assert(isClose(abs(cer), abs(c1)^^3, EPS)); 557 assert(isClose(arg(cer), arg(c1)*3, EPS)); 558 559 auto rpc = a + c1; 560 assert(rpc == cpr); 561 562 auto rmc = a - c1; 563 assert(rmc.re == a-c1.re); 564 assert(rmc.im == -c1.im); 565 566 auto rtc = a * c1; 567 assert(rtc == ctr); 568 569 auto rdc = a / c1; 570 assert(isClose(abs(rdc), a/abs(c1), EPS)); 571 assert(isClose(arg(rdc), -arg(c1), EPS)); 572 573 rdc = a / c2; 574 assert(isClose(abs(rdc), a/abs(c2), EPS)); 575 assert(isClose(arg(rdc), -arg(c2), EPS)); 576 577 auto rec1a = 1.0 ^^ c1; 578 assert(rec1a.re == 1.0); 579 assert(rec1a.im == 0.0); 580 581 auto rec2a = 1.0 ^^ c2; 582 assert(rec2a.re == 1.0); 583 assert(rec2a.im == 0.0); 584 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. 590 */ 591 assert(isClose(arg1b, PI, EPS) || isClose(arg1b, -PI, EPS)); 592 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)); 596 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)); 601 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)); 606 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); 613 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)); 619 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)); 625 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); 631 632 // Check Complex-int operations. 633 foreach (i; 0 .. 6) 634 { 635 auto cei = c1^^i; 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)); 640 } 641 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); 651 652 auto c1c = c1; 653 auto c2c = c2; 654 655 c1c /= c1; 656 assert(isClose(c1c.re, 1.0, EPS)); 657 assert(isClose(c1c.im, 0.0, 0.0, EPS)); 658 659 c1c = c1; 660 c1c /= c2; 661 assert(isClose(c1c.re, 0.5882352941177, 1e-12)); 662 assert(isClose(c1c.im, -0.3529411764706, 1e-12)); 663 664 c2c /= c1; 665 assert(isClose(c2c.re, 1.25, EPS)); 666 assert(isClose(c2c.im, 0.75, EPS)); 667 668 c2c = c2; 669 c2c /= c2; 670 assert(isClose(c2c.re, 1.0, EPS)); 671 assert(isClose(c2c.im, 0.0, 0.0, EPS)); 672 } 673 674 @safe pure nothrow unittest 675 { 676 // Initialization 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); 683 } 684 685 @safe pure nothrow unittest 686 { 687 // Assignments and comparisons 688 Complex!double z; 689 690 z = 1; 691 assert(z == 1); 692 assert(z.re == 1.0 && z.im == 0.0); 693 694 z = 2.0; 695 assert(z == 2.0); 696 assert(z.re == 2.0 && z.im == 0.0); 697 698 z = 1.0L; 699 assert(z == 1.0L); 700 assert(z.re == 1.0 && z.im == 0.0); 701 702 auto w = Complex!real(1.0, 1.0); 703 z = w; 704 assert(z == w); 705 assert(z.re == 1.0 && z.im == 1.0); 706 707 auto c = Complex!float(2.0, 2.0); 708 z = c; 709 assert(z == c); 710 assert(z.re == 2.0 && z.im == 2.0); 711 } 712 713 714 /* Makes Complex!(Complex!T) fold to Complex!T. 715 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: 719 --- 720 Complex!T addI(T)(T x) 721 { 722 return x + Complex!T(0.0, 1.0); 723 } 724 --- 725 The above will work if T is both real and complex. 726 */ 727 template Complex(T) 728 if (is(T R == Complex!R)) 729 { 730 alias Complex = T; 731 } 732 733 @safe pure nothrow unittest 734 { 735 static assert(is(Complex!(Complex!real) == Complex!real)); 736 737 Complex!T addI(T)(T x) 738 { 739 return x + Complex!T(0.0, 1.0); 740 } 741 742 auto z1 = addI(1.0); 743 assert(z1.re == 1.0 && z1.im == 1.0); 744 745 enum one = Complex!double(1.0, 0.0); 746 auto z2 = addI(one); 747 assert(z1 == z2); 748 } 749 750 751 /** 752 * Calculates the absolute value (or modulus) of a complex number. 753 * 754 * $(TABLE_SV 755 * $(TR $(TH $(I z)) $(TH abs(z)) $(TH Notes)) 756 * $(TR $(TD (0, 0)) $(TD 0) $(TD )) 757 * $(TR $(TD (NaN, any) or (any, NaN)) $(TD NaN) $(TD )) 758 * $(TR $(TD (Inf, any) or (any, Inf)) $(TD Inf) $(TD )) 759 * $(TR $(TD (a, b)) normal case $(TD hypot(a, b)) $(TD Uses algorithm to prevent overflow/underflow )) 760 * ) 761 * 762 * Params: 763 * z = A complex number of type Complex!T 764 * 765 * Returns: 766 * The absolute value (modulus) of `z` 767 */ 768 T abs(T)(Complex!T z) @safe pure nothrow @nogc 769 { 770 import std.math.algebraic : hypot; 771 return hypot(z.re, z.im); 772 } 773 774 /// 775 @safe pure nothrow unittest 776 { 777 static import core.math; 778 assert(abs(complex(1.0)) == 1.0); 779 assert(abs(complex(0.0, 1.0)) == 1.0); 780 assert(abs(complex(1.0L, -2.0L)) == core.math.sqrt(5.0L)); 781 } 782 783 @safe pure nothrow unittest 784 { 785 { 786 auto x = Complex!float(-5.016556e-20, 0); 787 assert(x.abs == 5.016556e-20f); 788 auto x1 = Complex!float(-5.016556e-20f, 0); 789 assert(x1.abs == 5.016556e-20f); 790 auto x2 = Complex!float(5.016556e-20f, 0); 791 assert(x2.abs == 5.016556e-20f); 792 } 793 { 794 import std.math.traits : isNaN, isInfinity; 795 assert(Complex!double(double.nan, 0).abs.isNaN); 796 assert(Complex!double(double.nan, double.nan).abs.isNaN); 797 assert(Complex!double(double.infinity, 0).abs.isInfinity); 798 assert(Complex!double(0, double.infinity).abs.isInfinity); 799 assert(Complex!double(0, 0).abs == 0); 800 } 801 } 802 803 @safe pure nothrow @nogc unittest 804 { 805 static import core.math; 806 assert(abs(complex(0.0L, -3.2L)) == 3.2L); 807 assert(abs(complex(0.0L, 71.6L)) == 71.6L); 808 assert(abs(complex(-1.0L, 1.0L)) == core.math.sqrt(2.0L)); 809 } 810 811 @safe pure nothrow @nogc unittest 812 { 813 import std.meta : AliasSeq; 814 static foreach (T; AliasSeq!(float, double, real)) 815 {{ 816 static import std.math; 817 Complex!T a = complex(T(-12), T(3)); 818 T b = std.math.hypot(a.re, a.im); 819 assert(std.math.isClose(abs(a), b)); 820 assert(std.math.isClose(abs(-a), b)); 821 }} 822 } 823 824 825 /++ 826 Params: 827 z = A complex number. 828 x = A real number. 829 Returns: The squared modulus of `z`. 830 For genericity, if called on a real number, returns its square. 831 +/ 832 T sqAbs(T)(Complex!T z) @safe pure nothrow @nogc 833 { 834 return z.re*z.re + z.im*z.im; 835 } 836 837 /// 838 @safe pure nothrow unittest 839 { 840 import std.math.operations : isClose; 841 assert(sqAbs(complex(0.0)) == 0.0); 842 assert(sqAbs(complex(1.0)) == 1.0); 843 assert(sqAbs(complex(0.0, 1.0)) == 1.0); 844 assert(isClose(sqAbs(complex(1.0L, -2.0L)), 5.0L)); 845 assert(isClose(sqAbs(complex(-3.0L, 1.0L)), 10.0L)); 846 assert(isClose(sqAbs(complex(1.0f,-1.0f)), 2.0f)); 847 } 848 849 850 /// ditto 851 T sqAbs(T)(const T x) @safe pure nothrow @nogc 852 if (isFloatingPoint!T) 853 { 854 return x*x; 855 } 856 857 @safe pure nothrow unittest 858 { 859 import std.math.operations : isClose; 860 assert(sqAbs(0.0) == 0.0); 861 assert(sqAbs(-1.0) == 1.0); 862 assert(isClose(sqAbs(-3.0L), 9.0L)); 863 assert(isClose(sqAbs(-5.0f), 25.0f)); 864 } 865 866 867 /** 868 Params: z = A complex number. 869 Returns: The argument (or phase) of `z`. 870 */ 871 T arg(T)(Complex!T z) @safe pure nothrow @nogc 872 { 873 import std.math.trigonometry : atan2; 874 return atan2(z.im, z.re); 875 } 876 877 /// 878 @safe pure nothrow unittest 879 { 880 import std.math.constants : PI_2, PI_4; 881 assert(arg(complex(1.0)) == 0.0); 882 assert(arg(complex(0.0L, 1.0L)) == PI_2); 883 assert(arg(complex(1.0L, 1.0L)) == PI_4); 884 } 885 886 887 /** 888 * Extracts the norm of a complex number. 889 * Params: 890 * z = A complex number 891 * Returns: 892 * The squared magnitude of `z`. 893 */ 894 T norm(T)(Complex!T z) @safe pure nothrow @nogc 895 { 896 return z.re * z.re + z.im * z.im; 897 } 898 899 /// 900 @safe pure nothrow @nogc unittest 901 { 902 import std.math.operations : isClose; 903 import std.math.constants : PI; 904 assert(norm(complex(3.0, 4.0)) == 25.0); 905 assert(norm(fromPolar(5.0, 0.0)) == 25.0); 906 assert(isClose(norm(fromPolar(5.0L, PI / 6)), 25.0L)); 907 assert(isClose(norm(fromPolar(5.0L, 13 * PI / 6)), 25.0L)); 908 } 909 910 911 /** 912 Params: z = A complex number. 913 Returns: The complex conjugate of `z`. 914 */ 915 Complex!T conj(T)(Complex!T z) @safe pure nothrow @nogc 916 { 917 return Complex!T(z.re, -z.im); 918 } 919 920 /// 921 @safe pure nothrow unittest 922 { 923 assert(conj(complex(1.0)) == complex(1.0)); 924 assert(conj(complex(1.0, 2.0)) == complex(1.0, -2.0)); 925 } 926 927 @safe pure nothrow @nogc unittest 928 { 929 import std.meta : AliasSeq; 930 static foreach (T; AliasSeq!(float, double, real)) 931 {{ 932 auto c = Complex!T(7, 3L); 933 assert(conj(c) == Complex!T(7, -3L)); 934 auto z = Complex!T(0, -3.2L); 935 assert(conj(z) == -z); 936 }} 937 } 938 939 /** 940 * Returns the projection of `z` onto the Riemann sphere. 941 * Params: 942 * z = A complex number 943 * Returns: 944 * The projection of `z` onto the Riemann sphere. 945 */ 946 Complex!T proj(T)(Complex!T z) 947 { 948 static import std.math; 949 950 if (std.math.isInfinity(z.re) || std.math.isInfinity(z.im)) 951 return Complex!T(T.infinity, std.math.copysign(0.0, z.im)); 952 953 return z; 954 } 955 956 /// 957 @safe pure nothrow unittest 958 { 959 assert(proj(complex(1.0)) == complex(1.0)); 960 assert(proj(complex(double.infinity, 5.0)) == complex(double.infinity, 0.0)); 961 assert(proj(complex(5.0, -double.infinity)) == complex(double.infinity, -0.0)); 962 } 963 964 965 /** 966 Constructs a complex number given its absolute value and argument. 967 Params: 968 modulus = The modulus 969 argument = The argument 970 Returns: The complex number with the given modulus and argument. 971 */ 972 Complex!(CommonType!(T, U)) fromPolar(T, U)(const T modulus, const U argument) 973 @safe pure nothrow @nogc 974 { 975 import core.math : sin, cos; 976 return Complex!(CommonType!(T,U)) 977 (modulus*cos(argument), modulus*sin(argument)); 978 } 979 980 /// 981 @safe pure nothrow unittest 982 { 983 import core.math; 984 import std.math.operations : isClose; 985 import std.math.algebraic : sqrt; 986 import std.math.constants : PI_4; 987 auto z = fromPolar(core.math.sqrt(2.0L), PI_4); 988 assert(isClose(z.re, 1.0L)); 989 assert(isClose(z.im, 1.0L)); 990 } 991 992 version (StdUnittest) 993 { 994 // Helper function for comparing two Complex numbers. 995 int ceqrel(T)(const Complex!T x, const Complex!T y) @safe pure nothrow @nogc 996 { 997 import std.math.operations : feqrel; 998 const r = feqrel(x.re, y.re); 999 const i = feqrel(x.im, y.im); 1000 return r < i ? r : i; 1001 } 1002 } 1003 1004 /** 1005 Trigonometric functions on complex numbers. 1006 1007 Params: z = A complex number. 1008 Returns: The sine, cosine and tangent of `z`, respectively. 1009 */ 1010 Complex!T sin(T)(Complex!T z) @safe pure nothrow @nogc 1011 { 1012 auto cs = expi(z.re); 1013 auto csh = coshisinh(z.im); 1014 return typeof(return)(cs.im * csh.re, cs.re * csh.im); 1015 } 1016 1017 /// 1018 @safe pure nothrow unittest 1019 { 1020 static import core.math; 1021 assert(sin(complex(0.0)) == 0.0); 1022 assert(sin(complex(2.0, 0)) == core.math.sin(2.0)); 1023 } 1024 1025 @safe pure nothrow unittest 1026 { 1027 static import core.math; 1028 assert(ceqrel(sin(complex(2.0L, 0)), complex(core.math.sin(2.0L))) >= real.mant_dig - 1); 1029 } 1030 1031 /// ditto 1032 Complex!T cos(T)(Complex!T z) @safe pure nothrow @nogc 1033 { 1034 auto cs = expi(z.re); 1035 auto csh = coshisinh(z.im); 1036 return typeof(return)(cs.re * csh.re, - cs.im * csh.im); 1037 } 1038 1039 /// 1040 @safe pure nothrow unittest 1041 { 1042 static import core.math; 1043 static import std.math; 1044 assert(cos(complex(0.0)) == 1.0); 1045 assert(cos(complex(1.3, 0.0)) == core.math.cos(1.3)); 1046 assert(cos(complex(0.0, 5.2)) == std.math.cosh(5.2)); 1047 } 1048 1049 @safe pure nothrow unittest 1050 { 1051 static import core.math; 1052 static import std.math; 1053 assert(ceqrel(cos(complex(0, 5.2L)), complex(std.math.cosh(5.2L), 0.0L)) >= real.mant_dig - 1); 1054 assert(ceqrel(cos(complex(1.3L)), complex(core.math.cos(1.3L))) >= real.mant_dig - 1); 1055 } 1056 1057 /// ditto 1058 Complex!T tan(T)(Complex!T z) @safe pure nothrow @nogc 1059 { 1060 return sin(z) / cos(z); 1061 } 1062 1063 /// 1064 @safe pure nothrow @nogc unittest 1065 { 1066 static import std.math; 1067 1068 int ceqrel(T)(const Complex!T x, const Complex!T y) @safe pure nothrow @nogc 1069 { 1070 import std.math.operations : feqrel; 1071 const r = feqrel(x.re, y.re); 1072 const i = feqrel(x.im, y.im); 1073 return r < i ? r : i; 1074 } 1075 assert(ceqrel(tan(complex(1.0, 0.0)), complex(std.math.tan(1.0), 0.0)) >= double.mant_dig - 2); 1076 assert(ceqrel(tan(complex(0.0, 1.0)), complex(0.0, std.math.tanh(1.0))) >= double.mant_dig - 2); 1077 } 1078 1079 /** 1080 Inverse trigonometric functions on complex numbers. 1081 1082 Params: z = A complex number. 1083 Returns: The arcsine, arccosine and arctangent of `z`, respectively. 1084 */ 1085 Complex!T asin(T)(Complex!T z) @safe pure nothrow @nogc 1086 { 1087 auto ash = asinh(Complex!T(-z.im, z.re)); 1088 return Complex!T(ash.im, -ash.re); 1089 } 1090 1091 /// 1092 @safe pure nothrow unittest 1093 { 1094 import std.math.operations : isClose; 1095 import std.math.constants : PI; 1096 assert(asin(complex(0.0)) == 0.0); 1097 assert(isClose(asin(complex(0.5L)), PI / 6)); 1098 } 1099 1100 @safe pure nothrow unittest 1101 { 1102 import std.math.operations : isClose; 1103 import std.math.constants : PI; 1104 version (DigitalMars) {} else // Disabled because of https://issues.dlang.org/show_bug.cgi?id=21376 1105 assert(isClose(asin(complex(0.5f)), float(PI) / 6)); 1106 } 1107 1108 /// ditto 1109 Complex!T acos(T)(Complex!T z) @safe pure nothrow @nogc 1110 { 1111 static import std.math; 1112 auto as = asin(z); 1113 return Complex!T(T(std.math.PI_2) - as.re, as.im); 1114 } 1115 1116 /// 1117 @safe pure nothrow unittest 1118 { 1119 import std.math.operations : isClose; 1120 import std.math.constants : PI; 1121 import std.math.trigonometry : std_math_acos = acos; 1122 assert(acos(complex(0.0)) == std_math_acos(0.0)); 1123 assert(isClose(acos(complex(0.5L)), PI / 3)); 1124 } 1125 1126 @safe pure nothrow unittest 1127 { 1128 import std.math.operations : isClose; 1129 import std.math.constants : PI; 1130 version (DigitalMars) {} else // Disabled because of https://issues.dlang.org/show_bug.cgi?id=21376 1131 assert(isClose(acos(complex(0.5f)), float(PI) / 3)); 1132 } 1133 1134 /// ditto 1135 Complex!T atan(T)(Complex!T z) @safe pure nothrow @nogc 1136 { 1137 static import std.math; 1138 const T re2 = z.re * z.re; 1139 const T x = 1 - re2 - z.im * z.im; 1140 1141 T num = z.im + 1; 1142 T den = z.im - 1; 1143 1144 num = re2 + num * num; 1145 den = re2 + den * den; 1146 1147 return Complex!T(T(0.5) * std.math.atan2(2 * z.re, x), 1148 T(0.25) * std.math.log(num / den)); 1149 } 1150 1151 /// 1152 @safe pure nothrow @nogc unittest 1153 { 1154 import std.math.operations : isClose; 1155 import std.math.constants : PI; 1156 assert(atan(complex(0.0)) == 0.0); 1157 assert(isClose(atan(sqrt(complex(3.0L))), PI / 3)); 1158 assert(isClose(atan(sqrt(complex(3.0f))), float(PI) / 3)); 1159 } 1160 1161 /** 1162 Hyperbolic trigonometric functions on complex numbers. 1163 1164 Params: z = A complex number. 1165 Returns: The hyperbolic sine, cosine and tangent of `z`, respectively. 1166 */ 1167 Complex!T sinh(T)(Complex!T z) @safe pure nothrow @nogc 1168 { 1169 static import core.math, std.math; 1170 return Complex!T(std.math.sinh(z.re) * core.math.cos(z.im), 1171 std.math.cosh(z.re) * core.math.sin(z.im)); 1172 } 1173 1174 /// 1175 @safe pure nothrow unittest 1176 { 1177 static import std.math; 1178 assert(sinh(complex(0.0)) == 0.0); 1179 assert(sinh(complex(1.0L)) == std.math.sinh(1.0L)); 1180 assert(sinh(complex(1.0f)) == std.math.sinh(1.0f)); 1181 } 1182 1183 /// ditto 1184 Complex!T cosh(T)(Complex!T z) @safe pure nothrow @nogc 1185 { 1186 static import core.math, std.math; 1187 return Complex!T(std.math.cosh(z.re) * core.math.cos(z.im), 1188 std.math.sinh(z.re) * core.math.sin(z.im)); 1189 } 1190 1191 /// 1192 @safe pure nothrow unittest 1193 { 1194 static import std.math; 1195 assert(cosh(complex(0.0)) == 1.0); 1196 assert(cosh(complex(1.0L)) == std.math.cosh(1.0L)); 1197 assert(cosh(complex(1.0f)) == std.math.cosh(1.0f)); 1198 } 1199 1200 /// ditto 1201 Complex!T tanh(T)(Complex!T z) @safe pure nothrow @nogc 1202 { 1203 return sinh(z) / cosh(z); 1204 } 1205 1206 /// 1207 @safe pure nothrow @nogc unittest 1208 { 1209 import std.math.operations : isClose; 1210 import std.math.trigonometry : std_math_tanh = tanh; 1211 assert(tanh(complex(0.0)) == 0.0); 1212 assert(isClose(tanh(complex(1.0L)), std_math_tanh(1.0L))); 1213 assert(isClose(tanh(complex(1.0f)), std_math_tanh(1.0f))); 1214 } 1215 1216 /** 1217 Inverse hyperbolic trigonometric functions on complex numbers. 1218 1219 Params: z = A complex number. 1220 Returns: The hyperbolic arcsine, arccosine and arctangent of `z`, respectively. 1221 */ 1222 Complex!T asinh(T)(Complex!T z) @safe pure nothrow @nogc 1223 { 1224 auto t = Complex!T((z.re - z.im) * (z.re + z.im) + 1, 2 * z.re * z.im); 1225 return log(sqrt(t) + z); 1226 } 1227 1228 /// 1229 @safe pure nothrow unittest 1230 { 1231 import std.math.operations : isClose; 1232 import std.math.trigonometry : std_math_asinh = asinh; 1233 assert(asinh(complex(0.0)) == 0.0); 1234 assert(isClose(asinh(complex(1.0L)), std_math_asinh(1.0L))); 1235 assert(isClose(asinh(complex(1.0f)), std_math_asinh(1.0f))); 1236 } 1237 1238 /// ditto 1239 Complex!T acosh(T)(Complex!T z) @safe pure nothrow @nogc 1240 { 1241 return 2 * log(sqrt(T(0.5) * (z + 1)) + sqrt(T(0.5) * (z - 1))); 1242 } 1243 1244 /// 1245 @safe pure nothrow unittest 1246 { 1247 import std.math.operations : isClose; 1248 import std.math.trigonometry : std_math_acosh = acosh; 1249 assert(acosh(complex(1.0)) == 0.0); 1250 assert(isClose(acosh(complex(3.0L)), std_math_acosh(3.0L))); 1251 assert(isClose(acosh(complex(3.0f)), std_math_acosh(3.0f))); 1252 } 1253 1254 /// ditto 1255 Complex!T atanh(T)(Complex!T z) @safe pure nothrow @nogc 1256 { 1257 static import std.math; 1258 const T im2 = z.im * z.im; 1259 const T x = 1 - im2 - z.re * z.re; 1260 1261 T num = 1 + z.re; 1262 T den = 1 - z.re; 1263 1264 num = im2 + num * num; 1265 den = im2 + den * den; 1266 1267 return Complex!T(T(0.25) * (std.math.log(num) - std.math.log(den)), 1268 T(0.5) * std.math.atan2(2 * z.im, x)); 1269 } 1270 1271 /// 1272 @safe pure nothrow @nogc unittest 1273 { 1274 import std.math.operations : isClose; 1275 import std.math.trigonometry : std_math_atanh = atanh; 1276 assert(atanh(complex(0.0)) == 0.0); 1277 assert(isClose(atanh(complex(0.5L)), std_math_atanh(0.5L))); 1278 assert(isClose(atanh(complex(0.5f)), std_math_atanh(0.5f))); 1279 } 1280 1281 /** 1282 Params: y = A real number. 1283 Returns: The value of cos(y) + i sin(y). 1284 1285 Note: 1286 `expi` is included here for convenience and for easy migration of code. 1287 */ 1288 Complex!real expi(real y) @trusted pure nothrow @nogc 1289 { 1290 import core.math : cos, sin; 1291 return Complex!real(cos(y), sin(y)); 1292 } 1293 1294 /// 1295 @safe pure nothrow unittest 1296 { 1297 import core.math : cos, sin; 1298 assert(expi(0.0L) == 1.0L); 1299 assert(expi(1.3e5L) == complex(cos(1.3e5L), sin(1.3e5L))); 1300 } 1301 1302 /** 1303 Params: y = A real number. 1304 Returns: The value of cosh(y) + i sinh(y) 1305 1306 Note: 1307 `coshisinh` is included here for convenience and for easy migration of code. 1308 */ 1309 Complex!real coshisinh(real y) @safe pure nothrow @nogc 1310 { 1311 static import core.math; 1312 static import std.math; 1313 if (core.math.fabs(y) <= 0.5) 1314 return Complex!real(std.math.cosh(y), std.math.sinh(y)); 1315 else 1316 { 1317 auto z = std.math.exp(y); 1318 auto zi = 0.5 / z; 1319 z = 0.5 * z; 1320 return Complex!real(z + zi, z - zi); 1321 } 1322 } 1323 1324 /// 1325 @safe pure nothrow @nogc unittest 1326 { 1327 import std.math.trigonometry : cosh, sinh; 1328 assert(coshisinh(3.0L) == complex(cosh(3.0L), sinh(3.0L))); 1329 } 1330 1331 /** 1332 Params: z = A complex number. 1333 Returns: The square root of `z`. 1334 */ 1335 Complex!T sqrt(T)(Complex!T z) @safe pure nothrow @nogc 1336 { 1337 static import core.math; 1338 typeof(return) c; 1339 real x,y,w,r; 1340 1341 if (z == 0) 1342 { 1343 c = typeof(return)(0, 0); 1344 } 1345 else 1346 { 1347 real z_re = z.re; 1348 real z_im = z.im; 1349 1350 x = core.math.fabs(z_re); 1351 y = core.math.fabs(z_im); 1352 if (x >= y) 1353 { 1354 r = y / x; 1355 w = core.math.sqrt(x) 1356 * core.math.sqrt(0.5 * (1 + core.math.sqrt(1 + r * r))); 1357 } 1358 else 1359 { 1360 r = x / y; 1361 w = core.math.sqrt(y) 1362 * core.math.sqrt(0.5 * (r + core.math.sqrt(1 + r * r))); 1363 } 1364 1365 if (z_re >= 0) 1366 { 1367 c = typeof(return)(w, z_im / (w + w)); 1368 } 1369 else 1370 { 1371 if (z_im < 0) 1372 w = -w; 1373 c = typeof(return)(z_im / (w + w), w); 1374 } 1375 } 1376 return c; 1377 } 1378 1379 /// 1380 @safe pure nothrow unittest 1381 { 1382 static import core.math; 1383 assert(sqrt(complex(0.0)) == 0.0); 1384 assert(sqrt(complex(1.0L, 0)) == core.math.sqrt(1.0L)); 1385 assert(sqrt(complex(-1.0L, 0)) == complex(0, 1.0L)); 1386 assert(sqrt(complex(-8.0, -6.0)) == complex(1.0, -3.0)); 1387 } 1388 1389 @safe pure nothrow unittest 1390 { 1391 import std.math.operations : isClose; 1392 1393 auto c1 = complex(1.0, 1.0); 1394 auto c2 = Complex!double(0.5, 2.0); 1395 1396 auto c1s = sqrt(c1); 1397 assert(isClose(c1s.re, 1.09868411347)); 1398 assert(isClose(c1s.im, 0.455089860562)); 1399 1400 auto c2s = sqrt(c2); 1401 assert(isClose(c2s.re, 1.13171392428)); 1402 assert(isClose(c2s.im, 0.883615530876)); 1403 } 1404 1405 // support %f formatting of complex numbers 1406 // https://issues.dlang.org/show_bug.cgi?id=10881 1407 @safe unittest 1408 { 1409 import std.format : format; 1410 1411 auto x = complex(1.2, 3.4); 1412 assert(format("%.2f", x) == "1.20+3.40i"); 1413 1414 auto y = complex(1.2, -3.4); 1415 assert(format("%.2f", y) == "1.20-3.40i"); 1416 } 1417 1418 @safe unittest 1419 { 1420 // Test wide string formatting 1421 import std.format.write : formattedWrite; 1422 wstring wformat(T)(string format, Complex!T c) 1423 { 1424 import std.array : appender; 1425 auto w = appender!wstring(); 1426 auto n = formattedWrite(w, format, c); 1427 return w.data; 1428 } 1429 1430 auto x = complex(1.2, 3.4); 1431 assert(wformat("%.2f", x) == "1.20+3.40i"w); 1432 } 1433 1434 @safe unittest 1435 { 1436 // Test ease of use (vanilla toString() should be supported) 1437 assert(complex(1.2, 3.4).toString() == "1.2+3.4i"); 1438 } 1439 1440 @safe pure nothrow @nogc unittest 1441 { 1442 auto c = complex(3.0L, 4.0L); 1443 c = sqrt(c); 1444 assert(c.re == 2.0L); 1445 assert(c.im == 1.0L); 1446 } 1447 1448 /** 1449 * Calculates e$(SUPERSCRIPT x). 1450 * Params: 1451 * x = A complex number 1452 * Returns: 1453 * The complex base e exponential of `x` 1454 * 1455 * $(TABLE_SV 1456 * $(TR $(TH x) $(TH exp(x))) 1457 * $(TR $(TD ($(PLUSMN)0, +0)) $(TD (1, +0))) 1458 * $(TR $(TD (any, +$(INFIN))) $(TD ($(NAN), $(NAN)))) 1459 * $(TR $(TD (any, $(NAN)) $(TD ($(NAN), $(NAN))))) 1460 * $(TR $(TD (+$(INFIN), +0)) $(TD (+$(INFIN), +0))) 1461 * $(TR $(TD (-$(INFIN), any)) $(TD ($(PLUSMN)0, cis(x.im)))) 1462 * $(TR $(TD (+$(INFIN), any)) $(TD ($(PLUSMN)$(INFIN), cis(x.im)))) 1463 * $(TR $(TD (-$(INFIN), +$(INFIN))) $(TD ($(PLUSMN)0, $(PLUSMN)0))) 1464 * $(TR $(TD (+$(INFIN), +$(INFIN))) $(TD ($(PLUSMN)$(INFIN), $(NAN)))) 1465 * $(TR $(TD (-$(INFIN), $(NAN))) $(TD ($(PLUSMN)0, $(PLUSMN)0))) 1466 * $(TR $(TD (+$(INFIN), $(NAN))) $(TD ($(PLUSMN)$(INFIN), $(NAN)))) 1467 * $(TR $(TD ($(NAN), +0)) $(TD ($(NAN), +0))) 1468 * $(TR $(TD ($(NAN), any)) $(TD ($(NAN), $(NAN)))) 1469 * $(TR $(TD ($(NAN), $(NAN))) $(TD ($(NAN), $(NAN)))) 1470 * ) 1471 */ 1472 Complex!T exp(T)(Complex!T x) @trusted pure nothrow @nogc // TODO: @safe 1473 { 1474 static import std.math; 1475 1476 // Handle special cases explicitly here, as fromPolar will otherwise 1477 // cause them to return Complex!T(NaN, NaN), or with the wrong sign. 1478 if (std.math.isInfinity(x.re)) 1479 { 1480 if (std.math.isNaN(x.im)) 1481 { 1482 if (std.math.signbit(x.re)) 1483 return Complex!T(0, std.math.copysign(0, x.im)); 1484 else 1485 return x; 1486 } 1487 if (std.math.isInfinity(x.im)) 1488 { 1489 if (std.math.signbit(x.re)) 1490 return Complex!T(0, std.math.copysign(0, x.im)); 1491 else 1492 return Complex!T(T.infinity, -T.nan); 1493 } 1494 if (x.im == 0.0) 1495 { 1496 if (std.math.signbit(x.re)) 1497 return Complex!T(0.0); 1498 else 1499 return Complex!T(T.infinity); 1500 } 1501 } 1502 if (std.math.isNaN(x.re)) 1503 { 1504 if (std.math.isNaN(x.im) || std.math.isInfinity(x.im)) 1505 return Complex!T(T.nan, T.nan); 1506 if (x.im == 0.0) 1507 return x; 1508 } 1509 if (x.re == 0.0) 1510 { 1511 if (std.math.isNaN(x.im) || std.math.isInfinity(x.im)) 1512 return Complex!T(T.nan, T.nan); 1513 if (x.im == 0.0) 1514 return Complex!T(1.0, 0.0); 1515 } 1516 1517 return fromPolar!(T, T)(std.math.exp(x.re), x.im); 1518 } 1519 1520 /// 1521 @safe pure nothrow @nogc unittest 1522 { 1523 import std.math.operations : isClose; 1524 import std.math.constants : PI; 1525 1526 assert(exp(complex(0.0, 0.0)) == complex(1.0, 0.0)); 1527 1528 auto a = complex(2.0, 1.0); 1529 assert(exp(conj(a)) == conj(exp(a))); 1530 1531 auto b = exp(complex(0.0L, 1.0L) * PI); 1532 assert(isClose(b, -1.0L, 0.0, 1e-15)); 1533 } 1534 1535 @safe pure nothrow @nogc unittest 1536 { 1537 import std.math.traits : isNaN, isInfinity; 1538 1539 auto a = exp(complex(0.0, double.infinity)); 1540 assert(a.re.isNaN && a.im.isNaN); 1541 auto b = exp(complex(0.0, double.infinity)); 1542 assert(b.re.isNaN && b.im.isNaN); 1543 auto c = exp(complex(0.0, double.nan)); 1544 assert(c.re.isNaN && c.im.isNaN); 1545 1546 auto d = exp(complex(+double.infinity, 0.0)); 1547 assert(d == complex(double.infinity, 0.0)); 1548 auto e = exp(complex(-double.infinity, 0.0)); 1549 assert(e == complex(0.0)); 1550 auto f = exp(complex(-double.infinity, 1.0)); 1551 assert(f == complex(0.0)); 1552 auto g = exp(complex(+double.infinity, 1.0)); 1553 assert(g == complex(double.infinity, double.infinity)); 1554 auto h = exp(complex(-double.infinity, +double.infinity)); 1555 assert(h == complex(0.0)); 1556 auto i = exp(complex(+double.infinity, +double.infinity)); 1557 assert(i.re.isInfinity && i.im.isNaN); 1558 auto j = exp(complex(-double.infinity, double.nan)); 1559 assert(j == complex(0.0)); 1560 auto k = exp(complex(+double.infinity, double.nan)); 1561 assert(k.re.isInfinity && k.im.isNaN); 1562 1563 auto l = exp(complex(double.nan, 0)); 1564 assert(l.re.isNaN && l.im == 0.0); 1565 auto m = exp(complex(double.nan, 1)); 1566 assert(m.re.isNaN && m.im.isNaN); 1567 auto n = exp(complex(double.nan, double.nan)); 1568 assert(n.re.isNaN && n.im.isNaN); 1569 } 1570 1571 @safe pure nothrow @nogc unittest 1572 { 1573 import std.math.constants : PI; 1574 import std.math.operations : isClose; 1575 1576 auto a = exp(complex(0.0, -PI)); 1577 assert(isClose(a, -1.0, 0.0, 1e-15)); 1578 1579 auto b = exp(complex(0.0, -2.0 * PI / 3.0)); 1580 assert(isClose(b, complex(-0.5L, -0.866025403784438646763L))); 1581 1582 auto c = exp(complex(0.0, PI / 3.0)); 1583 assert(isClose(c, complex(0.5L, 0.866025403784438646763L))); 1584 1585 auto d = exp(complex(0.0, 2.0 * PI / 3.0)); 1586 assert(isClose(d, complex(-0.5L, 0.866025403784438646763L))); 1587 1588 auto e = exp(complex(0.0, PI)); 1589 assert(isClose(e, -1.0, 0.0, 1e-15)); 1590 } 1591 1592 /** 1593 * Calculate the natural logarithm of x. 1594 * The branch cut is along the negative axis. 1595 * Params: 1596 * x = A complex number 1597 * Returns: 1598 * The complex natural logarithm of `x` 1599 * 1600 * $(TABLE_SV 1601 * $(TR $(TH x) $(TH log(x))) 1602 * $(TR $(TD (-0, +0)) $(TD (-$(INFIN), $(PI)))) 1603 * $(TR $(TD (+0, +0)) $(TD (-$(INFIN), +0))) 1604 * $(TR $(TD (any, +$(INFIN))) $(TD (+$(INFIN), $(PI)/2))) 1605 * $(TR $(TD (any, $(NAN))) $(TD ($(NAN), $(NAN)))) 1606 * $(TR $(TD (-$(INFIN), any)) $(TD (+$(INFIN), $(PI)))) 1607 * $(TR $(TD (+$(INFIN), any)) $(TD (+$(INFIN), +0))) 1608 * $(TR $(TD (-$(INFIN), +$(INFIN))) $(TD (+$(INFIN), 3$(PI)/4))) 1609 * $(TR $(TD (+$(INFIN), +$(INFIN))) $(TD (+$(INFIN), $(PI)/4))) 1610 * $(TR $(TD ($(PLUSMN)$(INFIN), $(NAN))) $(TD (+$(INFIN), $(NAN)))) 1611 * $(TR $(TD ($(NAN), any)) $(TD ($(NAN), $(NAN)))) 1612 * $(TR $(TD ($(NAN), +$(INFIN))) $(TD (+$(INFIN), $(NAN)))) 1613 * $(TR $(TD ($(NAN), $(NAN))) $(TD ($(NAN), $(NAN)))) 1614 * ) 1615 */ 1616 Complex!T log(T)(Complex!T x) @safe pure nothrow @nogc 1617 { 1618 static import std.math; 1619 1620 // Handle special cases explicitly here for better accuracy. 1621 // The order here is important, so that the correct path is chosen. 1622 if (std.math.isNaN(x.re)) 1623 { 1624 if (std.math.isInfinity(x.im)) 1625 return Complex!T(T.infinity, T.nan); 1626 else 1627 return Complex!T(T.nan, T.nan); 1628 } 1629 if (std.math.isInfinity(x.re)) 1630 { 1631 if (std.math.isNaN(x.im)) 1632 return Complex!T(T.infinity, T.nan); 1633 else if (std.math.isInfinity(x.im)) 1634 { 1635 if (std.math.signbit(x.re)) 1636 return Complex!T(T.infinity, std.math.copysign(3.0 * std.math.PI_4, x.im)); 1637 else 1638 return Complex!T(T.infinity, std.math.copysign(std.math.PI_4, x.im)); 1639 } 1640 else 1641 { 1642 if (std.math.signbit(x.re)) 1643 return Complex!T(T.infinity, std.math.copysign(std.math.PI, x.im)); 1644 else 1645 return Complex!T(T.infinity, std.math.copysign(0.0, x.im)); 1646 } 1647 } 1648 if (std.math.isNaN(x.im)) 1649 return Complex!T(T.nan, T.nan); 1650 if (std.math.isInfinity(x.im)) 1651 return Complex!T(T.infinity, std.math.copysign(std.math.PI_2, x.im)); 1652 if (x.re == 0.0 && x.im == 0.0) 1653 { 1654 if (std.math.signbit(x.re)) 1655 return Complex!T(-T.infinity, std.math.copysign(std.math.PI, x.im)); 1656 else 1657 return Complex!T(-T.infinity, std.math.copysign(0.0, x.im)); 1658 } 1659 1660 return Complex!T(std.math.log(abs(x)), arg(x)); 1661 } 1662 1663 /// 1664 @safe pure nothrow @nogc unittest 1665 { 1666 import core.math : sqrt; 1667 import std.math.constants : PI; 1668 import std.math.operations : isClose; 1669 1670 auto a = complex(2.0, 1.0); 1671 assert(log(conj(a)) == conj(log(a))); 1672 1673 auto b = 2.0 * log10(complex(0.0, 1.0)); 1674 auto c = 4.0 * log10(complex(sqrt(2.0) / 2, sqrt(2.0) / 2)); 1675 assert(isClose(b, c, 0.0, 1e-15)); 1676 1677 assert(log(complex(-1.0L, 0.0L)) == complex(0.0L, PI)); 1678 assert(log(complex(-1.0L, -0.0L)) == complex(0.0L, -PI)); 1679 } 1680 1681 @safe pure nothrow @nogc unittest 1682 { 1683 import std.math.traits : isNaN, isInfinity; 1684 import std.math.constants : PI, PI_2, PI_4; 1685 1686 auto a = log(complex(-0.0L, 0.0L)); 1687 assert(a == complex(-real.infinity, PI)); 1688 auto b = log(complex(0.0L, 0.0L)); 1689 assert(b == complex(-real.infinity, +0.0L)); 1690 auto c = log(complex(1.0L, real.infinity)); 1691 assert(c == complex(real.infinity, PI_2)); 1692 auto d = log(complex(1.0L, real.nan)); 1693 assert(d.re.isNaN && d.im.isNaN); 1694 1695 auto e = log(complex(-real.infinity, 1.0L)); 1696 assert(e == complex(real.infinity, PI)); 1697 auto f = log(complex(real.infinity, 1.0L)); 1698 assert(f == complex(real.infinity, 0.0L)); 1699 auto g = log(complex(-real.infinity, real.infinity)); 1700 assert(g == complex(real.infinity, 3.0 * PI_4)); 1701 auto h = log(complex(real.infinity, real.infinity)); 1702 assert(h == complex(real.infinity, PI_4)); 1703 auto i = log(complex(real.infinity, real.nan)); 1704 assert(i.re.isInfinity && i.im.isNaN); 1705 1706 auto j = log(complex(real.nan, 1.0L)); 1707 assert(j.re.isNaN && j.im.isNaN); 1708 auto k = log(complex(real.nan, real.infinity)); 1709 assert(k.re.isInfinity && k.im.isNaN); 1710 auto l = log(complex(real.nan, real.nan)); 1711 assert(l.re.isNaN && l.im.isNaN); 1712 } 1713 1714 @safe pure nothrow @nogc unittest 1715 { 1716 import std.math.constants : PI; 1717 import std.math.operations : isClose; 1718 1719 auto a = log(fromPolar(1.0, PI / 6.0)); 1720 assert(isClose(a, complex(0.0L, 0.523598775598298873077L), 0.0, 1e-15)); 1721 1722 auto b = log(fromPolar(1.0, PI / 3.0)); 1723 assert(isClose(b, complex(0.0L, 1.04719755119659774615L), 0.0, 1e-15)); 1724 1725 auto c = log(fromPolar(1.0, PI / 2.0)); 1726 assert(isClose(c, complex(0.0L, 1.57079632679489661923L), 0.0, 1e-15)); 1727 1728 auto d = log(fromPolar(1.0, 2.0 * PI / 3.0)); 1729 assert(isClose(d, complex(0.0L, 2.09439510239319549230L), 0.0, 1e-15)); 1730 1731 auto e = log(fromPolar(1.0, 5.0 * PI / 6.0)); 1732 assert(isClose(e, complex(0.0L, 2.61799387799149436538L), 0.0, 1e-15)); 1733 1734 auto f = log(complex(-1.0L, 0.0L)); 1735 assert(isClose(f, complex(0.0L, PI), 0.0, 1e-15)); 1736 } 1737 1738 /** 1739 * Calculate the base-10 logarithm of x. 1740 * Params: 1741 * x = A complex number 1742 * Returns: 1743 * The complex base 10 logarithm of `x` 1744 */ 1745 Complex!T log10(T)(Complex!T x) @safe pure nothrow @nogc 1746 { 1747 import std.math.constants : LN10; 1748 1749 return log(x) / Complex!T(LN10); 1750 } 1751 1752 /// 1753 @safe pure nothrow @nogc unittest 1754 { 1755 import core.math : sqrt; 1756 import std.math.constants : LN10, PI; 1757 import std.math.operations : isClose; 1758 1759 auto a = complex(2.0, 1.0); 1760 assert(log10(a) == log(a) / log(complex(10.0))); 1761 1762 auto b = log10(complex(0.0, 1.0)) * 2.0; 1763 auto c = log10(complex(sqrt(2.0) / 2, sqrt(2.0) / 2)) * 4.0; 1764 assert(isClose(b, c, 0.0, 1e-15)); 1765 } 1766 1767 @safe pure nothrow @nogc unittest 1768 { 1769 import std.math.constants : LN10, PI; 1770 import std.math.operations : isClose; 1771 1772 auto a = log10(fromPolar(1.0, PI / 6.0)); 1773 assert(isClose(a, complex(0.0L, 0.227396058973640224580L), 0.0, 1e-15)); 1774 1775 auto b = log10(fromPolar(1.0, PI / 3.0)); 1776 assert(isClose(b, complex(0.0L, 0.454792117947280449161L), 0.0, 1e-15)); 1777 1778 auto c = log10(fromPolar(1.0, PI / 2.0)); 1779 assert(isClose(c, complex(0.0L, 0.682188176920920673742L), 0.0, 1e-15)); 1780 1781 auto d = log10(fromPolar(1.0, 2.0 * PI / 3.0)); 1782 assert(isClose(d, complex(0.0L, 0.909584235894560898323L), 0.0, 1e-15)); 1783 1784 auto e = log10(fromPolar(1.0, 5.0 * PI / 6.0)); 1785 assert(isClose(e, complex(0.0L, 1.13698029486820112290L), 0.0, 1e-15)); 1786 1787 auto f = log10(complex(-1.0L, 0.0L)); 1788 assert(isClose(f, complex(0.0L, 1.36437635384184134748L), 0.0, 1e-15)); 1789 1790 assert(ceqrel(log10(complex(-100.0L, 0.0L)), complex(2.0L, PI / LN10)) >= real.mant_dig - 1); 1791 assert(ceqrel(log10(complex(-100.0L, -0.0L)), complex(2.0L, -PI / LN10)) >= real.mant_dig - 1); 1792 } 1793 1794 /** 1795 * Calculates x$(SUPERSCRIPT n). 1796 * The branch cut is on the negative axis. 1797 * Params: 1798 * x = base 1799 * n = exponent 1800 * Returns: 1801 * `x` raised to the power of `n` 1802 */ 1803 Complex!T pow(T, Int)(Complex!T x, const Int n) @safe pure nothrow @nogc 1804 if (isIntegral!Int) 1805 { 1806 alias UInt = Unsigned!(Unqual!Int); 1807 1808 UInt m = (n < 0) ? -cast(UInt) n : n; 1809 Complex!T y = (m % 2) ? x : Complex!T(1); 1810 1811 while (m >>= 1) 1812 { 1813 x *= x; 1814 if (m % 2) 1815 y *= x; 1816 } 1817 1818 return (n < 0) ? Complex!T(1) / y : y; 1819 } 1820 1821 /// 1822 @safe pure nothrow @nogc unittest 1823 { 1824 import std.math.operations : isClose; 1825 1826 auto a = complex(1.0, 2.0); 1827 assert(pow(a, 2) == a * a); 1828 assert(pow(a, 3) == a * a * a); 1829 assert(pow(a, -2) == 1.0 / (a * a)); 1830 assert(isClose(pow(a, -3), 1.0 / (a * a * a))); 1831 } 1832 1833 /// ditto 1834 Complex!T pow(T)(Complex!T x, const T n) @trusted pure nothrow @nogc 1835 { 1836 static import std.math; 1837 1838 if (x == 0.0) 1839 return Complex!T(0.0); 1840 1841 if (x.im == 0 && x.re > 0.0) 1842 return Complex!T(std.math.pow(x.re, n)); 1843 1844 Complex!T t = log(x); 1845 return fromPolar!(T, T)(std.math.exp(n * t.re), n * t.im); 1846 } 1847 1848 /// 1849 @safe pure nothrow @nogc unittest 1850 { 1851 import std.math.operations : isClose; 1852 assert(pow(complex(0.0), 2.0) == complex(0.0)); 1853 assert(pow(complex(5.0), 2.0) == complex(25.0)); 1854 1855 auto a = pow(complex(-1.0, 0.0), 0.5); 1856 assert(isClose(a, complex(0.0, +1.0), 0.0, 1e-16)); 1857 1858 auto b = pow(complex(-1.0, -0.0), 0.5); 1859 assert(isClose(b, complex(0.0, -1.0), 0.0, 1e-16)); 1860 } 1861 1862 /// ditto 1863 Complex!T pow(T)(Complex!T x, Complex!T y) @trusted pure nothrow @nogc 1864 { 1865 return (x == 0) ? Complex!T(0) : exp(y * log(x)); 1866 } 1867 1868 /// 1869 @safe pure nothrow @nogc unittest 1870 { 1871 import std.math.operations : isClose; 1872 import std.math.exponential : exp; 1873 import std.math.constants : PI; 1874 auto a = complex(0.0); 1875 auto b = complex(2.0); 1876 assert(pow(a, b) == complex(0.0)); 1877 1878 auto c = complex(0.0L, 1.0L); 1879 assert(isClose(pow(c, c), exp((-PI) / 2))); 1880 } 1881 1882 /// ditto 1883 Complex!T pow(T)(const T x, Complex!T n) @trusted pure nothrow @nogc 1884 { 1885 static import std.math; 1886 1887 return (x > 0.0) 1888 ? fromPolar!(T, T)(std.math.pow(x, n.re), n.im * std.math.log(x)) 1889 : pow(Complex!T(x), n); 1890 } 1891 1892 /// 1893 @safe pure nothrow @nogc unittest 1894 { 1895 import std.math.operations : isClose; 1896 assert(pow(2.0, complex(0.0)) == complex(1.0)); 1897 assert(pow(2.0, complex(5.0)) == complex(32.0)); 1898 1899 auto a = pow(-2.0, complex(-1.0)); 1900 assert(isClose(a, complex(-0.5), 0.0, 1e-16)); 1901 1902 auto b = pow(-0.5, complex(-1.0)); 1903 assert(isClose(b, complex(-2.0), 0.0, 1e-15)); 1904 } 1905 1906 @safe pure nothrow @nogc unittest 1907 { 1908 import std.math.constants : PI; 1909 import std.math.operations : isClose; 1910 1911 auto a = pow(complex(3.0, 4.0), 2); 1912 assert(isClose(a, complex(-7.0, 24.0))); 1913 1914 auto b = pow(complex(3.0, 4.0), PI); 1915 assert(ceqrel(b, complex(-152.91512205297134, 35.547499631917738)) >= double.mant_dig - 3); 1916 1917 auto c = pow(complex(3.0, 4.0), complex(-2.0, 1.0)); 1918 assert(ceqrel(c, complex(0.015351734187477306, -0.0038407695456661503)) >= double.mant_dig - 3); 1919 1920 auto d = pow(PI, complex(2.0, -1.0)); 1921 assert(ceqrel(d, complex(4.0790296880118296, -8.9872469554541869)) >= double.mant_dig - 1); 1922 1923 auto e = complex(2.0); 1924 assert(ceqrel(pow(e, 3), exp(3 * log(e))) >= double.mant_dig - 1); 1925 } 1926 1927 @safe pure nothrow @nogc unittest 1928 { 1929 import std.meta : AliasSeq; 1930 import std.math.traits : floatTraits, RealFormat; 1931 static foreach (T; AliasSeq!(float, double, real)) 1932 {{ 1933 static if (floatTraits!T.realFormat == RealFormat.ibmExtended) 1934 { 1935 /* For IBM real, epsilon is too small (since 1.0 plus any double is 1936 representable) to be able to expect results within epsilon * 100. */ 1937 } 1938 else 1939 { 1940 T eps = T.epsilon * 100; 1941 1942 T a = -1.0; 1943 T b = 0.5; 1944 Complex!T ref1 = pow(complex(a), complex(b)); 1945 Complex!T res1 = pow(a, complex(b)); 1946 Complex!T res2 = pow(complex(a), b); 1947 assert(abs(ref1 - res1) < eps); 1948 assert(abs(ref1 - res2) < eps); 1949 assert(abs(res1 - res2) < eps); 1950 1951 T c = -3.2; 1952 T d = 1.4; 1953 Complex!T ref2 = pow(complex(a), complex(b)); 1954 Complex!T res3 = pow(a, complex(b)); 1955 Complex!T res4 = pow(complex(a), b); 1956 assert(abs(ref2 - res3) < eps); 1957 assert(abs(ref2 - res4) < eps); 1958 assert(abs(res3 - res4) < eps); 1959 } 1960 }} 1961 } 1962 1963 @safe pure nothrow @nogc unittest 1964 { 1965 import std.meta : AliasSeq; 1966 static foreach (T; AliasSeq!(float, double, real)) 1967 {{ 1968 auto c = Complex!T(123, 456); 1969 auto n = c.toNative(); 1970 assert(c.re == n.re && c.im == n.im); 1971 }} 1972 }