File: src/gallery-complexnumber/js/ComplexNumber.js
"use strict";
/**
* @module gallery-complexnumber
*/
/**********************************************************************
* Class for representing a complex number.
*
* @class ComplexNumber
* @constructor
* @param real=0 {number} the real component
* @param imag=0 {number} the imaginary component
*/
function ComplexNumber(real, imag)
{
this.r = real || 0;
this.i = imag || 0;
}
/**
* Construct a ComplexNumber from polar coordinates.
*
* @method fromPolar
* @static
* @param magnitude {number}
* @param phase {number}
* @return ComplexNumber
*/
ComplexNumber.fromPolar = function(magnitude, phase)
{
return new ComplexNumber(
magnitude * Math.cos(phase),
magnitude * Math.sin(phase));
};
const logToLog10 = 1/Math.log(10);
ComplexNumber.prototype =
{
/**
* @method real
* @return {number} real component
*/
real: function()
{
return this.r;
},
/**
* @method imag
* @return {number} imaginary component
*/
imag: function()
{
return this.i;
},
/**
* @method magnitude
* @return {number} length of the vector in the complex plane
*/
magnitude: function()
{
return Math.sqrt(this.r*this.r + this.i*this.i);
},
/**
* @method phase
* @return {number} angle of the vector (in radians) in the complex plane relative to the positive real axis
*/
phase: function()
{
return Math.atan2(this.i, this.r);
},
/**
* Equivalent of += operator.
*
* @method add
* @param v {number}
* @chainable
*/
add: function(v)
{
failIfConstant(this);
if (ComplexMath.isComplexNumber(v))
{
this.r += v.r;
this.i += v.i;
}
else
{
this.r += v;
}
return this;
},
/**
* Equivalent of -= operator.
*
* @method subtract
* @param v {number}
* @chainable
*/
subtract: function(v)
{
failIfConstant(this);
if (ComplexMath.isComplexNumber(v))
{
this.r -= v.r;
this.i -= v.i;
}
else
{
this.r -= v;
}
return this;
},
/**
* Equivalent of *= operator.
*
* @method multiply
* @param v {number}
* @chainable
*/
multiply: function(v)
{
failIfConstant(this);
if (ComplexMath.isComplexNumber(v))
{
var r = this.r*v.r - this.i*v.i;
var i = this.r*v.i + this.i*v.r;
this.r = r;
this.i = i;
}
else
{
this.r *= v;
this.i *= v;
}
return this;
},
/**
* Equivalent of /= operator.
*
* @method divide
* @chainable
* @param v {number}
*/
divide: function(v)
{
failIfConstant(this);
if (ComplexMath.isComplexNumber(v))
{
var x = ComplexMath.divide(this, v);
this.r = x.r;
this.i = x.i;
}
else
{
this.r /= v;
this.i /= v;
}
return this;
},
/**
* Equivalent of unary minus operator.
*
* @method negate
* @chainable
*/
negate: function()
{
failIfConstant(this);
this.r = - this.r;
this.i = - this.i;
return this;
},
/**
* Negates the imaginary part.
*
* @method conjugate
* @chainable
*/
conjugate: function()
{
failIfConstant(this);
this.i = - this.i;
return this;
},
/**
* Rotates the number around the origin by the specified angle in radians.
*
* @method rotate
* @chainable
* @param angle {number}
*/
rotate: function(
/* float */ angle)
{
failIfConstant(this);
this.multiply(ComplexNumber.fromPolar(1, angle));
return this;
},
/**
* @method roundTo
* @chainable
* @param p {number} precision
*/
roundTo: function(p)
{
failIfConstant(this);
function computeScale(v)
{
return Math.pow(10, Math.floor(Math.log(Math.abs(v))*logToLog10) - p);
}
var scale = Math.max(computeScale(this.r), computeScale(this.i));
this.r = Math.round(this.r / scale, p) * scale;
this.i = Math.round(this.i / scale, p) * scale;
return this;
},
toString: function()
{
function i(v)
{
return v === 1 ? 'i' :
v === -1 ? '-i' :
v + 'i';
}
if (this.i === 0)
{
return this.r.toString();
}
else if (this.r === 0)
{
return i(this.i);
}
else
{
return this.r + (this.i > 0 ? '+' : '') + i(this.i);
}
}
};
Y.ComplexNumber = ComplexNumber;