-
Notifications
You must be signed in to change notification settings - Fork 20k
Miller-Rabin primality test implementation #4329
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
ad6e8a3
Add Miller-Rabin primality test algorithm
tomkrata 4dd9b58
Update sources
tomkrata 3561154
Update names to satisfy Java name conventions
tomkrata b9bb6bf
Update code by SonarLint
tomkrata 6ad5e6c
Update code with doozyX
tomkrata 3eaa492
Update the name of the file
tomkrata 7d5b2aa
Add unit tests
tomkrata bc614df
Lint the file
tomkrata 6d20d8e
Add comments
tomkrata 9dad335
Merge branch 'master' into master
siriak File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
102 changes: 102 additions & 0 deletions
102
src/main/java/com/thealgorithms/maths/MillerRabinPrimalityCheck.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) { | ||
siriak marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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; | ||
} | ||
} |
30 changes: 30 additions & 0 deletions
30
src/test/java/com/thealgorithms/maths/MillerRabinPrimalityCheckTest.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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)); | ||
} | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.