Skip to content

Commit ab94b8a

Browse files
committed
Merge branch 'arytmetyk-master'
2 parents dd360cd + 0efe55d commit ab94b8a

File tree

11 files changed

+306
-224
lines changed

11 files changed

+306
-224
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ This is a collection of algorithms and data structures which I've implement over
8888
+ is prime
8989
+ prime factorization
9090
+ sieve of eratosthenes
91+
+ Miller-Rabin test
9192
+ [Co-Primes (relatively prime, mutually prime)](src/com/jwetherell/algorithms/mathematics/Coprimes.java)
9293
+ [Greatest Common Divisor](src/com/jwetherell/algorithms/mathematics/GreatestCommonDivisor.java)
9394
- using Euclid's algorithm

src/com/jwetherell/algorithms/mathematics/Exponentiation.java

+8-7
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,25 @@
1717
* <p>
1818
* This implementation is the fast version of this algorithm with a complexity of O(lg N) also
1919
* <br>
20+
*
2021
* @author Bartlomiej Drozd <[email protected]>
2122
* @author Justin Wetherell <[email protected]>
2223
*/
2324
public class Exponentiation {
2425

2526
public static int recursiveExponentiation(int base, int exponent) {
26-
if (exponent == 0)
27+
if (exponent == 0)
2728
return 1;
28-
if (exponent == 1)
29+
if (exponent == 1)
2930
return base;
3031

3132
return recursiveExponentiation(base, exponent - 1) * base;
3233
}
3334

3435
public static int fastRecursiveExponentiation(int base, int exponent) {
35-
if (exponent == 0)
36+
if (exponent == 0)
3637
return 1;
37-
if (exponent == 1)
38+
if (exponent == 1)
3839
return base;
3940

4041
final int resultOnHalfExponent = fastRecursiveExponentiation(base, exponent / 2);
@@ -46,12 +47,12 @@ public static int fastRecursiveExponentiation(int base, int exponent) {
4647
}
4748

4849
public static int fastRecursiveExponentiationModulo(int base, int exponent, int mod) {
49-
if (exponent == 0)
50+
if (exponent == 0)
5051
return 1;
51-
if (exponent == 1)
52+
if (exponent == 1)
5253
return base;
5354

54-
final int resultOnHalfExponent = fastRecursiveExponentiation(base, exponent / 2);
55+
final int resultOnHalfExponent = fastRecursiveExponentiationModulo(base, exponent / 2, mod);
5556
if ((exponent % 2) == 0)
5657
return (resultOnHalfExponent * resultOnHalfExponent) % mod;
5758
else

src/com/jwetherell/algorithms/mathematics/Primes.java

+82-11
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,24 @@
22

33
import java.util.Arrays;
44
import java.util.HashMap;
5+
import java.util.List;
56
import java.util.Map;
67

8+
/**
9+
* @author Justin Wetherell <[email protected]>
10+
* @author Bartlomiej Drozd <[email protected]>
11+
*/
712
public class Primes {
813

14+
/**
15+
* In number theory, the prime factors of a positive integer are the prime numbers that divide that integer exactly. The prime
16+
* factorization of a positive integer is a list of the integer's prime factors, together with their multiplicities; the process
17+
* of determining these factors is called integer factorization. The fundamental theorem of arithmetic says that every positive
18+
* integer has a single unique prime factorization.
19+
* <p>
20+
* https://en.wikipedia.org/wiki/Prime_factor
21+
* <br>
22+
*/
923
public static final Map<Long, Long> getPrimeFactorization(long number) {
1024
Map<Long, Long> map = new HashMap<Long, Long>();
1125
long n = number;
@@ -34,15 +48,15 @@ public static final Map<Long, Long> getPrimeFactorization(long number) {
3448
return map;
3549
}
3650

37-
/*
51+
/**
3852
* isPrime() using the square root properties
39-
*
53+
* <p>
4054
* 1 is not a prime. All primes except 2 are odd. All primes greater than 3
4155
* can be written in the form 6k+/-1. Any number n can have only one
42-
* primefactor greater than n . The consequence for primality testing of a
56+
* prime factor greater than n . The consequence for primality testing of a
4357
* number n is: if we cannot find a number f less than or equal n that
44-
* divides n then n is prime: the only primefactor of n is n itself
45-
*/
58+
* divides n then n is prime: the only prime factor of n is n itself
59+
**/
4660
public static final boolean isPrime(long number) {
4761
if (number == 1)
4862
return false;
@@ -52,11 +66,11 @@ public static final boolean isPrime(long number) {
5266
return false; // short circuit
5367
if (number < 9)
5468
return true; // we have already excluded 4, 6 and 8.
55-
// (testing for 5 & 7)
69+
// (testing for 5 & 7)
5670
if (number % 3 == 0)
5771
return false; // short circuit
5872
long r = (long) (Math.sqrt(number)); // n rounded to the greatest integer
59-
// r so that r*r<=n
73+
// r so that r*r<=n
6074
int f = 5;
6175
while (f <= r) {
6276
if (number % f == 0)
@@ -69,30 +83,87 @@ public static final boolean isPrime(long number) {
6983
}
7084

7185
/*
72-
* Sieve of Eratosthenes
86+
* Sieve of Eratosthenes, only has to be set once.
7387
*/
7488
private static boolean[] sieve = null;
7589

90+
/**
91+
* In mathematics, the sieve of Eratosthenes is a simple, ancient algorithm for finding all prime numbers up to any given limit.
92+
* <p>
93+
* It does so by iteratively marking as composite (i.e., not prime) the multiples of each prime, starting with the first prime
94+
* number, 2. The multiples of a given prime are generated as a sequence of numbers starting from that prime, with constant
95+
* difference between them that is equal to that prime.
96+
* <p>
97+
* https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
98+
* <br>
99+
*/
76100
public static final boolean sieveOfEratosthenes(int number) {
77101
if (number == 1) {
78102
return false;
79103
}
80104
if (sieve == null || number >= sieve.length) {
81105
int start = 2;
106+
82107
if (sieve == null) {
83-
sieve = new boolean[number+1];
108+
sieve = new boolean[number + 1];
84109
} else if (number >= sieve.length) {
85-
sieve = Arrays.copyOf(sieve, number+1);
110+
sieve = Arrays.copyOf(sieve, number + 1);
86111
}
87112

88113
for (int i = start; i <= Math.sqrt(number); i++) {
89114
if (!sieve[i]) {
90-
for (int j = i*2; j <= number; j += i) {
115+
for (int j = i * 2; j <= number; j += i) {
91116
sieve[j] = true;
92117
}
93118
}
94119
}
95120
}
96121
return !sieve[number];
97122
}
123+
124+
/**
125+
* Miller-Rabin primality test is the fastest way to check if number is prime.
126+
* Regular version of this algorithm returns false when number is composite and true
127+
* when number is probably prime. Here is implemented a deterministic version of this
128+
* algorithm, witnesses are not randomized. Used set of witnesses guarantees that result
129+
* will be correct for sure (not probably) for any number lower than 10^18.
130+
* <p>
131+
* https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test
132+
* <br>
133+
*/
134+
public static final boolean millerRabinTest(int number) {
135+
final List<Integer> witnesses = Arrays.asList(2, 325, 9375, 28178, 450775, 9780504, 1795265022);
136+
137+
if (number == 0 || number == 1)
138+
return false;
139+
if (number == 2 || number == 3)
140+
return true;
141+
142+
int maximumPowerOf2 = 0;
143+
while (((number - 1) % Exponentiation.fastRecursiveExponentiation(2, maximumPowerOf2)) == 0)
144+
maximumPowerOf2++;
145+
maximumPowerOf2--;
146+
147+
int d = (number - 1) / Exponentiation.fastRecursiveExponentiation(2, maximumPowerOf2);
148+
boolean isPrime = true;
149+
for (int a : witnesses) {
150+
if (a > number)
151+
break;
152+
if (Exponentiation.fastRecursiveExponentiationModulo(a, d, number) != 1) {
153+
boolean isLocalPrime = false;
154+
for (int r = 0; r < maximumPowerOf2; r++) {
155+
if (Exponentiation.fastRecursiveExponentiationModulo(a, d * Exponentiation.fastRecursiveExponentiation(2, r), number) == (number - 1)) {
156+
isLocalPrime = true;
157+
break;
158+
}
159+
}
160+
if (!isLocalPrime) {
161+
isPrime = false;
162+
break;
163+
}
164+
}
165+
}
166+
167+
return isPrime;
168+
}
98169
}

test/com/jwetherell/algorithms/mathematics/test/CoprimesTest.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ public class CoprimesTest {
1212

1313
@Test
1414
public void totientTest(){
15-
List<Long> args = Arrays.asList(1L, 17L, 96L, 498L, 4182119424L);
16-
List<Long> expected = Arrays.asList(1L, 16L, 32L, 164L, 1194891264L);
17-
for(int i = 0; i < args.size(); i++) {
15+
final List<Long> args = Arrays.asList(1L, 17L, 96L, 498L, 4182119424L);
16+
final List<Long> expected = Arrays.asList(1L, 16L, 32L, 164L, 1194891264L);
17+
18+
for(int i = 0; i < args.size(); i++)
1819
assertEquals(expected.get(i), Coprimes.getNumberOfCoprimes(args.get(i)));
19-
}
2020
}
2121
}

test/com/jwetherell/algorithms/mathematics/test/ExponentiationTest.java

+10-10
Original file line numberDiff line numberDiff line change
@@ -14,30 +14,30 @@ public class ExponentiationTest {
1414

1515
@Test
1616
public void recusriveExponentiationTest() {
17-
List<Integer> baseList = Arrays.asList(1, 2, 4, 6, 8, 17, 24);
18-
List<Integer> exponentList = Arrays.asList(1000, 27, 14, 11, 10, 7, 5);
19-
List<Integer> expectedResultList = Arrays.asList(1, 134217728, 268435456, 362797056, 1073741824, 410338673, 7962624);
17+
final List<Integer> baseList = Arrays.asList(1, 2, 4, 6, 8, 17, 24);
18+
final List<Integer> exponentList = Arrays.asList(1000, 27, 14, 11, 10, 7, 5);
19+
final List<Integer> expectedResultList = Arrays.asList(1, 134217728, 268435456, 362797056, 1073741824, 410338673, 7962624);
2020

2121
for (int i = 0; i < expectedResultList.size(); i++)
2222
assertEquals(expectedResultList.get(i), Exponentiation.recursiveExponentiation(baseList.get(i), exponentList.get(i)));
2323
}
2424

2525
@Test
2626
public void fastRecusriveExponentiationTest() {
27-
List<Integer> baseList = Arrays.asList(1, 2, 4, 6, 8, 17, 24);
28-
List<Integer> exponentList = Arrays.asList(1000, 27, 14, 11, 10, 7, 5);
29-
List<Integer> expectedResultList = Arrays.asList(1, 134217728, 268435456, 362797056, 1073741824, 410338673, 7962624);
27+
final List<Integer> baseList = Arrays.asList(1, 2, 4, 6, 8, 17, 24);
28+
final List<Integer> exponentList = Arrays.asList(1000, 27, 14, 11, 10, 7, 5);
29+
final List<Integer> expectedResultList = Arrays.asList(1, 134217728, 268435456, 362797056, 1073741824, 410338673, 7962624);
3030

3131
for (int i = 0; i < expectedResultList.size(); i++)
3232
assertEquals(expectedResultList.get(i), Exponentiation.fastRecursiveExponentiation(baseList.get(i), exponentList.get(i)));
3333
}
3434

3535
@Test
3636
public void fastRecusriveExponentiationModuloTest() {
37-
List<Integer> baseList = Arrays.asList(1, 2, 4, 6, 8, 17, 24);
38-
List<Integer> exponentList = Arrays.asList(1000, 27, 14, 11, 10, 7, 5);
39-
List<Integer> divisorList = Arrays.asList(2, 6, 3, 2, 9, 11, 5);
40-
List<Integer> expectedResultList = Arrays.asList(1, 2, 1, 0, 1, 8, 4);
37+
final List<Integer> baseList = Arrays.asList(1, 2, 4, 6, 8, 17, 24, 2);
38+
final List<Integer> exponentList = Arrays.asList(1000, 27, 14, 11, 10, 7, 5, 1089);
39+
final List<Integer> divisorList = Arrays.asList(2, 6, 3, 2, 9, 11, 5, 2179);
40+
final List<Integer> expectedResultList = Arrays.asList(1, 2, 1, 0, 1, 8, 4, 2178);
4141

4242
for (int i = 0; i < expectedResultList.size(); i++)
4343
assertEquals(expectedResultList.get(i), Exponentiation.fastRecursiveExponentiationModulo(baseList.get(i), exponentList.get(i), divisorList.get(i)));

test/com/jwetherell/algorithms/mathematics/test/GCD.java renamed to test/com/jwetherell/algorithms/mathematics/test/GCDTest.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import com.jwetherell.algorithms.mathematics.GreatestCommonDivisor;
99

1010

11-
public class GCD {
11+
public class GCDTest {
1212

1313
@Test
1414
public void testRecursiveGCD() {
@@ -37,5 +37,4 @@ public void testEuclideanGCD() {
3737
check = 5;
3838
assertTrue("Euclids GCD error. expected="+check+" got="+gcd, (gcd==check));
3939
}
40-
4140
}

0 commit comments

Comments
 (0)