Add Miller-Rabin Primality Test (#4329)
This commit is contained in:
parent
8d9c49dafe
commit
ebd356e182
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user