immutable-complex
Version:
Do calculations with Complex numbers
258 lines (214 loc) • 5.17 kB
JavaScript
var Complex = function(real, imag){
Object.defineProperty(this, 'real', {
value: real !== undefined ? real : 0
, writable: false
})
Object.defineProperty(this, 'imag', {
value: imag !== undefined ? imag : 0
, writable: false
})
};
var prototype = Complex.prototype = {
constructor: Complex,
fromRect: function(a, b) {
return new this.constructor(a, b)
},
fromPolar: function(r, phi){
if (typeof r == 'string'){
var parts = r.split(' ');
r = parts[0];
phi = parts[1];
}
return new this.constructor(
r * Math.cos(phi),
r * Math.sin(phi)
);
},
toPrecision: function(k){
return new this.constructor(
this.real.toPrecision(k),
this.imag.toPrecision(k)
);
},
toFixed: function(k){
return new this.constructor(
this.real.toFixed(k),
this.imag.toFixed(k)
);
},
magnitude: function(){
var a = this.real, b = this.imag;
return Math.sqrt(a * a + b * b);
},
angle: function(){
return Math.atan2(this.imag, this.real);
},
conjugate: function(){
return new this.constructor(this.real, -this.imag);
},
negate: function(){
return new this.constructor(-this.real, -this.imag);
},
multiply: function(z){
z = this.constructor.from(z);
var a = this.real, b = this.imag;
return new this.constructor(
z.real * a - z.imag * b,
b * z.real + z.imag * a
);
},
divide: function(z){
z = this.constructor.from(z);
var divident = (Math.pow(z.real, 2) + Math.pow(z.imag, 2)),
a = this.real, b = this.imag;
return new this.constructor(
(a * z.real + b * z.imag) / divident,
(b * z.real - a * z.imag) / divident
);
},
add: function(z){
z = this.constructor.from(z);
return new this.constructor(this.real + z.real, this.imag + z.imag);
},
subtract: function(z){
z = this.constructor.from(z);
return new this.constructor(this.real - z.real, this.imag - z.imag);
},
pow: function(z){
z = this.constructor.from(z);
var result = z.multiply(this.clone().log()).exp(); // z^w = e^(w*log(z))
return new this.constructor(result.real, result.imag);
},
sqrt: function(){
var abs = this.magnitude(),
sgn = this.imag < 0 ? -1 : 1;
return new this.constructor(
Math.sqrt((abs + this.real) / 2),
sgn * Math.sqrt((abs - this.real) / 2)
);
},
log: function(k){
if (!k) k = 0;
return new this.constructor(
Math.log(this.magnitude()),
this.angle() + k * 2 * Math.PI
);
},
exp: function(){
return this.fromPolar(
Math.exp(this.real),
this.imag
);
},
sin: function(){
var a = this.real, b = this.imag;
return new this.constructor(
Math.sin(a) * cosh(b),
Math.cos(a) * sinh(b)
);
},
cos: function(){
var a = this.real, b = this.imag;
return new this.constructor(
Math.cos(a) * cosh(b),
Math.sin(a) * sinh(b) * -1
);
},
tan: function(){
var a = this.real, b = this.imag,
divident = Math.cos(2 * a) + cosh(2 * b);
return new this.constructor(
Math.sin(2 * a) / divident,
sinh(2 * b) / divident
);
},
sinh: function(){
var a = this.real, b = this.imag;
return new this.constructor(
sinh(a) * Math.cos(b),
cosh(a) * Math.sin(b)
);
},
cosh: function(){
var a = this.real, b = this.imag;
return new this.constructor(
cosh(a) * Math.cos(b),
sinh(a) * Math.sin(b)
);
},
tanh: function(){
var a = this.real, b = this.imag,
divident = cosh(2 * a) + Math.cos(2 * b);
return new this.constructor(
sinh(2 * a) / divident,
Math.sin(2 * b) / divident
);
},
clone: function(){
return new this.constructor(this.real, this.imag);
},
toString: function(polar){
if (polar) return this.magnitude() + ' ' + this.angle();
var ret = '', a = this.real, b = this.imag;
if (a) ret += a;
if (a && b || b < 0) ret += b < 0 ? '-' : '+';
if (b){
var absIm = Math.abs(b);
if (absIm != 1) ret += absIm;
ret += 'i';
}
return ret || '0';
},
equals: function(z) {
z = this.constructor.from(z);
return (z.real == this.real && z.imag == this.imag);
}
};
var alias = {
abs: 'magnitude'
, arg: 'angle'
, phase: 'angle'
, conj: 'conjugate'
, '**': 'pow'
, mult: 'multiply'
, '*': 'multiply'
, dev: 'divide'
, '/': 'divide'
, '+': 'add'
, sub: 'subtract'
, '-': 'subtract'
, '=': 'equals'
};
for (var a in alias) prototype[a] = prototype[alias[a]];
// factories and constants
var extend = {
from: function(real, im) {
if (real instanceof Complex) return new Complex(real.real, real.imag);
return new Complex(real, im);
},
fromString: function(str) {
var match, real, im;
if (str == 'i') str = '0+1i';
match = str.match(/(\d+)?([\+\-]\d*)[ij]/);
if (match) {
real = match[1];
im = (match[2] == '+' || match[2] == '-')
? match[2] + '1'
: match[2];
}
return new Complex(+real, +im);
},
fromPolar: function(r, phi) {
return new Complex(1, 1).fromPolar(r, phi);
},
i: new Complex(0, 1),
one: new Complex(1, 0)
};
for (var e in extend) Complex[e] = extend[e];
var sinh = function(x){
return (Math.pow(Math.E, x) - Math.pow(Math.E, -x)) / 2;
};
var cosh = function(x){
return (Math.pow(Math.E, x) + Math.pow(Math.E, -x)) / 2;
};
module.exports = Complex;