mirror of
https://github.moeyy.xyz/https://github.com/trekhleb/javascript-algorithms.git
synced 2024-12-26 15:11:16 +08:00
Add ComplexNumber.
This commit is contained in:
parent
46b13f04fd
commit
70ec623cbf
@ -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` [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` [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` [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` [Integer Partition](src/algorithms/math/integer-partition)
|
||||||
* `A` [Liu Hui π Algorithm](src/algorithms/math/liu-hui) - approximate π calculations based on N-gons
|
* `A` [Liu Hui π Algorithm](src/algorithms/math/liu-hui) - approximate π calculations based on N-gons
|
||||||
* **Sets**
|
* **Sets**
|
||||||
|
73
src/algorithms/math/complex-number/ComplexNumber.js
Normal file
73
src/algorithms/math/complex-number/ComplexNumber.js
Normal file
@ -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,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
193
src/algorithms/math/complex-number/README.md
Normal file
193
src/algorithms/math/complex-number/README.md
Normal file
@ -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)
|
@ -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);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user