From 70ec623cbff88eb73e45506c396403acfeb6d404 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Sat, 11 Aug 2018 15:58:19 +0300 Subject: [PATCH] Add ComplexNumber. --- README.md | 1 + .../math/complex-number/ComplexNumber.js | 73 +++++++ src/algorithms/math/complex-number/README.md | 193 ++++++++++++++++++ .../__test__/ComplexNumber.test.js | 113 ++++++++++ 4 files changed, 380 insertions(+) create mode 100644 src/algorithms/math/complex-number/ComplexNumber.js create mode 100644 src/algorithms/math/complex-number/README.md create mode 100644 src/algorithms/math/complex-number/__test__/ComplexNumber.test.js diff --git a/README.md b/README.md index 27790cfe..2dc39d8d 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,7 @@ a set of rules that precisely define a sequence of operations. * `B` [Sieve of Eratosthenes](src/algorithms/math/sieve-of-eratosthenes) - finding all prime numbers up to any given limit * `B` [Is Power of Two](src/algorithms/math/is-power-of-two) - check if the number is power of two (naive and bitwise algorithms) * `B` [Pascal's Triangle](src/algorithms/math/pascal-triangle) + * `B` [Complex Number](src/algorithms/math/complex-number) - complex numbers and basic operations with them * `A` [Integer Partition](src/algorithms/math/integer-partition) * `A` [Liu Hui π Algorithm](src/algorithms/math/liu-hui) - approximate π calculations based on N-gons * **Sets** diff --git a/src/algorithms/math/complex-number/ComplexNumber.js b/src/algorithms/math/complex-number/ComplexNumber.js new file mode 100644 index 00000000..61da9744 --- /dev/null +++ b/src/algorithms/math/complex-number/ComplexNumber.js @@ -0,0 +1,73 @@ +export default class ComplexNumber { + /** + * @param {number} [real] + * @param {number} [imaginary] + */ + constructor({ real = 0, imaginary = 0 } = {}) { + this.real = real; + this.imaginary = imaginary; + } + + /** + * @param {ComplexNumber} addend + * @return {ComplexNumber} + */ + add(addend) { + return new ComplexNumber({ + real: this.real + addend.real, + imaginary: this.imaginary + addend.imaginary, + }); + } + + /** + * @param {ComplexNumber} subtrahend + * @return {ComplexNumber} + */ + subtract(subtrahend) { + return new ComplexNumber({ + real: this.real - subtrahend.real, + imaginary: this.imaginary - subtrahend.imaginary, + }); + } + + /** + * @param {ComplexNumber} multiplicand + * @return {ComplexNumber} + */ + multiply(multiplicand) { + return new ComplexNumber({ + real: this.real * multiplicand.real - this.imaginary * multiplicand.imaginary, + imaginary: this.real * multiplicand.imaginary + this.imaginary * multiplicand.real, + }); + } + + /** + * @param {ComplexNumber} divider + * @return {ComplexNumber} + */ + divide(divider) { + // Get divider conjugate. + const dividerConjugate = this.conjugate(divider); + + // 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.real ** 2) + (divider.imaginary ** 2); + + return new ComplexNumber({ + real: finalDivident.real / finalDivider, + imaginary: finalDivident.imaginary / finalDivider, + }); + } + + /** + * @param {ComplexNumber} complexNumber + */ + conjugate(complexNumber) { + return new ComplexNumber({ + real: complexNumber.real, + imaginary: -1 * complexNumber.imaginary, + }); + } +} diff --git a/src/algorithms/math/complex-number/README.md b/src/algorithms/math/complex-number/README.md new file mode 100644 index 00000000..ec6b4970 --- /dev/null +++ b/src/algorithms/math/complex-number/README.md @@ -0,0 +1,193 @@ +# Complex Number + +A **complex number** is a number that can be expressed in the +form `a + b * i`, where `a` and `b` are real numbers, and `i` is a solution of +the equation `x^2 = −1`. Because no *real number* satisfies this +equation, `i` is called an *imaginary number*. For the complex +number `a + b * i`, `a` is called the *real part*, and `b` is called +the *imaginary part*. + +![Complex Number](https://www.mathsisfun.com/numbers/images/complex-example.svg) + +A Complex Number is a combination of a Real Number and an Imaginary Number: + +![Complex Number](https://www.mathsisfun.com/numbers/images/complex-number.svg) + +Geometrically, complex numbers extend the concept of the one-dimensional number +line to the *two-dimensional complex plane* by using the horizontal axis for the +real part and the vertical axis for the imaginary part. The complex +number `a + b * i` can be identified with the point `(a, b)` in the complex plane. + +A complex number whose real part is zero is said to be *purely imaginary*; the +points for these numbers lie on the vertical axis of the complex plane. A complex +number whose imaginary part is zero can be viewed as a *real number*; its point +lies on the horizontal axis of the complex plane. + +| Complex Number | Real Part | Imaginary Part | | +| :------------- | :-------: | :------------: | --- | +| 3 + 2i | 3 | 2 | | +| 5 | 5 | **0** | Purely Real | +| −6i | **0** | -6 | Purely Imaginary | + +A complex number can be visually represented as a pair of numbers `(a, b)` forming +a vector on a diagram called an *Argand diagram*, representing the *complex plane*. +`Re` is the real axis, `Im` is the imaginary axis, and `i` satisfies `i^2 = −1`. + +![Complex Number](https://upload.wikimedia.org/wikipedia/commons/a/af/Complex_number_illustration.svg) + +> Complex does not mean complicated. It means the two types of numbers, real and +imaginary, together form a complex, just like a building complex (buildings +joined together). + +## Basic Operations + +### Adding + +To add two complex numbers we add each part separately: + +```text +(a + b * i) + (c + d * i) = (a + c) + (b + d) * i +``` + +**Example** + +```text +(3 + 5i) + (4 − 3i) = (3 + 4) + (5 − 3)i = 7 + 2i +``` + +On complex plane the adding operation will look like the following: + +![Complex Addition](https://www.mathsisfun.com/algebra/images/complex-plane-vector-add.svg) + +### Subtracting + +To subtract two complex numbers we subtract each part separately: + +```text +(a + b * i) - (c + d * i) = (a - c) + (b - d) * i +``` + +**Example** + +```text +(3 + 5i) - (4 − 3i) = (3 - 4) + (5 + 3)i = -1 + 8i +``` + +### Multiplying + +To multiply complex numbers each part of the first complex number gets multiplied +by each part of the second complex number: + +Just use "FOIL", which stands for "**F**irsts, **O**uters, **I**nners, **L**asts" ( +see [Binomial Multiplication](ttps://www.mathsisfun.com/algebra/polynomials-multiplying.html) for +more details): + +![Complex Multiplication](https://www.mathsisfun.com/algebra/images/foil-complex.svg) + +- Firsts: `a × c` +- Outers: `a × di` +- Inners: `bi × c` +- Lasts: `bi × di` + +In general it looks like this: + +```text +(a + bi)(c + di) = ac + adi + bci + bdi^2 +``` + +But there is also a quicker way! + +Use this rule: + +```text +(a + bi)(c + di) = (ac − bd) + (ad + bc)i +``` + +**Example** + +```text +(3 + 2i)(1 + 7i) += 3×1 + 3×7i + 2i×1+ 2i×7i += 3 + 21i + 2i + 14i^2 += 3 + 21i + 2i − 14 (because i^2 = −1) += −11 + 23i +``` + +```text +(3 + 2i)(1 + 7i) = (3×1 − 2×7) + (3×7 + 2×1)i = −11 + 23i +``` + +### Conjugates + +We will need to know about conjugates in a minute! + +A conjugate is where we change the sign in the middle like this: + +![Complex Conjugate](https://www.mathsisfun.com/numbers/images/complex-conjugate.svg) + +A conjugate is often written with a bar over it: + +```text +______ +5 − 3i = 5 + 3i +``` + +On the complex plane the conjugate number will be mirrored against real axes. + +![Complex Conjugate](https://upload.wikimedia.org/wikipedia/commons/6/69/Complex_conjugate_picture.svg) + +### Dividing + +The conjugate is used to help complex division. + +The trick is to *multiply both top and bottom by the conjugate of the bottom*. + +**Example** + +```text +2 + 3i +------ +4 − 5i +``` + +Multiply top and bottom by the conjugate of `4 − 5i`: + +```text + (2 + 3i) * (4 + 5i) 8 + 10i + 12i + 15i^2 += ------------------- = ---------------------- + (4 − 5i) * (4 + 5i) 16 + 20i − 20i − 25i^2 +``` + +Now remember that `i^2 = −1`, so: + +```text + 8 + 10i + 12i − 15 −7 + 22i −7 22 += ------------------- = -------- = -- + -- * i + 16 + 20i − 20i + 25 41 41 41 + +``` + +There is a faster way though. + +In the previous example, what happened on the bottom was interesting: + +```text +(4 − 5i)(4 + 5i) = 16 + 20i − 20i − 25i +``` + +The middle terms `(20i − 20i)` cancel out! Also `i^2 = −1` so we end up with this: + +```text +(4 − 5i)(4 + 5i) = 4^2 + 5^2 +``` + +Which is really quite a simple result. The general rule is: + +```text +(a + bi)(a − bi) = a^2 + b^2 +``` + +## References + +- [Wikipedia](https://en.wikipedia.org/wiki/Complex_number) +- [Math is Fun](https://www.mathsisfun.com/numbers/complex-numbers.html) diff --git a/src/algorithms/math/complex-number/__test__/ComplexNumber.test.js b/src/algorithms/math/complex-number/__test__/ComplexNumber.test.js new file mode 100644 index 00000000..f6d2a6b5 --- /dev/null +++ b/src/algorithms/math/complex-number/__test__/ComplexNumber.test.js @@ -0,0 +1,113 @@ +import ComplexNumber from '../ComplexNumber'; + +describe('ComplexNumber', () => { + it('should create complex numbers', () => { + const complexNumber = new ComplexNumber({ real: 1, imaginary: 2 }); + + expect(complexNumber).toBeDefined(); + expect(complexNumber.real).toBe(1); + expect(complexNumber.imaginary).toBe(2); + + const defaultComplexNumber = new ComplexNumber(); + expect(defaultComplexNumber.real).toBe(0); + expect(defaultComplexNumber.imaginary).toBe(0); + }); + + it('should add complex numbers', () => { + const complexNumber1 = new ComplexNumber({ real: 1, imaginary: 2 }); + const complexNumber2 = new ComplexNumber({ real: 3, imaginary: 8 }); + + const complexNumber3 = complexNumber1.add(complexNumber2); + const complexNumber4 = complexNumber2.add(complexNumber1); + + expect(complexNumber3.real).toBe(1 + 3); + expect(complexNumber3.imaginary).toBe(2 + 8); + + expect(complexNumber4.real).toBe(1 + 3); + expect(complexNumber4.imaginary).toBe(2 + 8); + }); + + it('should add complex and natural numbers', () => { + const complexNumber = new ComplexNumber({ real: 1, imaginary: 2 }); + const realNumber = new ComplexNumber({ real: 3 }); + + const complexNumber3 = complexNumber.add(realNumber); + const complexNumber4 = realNumber.add(complexNumber); + + expect(complexNumber3.real).toBe(1 + 3); + expect(complexNumber3.imaginary).toBe(2); + + expect(complexNumber4.real).toBe(1 + 3); + expect(complexNumber4.imaginary).toBe(2); + }); + + it('should subtract complex numbers', () => { + const complexNumber1 = new ComplexNumber({ real: 1, imaginary: 2 }); + const complexNumber2 = new ComplexNumber({ real: 3, imaginary: 8 }); + + const complexNumber3 = complexNumber1.subtract(complexNumber2); + const complexNumber4 = complexNumber2.subtract(complexNumber1); + + expect(complexNumber3.real).toBe(1 - 3); + expect(complexNumber3.imaginary).toBe(2 - 8); + + expect(complexNumber4.real).toBe(3 - 1); + expect(complexNumber4.imaginary).toBe(8 - 2); + }); + + it('should subtract complex and natural numbers', () => { + const complexNumber = new ComplexNumber({ real: 1, imaginary: 2 }); + const realNumber = new ComplexNumber({ real: 3 }); + + const complexNumber3 = complexNumber.subtract(realNumber); + const complexNumber4 = realNumber.subtract(complexNumber); + + expect(complexNumber3.real).toBe(1 - 3); + expect(complexNumber3.imaginary).toBe(2); + + expect(complexNumber4.real).toBe(3 - 1); + expect(complexNumber4.imaginary).toBe(-2); + }); + + it('should multiply complex numbers', () => { + const complexNumber1 = new ComplexNumber({ real: 3, imaginary: 2 }); + const complexNumber2 = new ComplexNumber({ real: 1, imaginary: 7 }); + + const complexNumber3 = complexNumber1.multiply(complexNumber2); + const complexNumber4 = complexNumber2.multiply(complexNumber1); + + expect(complexNumber3.real).toBe(-11); + expect(complexNumber3.imaginary).toBe(23); + + expect(complexNumber4.real).toBe(-11); + expect(complexNumber4.imaginary).toBe(23); + }); + + it('should multiply complex numbers by themselves', () => { + const complexNumber = new ComplexNumber({ real: 1, imaginary: 1 }); + + const result = complexNumber.multiply(complexNumber); + + expect(result.real).toBe(0); + expect(result.imaginary).toBe(2); + }); + + it('should calculate i in power of two', () => { + const complexNumber = new ComplexNumber({ real: 0, imaginary: 1 }); + + const result = complexNumber.multiply(complexNumber); + + expect(result.real).toBe(-1); + expect(result.imaginary).toBe(0); + }); + + it('should divide complex numbers', () => { + const complexNumber1 = new ComplexNumber({ real: 2, imaginary: 3 }); + const complexNumber2 = new ComplexNumber({ real: 4, imaginary: -5 }); + + const complexNumber3 = complexNumber1.divide(complexNumber2); + + expect(complexNumber3.real).toBe(-7 / 41); + expect(complexNumber3.imaginary).toBe(22 / 41); + }); +});