mirror of
https://github.com/trekhleb/javascript-algorithms.git
synced 2025-07-14 07:52:03 +08:00
Fix bug with converting complex number into polar form.
This commit is contained in:
@ -14,51 +14,63 @@ export default class ComplexNumber {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {ComplexNumber} addend
|
* @param {ComplexNumber|number} addend
|
||||||
* @return {ComplexNumber}
|
* @return {ComplexNumber}
|
||||||
*/
|
*/
|
||||||
add(addend) {
|
add(addend) {
|
||||||
|
// Make sure we're dealing with complex number.
|
||||||
|
const complexAddend = this.toComplexNumber(addend);
|
||||||
|
|
||||||
return new ComplexNumber({
|
return new ComplexNumber({
|
||||||
re: this.re + addend.re,
|
re: this.re + complexAddend.re,
|
||||||
im: this.im + addend.im,
|
im: this.im + complexAddend.im,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {ComplexNumber} subtrahend
|
* @param {ComplexNumber|number} subtrahend
|
||||||
* @return {ComplexNumber}
|
* @return {ComplexNumber}
|
||||||
*/
|
*/
|
||||||
subtract(subtrahend) {
|
subtract(subtrahend) {
|
||||||
|
// Make sure we're dealing with complex number.
|
||||||
|
const complexSubtrahend = this.toComplexNumber(subtrahend);
|
||||||
|
|
||||||
return new ComplexNumber({
|
return new ComplexNumber({
|
||||||
re: this.re - subtrahend.re,
|
re: this.re - complexSubtrahend.re,
|
||||||
im: this.im - subtrahend.im,
|
im: this.im - complexSubtrahend.im,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {ComplexNumber} multiplicand
|
* @param {ComplexNumber|number} multiplicand
|
||||||
* @return {ComplexNumber}
|
* @return {ComplexNumber}
|
||||||
*/
|
*/
|
||||||
multiply(multiplicand) {
|
multiply(multiplicand) {
|
||||||
|
// Make sure we're dealing with complex number.
|
||||||
|
const complexMultiplicand = this.toComplexNumber(multiplicand);
|
||||||
|
|
||||||
return new ComplexNumber({
|
return new ComplexNumber({
|
||||||
re: this.re * multiplicand.re - this.im * multiplicand.im,
|
re: this.re * complexMultiplicand.re - this.im * complexMultiplicand.im,
|
||||||
im: this.re * multiplicand.im + this.im * multiplicand.re,
|
im: this.re * complexMultiplicand.im + this.im * complexMultiplicand.re,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {ComplexNumber} divider
|
* @param {ComplexNumber|number} divider
|
||||||
* @return {ComplexNumber}
|
* @return {ComplexNumber}
|
||||||
*/
|
*/
|
||||||
divide(divider) {
|
divide(divider) {
|
||||||
|
// Make sure we're dealing with complex number.
|
||||||
|
const complexDivider = this.toComplexNumber(divider);
|
||||||
|
|
||||||
// Get divider conjugate.
|
// Get divider conjugate.
|
||||||
const dividerConjugate = this.conjugate(divider);
|
const dividerConjugate = this.conjugate(complexDivider);
|
||||||
|
|
||||||
// Multiply dividend by divider's conjugate.
|
// Multiply dividend by divider's conjugate.
|
||||||
const finalDivident = this.multiply(dividerConjugate);
|
const finalDivident = this.multiply(dividerConjugate);
|
||||||
|
|
||||||
// Calculating final divider using formula (a + bi)(a − bi) = a^2 + b^2
|
// Calculating final divider using formula (a + bi)(a − bi) = a^2 + b^2
|
||||||
const finalDivider = (divider.re ** 2) + (divider.im ** 2);
|
const finalDivider = (complexDivider.re ** 2) + (complexDivider.im ** 2);
|
||||||
|
|
||||||
return new ComplexNumber({
|
return new ComplexNumber({
|
||||||
re: finalDivident.re / finalDivider,
|
re: finalDivident.re / finalDivider,
|
||||||
@ -67,9 +79,12 @@ export default class ComplexNumber {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {ComplexNumber} complexNumber
|
* @param {ComplexNumber|number} number
|
||||||
*/
|
*/
|
||||||
conjugate(complexNumber) {
|
conjugate(number) {
|
||||||
|
// Make sure we're dealing with complex number.
|
||||||
|
const complexNumber = this.toComplexNumber(number);
|
||||||
|
|
||||||
return new ComplexNumber({
|
return new ComplexNumber({
|
||||||
re: complexNumber.re,
|
re: complexNumber.re,
|
||||||
im: -1 * complexNumber.im,
|
im: -1 * complexNumber.im,
|
||||||
@ -96,6 +111,18 @@ export default class ComplexNumber {
|
|||||||
phase = -(Math.PI - phase);
|
phase = -(Math.PI - phase);
|
||||||
} else if (this.re > 0 && this.im < 0) {
|
} else if (this.re > 0 && this.im < 0) {
|
||||||
phase = -phase;
|
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) {
|
if (!inRadians) {
|
||||||
@ -115,4 +142,19 @@ export default class ComplexNumber {
|
|||||||
phase: this.getPhase(inRadians),
|
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 });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,12 +33,16 @@ describe('ComplexNumber', () => {
|
|||||||
|
|
||||||
const complexNumber3 = complexNumber.add(realNumber);
|
const complexNumber3 = complexNumber.add(realNumber);
|
||||||
const complexNumber4 = realNumber.add(complexNumber);
|
const complexNumber4 = realNumber.add(complexNumber);
|
||||||
|
const complexNumber5 = complexNumber.add(3);
|
||||||
|
|
||||||
expect(complexNumber3.re).toBe(1 + 3);
|
expect(complexNumber3.re).toBe(1 + 3);
|
||||||
expect(complexNumber3.im).toBe(2);
|
expect(complexNumber3.im).toBe(2);
|
||||||
|
|
||||||
expect(complexNumber4.re).toBe(1 + 3);
|
expect(complexNumber4.re).toBe(1 + 3);
|
||||||
expect(complexNumber4.im).toBe(2);
|
expect(complexNumber4.im).toBe(2);
|
||||||
|
|
||||||
|
expect(complexNumber5.re).toBe(1 + 3);
|
||||||
|
expect(complexNumber5.im).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should subtract complex numbers', () => {
|
it('should subtract complex numbers', () => {
|
||||||
@ -61,12 +65,16 @@ describe('ComplexNumber', () => {
|
|||||||
|
|
||||||
const complexNumber3 = complexNumber.subtract(realNumber);
|
const complexNumber3 = complexNumber.subtract(realNumber);
|
||||||
const complexNumber4 = realNumber.subtract(complexNumber);
|
const complexNumber4 = realNumber.subtract(complexNumber);
|
||||||
|
const complexNumber5 = complexNumber.subtract(3);
|
||||||
|
|
||||||
expect(complexNumber3.re).toBe(1 - 3);
|
expect(complexNumber3.re).toBe(1 - 3);
|
||||||
expect(complexNumber3.im).toBe(2);
|
expect(complexNumber3.im).toBe(2);
|
||||||
|
|
||||||
expect(complexNumber4.re).toBe(3 - 1);
|
expect(complexNumber4.re).toBe(3 - 1);
|
||||||
expect(complexNumber4.im).toBe(-2);
|
expect(complexNumber4.im).toBe(-2);
|
||||||
|
|
||||||
|
expect(complexNumber5.re).toBe(1 - 3);
|
||||||
|
expect(complexNumber5.im).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should multiply complex numbers', () => {
|
it('should multiply complex numbers', () => {
|
||||||
@ -75,12 +83,16 @@ describe('ComplexNumber', () => {
|
|||||||
|
|
||||||
const complexNumber3 = complexNumber1.multiply(complexNumber2);
|
const complexNumber3 = complexNumber1.multiply(complexNumber2);
|
||||||
const complexNumber4 = complexNumber2.multiply(complexNumber1);
|
const complexNumber4 = complexNumber2.multiply(complexNumber1);
|
||||||
|
const complexNumber5 = complexNumber1.multiply(5);
|
||||||
|
|
||||||
expect(complexNumber3.re).toBe(-11);
|
expect(complexNumber3.re).toBe(-11);
|
||||||
expect(complexNumber3.im).toBe(23);
|
expect(complexNumber3.im).toBe(23);
|
||||||
|
|
||||||
expect(complexNumber4.re).toBe(-11);
|
expect(complexNumber4.re).toBe(-11);
|
||||||
expect(complexNumber4.im).toBe(23);
|
expect(complexNumber4.im).toBe(23);
|
||||||
|
|
||||||
|
expect(complexNumber5.re).toBe(15);
|
||||||
|
expect(complexNumber5.im).toBe(10);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should multiply complex numbers by themselves', () => {
|
it('should multiply complex numbers by themselves', () => {
|
||||||
@ -106,9 +118,13 @@ describe('ComplexNumber', () => {
|
|||||||
const complexNumber2 = new ComplexNumber({ re: 4, im: -5 });
|
const complexNumber2 = new ComplexNumber({ re: 4, im: -5 });
|
||||||
|
|
||||||
const complexNumber3 = complexNumber1.divide(complexNumber2);
|
const complexNumber3 = complexNumber1.divide(complexNumber2);
|
||||||
|
const complexNumber4 = complexNumber1.divide(2);
|
||||||
|
|
||||||
expect(complexNumber3.re).toBe(-7 / 41);
|
expect(complexNumber3.re).toBe(-7 / 41);
|
||||||
expect(complexNumber3.im).toBe(22 / 41);
|
expect(complexNumber3.im).toBe(22 / 41);
|
||||||
|
|
||||||
|
expect(complexNumber4.re).toBe(1);
|
||||||
|
expect(complexNumber4.im).toBe(1.5);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return complex number in polar form', () => {
|
it('should return complex number in polar form', () => {
|
||||||
@ -136,5 +152,30 @@ describe('ComplexNumber', () => {
|
|||||||
expect(complexNumber5.getPolarForm().radius).toBeCloseTo(8.60);
|
expect(complexNumber5.getPolarForm().radius).toBeCloseTo(8.60);
|
||||||
expect(complexNumber5.getPolarForm().phase).toBeCloseTo(0.95);
|
expect(complexNumber5.getPolarForm().phase).toBeCloseTo(0.95);
|
||||||
expect(complexNumber5.getPolarForm(false).phase).toBeCloseTo(54.46);
|
expect(complexNumber5.getPolarForm(false).phase).toBeCloseTo(54.46);
|
||||||
|
|
||||||
|
const complexNumber6 = new ComplexNumber({ re: 0, im: 0.25 });
|
||||||
|
expect(complexNumber6.getPolarForm().radius).toBeCloseTo(0.25);
|
||||||
|
expect(complexNumber6.getPolarForm().phase).toBeCloseTo(1.57);
|
||||||
|
expect(complexNumber6.getPolarForm(false).phase).toBeCloseTo(90);
|
||||||
|
|
||||||
|
const complexNumber7 = new ComplexNumber({ re: 0, im: -0.25 });
|
||||||
|
expect(complexNumber7.getPolarForm().radius).toBeCloseTo(0.25);
|
||||||
|
expect(complexNumber7.getPolarForm().phase).toBeCloseTo(-1.57);
|
||||||
|
expect(complexNumber7.getPolarForm(false).phase).toBeCloseTo(-90);
|
||||||
|
|
||||||
|
const complexNumber8 = new ComplexNumber();
|
||||||
|
expect(complexNumber8.getPolarForm().radius).toBeCloseTo(0);
|
||||||
|
expect(complexNumber8.getPolarForm().phase).toBeCloseTo(0);
|
||||||
|
expect(complexNumber8.getPolarForm(false).phase).toBeCloseTo(0);
|
||||||
|
|
||||||
|
const complexNumber9 = new ComplexNumber({ re: -0.25, im: 0 });
|
||||||
|
expect(complexNumber9.getPolarForm().radius).toBeCloseTo(0.25);
|
||||||
|
expect(complexNumber9.getPolarForm().phase).toBeCloseTo(Math.PI);
|
||||||
|
expect(complexNumber9.getPolarForm(false).phase).toBeCloseTo(180);
|
||||||
|
|
||||||
|
const complexNumber10 = new ComplexNumber({ re: 0.25, im: 0 });
|
||||||
|
expect(complexNumber10.getPolarForm().radius).toBeCloseTo(0.25);
|
||||||
|
expect(complexNumber10.getPolarForm().phase).toBeCloseTo(0);
|
||||||
|
expect(complexNumber10.getPolarForm(false).phase).toBeCloseTo(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user