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: master
Choose a base ref
...
head repository: appleJax/javascript-algorithms
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: feature/algorithm/karatsuba
Choose a head ref
Able to merge. These branches can be automatically merged.
  • 4 commits
  • 3 files changed
  • 1 contributor

Commits on Oct 18, 2018

  1. Copy the full SHA
    42b5a46 View commit details
  2. add partial README

    appleJax committed Oct 18, 2018
    Copy the full SHA
    4b67f1e View commit details
  3. finish README

    appleJax committed Oct 18, 2018
    Copy the full SHA
    0cdb6b3 View commit details
  4. fix typos

    appleJax committed Oct 18, 2018
    Copy the full SHA
    c4eead4 View commit details
41 changes: 41 additions & 0 deletions src/algorithms/math/karatsuba-multiplication/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Karatsuba Multiplication

Karatsuba is a fast multiplication algorithm discovered by Anatoly Karatsuba in 1960. Given two n-digit numbers, the "grade-school" method of long multiplication has a time complexity of O(n<sup>2</sup>), whereas the karatsuba algorithm has a time complexity of O(n<sup>1.59</sup>).

## Recursive Formula

```
x = 1234
y = 5678
karatsuba(x, y)
```

1. Split each number into numbers with half as many digits
```
a = 12
b = 34
c = 56
d = 78
```

2. Compute 3 subexpressions from the smaller numbers
- `ac = a * c`
- `bd = b * d`
- `abcd = (a + b) * (c + d)`

3. Combine subexpressions to calculate the product
```
A = ac * 10000
B = (abcd - ac - bd) * 100
C = bd
x * y = A + B + C
```

_**Note:**_ *The karatsuba algorithm can be applied recursively to calculate each product in the subexpressions.* (`a * c = karatsuba(a, c)`*). When the numbers get smaller than some arbitrary threshold, they are multiplied in the traditional way.*

## References
[Stanford Algorithms (YouTube)](https://www.youtube.com/watch?v=JCbZayFr9RE)
[Wikipedia](https://en.wikipedia.org/wiki/Karatsuba_algorithm)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import karatsuba from '../karatsuba';

describe('karatsuba multiplication', () => {
it('should multiply simple numbers correctly', () => {
expect(karatsuba(0, 37)).toEqual(0);
expect(karatsuba(1, 8)).toEqual(8);
expect(karatsuba(5, 6)).toEqual(30);
});

it('should multiply larger numbers correctly', () => {
expect(karatsuba(1234, 5678)).toEqual(7006652);
expect(karatsuba(9182734, 726354172)).toEqual(6669917151266248);
});
});
68 changes: 68 additions & 0 deletions src/algorithms/math/karatsuba-multiplication/karatsuba.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
*
* @param {number} x
* @param {number} y
* @return {number}
*/
export default function karatsuba(x, y) {
// BASE CASE:
// if numbers are sufficiently small,
// multiply them together in the traditional way
if (x < 10 || y < 10) {
return x * y;
}

// SCALE FACTOR:
// scaleFactor is used to split the numbers
// into smaller numbers for recursion.
// when combining the subexpressions back
// together, the scaleFactor is used to
// recreate the magnitude of the original numbers
const minDigits = Math.min(
String(x).length,
String(y).length,
);
const scaleFactor = 10 ** Math.floor(minDigits / 2);

// PARAMETER COMPONENTS:
// a b are the two components of x
// c d are the two components of y
//
// e.g.
// x = 1234 -> a = 12, b = 34
// y = 5678 -> c = 56, d = 78

// example of component computations:
// x = 1234, y = 5678
// scaleFactor = 100

// a = floor(1234 / 100) = floor(12.34) = 12
const a = Math.floor(x / scaleFactor);

// b = 1234 - (12 * 100) = 1234 - 1200 = 34
const b = x - (a * scaleFactor);

// c = floor(5678 / 100) = floor(56.78) = 56
const c = Math.floor(y / scaleFactor);

// d = 5678 - (56 * 100) = 5678 - 5600 = 78
const d = y - (c * scaleFactor);

// COMPUTE SUBEXPRESSIONS:
// since a + b is less than x, and c + d is less than y
// the recursion is guaranteed to reach the base case
const ac = karatsuba(a, c);
const bd = karatsuba(b, d);
const abcd = karatsuba(a + b, c + d);

// COMBINE SUBEXPRESSIONS:
// since the scaleFactor was used to
// reduce the size of the components,
// the scaleFactor must be applied in reverse
// to reconstruct the magnitude of the original components
const A = ac * (scaleFactor ** 2);
const B = (abcd - ac - bd) * scaleFactor;
const C = bd;

return A + B + C;
}