Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: trekhleb/javascript-algorithms
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: a274395
Choose a base ref
...
head repository: trekhleb/javascript-algorithms
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 680ee71
Choose a head ref
  • 2 commits
  • 5 files changed
  • 2 contributors

Commits on Aug 11, 2018

  1. Add ComplexNumber.

    trekhleb committed Aug 11, 2018
    Copy the full SHA
    70ec623 View commit details
  2. Copy the full SHA
    680ee71 View commit details
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -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**
73 changes: 73 additions & 0 deletions src/algorithms/math/complex-number/ComplexNumber.js
Original file line number Diff line number Diff line change
@@ -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 changes: 193 additions & 0 deletions src/algorithms/math/complex-number/README.md
Original file line number Diff line number Diff line change
@@ -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)
113 changes: 113 additions & 0 deletions src/algorithms/math/complex-number/__test__/ComplexNumber.test.js
Original file line number Diff line number Diff line change
@@ -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