Skip to content

Commit f48e77e

Browse files
committed
Merge branch 'Dakurels-master' - modular math
2 parents 05cb074 + cb0a158 commit f48e77e

File tree

3 files changed

+273
-0
lines changed

3 files changed

+273
-0
lines changed

README.md

+6
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,12 @@ This is a collection of algorithms and data structures which I've implement over
8080
* Permutations
8181
+ strings
8282
+ numbers
83+
* Modular arithmetic
84+
+ add
85+
+ subtract
86+
+ multiply
87+
+ divide
88+
+ power
8389

8490
## Numbers
8591
* Integers
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package com.jwetherell.algorithms.mathematics;
2+
3+
/**
4+
* Class for modular arithmetic.
5+
*
6+
* @author Szymob Stankiewicz
7+
*/
8+
public class Modular {
9+
10+
private static long modularAbs(long n, long mod) {
11+
n %= mod;
12+
if (n < 0)
13+
n += mod;
14+
return n;
15+
}
16+
17+
18+
/**
19+
* Adds two numbers in modulo arithmetic.
20+
* This function is safe for large numbers and won't overflow long.
21+
*
22+
* @param a
23+
* @param b
24+
* @param mod grater than 0
25+
* @return (a+b)%mod
26+
*/
27+
public static long add(long a, long b, long mod) {
28+
if(mod <= 0)
29+
throw new IllegalArgumentException("Mod argument is not grater then 0");
30+
a = modularAbs(a, mod);
31+
b = modularAbs(b, mod);
32+
if(b > mod-a) {
33+
return b - (mod - a);
34+
}
35+
return (a + b)%mod;
36+
}
37+
38+
/**
39+
* Subtract two numbers in modulo arithmetic.
40+
* This function is safe for large numbers and won't overflow or underflow long.
41+
*
42+
* @param a
43+
* @param b
44+
* @param mod grater than 0
45+
* @return (a-b)%mod
46+
*/
47+
public static long subtract(long a, long b, long mod) {
48+
if(mod <= 0)
49+
throw new IllegalArgumentException("Mod argument is not grater then 0");
50+
return add(a, -b, mod);
51+
}
52+
53+
/**
54+
* Multiply two numbers in modulo arithmetic.
55+
* This function is safe for large numbers and won't overflow or underflow long.
56+
*
57+
* Complexity O(log b)
58+
*
59+
* @param a
60+
* @param b
61+
* @param mod grater than 0
62+
* @return (a*b)%mod
63+
*/
64+
65+
public static long multiply(long a, long b, long mod) {
66+
if(mod <= 0)
67+
throw new IllegalArgumentException("Mod argument is not grater then 0");
68+
a = modularAbs(a, mod);
69+
b = modularAbs(b, mod);
70+
if(b == 0) return 0;
71+
return add(multiply(add(a, a, mod), b/2, mod), (b%2 == 1 ? a : 0), mod);
72+
}
73+
74+
/**
75+
* Calculate power in modulo arithmetic.
76+
* This function is safe for large numbers and won't overflow or underflow long.
77+
*
78+
* Complexity O(log a * log b)
79+
*
80+
* @param a
81+
* @param b integer grater or equal to zero
82+
* @param mod grater than 0
83+
* @return (a^b)%mod
84+
*/
85+
public static long pow(long a, long b, long mod) {
86+
if(mod <= 0)
87+
throw new IllegalArgumentException("Mod argument is not grater then 0");
88+
if (b < 0)
89+
throw new IllegalArgumentException("Exponent have to be grater or equal to zero");
90+
a = modularAbs(a, mod);
91+
if (a == 0 && b == 0)
92+
throw new IllegalArgumentException("0^0 expression");
93+
if (a == 0)
94+
return 0;
95+
long res = 1;
96+
while(b > 0) {
97+
if(b%2 == 1) res = multiply(res, a, mod);
98+
a = multiply(a, a, mod);
99+
b /= 2;
100+
}
101+
return res;
102+
}
103+
104+
/**
105+
* Divide two numbers in modulo arithmetic.
106+
* This function is safe for large numbers and won't overflow or underflow long.
107+
* b and mod have to be coprime.
108+
*
109+
* Complexity O(sqrt(mod))
110+
*
111+
* @param a
112+
* @param b non zero
113+
* @param mod grater than 0
114+
* @return (a/b)%mod
115+
*/
116+
117+
public static long divide(long a, long b, long mod) {
118+
a = modularAbs(a, mod);
119+
b = modularAbs(b, mod);
120+
if(mod <= 0)
121+
throw new IllegalArgumentException("Mod argument is not grater then 0");
122+
if (b == 0)
123+
throw new IllegalArgumentException("Dividing by zero");
124+
if (GreatestCommonDivisor.gcdUsingRecursion(b, mod) != 1) {
125+
throw new IllegalArgumentException("b and mod are not coprime");
126+
}
127+
if (a == 0) {
128+
return 0;
129+
}
130+
if (b == 1) {
131+
return a;
132+
}
133+
134+
long reverted = pow(b, Coprimes.getNumberOfCoprimes(mod)-1, mod);
135+
return multiply(reverted, a, mod);
136+
137+
}
138+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package com.jwetherell.algorithms.mathematics.test;
2+
3+
import com.jwetherell.algorithms.mathematics.Modular;
4+
import org.junit.Test;
5+
import static org.junit.Assert.*;
6+
7+
public class ModularArithmetic {
8+
9+
@Test
10+
public void sumTest() {
11+
assertEquals(4,
12+
Modular.add(-3, 22, 5));
13+
14+
assertEquals(Long.MAX_VALUE-2,
15+
Modular.add(Long.MAX_VALUE-1, Long.MAX_VALUE-1, Long.MAX_VALUE));
16+
17+
assertEquals(2,
18+
Modular.add(1-Long.MAX_VALUE, 1-Long.MAX_VALUE, Long.MAX_VALUE));
19+
20+
21+
assertEquals(0,
22+
Modular.add(Long.MAX_VALUE/2, Long.MAX_VALUE/2 + 1, Long.MAX_VALUE));
23+
24+
assertEquals(0,
25+
Modular.add(-1000, -10000000, 10));
26+
27+
try {
28+
Modular.add(1, 1,0);
29+
assertTrue("No exception", false);
30+
} catch (Exception ignored) {
31+
}
32+
}
33+
34+
@Test
35+
public void subtractTest() {
36+
assertEquals(0,
37+
Modular.subtract(-22, 3, 5));
38+
39+
assertEquals(Long.MAX_VALUE-1,
40+
Modular.subtract(Long.MAX_VALUE-2, Long.MAX_VALUE-1, Long.MAX_VALUE));
41+
42+
assertEquals(Long.MAX_VALUE-1,
43+
Modular.subtract(1-Long.MAX_VALUE, 2, Long.MAX_VALUE));
44+
45+
assertEquals(0,
46+
Modular.subtract(-1000, -10000000, 10));
47+
48+
try {
49+
Modular.subtract(1, 1,0);
50+
assertTrue("No exception", false);
51+
} catch (Exception ignored) {
52+
}
53+
}
54+
55+
@Test
56+
public void multiplyTest() {
57+
assertEquals(10,
58+
Modular.multiply(Long.MAX_VALUE-2, Long.MAX_VALUE-5, Long.MAX_VALUE));
59+
60+
assertEquals(3,
61+
Modular.multiply(-5, -7, 32));
62+
63+
try {
64+
Modular.multiply(1, 1,0);
65+
assertTrue("No exception", false);
66+
} catch (Exception ignored) {
67+
}
68+
69+
}
70+
71+
@Test
72+
public void powerTest() {
73+
assertEquals(1,
74+
Modular.pow(3, 1000000006, 1000000007));
75+
76+
assertEquals(8,
77+
Modular.pow(2, 66, Long.MAX_VALUE));
78+
79+
assertEquals(1,
80+
Modular.pow(123, 0, 1111));
81+
82+
assertEquals(0,
83+
Modular.pow(0, 123, 2));
84+
85+
try {
86+
Modular.pow(5, 0,5);
87+
assertTrue("No exception", false);
88+
} catch (Exception ignored) {
89+
}
90+
91+
try {
92+
Modular.pow(5, -5,5);
93+
assertTrue("No exception", false);
94+
} catch (Exception ignored) {
95+
}
96+
97+
try {
98+
Modular.pow(5, 5,0);
99+
assertTrue("No exception", false);
100+
} catch (Exception ignored) {
101+
}
102+
}
103+
104+
@Test
105+
public void divideTest() {
106+
try {
107+
Modular.divide(11, 6, 120);
108+
assertTrue("No exception", false);
109+
} catch (Exception ignored) {
110+
}
111+
112+
try {
113+
Modular.divide(2, 2, 0);
114+
assertTrue("No exception", false);
115+
} catch (Exception ignored) {
116+
}
117+
118+
assertEquals(1,
119+
Modular.divide(7, 7, 125));
120+
121+
assertEquals(97,
122+
Modular.divide(Modular.multiply(97, 25, 1023), 25, 1023));
123+
124+
assertEquals(Long.MAX_VALUE-11,
125+
Modular.divide(Modular.multiply(Long.MAX_VALUE-11, Long.MAX_VALUE-12, Long.MAX_VALUE),
126+
Long.MAX_VALUE-12,
127+
Long.MAX_VALUE));
128+
}
129+
}

0 commit comments

Comments
 (0)