From 5341547455f8aeee1d0d588bb09113bcce080e51 Mon Sep 17 00:00:00 2001
From: svr8 <shikhar.vaish90@gmail.com>
Date: Mon, 3 Sep 2018 23:09:28 +0530
Subject: [PATCH] Added fast-exponentiation algorithm

---
 README.md                                     |  4 ++-
 package-lock.json                             | 36 ++++++++++++++-----
 .../math/fast-exponentiation/README.md        | 10 ++++++
 .../__test__/fastExponent.test.js             | 16 +++++++++
 .../__test__/modularExponent.test.js          | 16 +++++++++
 .../math/fast-exponentiation/fastExponent.js  | 20 +++++++++++
 .../fast-exponentiation/modularExponent.js    | 23 ++++++++++++
 7 files changed, 115 insertions(+), 10 deletions(-)
 create mode 100644 src/algorithms/math/fast-exponentiation/README.md
 create mode 100644 src/algorithms/math/fast-exponentiation/__test__/fastExponent.test.js
 create mode 100644 src/algorithms/math/fast-exponentiation/__test__/modularExponent.test.js
 create mode 100644 src/algorithms/math/fast-exponentiation/fastExponent.js
 create mode 100644 src/algorithms/math/fast-exponentiation/modularExponent.js

diff --git a/README.md b/README.md
index 915b3fb38e..26c3b5234e 100644
--- a/README.md
+++ b/README.md
@@ -60,7 +60,9 @@ a set of rules that precisely define a sequence of operations.
   * `B` [Factorial](src/algorithms/math/factorial) 
   * `B` [Fibonacci Number](src/algorithms/math/fibonacci)
   * `B` [Primality Test](src/algorithms/math/primality-test) (trial division method)
-  * `B` [Euclidean Algorithm](src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD)
+  * `B` [Euclidean Algorithm](src/algorithms/math/euclidean-algorithm) - calculate the Greatest 
+  Common Divisor (GCD)
+  * `B` [Fast Exponentiation](src/algorithms/math/fast-exponentiation)
   * `B` [Least Common Multiple](src/algorithms/math/least-common-multiple) (LCM)
   * `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)
diff --git a/package-lock.json b/package-lock.json
index 7fd3e2e127..11cfc72b28 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2478,12 +2478,14 @@
         "balanced-match": {
           "version": "1.0.0",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "brace-expansion": {
           "version": "1.1.11",
           "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "balanced-match": "^1.0.0",
             "concat-map": "0.0.1"
@@ -2498,17 +2500,20 @@
         "code-point-at": {
           "version": "1.1.0",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "concat-map": {
           "version": "0.0.1",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "console-control-strings": {
           "version": "1.1.0",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "core-util-is": {
           "version": "1.0.2",
@@ -2625,7 +2630,8 @@
         "inherits": {
           "version": "2.0.3",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "ini": {
           "version": "1.3.5",
@@ -2637,6 +2643,7 @@
           "version": "1.0.0",
           "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "number-is-nan": "^1.0.0"
           }
@@ -2651,6 +2658,7 @@
           "version": "3.0.4",
           "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "brace-expansion": "^1.1.7"
           }
@@ -2658,12 +2666,14 @@
         "minimist": {
           "version": "0.0.8",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "minipass": {
           "version": "2.2.4",
           "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "safe-buffer": "^5.1.1",
             "yallist": "^3.0.0"
@@ -2682,6 +2692,7 @@
           "version": "0.5.1",
           "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "minimist": "0.0.8"
           }
@@ -2762,7 +2773,8 @@
         "number-is-nan": {
           "version": "1.0.1",
           "bundled": true,
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "object-assign": {
           "version": "4.1.1",
@@ -2774,6 +2786,7 @@
           "version": "1.4.0",
           "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "wrappy": "1"
           }
@@ -2895,6 +2908,7 @@
           "version": "1.0.2",
           "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "code-point-at": "^1.0.0",
             "is-fullwidth-code-point": "^1.0.0",
@@ -7360,12 +7374,14 @@
             "balanced-match": {
               "version": "1.0.0",
               "bundled": true,
-              "dev": true
+              "dev": true,
+              "optional": true
             },
             "brace-expansion": {
               "version": "1.1.11",
               "bundled": true,
               "dev": true,
+              "optional": true,
               "requires": {
                 "balanced-match": "^1.0.0",
                 "concat-map": "0.0.1"
@@ -7385,7 +7401,8 @@
             "concat-map": {
               "version": "0.0.1",
               "bundled": true,
-              "dev": true
+              "dev": true,
+              "optional": true
             },
             "console-control-strings": {
               "version": "1.1.0",
@@ -7533,6 +7550,7 @@
               "version": "3.0.4",
               "bundled": true,
               "dev": true,
+              "optional": true,
               "requires": {
                 "brace-expansion": "^1.1.7"
               }
diff --git a/src/algorithms/math/fast-exponentiation/README.md b/src/algorithms/math/fast-exponentiation/README.md
new file mode 100644
index 0000000000..771ec39057
--- /dev/null
+++ b/src/algorithms/math/fast-exponentiation/README.md
@@ -0,0 +1,10 @@
+# Fast Exponentiation Algorithm
+The operation of modular exponentiation calculates the remainder when an integer `b` (the base) raised to the eth power (the exponent), be, is divided by a positive integer m (the modulus). In symbols, given base `b`, exponent e, and modulus m, the modular exponentiation `c` is: `c ≡ b^e (mod m)`. 
+
+# Modular Arithmetic
+- `(a + b) % m` = `( a%m + b%m ) % m`
+- `(a * b) % m` = `( a%m * b%m ) % m`
+
+
+## References
+- [Wikipedia](https://en.wikipedia.org/wiki/Modular_exponentiation)
\ No newline at end of file
diff --git a/src/algorithms/math/fast-exponentiation/__test__/fastExponent.test.js b/src/algorithms/math/fast-exponentiation/__test__/fastExponent.test.js
new file mode 100644
index 0000000000..ed09a47881
--- /dev/null
+++ b/src/algorithms/math/fast-exponentiation/__test__/fastExponent.test.js
@@ -0,0 +1,16 @@
+import fastExponent from '../fastExponent';
+
+describe('fastExponent', () => {
+  it('should calculate power using fast exponentiation algorithm', () => {
+    expect(fastExponent(5, 5)).toBe(3125);
+  });
+  it('should calculate power using fast exponentiation algorithm', () => {
+    expect(fastExponent(123, 4)).toBe(228886641);
+  });
+  it('should calculate power using fast exponentiation algorithm', () => {
+    expect(fastExponent(2, 15)).toBe(32768);
+  });
+  it('should calculate power using fast exponentiation algorithm', () => {
+    expect(fastExponent(43, 3)).toBe(79507);
+  });
+});
diff --git a/src/algorithms/math/fast-exponentiation/__test__/modularExponent.test.js b/src/algorithms/math/fast-exponentiation/__test__/modularExponent.test.js
new file mode 100644
index 0000000000..d9885a7f1d
--- /dev/null
+++ b/src/algorithms/math/fast-exponentiation/__test__/modularExponent.test.js
@@ -0,0 +1,16 @@
+import modularExponent from '../modularExponent';
+
+describe('modularExponent', () => {
+  it('should calculate power using fast exponentiation algorithm', () => {
+    expect(modularExponent(5, 5, 23)).toBe(20);
+  });
+  it('should calculate power using fast exponentiation algorithm', () => {
+    expect(modularExponent(123, 4, 10001)).toBe(3755);
+  });
+  it('should calculate power using fast exponentiation algorithm', () => {
+    expect(modularExponent(2, 15, 13)).toBe(8);
+  });
+  it('should calculate power using fast exponentiation algorithm', () => {
+    expect(modularExponent(43, 3, 1000000007)).toBe(79507);
+  });
+});
diff --git a/src/algorithms/math/fast-exponentiation/fastExponent.js b/src/algorithms/math/fast-exponentiation/fastExponent.js
new file mode 100644
index 0000000000..4f22ad9346
--- /dev/null
+++ b/src/algorithms/math/fast-exponentiation/fastExponent.js
@@ -0,0 +1,20 @@
+/**
+ * @param {number} base
+ * @param {number} exponent
+ * @return {number}
+ */
+
+export default function fastExponent(base, exponent) {
+  let x = base;
+  let y = exponent;
+  let res = 1;
+
+
+  while (y > 0) {
+    if (y & 1) res *= x;
+    y >>= 1;
+    x *= x;
+  }
+
+  return res;
+}
diff --git a/src/algorithms/math/fast-exponentiation/modularExponent.js b/src/algorithms/math/fast-exponentiation/modularExponent.js
new file mode 100644
index 0000000000..51c7272181
--- /dev/null
+++ b/src/algorithms/math/fast-exponentiation/modularExponent.js
@@ -0,0 +1,23 @@
+/**
+ * @param {number} base
+ * @param {number} exponent
+ * @param {number} m
+ * @return {number}
+ */
+
+export default function modularExponent(base, exponent, m) {
+  let x = base;
+  let y = exponent;
+  let res = 1;
+  const p = m;
+
+  x %= p;
+
+  while (y > 0) {
+    if (y & 1) res = (res * x) % p;
+    y >>= 1;
+    x = (x * x) % p;
+  }
+
+  return res;
+}