From 3bda442f75ccde5f2d8ed45bf63f39953d776fe7 Mon Sep 17 00:00:00 2001 From: Jamie Law Date: Wed, 20 May 2026 15:48:53 +0100 Subject: [PATCH] Change return type of `parse` --- LICENSE | 2 +- README.md | 2 +- dist/complex.js | 146 +++++++++++++++++++----------------------- dist/complex.min.js | 43 +++++++------ dist/complex.mjs | 146 +++++++++++++++++++----------------------- src/complex.js | 150 ++++++++++++++++++++------------------------ 6 files changed, 223 insertions(+), 266 deletions(-) diff --git a/LICENSE b/LICENSE index 8741015..127b21a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2025 Robert Eisele +Copyright (c) 2026 Robert Eisele Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 8e3e2ec..8e3a96a 100644 --- a/README.md +++ b/README.md @@ -369,5 +369,5 @@ npm run test ## Copyright and Licensing -Copyright (c) 2025, [Robert Eisele](https://raw.org/) +Copyright (c) 2026, [Robert Eisele](https://raw.org/) Licensed under the MIT license. diff --git a/dist/complex.js b/dist/complex.js index 11ff7ec..652c1d2 100644 --- a/dist/complex.js +++ b/dist/complex.js @@ -131,49 +131,44 @@ function logHypot(a, b) { return 0.5 * Math.log(a * a + b * b) + Math.LN2; } -const P = { 're': 0, 'im': 0 }; const parse = function (a, b) { - const z = P; - if (a === undefined || a === null) { - z['re'] = - z['im'] = 0; + return [0, 0]; } else if (b !== undefined) { - z['re'] = a; - z['im'] = b; + return [a, b]; } else switch (typeof a) { case 'object': if ('im' in a && 're' in a) { - z['re'] = a['re']; - z['im'] = a['im']; + return [a['re'], a['im']]; } else if ('abs' in a && 'arg' in a) { if (!isFinite(a['abs']) && isFinite(a['arg'])) { - return Complex['INFINITY']; + return [Infinity, Infinity]; } - z['re'] = a['abs'] * Math.cos(a['arg']); - z['im'] = a['abs'] * Math.sin(a['arg']); + return [ + a['abs'] * Math.cos(a['arg']), + a['abs'] * Math.sin(a['arg']) + ]; } else if ('r' in a && 'phi' in a) { if (!isFinite(a['r']) && isFinite(a['phi'])) { - return Complex['INFINITY']; + return [Infinity, Infinity]; } - z['re'] = a['r'] * Math.cos(a['phi']); - z['im'] = a['r'] * Math.sin(a['phi']); + return [ + a['r'] * Math.cos(a['phi']), + a['r'] * Math.sin(a['phi']) + ]; } else if (a.length === 2) { // Quick array check - z['re'] = a[0]; - z['im'] = a[1]; + return [a[0], a[1]]; } else { parser_exit(); } - break; case 'string': - z['im'] = /* void */ - z['re'] = 0; + let re = 0, im = 0; const tokens = a.replace(/_/g, '') .match(/\d+\.?\d*e[+-]?\d+|\d+\.?\d*|\.\d+|./g); @@ -201,10 +196,10 @@ const parse = function (a, b) { } if (tokens[i + 1] !== ' ' && !isNaN(tokens[i + 1])) { - z['im'] += parseFloat((minus % 2 ? '-' : '') + tokens[i + 1]); + im += parseFloat((minus % 2 ? '-' : '') + tokens[i + 1]); i++; } else { - z['im'] += parseFloat((minus % 2 ? '-' : '') + '1'); + im += parseFloat((minus % 2 ? '-' : '') + '1'); } plus = minus = 0; @@ -215,10 +210,10 @@ const parse = function (a, b) { } if (tokens[i + 1] === 'i' || tokens[i + 1] === 'I') { - z['im'] += parseFloat((minus % 2 ? '-' : '') + c); + im += parseFloat((minus % 2 ? '-' : '') + c); i++; } else { - z['re'] += parseFloat((minus % 2 ? '-' : '') + c); + re += parseFloat((minus % 2 ? '-' : '') + c); } plus = minus = 0; } @@ -228,23 +223,14 @@ const parse = function (a, b) { if (plus + minus > 0) { parser_exit(); } - break; + return [re, im]; case 'number': - z['im'] = 0; - z['re'] = a; - break; + return [a, 0]; default: parser_exit(); } - - if (isNaN(z['re']) || isNaN(z['im'])) { - // If a calculation is NaN, we treat it as NaN and don't throw - //parser_exit(); - } - - return z; }; /** @@ -257,10 +243,10 @@ function Complex(a, b) { return new Complex(a, b); } - const z = parse(a, b); + const [re, im] = parse(a, b); - this['re'] = z['re']; - this['im'] = z['im']; + this['re'] = re; + this['im'] = im; } Complex.prototype = { @@ -289,10 +275,10 @@ Complex.prototype = { */ 'add': function (a, b) { - const z = parse(a, b); + const [re, im] = parse(a, b); const tInfin = this['isInfinite'](); - const zInfin = !(isFinite(z['re']) && isFinite(z['im'])); + const zInfin = !(isFinite(re) && isFinite(im)); if (tInfin || zInfin) { @@ -305,8 +291,8 @@ Complex.prototype = { } return new Complex( - this['re'] + z['re'], - this['im'] + z['im']); + this['re'] + re, + this['im'] + im); }, /** @@ -316,10 +302,10 @@ Complex.prototype = { */ 'sub': function (a, b) { - const z = parse(a, b); + const [re, im] = parse(a, b); const tInfin = this['isInfinite'](); - const zInfin = !(isFinite(z['re']) && isFinite(z['im'])); + const zInfin = !(isFinite(re) && isFinite(im)); if (tInfin || zInfin) { @@ -332,8 +318,8 @@ Complex.prototype = { } return new Complex( - this['re'] - z['re'], - this['im'] - z['im']); + this['re'] - re, + this['im'] - im); }, /** @@ -343,12 +329,12 @@ Complex.prototype = { */ 'mul': function (a, b) { - const z = parse(a, b); + const [re, im] = parse(a, b); const tInfin = this['isInfinite'](); - const zInfin = !(isFinite(z['re']) && isFinite(z['im'])); + const zInfin = !(isFinite(re) && isFinite(im)); const tIsZero = this['re'] === 0 && this['im'] === 0; - const zIsZero = z['re'] === 0 && z['im'] === 0; + const zIsZero = re === 0 && im === 0; // Infinity * 0 = NaN if (tInfin && zIsZero || zInfin && tIsZero) { @@ -361,13 +347,13 @@ Complex.prototype = { } // Shortcut for real values - if (z['im'] === 0 && this['im'] === 0) { - return new Complex(this['re'] * z['re'], 0); + if (im === 0 && this['im'] === 0) { + return new Complex(this['re'] * re, 0); } return new Complex( - this['re'] * z['re'] - this['im'] * z['im'], - this['re'] * z['im'] + this['im'] * z['re']); + this['re'] * re - this['im'] * im, + this['re'] * im + this['im'] * re); }, /** @@ -377,12 +363,12 @@ Complex.prototype = { */ 'div': function (a, b) { - const z = parse(a, b); + const [re, im] = parse(a, b); const tInfin = this['isInfinite'](); - const zInfin = !(isFinite(z['re']) && isFinite(z['im'])); + const zInfin = !(isFinite(re) && isFinite(im)); const tIsZero = this['re'] === 0 && this['im'] === 0; - const zIsZero = z['re'] === 0 && z['im'] === 0; + const zIsZero = re === 0 && im === 0; // 0 / 0 = NaN and Infinity / Infinity = NaN if (tIsZero && zIsZero || tInfin && zInfin) { @@ -399,15 +385,15 @@ Complex.prototype = { return Complex['ZERO']; } - if (0 === z['im']) { + if (im === 0) { // Divisor is real - return new Complex(this['re'] / z['re'], this['im'] / z['re']); + return new Complex(this['re'] / re, this['im'] / re); } - if (Math.abs(z['re']) < Math.abs(z['im'])) { + if (Math.abs(re) < Math.abs(im)) { - const x = z['re'] / z['im']; - const t = z['re'] * x + z['im']; + const x = re / im; + const t = re * x + im; return new Complex( (this['re'] * x + this['im']) / t, @@ -415,8 +401,8 @@ Complex.prototype = { } else { - const x = z['im'] / z['re']; - const t = z['im'] * x + z['re']; + const x = im / re; + const t = im * x + re; return new Complex( (this['re'] + this['im'] * x) / t, @@ -431,33 +417,33 @@ Complex.prototype = { */ 'pow': function (a, b) { - const z = parse(a, b); + const [re, im] = parse(a, b); const tIsZero = this['re'] === 0 && this['im'] === 0; - const zIsZero = z['re'] === 0 && z['im'] === 0; + const zIsZero = re === 0 && im === 0; if (zIsZero) { return Complex['ONE']; } // If the exponent is real - if (z['im'] === 0) { + if (im === 0) { if (this['im'] === 0 && this['re'] > 0) { - return new Complex(Math.pow(this['re'], z['re']), 0); + return new Complex(Math.pow(this['re'], re), 0); } else if (this['re'] === 0) { // If base is fully imaginary - switch ((z['re'] % 4 + 4) % 4) { + switch ((re % 4 + 4) % 4) { case 0: - return new Complex(Math.pow(this['im'], z['re']), 0); + return new Complex(Math.pow(this['im'], re), 0); case 1: - return new Complex(0, Math.pow(this['im'], z['re'])); + return new Complex(0, Math.pow(this['im'], re)); case 2: - return new Complex(-Math.pow(this['im'], z['re']), 0); + return new Complex(-Math.pow(this['im'], re), 0); case 3: - return new Complex(0, -Math.pow(this['im'], z['re'])); + return new Complex(0, -Math.pow(this['im'], re)); } } } @@ -481,18 +467,18 @@ Complex.prototype = { * */ - if (tIsZero && z['re'] > 0) { // Same behavior as Wolframalpha, Zero if real part is zero + if (tIsZero && re > 0) { // Same behavior as Wolframalpha, Zero if real part is zero return Complex['ZERO']; } const arg = Math.atan2(this['im'], this['re']); const loh = logHypot(this['re'], this['im']); - let re = Math.exp(z['re'] * loh - z['im'] * arg); - let im = z['im'] * loh + z['re'] * arg; + let r = Math.exp(re * loh - im * arg); + let theta = im * loh + re * arg; return new Complex( - re * Math.cos(im), - re * Math.sin(im)); + r * Math.cos(theta), + r * Math.sin(theta)); }, /** @@ -1329,10 +1315,10 @@ Complex.prototype = { */ 'equals': function (a, b) { - const z = parse(a, b); + const [re, im] = parse(a, b); - return Math.abs(z['re'] - this['re']) <= Complex['EPSILON'] && - Math.abs(z['im'] - this['im']) <= Complex['EPSILON']; + return Math.abs(re - this['re']) <= Complex['EPSILON'] && + Math.abs(im - this['im']) <= Complex['EPSILON']; }, /** diff --git a/dist/complex.min.js b/dist/complex.min.js index 37c9da1..e400f18 100644 --- a/dist/complex.min.js +++ b/dist/complex.min.js @@ -1,27 +1,26 @@ /* -Complex.js v2.4.3 11/13/2025 +Complex.js v2.4.3 5/20/2026 https://raw.org/article/complex-numbers-in-javascript/ -Copyright (c) 2025, Robert Eisele (https://raw.org/) +Copyright (c) 2026, Robert Eisele (https://raw.org/) Licensed under the MIT license. */ -'use strict';(function(q){function l(a,b){if(a===void 0||a===null)f.re=f.im=0;else if(b!==void 0)f.re=a,f.im=b;else switch(typeof a){case "object":if("im"in a&&"re"in a)f.re=a.re,f.im=a.im;else if("abs"in a&&"arg"in a){if(!isFinite(a.abs)&&isFinite(a.arg))return c.INFINITY;f.re=a.abs*Math.cos(a.arg);f.im=a.abs*Math.sin(a.arg)}else if("r"in a&&"phi"in a){if(!isFinite(a.r)&&isFinite(a.phi))return c.INFINITY;f.re=a.r*Math.cos(a.phi);f.im=a.r*Math.sin(a.phi)}else a.length===2?(f.re=a[0],f.im=a[1]):m(); -break;case "string":f.im=f.re=0;a=a.replace(/_/g,"").match(/\d+\.?\d*e[+-]?\d+|\d+\.?\d*|\.\d+|./g);b=1;let d=0;a===null&&m();for(let e=0;e0&& -m();break;case "number":f.im=0;f.re=a;break;default:m()}return f}function m(){throw SyntaxError("Invalid Param");}function n(a,b){a=Math.abs(a);b=Math.abs(b);a -0)return new c(Math.pow(this.re,a.re),0);if(this.re===0)switch((a.re%4+4)%4){case 0:return new c(Math.pow(this.im,a.re),0);case 1:return new c(0,Math.pow(this.im,a.re));case 2:return new c(-Math.pow(this.im,a.re),0);case 3:return new c(0,-Math.pow(this.im,a.re))}}if(b&&a.re>0)return c.ZERO;const d=Math.atan2(this.im,this.re),e=p(this.re,this.im);b=Math.exp(a.re*e-a.im*d);a=a.im*e+a.re*d;return new c(b*Math.cos(a),b*Math.sin(a))},sqrt:function(){const a=this.re,b=this.im;if(b===0)return a>=0?new c(Math.sqrt(a), -0):new c(0,Math.sqrt(-a));var d=n(a,b);d=Math.sqrt(.5*(d+Math.abs(a)));let e=Math.abs(b)/(2*d);return a>=0?new c(d,b<0?-e:e):new c(e,b<0?-d:d)},exp:function(){const a=Math.exp(this.re);return this.im===0?new c(a,0):new c(a*Math.cos(this.im),a*Math.sin(this.im))},expm1:function(){const a=this.re,b=this.im,d=Math.sin(.5*b);return new c(Math.expm1(a)*Math.cos(b)+-2*d*d,Math.exp(a)*Math.sin(b))},log:function(){const a=this.re,b=this.im;return b===0&&a>0?new c(Math.log(a),0):new c(p(a,b),Math.atan2(b, -a))},abs:function(){return n(this.re,this.im)},arg:function(){return Math.atan2(this.im,this.re)},sin:function(){const a=this.re,b=this.im;return new c(Math.sin(a)*h(b),Math.cos(a)*k(b))},cos:function(){const a=this.re,b=this.im;return new c(Math.cos(a)*h(b),-Math.sin(a)*k(b))},tan:function(){const a=2*this.re,b=2*this.im,d=Math.cos(a)+h(b);return new c(Math.sin(a)/d,k(b)/d)},cot:function(){const a=2*this.re,b=2*this.im,d=Math.cos(a)-h(b);return new c(-Math.sin(a)/d,k(b)/d)},sec:function(){const a= -this.re,b=this.im,d=.5*h(2*b)+.5*Math.cos(2*a);return new c(Math.cos(a)*h(b)/d,Math.sin(a)*k(b)/d)},csc:function(){const a=this.re,b=this.im,d=.5*h(2*b)-.5*Math.cos(2*a);return new c(Math.sin(a)*h(b)/d,-Math.cos(a)*k(b)/d)},asin:function(){var a=this.re;const b=this.im,d=(new c(b*b-a*a+1,-2*a*b)).sqrt();a=(new c(d.re-b,d.im+a)).log();return new c(a.im,-a.re)},acos:function(){var a=this.re;const b=this.im,d=(new c(b*b-a*a+1,-2*a*b)).sqrt();a=(new c(d.re-b,d.im+a)).log();return new c(Math.PI/2-a.im, -a.re)},atan:function(){var a=this.re;const b=this.im;if(a===0){if(b===1)return new c(0,Infinity);if(b===-1)return new c(0,-Infinity)}const d=a*a+(1-b)*(1-b);a=(new c((1-b*b-a*a)/d,-2*a/d)).log();return new c(-.5*a.im,.5*a.re)},acot:function(){const a=this.re,b=this.im;if(b===0)return new c(Math.atan2(1,a),0);const d=a*a+b*b;return d!==0?(new c(a/d,-b/d)).atan():(new c(a!==0?a/0:0,b!==0?-b/0:0)).atan()},asec:function(){const a=this.re,b=this.im;if(a===0&&b===0)return new c(0,Infinity);const d=a*a+ -b*b;return d!==0?(new c(a/d,-b/d)).acos():(new c(a!==0?a/0:0,b!==0?-b/0:0)).acos()},acsc:function(){const a=this.re,b=this.im;if(a===0&&b===0)return new c(Math.PI/2,Infinity);const d=a*a+b*b;return d!==0?(new c(a/d,-b/d)).asin():(new c(a!==0?a/0:0,b!==0?-b/0:0)).asin()},sinh:function(){const a=this.re,b=this.im;return new c(k(a)*Math.cos(b),h(a)*Math.sin(b))},cosh:function(){const a=this.re,b=this.im;return new c(h(a)*Math.cos(b),k(a)*Math.sin(b))},tanh:function(){const a=2*this.re,b=2*this.im,d= -h(a)+Math.cos(b);return new c(k(a)/d,Math.sin(b)/d)},coth:function(){const a=2*this.re,b=2*this.im,d=h(a)-Math.cos(b);return new c(k(a)/d,-Math.sin(b)/d)},csch:function(){const a=this.re,b=this.im,d=Math.cos(2*b)-h(2*a);return new c(-2*k(a)*Math.cos(b)/d,2*h(a)*Math.sin(b)/d)},sech:function(){const a=this.re,b=this.im,d=Math.cos(2*b)+h(2*a);return new c(2*h(a)*Math.cos(b)/d,-2*k(a)*Math.sin(b)/d)},asinh:function(){const a=this.re;var b=this.im;if(b===0){if(a===0)return new c(0,0);b=Math.abs(a);b= -Math.log(b+Math.sqrt(b*b+1));return new c(a<0?-b:b,0)}const d=(new c(a*a-b*b+1,2*a*b)).sqrt();return(new c(a+d.re,b+d.im)).log()},acosh:function(){const a=this.re,b=this.im;if(b===0)return a>1?new c(Math.log(a+Math.sqrt(a-1)*Math.sqrt(a+1)),0):a<-1?new c(Math.log(-a+Math.sqrt(a*a-1)),Math.PI):new c(0,Math.acos(a));const d=(new c(a-1,b)).sqrt(),e=(new c(a+1,b)).sqrt();return(new c(a+d.re*e.re-d.im*e.im,b+d.re*e.im+d.im*e.re)).log()},atanh:function(){var a=this.re,b=this.im;if(b===0)return a===0?new c(0, -0):a===1?new c(Infinity,0):a===-1?new c(-Infinity,0):-11?new c(.5*Math.log((a+1)/(a-1)),-Math.PI/2):new c(.5*Math.log(-((1+a)/(1-a))),Math.PI/2);const d=1-a,e=1+a,g=d*d+b*b;if(g===0)return new c(a!==-1?a/0:0,b!==0?b/0:0);a=(e*d-b*b)/g;b=(b*d+e*b)/g;return new c(p(a,b)/2,Math.atan2(b,a)/2)},acoth:function(){const a=this.re,b=this.im;if(a===0&&b===0)return new c(0,Math.PI/2);const d=a*a+b*b;return d!==0?(new c(a/d,-b/d)).atanh():(new c(a!==0?a/0:0,b!==0?-b/ -0:0)).atanh()},acsch:function(){var a=this.re;const b=this.im;if(b===0){if(a===0)return new c(Infinity,0);a=1/a;return new c(Math.log(a+Math.sqrt(a*a+1)),0)}const d=a*a+b*b;return d!==0?(new c(a/d,-b/d)).asinh():(new c(a!==0?a/0:0,b!==0?-b/0:0)).asinh()},asech:function(){const a=this.re,b=this.im;if(this.isZero())return c.INFINITY;const d=a*a+b*b;return d!==0?(new c(a/d,-b/d)).acosh():(new c(a!==0?a/0:0,b!==0?-b/0:0)).acosh()},inverse:function(){if(this.isZero())return c.INFINITY;if(this.isInfinite())return c.ZERO; -const a=this.re,b=this.im,d=a*a+b*b;return new c(a/d,-b/d)},conjugate:function(){return new c(this.re,-this.im)},neg:function(){return new c(-this.re,-this.im)},ceil:function(a){a=Math.pow(10,a||0);return new c(Math.ceil(this.re*a)/a,Math.ceil(this.im*a)/a)},floor:function(a){a=Math.pow(10,a||0);return new c(Math.floor(this.re*a)/a,Math.floor(this.im*a)/a)},round:function(a){a=Math.pow(10,a||0);return new c(Math.round(this.re*a)/a,Math.round(this.im*a)/a)},equals:function(a,b){a=l(a,b);return Math.abs(a.re- -this.re)<=c.EPSILON&&Math.abs(a.im-this.im)<=c.EPSILON},clone:function(){return new c(this.re,this.im)},toString:function(){let a=this.re,b=this.im,d="";if(this.isNaN())return"NaN";if(this.isInfinite())return"Infinity";Math.abs(a)a)return Math.sqrt(a*a+b*b);b/=a;return a*Math.sqrt(1+b*b)}function q(a,b){const c=Math.abs(a),e=Math.abs(b);if(0===a)return Math.log(e);if(0===b)return Math.log(c);if(3E3>c&&3E3>e)return.5*Math.log(a*a+b*b);a*=.5;b*=.5;return.5*Math.log(a*a+b*b)+Math.LN2}function d(a,b){if(!(this instanceof d))return new d(a,b);const [c,e]=m(a,b);this.re=c;this.im=e}const g=Math.cosh||function(a){return 1E-9>Math.abs(a)?1-a:.5*(Math.exp(a)+Math.exp(-a))}, +k=Math.sinh||function(a){return 1E-9>Math.abs(a)?a:.5*(Math.exp(a)-Math.exp(-a))};d.prototype={re:0,im:0,sign:function(){const a=p(this.re,this.im);return new d(this.re/a,this.im/a)},add:function(a,b){const [c,e]=m(a,b);a=this.isInfinite();b=!(isFinite(c)&&isFinite(e));return a||b?a&&b?d.NAN:d.INFINITY:new d(this.re+c,this.im+e)},sub:function(a,b){const [c,e]=m(a,b);a=this.isInfinite();b=!(isFinite(c)&&isFinite(e));return a||b?a&&b?d.NAN:d.INFINITY:new d(this.re-c,this.im-e)},mul:function(a,b){const [c, +e]=m(a,b);a=this.isInfinite();b=!(isFinite(c)&&isFinite(e));const f=0===this.re&&0===this.im;return a&&0===c&&0===e||b&&f?d.NAN:a||b?d.INFINITY:0===e&&0===this.im?new d(this.re*c,0):new d(this.re*c-this.im*e,this.re*e+this.im*c)},div:function(a,b){const [c,e]=m(a,b);a=this.isInfinite();b=!(isFinite(c)&&isFinite(e));const f=0===this.re&&0===this.im,h=0===c&&0===e;if(f&&h||a&&b)return d.NAN;if(h||a)return d.INFINITY;if(f||b)return d.ZERO;if(0===e)return new d(this.re/c,this.im/c);if(Math.abs(c)b?-e:e):new d(e,0>b?-c:c)},exp:function(){const a=Math.exp(this.re);return 0===this.im?new d(a,0):new d(a*Math.cos(this.im),a*Math.sin(this.im))}, +expm1:function(){const a=this.re,b=this.im,c=Math.sin(.5*b);return new d(Math.expm1(a)*Math.cos(b)+-2*c*c,Math.exp(a)*Math.sin(b))},log:function(){const a=this.re,b=this.im;return 0===b&&0a?-b:b,0)}const c=(new d(a*a-b*b+1,2*a*b)).sqrt();return(new d(a+c.re,b+c.im)).log()},acosh:function(){const a=this.re,b=this.im;if(0===b)return 1a?new d(Math.log(-a+Math.sqrt(a* +a-1)),Math.PI):new d(0,Math.acos(a));const c=(new d(a-1,b)).sqrt(),e=(new d(a+1,b)).sqrt();return(new d(a+c.re*e.re-c.im*e.im,b+c.re*e.im+c.im*e.re)).log()},atanh:function(){var a=this.re,b=this.im;if(0===b)return 0===a?new d(0,0):1===a?new d(Infinity,0):-1===a?new d(-Infinity,0):-1a?new d(.5*Math.log((1+a)/(1-a)),0):1b?(b=-b,c+="-"):c+="+",c+=" "):0>b&&(b=-b,c+="-");1!==b&&(c+=b);return c+"i"},toVector:function(){return[this.re,this.im]},valueOf:function(){return 0===this.im?this.re:null},isNaN:function(){return isNaN(this.re)||isNaN(this.im)},isZero:function(){return 0===this.im&&0===this.re},isFinite:function(){return isFinite(this.re)&&isFinite(this.im)},isInfinite:function(){return!this.isFinite()}};d.ZERO=new d(0,0);d.ONE=new d(1,0);d.I=new d(0,1);d.PI=new d(Math.PI, +0);d.E=new d(Math.E,0);d.INFINITY=new d(Infinity,Infinity);d.NAN=new d(NaN,NaN);d.EPSILON=1E-15;"function"===typeof define&&define.amd?define([],function(){return d}):"object"===typeof exports?(Object.defineProperty(d,"__esModule",{value:!0}),d["default"]=d,d.Complex=d,module.exports=d):r.Complex=d})(this); diff --git a/dist/complex.mjs b/dist/complex.mjs index 19e3d0d..b9de062 100644 --- a/dist/complex.mjs +++ b/dist/complex.mjs @@ -131,49 +131,44 @@ function logHypot(a, b) { return 0.5 * Math.log(a * a + b * b) + Math.LN2; } -const P = { 're': 0, 'im': 0 }; const parse = function (a, b) { - const z = P; - if (a === undefined || a === null) { - z['re'] = - z['im'] = 0; + return [0, 0]; } else if (b !== undefined) { - z['re'] = a; - z['im'] = b; + return [a, b]; } else switch (typeof a) { case 'object': if ('im' in a && 're' in a) { - z['re'] = a['re']; - z['im'] = a['im']; + return [a['re'], a['im']]; } else if ('abs' in a && 'arg' in a) { if (!isFinite(a['abs']) && isFinite(a['arg'])) { - return Complex['INFINITY']; + return [Infinity, Infinity]; } - z['re'] = a['abs'] * Math.cos(a['arg']); - z['im'] = a['abs'] * Math.sin(a['arg']); + return [ + a['abs'] * Math.cos(a['arg']), + a['abs'] * Math.sin(a['arg']) + ]; } else if ('r' in a && 'phi' in a) { if (!isFinite(a['r']) && isFinite(a['phi'])) { - return Complex['INFINITY']; + return [Infinity, Infinity]; } - z['re'] = a['r'] * Math.cos(a['phi']); - z['im'] = a['r'] * Math.sin(a['phi']); + return [ + a['r'] * Math.cos(a['phi']), + a['r'] * Math.sin(a['phi']) + ]; } else if (a.length === 2) { // Quick array check - z['re'] = a[0]; - z['im'] = a[1]; + return [a[0], a[1]]; } else { parser_exit(); } - break; case 'string': - z['im'] = /* void */ - z['re'] = 0; + let re = 0, im = 0; const tokens = a.replace(/_/g, '') .match(/\d+\.?\d*e[+-]?\d+|\d+\.?\d*|\.\d+|./g); @@ -201,10 +196,10 @@ const parse = function (a, b) { } if (tokens[i + 1] !== ' ' && !isNaN(tokens[i + 1])) { - z['im'] += parseFloat((minus % 2 ? '-' : '') + tokens[i + 1]); + im += parseFloat((minus % 2 ? '-' : '') + tokens[i + 1]); i++; } else { - z['im'] += parseFloat((minus % 2 ? '-' : '') + '1'); + im += parseFloat((minus % 2 ? '-' : '') + '1'); } plus = minus = 0; @@ -215,10 +210,10 @@ const parse = function (a, b) { } if (tokens[i + 1] === 'i' || tokens[i + 1] === 'I') { - z['im'] += parseFloat((minus % 2 ? '-' : '') + c); + im += parseFloat((minus % 2 ? '-' : '') + c); i++; } else { - z['re'] += parseFloat((minus % 2 ? '-' : '') + c); + re += parseFloat((minus % 2 ? '-' : '') + c); } plus = minus = 0; } @@ -228,23 +223,14 @@ const parse = function (a, b) { if (plus + minus > 0) { parser_exit(); } - break; + return [re, im]; case 'number': - z['im'] = 0; - z['re'] = a; - break; + return [a, 0]; default: parser_exit(); } - - if (isNaN(z['re']) || isNaN(z['im'])) { - // If a calculation is NaN, we treat it as NaN and don't throw - //parser_exit(); - } - - return z; }; /** @@ -257,10 +243,10 @@ function Complex(a, b) { return new Complex(a, b); } - const z = parse(a, b); + const [re, im] = parse(a, b); - this['re'] = z['re']; - this['im'] = z['im']; + this['re'] = re; + this['im'] = im; } Complex.prototype = { @@ -289,10 +275,10 @@ Complex.prototype = { */ 'add': function (a, b) { - const z = parse(a, b); + const [re, im] = parse(a, b); const tInfin = this['isInfinite'](); - const zInfin = !(isFinite(z['re']) && isFinite(z['im'])); + const zInfin = !(isFinite(re) && isFinite(im)); if (tInfin || zInfin) { @@ -305,8 +291,8 @@ Complex.prototype = { } return new Complex( - this['re'] + z['re'], - this['im'] + z['im']); + this['re'] + re, + this['im'] + im); }, /** @@ -316,10 +302,10 @@ Complex.prototype = { */ 'sub': function (a, b) { - const z = parse(a, b); + const [re, im] = parse(a, b); const tInfin = this['isInfinite'](); - const zInfin = !(isFinite(z['re']) && isFinite(z['im'])); + const zInfin = !(isFinite(re) && isFinite(im)); if (tInfin || zInfin) { @@ -332,8 +318,8 @@ Complex.prototype = { } return new Complex( - this['re'] - z['re'], - this['im'] - z['im']); + this['re'] - re, + this['im'] - im); }, /** @@ -343,12 +329,12 @@ Complex.prototype = { */ 'mul': function (a, b) { - const z = parse(a, b); + const [re, im] = parse(a, b); const tInfin = this['isInfinite'](); - const zInfin = !(isFinite(z['re']) && isFinite(z['im'])); + const zInfin = !(isFinite(re) && isFinite(im)); const tIsZero = this['re'] === 0 && this['im'] === 0; - const zIsZero = z['re'] === 0 && z['im'] === 0; + const zIsZero = re === 0 && im === 0; // Infinity * 0 = NaN if (tInfin && zIsZero || zInfin && tIsZero) { @@ -361,13 +347,13 @@ Complex.prototype = { } // Shortcut for real values - if (z['im'] === 0 && this['im'] === 0) { - return new Complex(this['re'] * z['re'], 0); + if (im === 0 && this['im'] === 0) { + return new Complex(this['re'] * re, 0); } return new Complex( - this['re'] * z['re'] - this['im'] * z['im'], - this['re'] * z['im'] + this['im'] * z['re']); + this['re'] * re - this['im'] * im, + this['re'] * im + this['im'] * re); }, /** @@ -377,12 +363,12 @@ Complex.prototype = { */ 'div': function (a, b) { - const z = parse(a, b); + const [re, im] = parse(a, b); const tInfin = this['isInfinite'](); - const zInfin = !(isFinite(z['re']) && isFinite(z['im'])); + const zInfin = !(isFinite(re) && isFinite(im)); const tIsZero = this['re'] === 0 && this['im'] === 0; - const zIsZero = z['re'] === 0 && z['im'] === 0; + const zIsZero = re === 0 && im === 0; // 0 / 0 = NaN and Infinity / Infinity = NaN if (tIsZero && zIsZero || tInfin && zInfin) { @@ -399,15 +385,15 @@ Complex.prototype = { return Complex['ZERO']; } - if (0 === z['im']) { + if (im === 0) { // Divisor is real - return new Complex(this['re'] / z['re'], this['im'] / z['re']); + return new Complex(this['re'] / re, this['im'] / re); } - if (Math.abs(z['re']) < Math.abs(z['im'])) { + if (Math.abs(re) < Math.abs(im)) { - const x = z['re'] / z['im']; - const t = z['re'] * x + z['im']; + const x = re / im; + const t = re * x + im; return new Complex( (this['re'] * x + this['im']) / t, @@ -415,8 +401,8 @@ Complex.prototype = { } else { - const x = z['im'] / z['re']; - const t = z['im'] * x + z['re']; + const x = im / re; + const t = im * x + re; return new Complex( (this['re'] + this['im'] * x) / t, @@ -431,33 +417,33 @@ Complex.prototype = { */ 'pow': function (a, b) { - const z = parse(a, b); + const [re, im] = parse(a, b); const tIsZero = this['re'] === 0 && this['im'] === 0; - const zIsZero = z['re'] === 0 && z['im'] === 0; + const zIsZero = re === 0 && im === 0; if (zIsZero) { return Complex['ONE']; } // If the exponent is real - if (z['im'] === 0) { + if (im === 0) { if (this['im'] === 0 && this['re'] > 0) { - return new Complex(Math.pow(this['re'], z['re']), 0); + return new Complex(Math.pow(this['re'], re), 0); } else if (this['re'] === 0) { // If base is fully imaginary - switch ((z['re'] % 4 + 4) % 4) { + switch ((re % 4 + 4) % 4) { case 0: - return new Complex(Math.pow(this['im'], z['re']), 0); + return new Complex(Math.pow(this['im'], re), 0); case 1: - return new Complex(0, Math.pow(this['im'], z['re'])); + return new Complex(0, Math.pow(this['im'], re)); case 2: - return new Complex(-Math.pow(this['im'], z['re']), 0); + return new Complex(-Math.pow(this['im'], re), 0); case 3: - return new Complex(0, -Math.pow(this['im'], z['re'])); + return new Complex(0, -Math.pow(this['im'], re)); } } } @@ -481,18 +467,18 @@ Complex.prototype = { * */ - if (tIsZero && z['re'] > 0) { // Same behavior as Wolframalpha, Zero if real part is zero + if (tIsZero && re > 0) { // Same behavior as Wolframalpha, Zero if real part is zero return Complex['ZERO']; } const arg = Math.atan2(this['im'], this['re']); const loh = logHypot(this['re'], this['im']); - let re = Math.exp(z['re'] * loh - z['im'] * arg); - let im = z['im'] * loh + z['re'] * arg; + let r = Math.exp(re * loh - im * arg); + let theta = im * loh + re * arg; return new Complex( - re * Math.cos(im), - re * Math.sin(im)); + r * Math.cos(theta), + r * Math.sin(theta)); }, /** @@ -1329,10 +1315,10 @@ Complex.prototype = { */ 'equals': function (a, b) { - const z = parse(a, b); + const [re, im] = parse(a, b); - return Math.abs(z['re'] - this['re']) <= Complex['EPSILON'] && - Math.abs(z['im'] - this['im']) <= Complex['EPSILON']; + return Math.abs(re - this['re']) <= Complex['EPSILON'] && + Math.abs(im - this['im']) <= Complex['EPSILON']; }, /** diff --git a/src/complex.js b/src/complex.js index fbc1913..70217de 100644 --- a/src/complex.js +++ b/src/complex.js @@ -1,8 +1,8 @@ /** - * @license Complex.js v2.4.3 11/13/2025 + * @license Complex.js v2.4.3 5/20/2026 * https://raw.org/article/complex-numbers-in-javascript/ * - * Copyright (c) 2025, Robert Eisele (https://raw.org/) + * Copyright (c) 2026, Robert Eisele (https://raw.org/) * Licensed under the MIT license. **/ @@ -137,49 +137,44 @@ function logHypot(a, b) { return 0.5 * Math.log(a * a + b * b) + Math.LN2; } -const P = { 're': 0, 'im': 0 }; const parse = function (a, b) { - const z = P; - if (a === undefined || a === null) { - z['re'] = - z['im'] = 0; + return [0, 0]; } else if (b !== undefined) { - z['re'] = a; - z['im'] = b; + return [a, b]; } else switch (typeof a) { case 'object': if ('im' in a && 're' in a) { - z['re'] = a['re']; - z['im'] = a['im']; + return [a['re'], a['im']]; } else if ('abs' in a && 'arg' in a) { if (!isFinite(a['abs']) && isFinite(a['arg'])) { - return Complex['INFINITY']; + return [Infinity, Infinity]; } - z['re'] = a['abs'] * Math.cos(a['arg']); - z['im'] = a['abs'] * Math.sin(a['arg']); + return [ + a['abs'] * Math.cos(a['arg']), + a['abs'] * Math.sin(a['arg']) + ]; } else if ('r' in a && 'phi' in a) { if (!isFinite(a['r']) && isFinite(a['phi'])) { - return Complex['INFINITY']; + return [Infinity, Infinity]; } - z['re'] = a['r'] * Math.cos(a['phi']); - z['im'] = a['r'] * Math.sin(a['phi']); + return [ + a['r'] * Math.cos(a['phi']), + a['r'] * Math.sin(a['phi']) + ]; } else if (a.length === 2) { // Quick array check - z['re'] = a[0]; - z['im'] = a[1]; + return [a[0], a[1]]; } else { parser_exit(); } - break; case 'string': - z['im'] = /* void */ - z['re'] = 0; + let re = 0, im = 0; const tokens = a.replace(/_/g, '') .match(/\d+\.?\d*e[+-]?\d+|\d+\.?\d*|\.\d+|./g); @@ -207,10 +202,10 @@ const parse = function (a, b) { } if (tokens[i + 1] !== ' ' && !isNaN(tokens[i + 1])) { - z['im'] += parseFloat((minus % 2 ? '-' : '') + tokens[i + 1]); + im += parseFloat((minus % 2 ? '-' : '') + tokens[i + 1]); i++; } else { - z['im'] += parseFloat((minus % 2 ? '-' : '') + '1'); + im += parseFloat((minus % 2 ? '-' : '') + '1'); } plus = minus = 0; @@ -221,10 +216,10 @@ const parse = function (a, b) { } if (tokens[i + 1] === 'i' || tokens[i + 1] === 'I') { - z['im'] += parseFloat((minus % 2 ? '-' : '') + c); + im += parseFloat((minus % 2 ? '-' : '') + c); i++; } else { - z['re'] += parseFloat((minus % 2 ? '-' : '') + c); + re += parseFloat((minus % 2 ? '-' : '') + c); } plus = minus = 0; } @@ -234,23 +229,14 @@ const parse = function (a, b) { if (plus + minus > 0) { parser_exit(); } - break; + return [re, im]; case 'number': - z['im'] = 0; - z['re'] = a; - break; + return [a, 0]; default: parser_exit(); } - - if (isNaN(z['re']) || isNaN(z['im'])) { - // If a calculation is NaN, we treat it as NaN and don't throw - //parser_exit(); - } - - return z; }; /** @@ -263,10 +249,10 @@ function Complex(a, b) { return new Complex(a, b); } - const z = parse(a, b); + const [re, im] = parse(a, b); - this['re'] = z['re']; - this['im'] = z['im']; + this['re'] = re; + this['im'] = im; } Complex.prototype = { @@ -295,10 +281,10 @@ Complex.prototype = { */ 'add': function (a, b) { - const z = parse(a, b); + const [re, im] = parse(a, b); const tInfin = this['isInfinite'](); - const zInfin = !(isFinite(z['re']) && isFinite(z['im'])); + const zInfin = !(isFinite(re) && isFinite(im)); if (tInfin || zInfin) { @@ -311,8 +297,8 @@ Complex.prototype = { } return new Complex( - this['re'] + z['re'], - this['im'] + z['im']); + this['re'] + re, + this['im'] + im); }, /** @@ -322,10 +308,10 @@ Complex.prototype = { */ 'sub': function (a, b) { - const z = parse(a, b); + const [re, im] = parse(a, b); const tInfin = this['isInfinite'](); - const zInfin = !(isFinite(z['re']) && isFinite(z['im'])); + const zInfin = !(isFinite(re) && isFinite(im)); if (tInfin || zInfin) { @@ -338,8 +324,8 @@ Complex.prototype = { } return new Complex( - this['re'] - z['re'], - this['im'] - z['im']); + this['re'] - re, + this['im'] - im); }, /** @@ -349,12 +335,12 @@ Complex.prototype = { */ 'mul': function (a, b) { - const z = parse(a, b); + const [re, im] = parse(a, b); const tInfin = this['isInfinite'](); - const zInfin = !(isFinite(z['re']) && isFinite(z['im'])); + const zInfin = !(isFinite(re) && isFinite(im)); const tIsZero = this['re'] === 0 && this['im'] === 0; - const zIsZero = z['re'] === 0 && z['im'] === 0; + const zIsZero = re === 0 && im === 0; // Infinity * 0 = NaN if (tInfin && zIsZero || zInfin && tIsZero) { @@ -367,13 +353,13 @@ Complex.prototype = { } // Shortcut for real values - if (z['im'] === 0 && this['im'] === 0) { - return new Complex(this['re'] * z['re'], 0); + if (im === 0 && this['im'] === 0) { + return new Complex(this['re'] * re, 0); } return new Complex( - this['re'] * z['re'] - this['im'] * z['im'], - this['re'] * z['im'] + this['im'] * z['re']); + this['re'] * re - this['im'] * im, + this['re'] * im + this['im'] * re); }, /** @@ -383,12 +369,12 @@ Complex.prototype = { */ 'div': function (a, b) { - const z = parse(a, b); + const [re, im] = parse(a, b); const tInfin = this['isInfinite'](); - const zInfin = !(isFinite(z['re']) && isFinite(z['im'])); + const zInfin = !(isFinite(re) && isFinite(im)); const tIsZero = this['re'] === 0 && this['im'] === 0; - const zIsZero = z['re'] === 0 && z['im'] === 0; + const zIsZero = re === 0 && im === 0; // 0 / 0 = NaN and Infinity / Infinity = NaN if (tIsZero && zIsZero || tInfin && zInfin) { @@ -405,15 +391,15 @@ Complex.prototype = { return Complex['ZERO']; } - if (0 === z['im']) { + if (im === 0) { // Divisor is real - return new Complex(this['re'] / z['re'], this['im'] / z['re']); + return new Complex(this['re'] / re, this['im'] / re); } - if (Math.abs(z['re']) < Math.abs(z['im'])) { + if (Math.abs(re) < Math.abs(im)) { - const x = z['re'] / z['im']; - const t = z['re'] * x + z['im']; + const x = re / im; + const t = re * x + im; return new Complex( (this['re'] * x + this['im']) / t, @@ -421,8 +407,8 @@ Complex.prototype = { } else { - const x = z['im'] / z['re']; - const t = z['im'] * x + z['re']; + const x = im / re; + const t = im * x + re; return new Complex( (this['re'] + this['im'] * x) / t, @@ -437,33 +423,33 @@ Complex.prototype = { */ 'pow': function (a, b) { - const z = parse(a, b); + const [re, im] = parse(a, b); const tIsZero = this['re'] === 0 && this['im'] === 0; - const zIsZero = z['re'] === 0 && z['im'] === 0; + const zIsZero = re === 0 && im === 0; if (zIsZero) { return Complex['ONE']; } // If the exponent is real - if (z['im'] === 0) { + if (im === 0) { if (this['im'] === 0 && this['re'] > 0) { - return new Complex(Math.pow(this['re'], z['re']), 0); + return new Complex(Math.pow(this['re'], re), 0); } else if (this['re'] === 0) { // If base is fully imaginary - switch ((z['re'] % 4 + 4) % 4) { + switch ((re % 4 + 4) % 4) { case 0: - return new Complex(Math.pow(this['im'], z['re']), 0); + return new Complex(Math.pow(this['im'], re), 0); case 1: - return new Complex(0, Math.pow(this['im'], z['re'])); + return new Complex(0, Math.pow(this['im'], re)); case 2: - return new Complex(-Math.pow(this['im'], z['re']), 0); + return new Complex(-Math.pow(this['im'], re), 0); case 3: - return new Complex(0, -Math.pow(this['im'], z['re'])); + return new Complex(0, -Math.pow(this['im'], re)); } } } @@ -487,18 +473,18 @@ Complex.prototype = { * */ - if (tIsZero && z['re'] > 0) { // Same behavior as Wolframalpha, Zero if real part is zero + if (tIsZero && re > 0) { // Same behavior as Wolframalpha, Zero if real part is zero return Complex['ZERO']; } const arg = Math.atan2(this['im'], this['re']); const loh = logHypot(this['re'], this['im']); - let re = Math.exp(z['re'] * loh - z['im'] * arg); - let im = z['im'] * loh + z['re'] * arg; + let r = Math.exp(re * loh - im * arg); + let theta = im * loh + re * arg; return new Complex( - re * Math.cos(im), - re * Math.sin(im)); + r * Math.cos(theta), + r * Math.sin(theta)); }, /** @@ -1335,10 +1321,10 @@ Complex.prototype = { */ 'equals': function (a, b) { - const z = parse(a, b); + const [re, im] = parse(a, b); - return Math.abs(z['re'] - this['re']) <= Complex['EPSILON'] && - Math.abs(z['im'] - this['im']) <= Complex['EPSILON']; + return Math.abs(re - this['re']) <= Complex['EPSILON'] && + Math.abs(im - this['im']) <= Complex['EPSILON']; }, /**