complex.js (30643B)
1 /** 2 * @license Complex.js v2.1.1 12/05/2020 3 * 4 * Copyright (c) 2020, Robert Eisele (robert@xarg.org) 5 * Dual licensed under the MIT or GPL Version 2 licenses. 6 **/ 7 8 /** 9 * 10 * This class allows the manipulation of complex numbers. 11 * You can pass a complex number in different formats. Either as object, double, string or two integer parameters. 12 * 13 * Object form 14 * { re: <real>, im: <imaginary> } 15 * { arg: <angle>, abs: <radius> } 16 * { phi: <angle>, r: <radius> } 17 * 18 * Array / Vector form 19 * [ real, imaginary ] 20 * 21 * Double form 22 * 99.3 - Single double value 23 * 24 * String form 25 * '23.1337' - Simple real number 26 * '15+3i' - a simple complex number 27 * '3-i' - a simple complex number 28 * 29 * Example: 30 * 31 * var c = new Complex('99.3+8i'); 32 * c.mul({r: 3, i: 9}).div(4.9).sub(3, 2); 33 * 34 */ 35 36 (function(root) { 37 38 'use strict'; 39 40 var cosh = Math.cosh || function(x) { 41 return Math.abs(x) < 1e-9 ? 1 - x : (Math.exp(x) + Math.exp(-x)) * 0.5; 42 }; 43 44 var sinh = Math.sinh || function(x) { 45 return Math.abs(x) < 1e-9 ? x : (Math.exp(x) - Math.exp(-x)) * 0.5; 46 }; 47 48 /** 49 * Calculates cos(x) - 1 using Taylor series if x is small (-¼π ≤ x ≤ ¼π). 50 * 51 * @param {number} x 52 * @returns {number} cos(x) - 1 53 */ 54 var cosm1 = function(x) { 55 56 var b = Math.PI / 4; 57 if (-b > x || x > b) { 58 return Math.cos(x) - 1.0; 59 } 60 61 /* Calculate horner form of polynomial of taylor series in Q 62 var fac = 1, alt = 1, pol = {}; 63 for (var i = 0; i <= 16; i++) { 64 fac*= i || 1; 65 if (i % 2 == 0) { 66 pol[i] = new Fraction(1, alt * fac); 67 alt = -alt; 68 } 69 } 70 console.log(new Polynomial(pol).toHorner()); // (((((((1/20922789888000x^2-1/87178291200)x^2+1/479001600)x^2-1/3628800)x^2+1/40320)x^2-1/720)x^2+1/24)x^2-1/2)x^2+1 71 */ 72 73 var xx = x * x; 74 return xx * ( 75 xx * ( 76 xx * ( 77 xx * ( 78 xx * ( 79 xx * ( 80 xx * ( 81 xx / 20922789888000 82 - 1 / 87178291200) 83 + 1 / 479001600) 84 - 1 / 3628800) 85 + 1 / 40320) 86 - 1 / 720) 87 + 1 / 24) 88 - 1 / 2); 89 }; 90 91 var hypot = function(x, y) { 92 93 var a = Math.abs(x); 94 var b = Math.abs(y); 95 96 if (a < 3000 && b < 3000) { 97 return Math.sqrt(a * a + b * b); 98 } 99 100 if (a < b) { 101 a = b; 102 b = x / y; 103 } else { 104 b = y / x; 105 } 106 return a * Math.sqrt(1 + b * b); 107 }; 108 109 var parser_exit = function() { 110 throw SyntaxError('Invalid Param'); 111 }; 112 113 /** 114 * Calculates log(sqrt(a^2+b^2)) in a way to avoid overflows 115 * 116 * @param {number} a 117 * @param {number} b 118 * @returns {number} 119 */ 120 function logHypot(a, b) { 121 122 var _a = Math.abs(a); 123 var _b = Math.abs(b); 124 125 if (a === 0) { 126 return Math.log(_b); 127 } 128 129 if (b === 0) { 130 return Math.log(_a); 131 } 132 133 if (_a < 3000 && _b < 3000) { 134 return Math.log(a * a + b * b) * 0.5; 135 } 136 137 /* I got 4 ideas to compute this property without overflow: 138 * 139 * Testing 1000000 times with random samples for a,b ∈ [1, 1000000000] against a big decimal library to get an error estimate 140 * 141 * 1. Only eliminate the square root: (OVERALL ERROR: 3.9122483030951116e-11) 142 143 Math.log(a * a + b * b) / 2 144 145 * 146 * 147 * 2. Try to use the non-overflowing pythagoras: (OVERALL ERROR: 8.889760039210159e-10) 148 149 var fn = function(a, b) { 150 a = Math.abs(a); 151 b = Math.abs(b); 152 var t = Math.min(a, b); 153 a = Math.max(a, b); 154 t = t / a; 155 156 return Math.log(a) + Math.log(1 + t * t) / 2; 157 }; 158 159 * 3. Abuse the identity cos(atan(y/x) = x / sqrt(x^2+y^2): (OVERALL ERROR: 3.4780178737037204e-10) 160 161 Math.log(a / Math.cos(Math.atan2(b, a))) 162 163 * 4. Use 3. and apply log rules: (OVERALL ERROR: 1.2014087502620896e-9) 164 165 Math.log(a) - Math.log(Math.cos(Math.atan2(b, a))) 166 167 */ 168 169 a = a / 2; 170 b = b / 2; 171 172 return 0.5 * Math.log(a * a + b * b) + Math.LN2; 173 } 174 175 var parse = function(a, b) { 176 177 var z = { 're': 0, 'im': 0 }; 178 179 if (a === undefined || a === null) { 180 z['re'] = 181 z['im'] = 0; 182 } else if (b !== undefined) { 183 z['re'] = a; 184 z['im'] = b; 185 } else 186 switch (typeof a) { 187 188 case 'object': 189 190 if ('im' in a && 're' in a) { 191 z['re'] = a['re']; 192 z['im'] = a['im']; 193 } else if ('abs' in a && 'arg' in a) { 194 if (!Number.isFinite(a['abs']) && Number.isFinite(a['arg'])) { 195 return Complex['INFINITY']; 196 } 197 z['re'] = a['abs'] * Math.cos(a['arg']); 198 z['im'] = a['abs'] * Math.sin(a['arg']); 199 } else if ('r' in a && 'phi' in a) { 200 if (!Number.isFinite(a['r']) && Number.isFinite(a['phi'])) { 201 return Complex['INFINITY']; 202 } 203 z['re'] = a['r'] * Math.cos(a['phi']); 204 z['im'] = a['r'] * Math.sin(a['phi']); 205 } else if (a.length === 2) { // Quick array check 206 z['re'] = a[0]; 207 z['im'] = a[1]; 208 } else { 209 parser_exit(); 210 } 211 break; 212 213 case 'string': 214 215 z['im'] = /* void */ 216 z['re'] = 0; 217 218 var tokens = a.match(/\d+\.?\d*e[+-]?\d+|\d+\.?\d*|\.\d+|./g); 219 var plus = 1; 220 var minus = 0; 221 222 if (tokens === null) { 223 parser_exit(); 224 } 225 226 for (var i = 0; i < tokens.length; i++) { 227 228 var c = tokens[i]; 229 230 if (c === ' ' || c === '\t' || c === '\n') { 231 /* void */ 232 } else if (c === '+') { 233 plus++; 234 } else if (c === '-') { 235 minus++; 236 } else if (c === 'i' || c === 'I') { 237 238 if (plus + minus === 0) { 239 parser_exit(); 240 } 241 242 if (tokens[i + 1] !== ' ' && !isNaN(tokens[i + 1])) { 243 z['im'] += parseFloat((minus % 2 ? '-' : '') + tokens[i + 1]); 244 i++; 245 } else { 246 z['im'] += parseFloat((minus % 2 ? '-' : '') + '1'); 247 } 248 plus = minus = 0; 249 250 } else { 251 252 if (plus + minus === 0 || isNaN(c)) { 253 parser_exit(); 254 } 255 256 if (tokens[i + 1] === 'i' || tokens[i + 1] === 'I') { 257 z['im'] += parseFloat((minus % 2 ? '-' : '') + c); 258 i++; 259 } else { 260 z['re'] += parseFloat((minus % 2 ? '-' : '') + c); 261 } 262 plus = minus = 0; 263 } 264 } 265 266 // Still something on the stack 267 if (plus + minus > 0) { 268 parser_exit(); 269 } 270 break; 271 272 case 'number': 273 z['im'] = 0; 274 z['re'] = a; 275 break; 276 277 default: 278 parser_exit(); 279 } 280 281 if (isNaN(z['re']) || isNaN(z['im'])) { 282 // If a calculation is NaN, we treat it as NaN and don't throw 283 //parser_exit(); 284 } 285 286 return z; 287 }; 288 289 /** 290 * @constructor 291 * @returns {Complex} 292 */ 293 function Complex(a, b) { 294 295 if (!(this instanceof Complex)) { 296 return new Complex(a, b); 297 } 298 299 var z = parse(a, b); 300 301 this['re'] = z['re']; 302 this['im'] = z['im']; 303 } 304 305 Complex.prototype = { 306 307 're': 0, 308 'im': 0, 309 310 /** 311 * Calculates the sign of a complex number, which is a normalized complex 312 * 313 * @returns {Complex} 314 */ 315 'sign': function() { 316 317 var abs = this['abs'](); 318 319 return new Complex( 320 this['re'] / abs, 321 this['im'] / abs); 322 }, 323 324 /** 325 * Adds two complex numbers 326 * 327 * @returns {Complex} 328 */ 329 'add': function(a, b) { 330 331 var z = new Complex(a, b); 332 333 // Infinity + Infinity = NaN 334 if (this['isInfinite']() && z['isInfinite']()) { 335 return Complex['NAN']; 336 } 337 338 // Infinity + z = Infinity { where z != Infinity } 339 if (this['isInfinite']() || z['isInfinite']()) { 340 return Complex['INFINITY']; 341 } 342 343 return new Complex( 344 this['re'] + z['re'], 345 this['im'] + z['im']); 346 }, 347 348 /** 349 * Subtracts two complex numbers 350 * 351 * @returns {Complex} 352 */ 353 'sub': function(a, b) { 354 355 var z = new Complex(a, b); 356 357 // Infinity - Infinity = NaN 358 if (this['isInfinite']() && z['isInfinite']()) { 359 return Complex['NAN']; 360 } 361 362 // Infinity - z = Infinity { where z != Infinity } 363 if (this['isInfinite']() || z['isInfinite']()) { 364 return Complex['INFINITY']; 365 } 366 367 return new Complex( 368 this['re'] - z['re'], 369 this['im'] - z['im']); 370 }, 371 372 /** 373 * Multiplies two complex numbers 374 * 375 * @returns {Complex} 376 */ 377 'mul': function(a, b) { 378 379 var z = new Complex(a, b); 380 381 // Infinity * 0 = NaN 382 if ((this['isInfinite']() && z['isZero']()) || (this['isZero']() && z['isInfinite']())) { 383 return Complex['NAN']; 384 } 385 386 // Infinity * z = Infinity { where z != 0 } 387 if (this['isInfinite']() || z['isInfinite']()) { 388 return Complex['INFINITY']; 389 } 390 391 // Short circuit for real values 392 if (z['im'] === 0 && this['im'] === 0) { 393 return new Complex(this['re'] * z['re'], 0); 394 } 395 396 return new Complex( 397 this['re'] * z['re'] - this['im'] * z['im'], 398 this['re'] * z['im'] + this['im'] * z['re']); 399 }, 400 401 /** 402 * Divides two complex numbers 403 * 404 * @returns {Complex} 405 */ 406 'div': function(a, b) { 407 408 var z = new Complex(a, b); 409 410 // 0 / 0 = NaN and Infinity / Infinity = NaN 411 if ((this['isZero']() && z['isZero']()) || (this['isInfinite']() && z['isInfinite']())) { 412 return Complex['NAN']; 413 } 414 415 // Infinity / 0 = Infinity 416 if (this['isInfinite']() || z['isZero']()) { 417 return Complex['INFINITY']; 418 } 419 420 // 0 / Infinity = 0 421 if (this['isZero']() || z['isInfinite']()) { 422 return Complex['ZERO']; 423 } 424 425 a = this['re']; 426 b = this['im']; 427 428 var c = z['re']; 429 var d = z['im']; 430 var t, x; 431 432 if (0 === d) { 433 // Divisor is real 434 return new Complex(a / c, b / c); 435 } 436 437 if (Math.abs(c) < Math.abs(d)) { 438 439 x = c / d; 440 t = c * x + d; 441 442 return new Complex( 443 (a * x + b) / t, 444 (b * x - a) / t); 445 446 } else { 447 448 x = d / c; 449 t = d * x + c; 450 451 return new Complex( 452 (a + b * x) / t, 453 (b - a * x) / t); 454 } 455 }, 456 457 /** 458 * Calculate the power of two complex numbers 459 * 460 * @returns {Complex} 461 */ 462 'pow': function(a, b) { 463 464 var z = new Complex(a, b); 465 466 a = this['re']; 467 b = this['im']; 468 469 if (z['isZero']()) { 470 return Complex['ONE']; 471 } 472 473 // If the exponent is real 474 if (z['im'] === 0) { 475 476 if (b === 0 && a > 0) { 477 478 return new Complex(Math.pow(a, z['re']), 0); 479 480 } else if (a === 0) { // If base is fully imaginary 481 482 switch ((z['re'] % 4 + 4) % 4) { 483 case 0: 484 return new Complex(Math.pow(b, z['re']), 0); 485 case 1: 486 return new Complex(0, Math.pow(b, z['re'])); 487 case 2: 488 return new Complex(-Math.pow(b, z['re']), 0); 489 case 3: 490 return new Complex(0, -Math.pow(b, z['re'])); 491 } 492 } 493 } 494 495 /* I couldn't find a good formula, so here is a derivation and optimization 496 * 497 * z_1^z_2 = (a + bi)^(c + di) 498 * = exp((c + di) * log(a + bi) 499 * = pow(a^2 + b^2, (c + di) / 2) * exp(i(c + di)atan2(b, a)) 500 * =>... 501 * Re = (pow(a^2 + b^2, c / 2) * exp(-d * atan2(b, a))) * cos(d * log(a^2 + b^2) / 2 + c * atan2(b, a)) 502 * Im = (pow(a^2 + b^2, c / 2) * exp(-d * atan2(b, a))) * sin(d * log(a^2 + b^2) / 2 + c * atan2(b, a)) 503 * 504 * =>... 505 * Re = exp(c * log(sqrt(a^2 + b^2)) - d * atan2(b, a)) * cos(d * log(sqrt(a^2 + b^2)) + c * atan2(b, a)) 506 * Im = exp(c * log(sqrt(a^2 + b^2)) - d * atan2(b, a)) * sin(d * log(sqrt(a^2 + b^2)) + c * atan2(b, a)) 507 * 508 * => 509 * Re = exp(c * logsq2 - d * arg(z_1)) * cos(d * logsq2 + c * arg(z_1)) 510 * Im = exp(c * logsq2 - d * arg(z_1)) * sin(d * logsq2 + c * arg(z_1)) 511 * 512 */ 513 514 if (a === 0 && b === 0 && z['re'] > 0 && z['im'] >= 0) { 515 return Complex['ZERO']; 516 } 517 518 var arg = Math.atan2(b, a); 519 var loh = logHypot(a, b); 520 521 a = Math.exp(z['re'] * loh - z['im'] * arg); 522 b = z['im'] * loh + z['re'] * arg; 523 return new Complex( 524 a * Math.cos(b), 525 a * Math.sin(b)); 526 }, 527 528 /** 529 * Calculate the complex square root 530 * 531 * @returns {Complex} 532 */ 533 'sqrt': function() { 534 535 var a = this['re']; 536 var b = this['im']; 537 var r = this['abs'](); 538 539 var re, im; 540 541 if (a >= 0) { 542 543 if (b === 0) { 544 return new Complex(Math.sqrt(a), 0); 545 } 546 547 re = 0.5 * Math.sqrt(2.0 * (r + a)); 548 } else { 549 re = Math.abs(b) / Math.sqrt(2 * (r - a)); 550 } 551 552 if (a <= 0) { 553 im = 0.5 * Math.sqrt(2.0 * (r - a)); 554 } else { 555 im = Math.abs(b) / Math.sqrt(2 * (r + a)); 556 } 557 558 return new Complex(re, b < 0 ? -im : im); 559 }, 560 561 /** 562 * Calculate the complex exponent 563 * 564 * @returns {Complex} 565 */ 566 'exp': function() { 567 568 var tmp = Math.exp(this['re']); 569 570 if (this['im'] === 0) { 571 //return new Complex(tmp, 0); 572 } 573 return new Complex( 574 tmp * Math.cos(this['im']), 575 tmp * Math.sin(this['im'])); 576 }, 577 578 /** 579 * Calculate the complex exponent and subtracts one. 580 * 581 * This may be more accurate than `Complex(x).exp().sub(1)` if 582 * `x` is small. 583 * 584 * @returns {Complex} 585 */ 586 'expm1': function() { 587 588 /** 589 * exp(a + i*b) - 1 590 = exp(a) * (cos(b) + j*sin(b)) - 1 591 = expm1(a)*cos(b) + cosm1(b) + j*exp(a)*sin(b) 592 */ 593 594 var a = this['re']; 595 var b = this['im']; 596 597 return new Complex( 598 Math.expm1(a) * Math.cos(b) + cosm1(b), 599 Math.exp(a) * Math.sin(b)); 600 }, 601 602 /** 603 * Calculate the natural log 604 * 605 * @returns {Complex} 606 */ 607 'log': function() { 608 609 var a = this['re']; 610 var b = this['im']; 611 612 if (b === 0 && a > 0) { 613 //return new Complex(Math.log(a), 0); 614 } 615 616 return new Complex( 617 logHypot(a, b), 618 Math.atan2(b, a)); 619 }, 620 621 /** 622 * Calculate the magnitude of the complex number 623 * 624 * @returns {number} 625 */ 626 'abs': function() { 627 628 return hypot(this['re'], this['im']); 629 }, 630 631 /** 632 * Calculate the angle of the complex number 633 * 634 * @returns {number} 635 */ 636 'arg': function() { 637 638 return Math.atan2(this['im'], this['re']); 639 }, 640 641 /** 642 * Calculate the sine of the complex number 643 * 644 * @returns {Complex} 645 */ 646 'sin': function() { 647 648 // sin(z) = ( e^iz - e^-iz ) / 2i 649 // = sin(a)cosh(b) + i cos(a)sinh(b) 650 651 var a = this['re']; 652 var b = this['im']; 653 654 return new Complex( 655 Math.sin(a) * cosh(b), 656 Math.cos(a) * sinh(b)); 657 }, 658 659 /** 660 * Calculate the cosine 661 * 662 * @returns {Complex} 663 */ 664 'cos': function() { 665 666 // cos(z) = ( e^iz + e^-iz ) / 2 667 // = cos(a)cosh(b) - i sin(a)sinh(b) 668 669 var a = this['re']; 670 var b = this['im']; 671 672 return new Complex( 673 Math.cos(a) * cosh(b), 674 -Math.sin(a) * sinh(b)); 675 }, 676 677 /** 678 * Calculate the tangent 679 * 680 * @returns {Complex} 681 */ 682 'tan': function() { 683 684 // tan(z) = sin(z) / cos(z) 685 // = ( e^iz - e^-iz ) / ( i( e^iz + e^-iz ) ) 686 // = ( e^2iz - 1 ) / i( e^2iz + 1 ) 687 // = ( sin(2a) + i sinh(2b) ) / ( cos(2a) + cosh(2b) ) 688 689 var a = 2 * this['re']; 690 var b = 2 * this['im']; 691 var d = Math.cos(a) + cosh(b); 692 693 return new Complex( 694 Math.sin(a) / d, 695 sinh(b) / d); 696 }, 697 698 /** 699 * Calculate the cotangent 700 * 701 * @returns {Complex} 702 */ 703 'cot': function() { 704 705 // cot(c) = i(e^(ci) + e^(-ci)) / (e^(ci) - e^(-ci)) 706 707 var a = 2 * this['re']; 708 var b = 2 * this['im']; 709 var d = Math.cos(a) - cosh(b); 710 711 return new Complex( 712 -Math.sin(a) / d, 713 sinh(b) / d); 714 }, 715 716 /** 717 * Calculate the secant 718 * 719 * @returns {Complex} 720 */ 721 'sec': function() { 722 723 // sec(c) = 2 / (e^(ci) + e^(-ci)) 724 725 var a = this['re']; 726 var b = this['im']; 727 var d = 0.5 * cosh(2 * b) + 0.5 * Math.cos(2 * a); 728 729 return new Complex( 730 Math.cos(a) * cosh(b) / d, 731 Math.sin(a) * sinh(b) / d); 732 }, 733 734 /** 735 * Calculate the cosecans 736 * 737 * @returns {Complex} 738 */ 739 'csc': function() { 740 741 // csc(c) = 2i / (e^(ci) - e^(-ci)) 742 743 var a = this['re']; 744 var b = this['im']; 745 var d = 0.5 * cosh(2 * b) - 0.5 * Math.cos(2 * a); 746 747 return new Complex( 748 Math.sin(a) * cosh(b) / d, 749 -Math.cos(a) * sinh(b) / d); 750 }, 751 752 /** 753 * Calculate the complex arcus sinus 754 * 755 * @returns {Complex} 756 */ 757 'asin': function() { 758 759 // asin(c) = -i * log(ci + sqrt(1 - c^2)) 760 761 var a = this['re']; 762 var b = this['im']; 763 764 var t1 = new Complex( 765 b * b - a * a + 1, 766 -2 * a * b)['sqrt'](); 767 768 var t2 = new Complex( 769 t1['re'] - b, 770 t1['im'] + a)['log'](); 771 772 return new Complex(t2['im'], -t2['re']); 773 }, 774 775 /** 776 * Calculate the complex arcus cosinus 777 * 778 * @returns {Complex} 779 */ 780 'acos': function() { 781 782 // acos(c) = i * log(c - i * sqrt(1 - c^2)) 783 784 var a = this['re']; 785 var b = this['im']; 786 787 var t1 = new Complex( 788 b * b - a * a + 1, 789 -2 * a * b)['sqrt'](); 790 791 var t2 = new Complex( 792 t1['re'] - b, 793 t1['im'] + a)['log'](); 794 795 return new Complex(Math.PI / 2 - t2['im'], t2['re']); 796 }, 797 798 /** 799 * Calculate the complex arcus tangent 800 * 801 * @returns {Complex} 802 */ 803 'atan': function() { 804 805 // atan(c) = i / 2 log((i + x) / (i - x)) 806 807 var a = this['re']; 808 var b = this['im']; 809 810 if (a === 0) { 811 812 if (b === 1) { 813 return new Complex(0, Infinity); 814 } 815 816 if (b === -1) { 817 return new Complex(0, -Infinity); 818 } 819 } 820 821 var d = a * a + (1.0 - b) * (1.0 - b); 822 823 var t1 = new Complex( 824 (1 - b * b - a * a) / d, 825 -2 * a / d).log(); 826 827 return new Complex(-0.5 * t1['im'], 0.5 * t1['re']); 828 }, 829 830 /** 831 * Calculate the complex arcus cotangent 832 * 833 * @returns {Complex} 834 */ 835 'acot': function() { 836 837 // acot(c) = i / 2 log((c - i) / (c + i)) 838 839 var a = this['re']; 840 var b = this['im']; 841 842 if (b === 0) { 843 return new Complex(Math.atan2(1, a), 0); 844 } 845 846 var d = a * a + b * b; 847 return (d !== 0) 848 ? new Complex( 849 a / d, 850 -b / d).atan() 851 : new Complex( 852 (a !== 0) ? a / 0 : 0, 853 (b !== 0) ? -b / 0 : 0).atan(); 854 }, 855 856 /** 857 * Calculate the complex arcus secant 858 * 859 * @returns {Complex} 860 */ 861 'asec': function() { 862 863 // asec(c) = -i * log(1 / c + sqrt(1 - i / c^2)) 864 865 var a = this['re']; 866 var b = this['im']; 867 868 if (a === 0 && b === 0) { 869 return new Complex(0, Infinity); 870 } 871 872 var d = a * a + b * b; 873 return (d !== 0) 874 ? new Complex( 875 a / d, 876 -b / d).acos() 877 : new Complex( 878 (a !== 0) ? a / 0 : 0, 879 (b !== 0) ? -b / 0 : 0).acos(); 880 }, 881 882 /** 883 * Calculate the complex arcus cosecans 884 * 885 * @returns {Complex} 886 */ 887 'acsc': function() { 888 889 // acsc(c) = -i * log(i / c + sqrt(1 - 1 / c^2)) 890 891 var a = this['re']; 892 var b = this['im']; 893 894 if (a === 0 && b === 0) { 895 return new Complex(Math.PI / 2, Infinity); 896 } 897 898 var d = a * a + b * b; 899 return (d !== 0) 900 ? new Complex( 901 a / d, 902 -b / d).asin() 903 : new Complex( 904 (a !== 0) ? a / 0 : 0, 905 (b !== 0) ? -b / 0 : 0).asin(); 906 }, 907 908 /** 909 * Calculate the complex sinh 910 * 911 * @returns {Complex} 912 */ 913 'sinh': function() { 914 915 // sinh(c) = (e^c - e^-c) / 2 916 917 var a = this['re']; 918 var b = this['im']; 919 920 return new Complex( 921 sinh(a) * Math.cos(b), 922 cosh(a) * Math.sin(b)); 923 }, 924 925 /** 926 * Calculate the complex cosh 927 * 928 * @returns {Complex} 929 */ 930 'cosh': function() { 931 932 // cosh(c) = (e^c + e^-c) / 2 933 934 var a = this['re']; 935 var b = this['im']; 936 937 return new Complex( 938 cosh(a) * Math.cos(b), 939 sinh(a) * Math.sin(b)); 940 }, 941 942 /** 943 * Calculate the complex tanh 944 * 945 * @returns {Complex} 946 */ 947 'tanh': function() { 948 949 // tanh(c) = (e^c - e^-c) / (e^c + e^-c) 950 951 var a = 2 * this['re']; 952 var b = 2 * this['im']; 953 var d = cosh(a) + Math.cos(b); 954 955 return new Complex( 956 sinh(a) / d, 957 Math.sin(b) / d); 958 }, 959 960 /** 961 * Calculate the complex coth 962 * 963 * @returns {Complex} 964 */ 965 'coth': function() { 966 967 // coth(c) = (e^c + e^-c) / (e^c - e^-c) 968 969 var a = 2 * this['re']; 970 var b = 2 * this['im']; 971 var d = cosh(a) - Math.cos(b); 972 973 return new Complex( 974 sinh(a) / d, 975 -Math.sin(b) / d); 976 }, 977 978 /** 979 * Calculate the complex coth 980 * 981 * @returns {Complex} 982 */ 983 'csch': function() { 984 985 // csch(c) = 2 / (e^c - e^-c) 986 987 var a = this['re']; 988 var b = this['im']; 989 var d = Math.cos(2 * b) - cosh(2 * a); 990 991 return new Complex( 992 -2 * sinh(a) * Math.cos(b) / d, 993 2 * cosh(a) * Math.sin(b) / d); 994 }, 995 996 /** 997 * Calculate the complex sech 998 * 999 * @returns {Complex} 1000 */ 1001 'sech': function() { 1002 1003 // sech(c) = 2 / (e^c + e^-c) 1004 1005 var a = this['re']; 1006 var b = this['im']; 1007 var d = Math.cos(2 * b) + cosh(2 * a); 1008 1009 return new Complex( 1010 2 * cosh(a) * Math.cos(b) / d, 1011 -2 * sinh(a) * Math.sin(b) / d); 1012 }, 1013 1014 /** 1015 * Calculate the complex asinh 1016 * 1017 * @returns {Complex} 1018 */ 1019 'asinh': function() { 1020 1021 // asinh(c) = log(c + sqrt(c^2 + 1)) 1022 1023 var tmp = this['im']; 1024 this['im'] = -this['re']; 1025 this['re'] = tmp; 1026 var res = this['asin'](); 1027 1028 this['re'] = -this['im']; 1029 this['im'] = tmp; 1030 tmp = res['re']; 1031 1032 res['re'] = -res['im']; 1033 res['im'] = tmp; 1034 return res; 1035 }, 1036 1037 /** 1038 * Calculate the complex acosh 1039 * 1040 * @returns {Complex} 1041 */ 1042 'acosh': function() { 1043 1044 // acosh(c) = log(c + sqrt(c^2 - 1)) 1045 1046 var res = this['acos'](); 1047 if (res['im'] <= 0) { 1048 var tmp = res['re']; 1049 res['re'] = -res['im']; 1050 res['im'] = tmp; 1051 } else { 1052 var tmp = res['im']; 1053 res['im'] = -res['re']; 1054 res['re'] = tmp; 1055 } 1056 return res; 1057 }, 1058 1059 /** 1060 * Calculate the complex atanh 1061 * 1062 * @returns {Complex} 1063 */ 1064 'atanh': function() { 1065 1066 // atanh(c) = log((1+c) / (1-c)) / 2 1067 1068 var a = this['re']; 1069 var b = this['im']; 1070 1071 var noIM = a > 1 && b === 0; 1072 var oneMinus = 1 - a; 1073 var onePlus = 1 + a; 1074 var d = oneMinus * oneMinus + b * b; 1075 1076 var x = (d !== 0) 1077 ? new Complex( 1078 (onePlus * oneMinus - b * b) / d, 1079 (b * oneMinus + onePlus * b) / d) 1080 : new Complex( 1081 (a !== -1) ? (a / 0) : 0, 1082 (b !== 0) ? (b / 0) : 0); 1083 1084 var temp = x['re']; 1085 x['re'] = logHypot(x['re'], x['im']) / 2; 1086 x['im'] = Math.atan2(x['im'], temp) / 2; 1087 if (noIM) { 1088 x['im'] = -x['im']; 1089 } 1090 return x; 1091 }, 1092 1093 /** 1094 * Calculate the complex acoth 1095 * 1096 * @returns {Complex} 1097 */ 1098 'acoth': function() { 1099 1100 // acoth(c) = log((c+1) / (c-1)) / 2 1101 1102 var a = this['re']; 1103 var b = this['im']; 1104 1105 if (a === 0 && b === 0) { 1106 return new Complex(0, Math.PI / 2); 1107 } 1108 1109 var d = a * a + b * b; 1110 return (d !== 0) 1111 ? new Complex( 1112 a / d, 1113 -b / d).atanh() 1114 : new Complex( 1115 (a !== 0) ? a / 0 : 0, 1116 (b !== 0) ? -b / 0 : 0).atanh(); 1117 }, 1118 1119 /** 1120 * Calculate the complex acsch 1121 * 1122 * @returns {Complex} 1123 */ 1124 'acsch': function() { 1125 1126 // acsch(c) = log((1+sqrt(1+c^2))/c) 1127 1128 var a = this['re']; 1129 var b = this['im']; 1130 1131 if (b === 0) { 1132 1133 return new Complex( 1134 (a !== 0) 1135 ? Math.log(a + Math.sqrt(a * a + 1)) 1136 : Infinity, 0); 1137 } 1138 1139 var d = a * a + b * b; 1140 return (d !== 0) 1141 ? new Complex( 1142 a / d, 1143 -b / d).asinh() 1144 : new Complex( 1145 (a !== 0) ? a / 0 : 0, 1146 (b !== 0) ? -b / 0 : 0).asinh(); 1147 }, 1148 1149 /** 1150 * Calculate the complex asech 1151 * 1152 * @returns {Complex} 1153 */ 1154 'asech': function() { 1155 1156 // asech(c) = log((1+sqrt(1-c^2))/c) 1157 1158 var a = this['re']; 1159 var b = this['im']; 1160 1161 if (this['isZero']()) { 1162 return Complex['INFINITY']; 1163 } 1164 1165 var d = a * a + b * b; 1166 return (d !== 0) 1167 ? new Complex( 1168 a / d, 1169 -b / d).acosh() 1170 : new Complex( 1171 (a !== 0) ? a / 0 : 0, 1172 (b !== 0) ? -b / 0 : 0).acosh(); 1173 }, 1174 1175 /** 1176 * Calculate the complex inverse 1/z 1177 * 1178 * @returns {Complex} 1179 */ 1180 'inverse': function() { 1181 1182 // 1 / 0 = Infinity and 1 / Infinity = 0 1183 if (this['isZero']()) { 1184 return Complex['INFINITY']; 1185 } 1186 1187 if (this['isInfinite']()) { 1188 return Complex['ZERO']; 1189 } 1190 1191 var a = this['re']; 1192 var b = this['im']; 1193 1194 var d = a * a + b * b; 1195 1196 return new Complex(a / d, -b / d); 1197 }, 1198 1199 /** 1200 * Returns the complex conjugate 1201 * 1202 * @returns {Complex} 1203 */ 1204 'conjugate': function() { 1205 1206 return new Complex(this['re'], -this['im']); 1207 }, 1208 1209 /** 1210 * Gets the negated complex number 1211 * 1212 * @returns {Complex} 1213 */ 1214 'neg': function() { 1215 1216 return new Complex(-this['re'], -this['im']); 1217 }, 1218 1219 /** 1220 * Ceils the actual complex number 1221 * 1222 * @returns {Complex} 1223 */ 1224 'ceil': function(places) { 1225 1226 places = Math.pow(10, places || 0); 1227 1228 return new Complex( 1229 Math.ceil(this['re'] * places) / places, 1230 Math.ceil(this['im'] * places) / places); 1231 }, 1232 1233 /** 1234 * Floors the actual complex number 1235 * 1236 * @returns {Complex} 1237 */ 1238 'floor': function(places) { 1239 1240 places = Math.pow(10, places || 0); 1241 1242 return new Complex( 1243 Math.floor(this['re'] * places) / places, 1244 Math.floor(this['im'] * places) / places); 1245 }, 1246 1247 /** 1248 * Ceils the actual complex number 1249 * 1250 * @returns {Complex} 1251 */ 1252 'round': function(places) { 1253 1254 places = Math.pow(10, places || 0); 1255 1256 return new Complex( 1257 Math.round(this['re'] * places) / places, 1258 Math.round(this['im'] * places) / places); 1259 }, 1260 1261 /** 1262 * Compares two complex numbers 1263 * 1264 * **Note:** new Complex(Infinity).equals(Infinity) === false 1265 * 1266 * @returns {boolean} 1267 */ 1268 'equals': function(a, b) { 1269 1270 var z = new Complex(a, b); 1271 1272 return Math.abs(z['re'] - this['re']) <= Complex['EPSILON'] && 1273 Math.abs(z['im'] - this['im']) <= Complex['EPSILON']; 1274 }, 1275 1276 /** 1277 * Clones the actual object 1278 * 1279 * @returns {Complex} 1280 */ 1281 'clone': function() { 1282 1283 return new Complex(this['re'], this['im']); 1284 }, 1285 1286 /** 1287 * Gets a string of the actual complex number 1288 * 1289 * @returns {string} 1290 */ 1291 'toString': function() { 1292 1293 var a = this['re']; 1294 var b = this['im']; 1295 var ret = ""; 1296 1297 if (this['isNaN']()) { 1298 return 'NaN'; 1299 } 1300 1301 if (this['isInfinite']()) { 1302 return 'Infinity'; 1303 } 1304 1305 if (Math.abs(a) < Complex['EPSILON']) { 1306 a = 0; 1307 } 1308 1309 if (Math.abs(b) < Complex['EPSILON']) { 1310 b = 0; 1311 } 1312 1313 // If is real number 1314 if (b === 0) { 1315 return ret + a; 1316 } 1317 1318 if (a !== 0) { 1319 ret += a; 1320 ret += " "; 1321 if (b < 0) { 1322 b = -b; 1323 ret += "-"; 1324 } else { 1325 ret += "+"; 1326 } 1327 ret += " "; 1328 } else if (b < 0) { 1329 b = -b; 1330 ret += "-"; 1331 } 1332 1333 if (1 !== b) { // b is the absolute imaginary part 1334 ret += b; 1335 } 1336 return ret + "i"; 1337 }, 1338 1339 /** 1340 * Returns the actual number as a vector 1341 * 1342 * @returns {Array} 1343 */ 1344 'toVector': function() { 1345 1346 return [this['re'], this['im']]; 1347 }, 1348 1349 /** 1350 * Returns the actual real value of the current object 1351 * 1352 * @returns {number|null} 1353 */ 1354 'valueOf': function() { 1355 1356 if (this['im'] === 0) { 1357 return this['re']; 1358 } 1359 return null; 1360 }, 1361 1362 /** 1363 * Determines whether a complex number is not on the Riemann sphere. 1364 * 1365 * @returns {boolean} 1366 */ 1367 'isNaN': function() { 1368 return isNaN(this['re']) || isNaN(this['im']); 1369 }, 1370 1371 /** 1372 * Determines whether or not a complex number is at the zero pole of the 1373 * Riemann sphere. 1374 * 1375 * @returns {boolean} 1376 */ 1377 'isZero': function() { 1378 return this['im'] === 0 && this['re'] === 0; 1379 }, 1380 1381 /** 1382 * Determines whether a complex number is not at the infinity pole of the 1383 * Riemann sphere. 1384 * 1385 * @returns {boolean} 1386 */ 1387 'isFinite': function() { 1388 return isFinite(this['re']) && isFinite(this['im']); 1389 }, 1390 1391 /** 1392 * Determines whether or not a complex number is at the infinity pole of the 1393 * Riemann sphere. 1394 * 1395 * @returns {boolean} 1396 */ 1397 'isInfinite': function() { 1398 return !(this['isNaN']() || this['isFinite']()); 1399 } 1400 }; 1401 1402 Complex['ZERO'] = new Complex(0, 0); 1403 Complex['ONE'] = new Complex(1, 0); 1404 Complex['I'] = new Complex(0, 1); 1405 Complex['PI'] = new Complex(Math.PI, 0); 1406 Complex['E'] = new Complex(Math.E, 0); 1407 Complex['INFINITY'] = new Complex(Infinity, Infinity); 1408 Complex['NAN'] = new Complex(NaN, NaN); 1409 Complex['EPSILON'] = 1e-15; 1410 1411 if (typeof define === 'function' && define['amd']) { 1412 define([], function() { 1413 return Complex; 1414 }); 1415 } else if (typeof exports === 'object') { 1416 Object.defineProperty(Complex, "__esModule", { 'value': true }); 1417 Complex['default'] = Complex; 1418 Complex['Complex'] = Complex; 1419 module['exports'] = Complex; 1420 } else { 1421 root['Complex'] = Complex; 1422 } 1423 1424 })(this);