@dxzmpk/js-algorithms-data-structures
Version:
Algorithms and data-structures implemented on JavaScript
161 lines (138 loc) • 4.04 kB
JavaScript
import radianToDegree from '../radian/radianToDegree';
export default class ComplexNumber {
/**
* z = re + im * i
* z = radius * e^(i * phase)
*
* @param {number} [re]
* @param {number} [im]
*/
constructor({ re = 0, im = 0 } = {}) {
this.re = re;
this.im = im;
}
/**
* @param {ComplexNumber|number} addend
* @return {ComplexNumber}
*/
add(addend) {
// Make sure we're dealing with complex number.
const complexAddend = this.toComplexNumber(addend);
return new ComplexNumber({
re: this.re + complexAddend.re,
im: this.im + complexAddend.im,
});
}
/**
* @param {ComplexNumber|number} subtrahend
* @return {ComplexNumber}
*/
subtract(subtrahend) {
// Make sure we're dealing with complex number.
const complexSubtrahend = this.toComplexNumber(subtrahend);
return new ComplexNumber({
re: this.re - complexSubtrahend.re,
im: this.im - complexSubtrahend.im,
});
}
/**
* @param {ComplexNumber|number} multiplicand
* @return {ComplexNumber}
*/
multiply(multiplicand) {
// Make sure we're dealing with complex number.
const complexMultiplicand = this.toComplexNumber(multiplicand);
return new ComplexNumber({
re: this.re * complexMultiplicand.re - this.im * complexMultiplicand.im,
im: this.re * complexMultiplicand.im + this.im * complexMultiplicand.re,
});
}
/**
* @param {ComplexNumber|number} divider
* @return {ComplexNumber}
*/
divide(divider) {
// Make sure we're dealing with complex number.
const complexDivider = this.toComplexNumber(divider);
// Get divider conjugate.
const dividerConjugate = this.conjugate(complexDivider);
// Multiply dividend by divider's conjugate.
const finalDivident = this.multiply(dividerConjugate);
// Calculating final divider using formula (a + bi)(a − bi) = a^2 + b^2
const finalDivider = (complexDivider.re ** 2) + (complexDivider.im ** 2);
return new ComplexNumber({
re: finalDivident.re / finalDivider,
im: finalDivident.im / finalDivider,
});
}
/**
* @param {ComplexNumber|number} number
*/
conjugate(number) {
// Make sure we're dealing with complex number.
const complexNumber = this.toComplexNumber(number);
return new ComplexNumber({
re: complexNumber.re,
im: -1 * complexNumber.im,
});
}
/**
* @return {number}
*/
getRadius() {
return Math.sqrt((this.re ** 2) + (this.im ** 2));
}
/**
* @param {boolean} [inRadians]
* @return {number}
*/
getPhase(inRadians = true) {
let phase = Math.atan(Math.abs(this.im) / Math.abs(this.re));
if (this.re < 0 && this.im > 0) {
phase = Math.PI - phase;
} else if (this.re < 0 && this.im < 0) {
phase = -(Math.PI - phase);
} else if (this.re > 0 && this.im < 0) {
phase = -phase;
} else if (this.re === 0 && this.im > 0) {
phase = Math.PI / 2;
} else if (this.re === 0 && this.im < 0) {
phase = -Math.PI / 2;
} else if (this.re < 0 && this.im === 0) {
phase = Math.PI;
} else if (this.re > 0 && this.im === 0) {
phase = 0;
} else if (this.re === 0 && this.im === 0) {
// More correctly would be to set 'indeterminate'.
// But just for simplicity reasons let's set zero.
phase = 0;
}
if (!inRadians) {
phase = radianToDegree(phase);
}
return phase;
}
/**
* @param {boolean} [inRadians]
* @return {{radius: number, phase: number}}
*/
getPolarForm(inRadians = true) {
return {
radius: this.getRadius(),
phase: this.getPhase(inRadians),
};
}
/**
* Convert real numbers to complex number.
* In case if complex number is provided then lefts it as is.
*
* @param {ComplexNumber|number} number
* @return {ComplexNumber}
*/
toComplexNumber(number) {
if (number instanceof ComplexNumber) {
return number;
}
return new ComplexNumber({ re: number });
}
}