DKL9 GitList
Repositories
DKL9 home
rtensor
Code
Commits
Branches
Tags
Search
Tree:
1312198
Branches
Tags
master
rtensor
types
complex.js
Import v2.3-dev from a demonic ritual
dkl9
commited
1312198
at 2023-184 18:25:57
complex.js
Blame
History
Raw
"use strict"; class Complex extends BasicNumber { constructor(x, y) { super(); this.re = x; this.im = y || 0; } toString() { if (this.im == 0) { return this.re.toString(); } else { return (this.re == 0 ? "" : this.re.toString() + (this.im > 0 ? " + " : " - ")) + Math.abs(this.im).toString() + "*i"; } } static ify(x) { if (typeof x == "object" && x.constructor == Complex) { return x; } else if (typeof x == "number") { return new Complex(x, 0); } else { return x; } } invalid() { return isNaN(this.re) || isNaN(this.im); } static zero() { return new Complex(0, 0); } static one() { return new Complex(1, 0); } add(z) { return new Complex(this.re + z.re, this.im + z.im); } neg() { return new Complex(-this.re, -this.im); } mul(z) { return new Complex(this.re * z.re - this.im * z.im, this.re * z.im + this.im * z.re); } recip() { const norm2 = this.re ** 2 + this.im ** 2; return new Complex(this.re / norm2, -this.im / norm2); } exp() { const sc = Math.exp(this.re); return new Complex(sc * Math.cos(this.im), sc * Math.sin(this.im)); } ln() { return new Complex(Math.log(Math.sqrt(this.re ** 2 + this.im ** 2)), Math.atan2(this.im, this.re)); } pow(z) { // exact repeated-multiplication exponentiation if (z.im == 0 && Math.floor(z.re) == z.re) { let ret = Complex.one(); const sign = Math.sign(z.re); let sse = Math.abs(z.re); let spt = this; // logarithmic-time exponent algorithm while (sse > 0) { if (sse % 2 == 1) { ret = ret.mul(spt); } spt = spt.mul(spt); sse >>= 1; } return (sign < 0) ? ret.recip() : ret; // arbitrary powers } else { return this.ln().mul(z).exp(); } } eq(z) { return this.re == z.re && this.im == z.im; } sqrt() { return this.pow(new Complex(0.5, 0)); } sin() { const iz = new Complex(-this.im, this.re); return (iz.exp().sub(iz.neg().exp())).div(new Complex(0, 2)); } cos() { const iz = new Complex(-this.im, this.re); return (iz.exp().add(iz.neg().exp())).div(new Complex(2, 0)); } asin() { const iz = new Complex(-this.im, this.re); const root = Complex.one().sub(this.mul(this)).sqrt(); const lv = (iz.add(root)).ln(); return new Complex(lv.im, -lv.re); } acos() { return (new Complex(Math.PI / 2, 0)).sub(this.asin()); } atan(x) { // TODO: handle two-argument const iz = new Complex(-this.im, this.re); return (Complex.one().sub(iz).ln().sub(Complex.one().add(iz).ln())).div(new Complex(0, -2)); } isNeg() { return this.re < 0; } mag() { return Math.sqrt(this.re ** 2 + this.im ** 2); } }