1 /// Author: Aziz Köksal 2 /// License: GPL3 3 /// $(Maturity low) 4 module dil.Complex; 5 6 import dil.Float; 7 import common; 8 9 alias Float = dil.Float.Float; 10 11 /// A class for working with imaginary numbers. 12 class Complex 13 { 14 Float re; /// The real part. 15 Float im; /// The imaginary part. 16 /// The length or magnitude of the vector. 17 alias mag = re; 18 /// The angle of the vector. 19 alias phi = im; 20 21 /// Constructs an initialized Float. 22 this() 23 { 24 re = new Float(); 25 im = new Float(); 26 } 27 28 /// Constructs from a Complex. 29 this(Complex c) 30 { 31 re = c.re.dup(); 32 im = c.im.dup(); 33 } 34 35 /// Constructs from two Floats. 36 this(Float r, Float i=null) 37 { 38 re = r; 39 im = i ? i : new Float(); 40 } 41 42 /// Constructs from two longs. 43 this(long r, long i=0) 44 { 45 re = new Float(r); 46 im = new Float(i); 47 } 48 49 /// Constructs from two ulongs. 50 this(ulong r, ulong i=0) 51 { 52 re = new Float(r); 53 im = new Float(i); 54 } 55 56 /// Constructs from two longs. 57 this(double r, double i=0) 58 { 59 re = new Float(r); 60 im = new Float(i); 61 } 62 63 /// Constructs from two strings. 64 this(cstring r, cstring i) 65 { 66 re = new Float(r); 67 im = new Float(i); 68 } 69 70 /// Constructs from a string. 71 /// Params: 72 /// x = Can be "a", "aj", "-ai", "a + bj", "a - bi" etc. 73 this(cstring x) 74 { 75 if (!x.length) 76 this(); 77 else 78 { 79 if (x[$-1] != '\0') 80 x = x ~ '\0'; // Terminate with zero 81 this(x.ptr); 82 } 83 } 84 85 /// Constructs a Complex from a zero-terminated string. 86 this(cchar* x) 87 { 88 set(x); 89 } 90 91 /// Parses the string and sets the real and imaginary parts. Returns itself. 92 Complex set(cchar* x) 93 { 94 x = x && *x ? x : "0"; 95 96 cstring r_str, i_str; 97 bool i_neg; 98 auto p = x; 99 while (*p == ' ') 100 p++; 101 x = p; // Let x point to the beginning of the number. 102 if (*p == '-' || *p == '+') 103 p++; // Skip for look-behind expression below (p[-1]). 104 while (*p != 0 && *p != ' ' && 105 (*p != '-' && *p != '+' || p[-1] == 'e')) 106 p++; 107 if (p[-1] == 'i' || p[-1] == 'j') 108 i_str = x[0..p-x]; // Only an imaginary component. 109 else 110 { 111 r_str = x[0..p-x]; // Real component. 112 while (*p == ' ') // Skip whitespace. 113 p++; 114 i_neg = *p == '-'; 115 if (i_neg || *p == '+') // ±bi 116 { 117 while (*++p == ' '){} // Skip whitespace. 118 x = p; // Update beginning of the imaginary component. 119 while (*p != 0 && *p != 'i' && *p != 'j') 120 p++; 121 if (*p != 0) 122 i_str = x[0..p-x]; 123 } 124 } 125 126 re = new Float(r_str); 127 im = new Float(i_str); 128 if (i_neg) 129 im.neg(); 130 return this; 131 } 132 133 /// For convenient construction of Complex numbers. 134 static Complex opCall(Params...)(Params P) 135 { 136 return new Complex(P); 137 } 138 139 /// Clears this number and deallocates its data. 140 void clear() 141 { 142 re.clear(); 143 im.clear(); 144 } 145 146 /// Returns a deep copy of this number. 147 Complex dup() 148 { 149 return new Complex(this); 150 } 151 152 /// Calculates z += x. Returns itself. 153 Complex opAddAssign(Complex x) 154 { 155 re += x.re; 156 im += x.im; 157 return this; 158 } 159 160 /// Calculates z+x. Returns a new number. 161 Complex opAdd(Complex x) 162 { 163 return new Complex() += x; 164 } 165 166 /// ditto 167 Complex opAdd(uint x) 168 { 169 auto z = new Complex(); 170 z.re += x; 171 return z; 172 } 173 174 // /// Calculates x-z. 175 // Complex opAdd_r(T)(T x) 176 // { 177 // static if (is(T == Complex)) 178 // return x.dup() + this; 179 // else 180 // return new Complex(x) + this; 181 // } 182 183 /// Calculates z -= x. Returns itself. 184 Complex opSubAssign(Complex x) 185 { 186 re -= x.re; 187 im -= x.im; 188 return this; 189 } 190 191 /// ditto 192 Complex opSubAssign(uint x) 193 { 194 re -= x; 195 return this; 196 } 197 198 /// Calculates z-x. Returns a new number. 199 Complex opSub(T)(T x) 200 { 201 static if (is(T == Complex) || is(T == uint)) 202 return dup() -= x; 203 else 204 return dup() -= new Complex(x); 205 } 206 207 // /// Calculates x-z. 208 // Complex opSub_r(T)(T x) 209 // { 210 // static if (is(T == Complex)) 211 // return x.dup() - this; 212 // else 213 // return new Complex(x) - this; 214 // } 215 216 /// Calculates z /= x. Returns itself. 217 Complex opDivAssign(T:Complex)(T x) 218 { // Special handling. 219 if (x.im == 0) 220 (re /= x.re), 221 (im /= x.re); 222 else 223 { 224 // auto n = x.re / x.im; 225 // auto d = x.re * n + x.im; 226 // auto r_ = re.dup(); 227 // re *= n; re += im; re /= d; 228 // im *= n; im -= r_; im /= d; 229 230 auto rx = x.re, ix = x.im; 231 // d = x.re² + x.im² 232 auto d = rx.dup().square() += ix.dup().square(); 233 auto r_ = re.dup(); 234 re *= rx; re += im * ix; re /= d; 235 im *= rx; im -= r_ * ix; im /= d; 236 } 237 return this; 238 } 239 240 /// ditto 241 Complex opDivAssign(T)(T x) 242 { 243 static if (is(T == Float) || is(T == uint)) 244 alias x z; 245 else 246 auto z = new Float(x); 247 re /= z; 248 im /= z; 249 return this; 250 } 251 252 /// Calculates z/x. Returns a new number. 253 Complex opDiv(T)(T x) 254 { 255 static if (is(T == Complex) || is(T == uint)) 256 alias x z; 257 else 258 auto z = new Complex(x); 259 return dup() /= z; 260 } 261 262 // Cannot do the following because it conflicts with opDiv. 263 // Complex opDiv_r(T)(T x) 264 // { return new Complex(x) /= this; } 265 266 /// Calculates x/z. Returns a new number. 267 Complex opDiv_r(uint x) 268 { 269 return new Complex(cast(ulong)x) /= this; 270 } 271 272 /// ditto 273 Complex opDiv_r(double x) 274 { 275 return new Complex(x) /= this; 276 } 277 278 /// ditto 279 Complex opDiv_r(cstring x) 280 { 281 return new Complex(x) /= this; 282 } 283 284 /// ditto 285 Complex opDiv_r(cchar* x) 286 { 287 return new Complex(x) /= this; 288 } 289 290 /// Calculates z %= w. Returns itself. 291 Complex opModAssign(Complex w) 292 { // modulo(z, w) = frac(z/w) * w 293 // TODO: optimize for certain cases. 294 (this /= w).fraction() *= w; 295 return this; 296 } 297 298 /// Calculates z %= f. Returns itself. 299 Complex opModAssign(Float f) 300 { 301 this %= new Complex(f); 302 return this; 303 } 304 305 /// Calculates z % w. Returns a new number. 306 Complex opMod(Complex w) 307 { 308 return dup() %= w; 309 } 310 311 /// Calculates z % f. Returns a new number. 312 Complex opMod(Float f) 313 { 314 return dup() %= f; 315 } 316 317 /// Calculates z *= x. Returns itself. 318 Complex opMulAssign(T:Complex)(T x) 319 { // Special handling. 320 if (x.im == 0) 321 (re *= x.re), 322 (im *= x.re); 323 else 324 { 325 auto r_ = re.dup(); 326 re *= x.re; re -= im*x.im; 327 im *= x.re; im += r_*=x.im; 328 } 329 return this; 330 } 331 332 /// ditto 333 Complex opMulAssign(T)(T x) 334 { 335 static if (is(T == Float) || is(T == uint)) 336 alias x z; 337 else 338 auto z = new Float(x); 339 re *= z; 340 im *= z; 341 return this; 342 } 343 344 /// Calculates z*x. Returns a new number. 345 Complex opMul(T)(T x) 346 { 347 static if (is(T == Complex) || is(T == uint)) 348 alias x z; 349 else 350 auto z = new Complex(x); 351 return dup() *= z; 352 } 353 354 // /// Calculates x*z. 355 // Complex opMul_r(T)(T x) 356 // { 357 // static if (is(T == Complex)) 358 // return x.dup() *= this; 359 // else 360 // return new Complex(x) *= this; 361 // } 362 363 /// Compares z to x. 364 override bool opEquals(Object x) 365 { 366 if (auto f = cast(Float)x) 367 return opEquals(f); 368 if (auto c = cast(Complex)x) 369 return opEquals(c); 370 return true; 371 } 372 373 /// Compares z to x. 374 bool opEquals(Complex x) 375 { 376 return re.equals(x.re) && im.equals(x.im); 377 } 378 379 static string opEqualsMacro(string s) 380 { 381 return "bool opEquals(" ~ s ~ " x) { return opEquals(new Complex(x)); }"; 382 } 383 384 mixin(opEqualsMacro("long")); 385 mixin(opEqualsMacro("Float")); 386 387 alias equals = opEquals; 388 389 /// Returns a negated copy of this number. 390 Complex opNeg() 391 { 392 auto n = dup(); 393 n.re.neg(); 394 n.im.neg(); 395 return n; 396 } 397 398 /// Negates this number. Returns itself. 399 Complex neg() 400 { 401 re.neg(); 402 im.neg(); 403 return this; 404 } 405 406 /// Converts this number to polar representation. Returns itself. 407 Complex polar() 408 { 409 auto phi_ = im.dup.atan2(re); 410 re.hypot(im); // r = √(re² + im²) 411 phi = phi_; // φ = arctan(im/re) 412 return this; 413 } 414 415 /// Converts this number to cartesian representation. Returns itself. 416 Complex cart() 417 { // Looks weird but saves temporary variables. 418 auto mag_ = mag.dup(); 419 mag *= phi.dup().cos(); // re = r*cos(φ) 420 phi.sin() *= mag_; // im = r*sin(φ) 421 return this; 422 } 423 424 /// Calculates frac(z). Returns itself. 425 Complex fraction() 426 { 427 re.fraction(); 428 im.fraction(); 429 return this; 430 } 431 432 /// Calculates √z. Returns itself. 433 Complex sqrt() 434 { // √z = √(r.e^iφ) = √(r).e^(iφ/2) 435 polar(); 436 mag.sqrt(); 437 phi /= 2; 438 return cart(); 439 } 440 441 /// Calculates z^w. Returns itself. 442 Complex pow(T:Complex)(T w) 443 { // z^w = e^(w*ln(z)) 444 ln() *= w; // z = ln(z); z *= w 445 return exp(); // e^z 446 } 447 448 /// Calculates z^x. Returns itself. 449 Complex pow(T)(T x) 450 { // z^x = (r.e^iφ)^x = r^x.e^(xφi) 451 polar(); 452 mag.pow(x); 453 phi *= x; 454 return cart(); 455 } 456 457 /// Calculates e^z. Returns itself. 458 Complex exp() 459 { // e^z = e^(a+bi) = e^a * e^bi = e^a (cos(b) + i.sin(b)) 460 re.exp(); // r = e^Re(z) φ = Im(z) 461 return cart(); 462 } 463 464 /// Calculates ln(z). Returns itself. 465 Complex ln() 466 { // ln(z) = ln(r.e^iφ) = ln(r) + ln(e^iφ) = ln(r) + iφ 467 polar(); 468 mag.ln(); 469 return this; 470 } 471 472 /// Calculates log$(SUB a+bi)(w) = ln(w)/ln(a+bi). Returns a new number. 473 Complex logz(Complex w) 474 { 475 return w.dup().ln() /= dup().ln(); 476 } 477 478 /// Conjugates this number: conj(z) = Re(z) - Im(z). Returns itself. 479 Complex conjugate() 480 { 481 im = -im; 482 return this; 483 } 484 485 /// Returns a conjugated copy of this number. 486 Complex conjugated() 487 { 488 return dup().conjugate(); 489 } 490 491 /// Inverses this number: z = z^-1. Returns itself. 492 Complex inverse() 493 { // re/(a²+b²) - im/(a²+b²) 494 auto d = re.dup().square() += im.dup().square(); 495 re /= d; 496 im /= d.neg(); 497 return this; 498 } 499 500 /// Returns an inversed copy of this number. 501 Complex inversed() 502 { 503 return dup().inverse(); 504 } 505 506 /// Returns the polar angle: φ = arctan(b/a). 507 Float arg() 508 { 509 return im.dup().atan2(re); 510 } 511 512 /// Returns the absolute value: |z| = √(re² + im²). 513 Float abs() 514 { 515 return hypot(re, im); 516 } 517 518 /// Returns this number as a string. 519 override string toString() 520 { 521 return toString(30).idup; 522 } 523 524 /// Returns this number as a string. 525 char[] toString(uint precision) 526 { 527 auto im_sign = im.isNeg() ? "" : "+"; 528 return re.toString(precision) ~ im_sign ~ im.toString(precision) ~ "i"; 529 } 530 } 531 532 void testComplex() 533 { 534 return; // Remove when Complex/Float is fixed. 535 scope msg = new UnittestMsg("Testing class Complex."); 536 537 alias F = Float; 538 alias C = Complex; 539 540 assert(C(F(3)) == F(3)); 541 assert(F(99) == C(F(99))); 542 assert(-C(F(10), F(9)) == C(F(-10), F(-9))); 543 assert(C(5., 20.) / 5. == C(1., 4.)); 544 assert(1. / C(5., 20.) == C(5., 20.).inverse()); 545 assert(C(3L, 2L) / C(4L,-6L) == C(0., 0.5)); 546 assert(C(3L, 4L).abs() == F(5)); 547 assert(C(3L, 4L).conjugate() == C(3L, -4L)); 548 // assert(C(3L, 4L).pow(2) == C(-7L, 24L)); 549 // assert(C(3L, 4L).sqrt() == C(2L, 1L)); 550 assert(C("3+4j") == C(3L, 4L)); 551 assert(C("-4e+2j") == C(0L, -400L)); 552 }