complex
Version:
Do calculations with Complex numbers
255 lines (211 loc) • 4.93 kB
JavaScript
var Complex = function(real, im){
this.real = real;
this.im = im;
};
var prototype = Complex.prototype = {
fromRect: function(a, b){
this.real = a;
this.im = b;
return this;
},
fromPolar: function(r, phi){
if (typeof r == 'string'){
var parts = r.split(' ');
r = parts[0];
phi = parts[1];
}
return this.fromRect(
r * Math.cos(phi),
r * Math.sin(phi)
);
},
toPrecision: function(k){
return this.fromRect(
this.real.toPrecision(k),
this.im.toPrecision(k)
);
},
toFixed: function(k){
return this.fromRect(
this.real.toFixed(k),
this.im.toFixed(k)
);
},
finalize: function(){
this.fromRect = function(a, b){
return new Complex(a, b);
};
if (Object.defineProperty){
Object.defineProperty(this, 'real', {writable: false, value: this.real});
Object.defineProperty(this, 'im', {writable: false, value: this.im});
}
return this;
},
magnitude: function(){
var a = this.real, b = this.im;
return Math.sqrt(a * a + b * b);
},
angle: function(){
return Math.atan2(this.im, this.real);
},
conjugate: function(){
return this.fromRect(this.real, -this.im);
},
negate: function(){
return this.fromRect(-this.real, -this.im);
},
multiply: function(z){
z = Complex.from(z);
var a = this.real, b = this.im;
return this.fromRect(
z.real * a - z.im * b,
b * z.real + z.im * a
);
},
divide: function(z){
z = Complex.from(z);
var divident = (Math.pow(z.real, 2) + Math.pow(z.im, 2)),
a = this.real, b = this.im;
return this.fromRect(
(a * z.real + b * z.im) / divident,
(b * z.real - a * z.im) / divident
);
},
add: function(z){
z = Complex.from(z);
return this.fromRect(this.real + z.real, this.im + z.im);
},
subtract: function(z){
z = Complex.from(z);
return this.fromRect(this.real - z.real, this.im - z.im);
},
pow: function(z){
z = Complex.from(z);
var result = z.multiply(this.clone().log()).exp(); // z^w = e^(w*log(z))
return this.fromRect(result.real, result.im);
},
sqrt: function(){
var abs = this.magnitude(),
sgn = this.im < 0 ? -1 : 1;
return this.fromRect(
Math.sqrt((abs + this.real) / 2),
sgn * Math.sqrt((abs - this.real) / 2)
);
},
log: function(k){
if (!k) k = 0;
return this.fromRect(
Math.log(this.magnitude()),
this.angle() + k * 2 * Math.PI
);
},
exp: function(){
return this.fromPolar(
Math.exp(this.real),
this.im
);
},
sin: function(){
var a = this.real, b = this.im;
return this.fromRect(
Math.sin(a) * cosh(b),
Math.cos(a) * sinh(b)
);
},
cos: function(){
var a = this.real, b = this.im;
return this.fromRect(
Math.cos(a) * cosh(b),
Math.sin(a) * sinh(b) * -1
);
},
tan: function(){
var a = this.real, b = this.im,
divident = Math.cos(2 * a) + cosh(2 * b);
return this.fromRect(
Math.sin(2 * a) / divident,
sinh(2 * b) / divident
);
},
sinh: function(){
var a = this.real, b = this.im;
return this.fromRect(
sinh(a) * Math.cos(b),
cosh(a) * Math.sin(b)
);
},
cosh: function(){
var a = this.real, b = this.im;
return this.fromRect(
cosh(a) * Math.cos(b),
sinh(a) * Math.sin(b)
);
},
tanh: function(){
var a = this.real, b = this.im,
divident = cosh(2 * a) + Math.cos(2 * b);
return this.fromRect(
sinh(2 * a) / divident,
Math.sin(2 * b) / divident
);
},
clone: function(){
return new Complex(this.real, this.im);
},
toString: function(polar){
if (polar) return this.magnitude() + ' ' + this.angle();
var ret = '', a = this.real, b = this.im;
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 = Complex.from(z);
return (z.real == this.real && z.im == this.im);
}
};
var alias = {
abs: 'magnitude',
arg: 'angle',
phase: 'angle',
conj: 'conjugate',
mult: 'multiply',
dev: 'divide',
sub: 'subtract'
};
for (var a in alias) prototype[a] = prototype[alias[a]];
var extend = {
from: function(real, im){
if (real instanceof Complex) return new Complex(real.real, real.im);
var type = typeof real;
if (type == 'string'){
if (real == 'i') real = '0+1i';
var match = real.match(/(\d+)?([\+\-]\d*)[ij]/);
if (match){
real = match[1];
im = (match[2] == '+' || match[2] == '-') ? match[2] + '1' : match[2];
}
}
real = +real;
im = +im;
return new Complex(isNaN(real) ? 0 : real, isNaN(im) ? 0 : im);
},
fromPolar: function(r, phi){
return new Complex(1, 1).fromPolar(r, phi);
},
i: new Complex(0, 1).finalize(),
one: new Complex(1, 0).finalize()
};
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;