From 53a0b6168d12d3e1d2582915847aeca8436c14b1 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Wed, 15 Aug 2018 12:55:35 +0300 Subject: [PATCH] Fix bug with converting complex number into polar form. --- .../math/complex-number/ComplexNumber.js | 70 +++++++++++++++---- .../__test__/ComplexNumber.test.js | 41 +++++++++++ 2 files changed, 97 insertions(+), 14 deletions(-) diff --git a/src/algorithms/math/complex-number/ComplexNumber.js b/src/algorithms/math/complex-number/ComplexNumber.js index 801c0c37..9e8ffa56 100644 --- a/src/algorithms/math/complex-number/ComplexNumber.js +++ b/src/algorithms/math/complex-number/ComplexNumber.js @@ -14,51 +14,63 @@ export default class ComplexNumber { } /** - * @param {ComplexNumber} addend + * @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 + addend.re, - im: this.im + addend.im, + re: this.re + complexAddend.re, + im: this.im + complexAddend.im, }); } /** - * @param {ComplexNumber} subtrahend + * @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 - subtrahend.re, - im: this.im - subtrahend.im, + re: this.re - complexSubtrahend.re, + im: this.im - complexSubtrahend.im, }); } /** - * @param {ComplexNumber} multiplicand + * @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 * multiplicand.re - this.im * multiplicand.im, - im: this.re * multiplicand.im + this.im * multiplicand.re, + re: this.re * complexMultiplicand.re - this.im * complexMultiplicand.im, + im: this.re * complexMultiplicand.im + this.im * complexMultiplicand.re, }); } /** - * @param {ComplexNumber} divider + * @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(divider); + 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 = (divider.re ** 2) + (divider.im ** 2); + const finalDivider = (complexDivider.re ** 2) + (complexDivider.im ** 2); return new ComplexNumber({ 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({ re: complexNumber.re, im: -1 * complexNumber.im, @@ -96,6 +111,18 @@ export default class ComplexNumber { 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) { @@ -115,4 +142,19 @@ export default class ComplexNumber { 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 }); + } } diff --git a/src/algorithms/math/complex-number/__test__/ComplexNumber.test.js b/src/algorithms/math/complex-number/__test__/ComplexNumber.test.js index 827d2308..4392103d 100644 --- a/src/algorithms/math/complex-number/__test__/ComplexNumber.test.js +++ b/src/algorithms/math/complex-number/__test__/ComplexNumber.test.js @@ -33,12 +33,16 @@ describe('ComplexNumber', () => { const complexNumber3 = complexNumber.add(realNumber); const complexNumber4 = realNumber.add(complexNumber); + const complexNumber5 = complexNumber.add(3); expect(complexNumber3.re).toBe(1 + 3); expect(complexNumber3.im).toBe(2); expect(complexNumber4.re).toBe(1 + 3); expect(complexNumber4.im).toBe(2); + + expect(complexNumber5.re).toBe(1 + 3); + expect(complexNumber5.im).toBe(2); }); it('should subtract complex numbers', () => { @@ -61,12 +65,16 @@ describe('ComplexNumber', () => { const complexNumber3 = complexNumber.subtract(realNumber); const complexNumber4 = realNumber.subtract(complexNumber); + const complexNumber5 = complexNumber.subtract(3); expect(complexNumber3.re).toBe(1 - 3); expect(complexNumber3.im).toBe(2); expect(complexNumber4.re).toBe(3 - 1); expect(complexNumber4.im).toBe(-2); + + expect(complexNumber5.re).toBe(1 - 3); + expect(complexNumber5.im).toBe(2); }); it('should multiply complex numbers', () => { @@ -75,12 +83,16 @@ describe('ComplexNumber', () => { const complexNumber3 = complexNumber1.multiply(complexNumber2); const complexNumber4 = complexNumber2.multiply(complexNumber1); + const complexNumber5 = complexNumber1.multiply(5); expect(complexNumber3.re).toBe(-11); expect(complexNumber3.im).toBe(23); expect(complexNumber4.re).toBe(-11); expect(complexNumber4.im).toBe(23); + + expect(complexNumber5.re).toBe(15); + expect(complexNumber5.im).toBe(10); }); it('should multiply complex numbers by themselves', () => { @@ -106,9 +118,13 @@ describe('ComplexNumber', () => { const complexNumber2 = new ComplexNumber({ re: 4, im: -5 }); const complexNumber3 = complexNumber1.divide(complexNumber2); + const complexNumber4 = complexNumber1.divide(2); expect(complexNumber3.re).toBe(-7 / 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', () => { @@ -136,5 +152,30 @@ describe('ComplexNumber', () => { expect(complexNumber5.getPolarForm().radius).toBeCloseTo(8.60); expect(complexNumber5.getPolarForm().phase).toBeCloseTo(0.95); 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); }); });