Repository: TheAlgorithms/Java
Pull request #4329 (2023-08-23 22:03:39)

Miller-Rabin primality test implementation
<!-- For completed items, change [ ] to [x] -->

- [x] I have read [CONTRIBUTING.md](https://github.com/TheAlgorithms/Java/blob/master/CONTRIBUTING.md).
- [x] This pull request is all my own work -- I have not plagiarized it.
- [x] All filenames are in PascalCase.
- [x] All functions and variable names follow Java naming conventions.
- [x] All new algorithms have a URL in their comments that points to Wikipedia or other similar explanations.



Patch:
diff --git a/src/main/java/com/thealgorithms/maths/MillerRabinPrimalityCheck.java b/src/main/java/com/thealgorithms/maths/MillerRabinPrimalityCheck.java
new file mode 100644
index 00000000..ed4f325b
--- /dev/null
+++ b/src/main/java/com/thealgorithms/maths/MillerRabinPrimalityCheck.java
@@ -0,0 +1,102 @@
+package com.thealgorithms.maths;
+
+import java.util.Random;
+
+public class MillerRabinPrimalityCheck {
+
+    /**
+     * Check whether the given number is prime or not
+     * MillerRabin algorithm is probabilistic. There is also an altered version which is deterministic.
+     * https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test
+     * https://cp-algorithms.com/algebra/primality_tests.html
+     *
+     * @param n Whole number which is tested on primality
+     * @param k Number of iterations
+     *       If n is composite then running k iterations of the Miller–Rabin
+     *       test will declare n probably prime with a probability at most 4^(−k)
+     * @return true or false whether the given number is probably prime or not
+     */
+
+    public static boolean millerRabin(long n, int k) { // returns true if n is probably prime, else returns false.
+        if (n < 4) return n == 2 || n == 3;
+
+        int s = 0;
+        long d = n - 1;
+        while ((d & 1) == 0) {
+            d >>= 1;
+            s++;
+        }
+        Random rnd = new Random();
+        for (int i = 0; i < k; i++) {
+            long a = 2 + rnd.nextLong(n) % (n - 3);
+            if (checkComposite(n, a, d, s)) return false;
+        }
+        return true;
+    }
+
+    public static boolean deterministicMillerRabin(long n) { // returns true if n is prime, else returns false.
+        if (n < 2) return false;
+
+        int r = 0;
+        long d = n - 1;
+        while ((d & 1) == 0) {
+            d >>= 1;
+            r++;
+        }
+
+        for (int a : new int[] {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}) {
+            if (n == a) return true;
+            if (checkComposite(n, a, d, r)) return false;
+        }
+        return true;
+    }
+
+    /**
+     * Check if number n is composite (probabilistic)
+     *
+     * @param n Whole number which is tested for compositeness
+     * @param a Random number (prime base) to check if it holds certain equality
+     * @param d Number which holds this equation: 'n - 1 = 2^s * d'
+     * @param s Number of twos in (n - 1) factorization
+     *
+     * @return true or false whether the numbers hold the equation or not
+     *          the equations are described on the websites mentioned at the beginning of the class
+     */
+    private static boolean checkComposite(long n, long a, long d, int s) {
+        long x = powerModP(a, d, n);
+        if (x == 1 || x == n - 1) return false;
+        for (int r = 1; r < s; r++) {
+            x = powerModP(x, 2, n);
+            if (x == n - 1) return false;
+        }
+        return true;
+    }
+
+    private static long powerModP(long x, long y, long p) {
+        long res = 1; // Initialize result
+
+        x = x % p; // Update x if it is more than or equal to p
+
+        if (x == 0) return 0; // In case x is divisible by p;
+
+        while (y > 0) {
+            // If y is odd, multiply x with result
+            if ((y & 1) == 1) res = multiplyModP(res, x, p);
+
+            // y must be even now
+            y = y >> 1; // y = y/2
+            x = multiplyModP(x, x, p);
+        }
+        return res;
+    }
+
+    private static long multiplyModP(long a, long b, long p) {
+        long aHi = a >> 24;
+        long aLo = a & ((1 << 24) - 1);
+        long bHi = b >> 24;
+        long bLo = b & ((1 << 24) - 1);
+        long result = ((((aHi * bHi << 16) % p) << 16) % p) << 16;
+        result += ((aLo * bHi + aHi * bLo) << 24) + aLo * bLo;
+        return result % p;
+    }
+}


Test patch:
diff --git a/src/test/java/com/thealgorithms/maths/MillerRabinPrimalityCheckTest.java b/src/test/java/com/thealgorithms/maths/MillerRabinPrimalityCheckTest.java
new file mode 100644
index 00000000..6e6fd491
--- /dev/null
+++ b/src/test/java/com/thealgorithms/maths/MillerRabinPrimalityCheckTest.java
@@ -0,0 +1,30 @@
+package com.thealgorithms.maths;
+
+import static com.thealgorithms.maths.MillerRabinPrimalityCheck.*;
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.junit.jupiter.api.Test;
+
+class MillerRabinPrimalityCheckTest {
+    @Test
+    void testDeterministicMillerRabinForPrimes() {
+        assertTrue(deterministicMillerRabin(2));
+        assertTrue(deterministicMillerRabin(37));
+        assertTrue(deterministicMillerRabin(123457));
+        assertTrue(deterministicMillerRabin(6472601713L));
+    }
+    @Test
+    void testDeterministicMillerRabinForNotPrimes() {
+        assertFalse(deterministicMillerRabin(1));
+        assertFalse(deterministicMillerRabin(35));
+        assertFalse(deterministicMillerRabin(123453));
+        assertFalse(deterministicMillerRabin(647260175));
+    }
+    @Test
+    void testMillerRabinForPrimes() {
+        assertTrue(millerRabin(11, 5));
+        assertTrue(millerRabin(97, 5));
+        assertTrue(millerRabin(6720589, 5));
+        assertTrue(millerRabin(9549401549L, 5));
+    }
+}