forked from phishman3579/java-algorithms-implementation
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Modular.java
143 lines (131 loc) · 4.28 KB
/
Modular.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package com.jwetherell.algorithms.mathematics;
/**
* In mathematics, modular arithmetic is a system of arithmetic for integers, where numbers "wrap around"
* upon reaching a certain value—the modulus (plural moduli). The modern approach to modular arithmetic was
* developed by Carl Friedrich Gauss in his book Disquisitiones Arithmeticae, published in 1801.
* <p>
* @see <a href="https://en.wikipedia.org/wiki/Modular_arithmetic">Modular Arithmetic (Wikipedia)</a>
* <br>
* @author Szymon Stankiewicz <[email protected]>
* @author Justin Wetherell <[email protected]>
*/
public class Modular {
private static long modularAbs(long n, long mod) {
n %= mod;
if (n < 0)
n += mod;
return n;
}
/**
* Adds two numbers in modulo arithmetic.
* This function is safe for large numbers and won't overflow long.
*
* @param a
* @param b
* @param mod grater than 0
* @return (a+b)%mod
*/
public static long add(long a, long b, long mod) {
if(mod <= 0)
throw new IllegalArgumentException("Mod argument is not grater then 0");
a = modularAbs(a, mod);
b = modularAbs(b, mod);
if(b > mod-a) {
return b - (mod - a);
}
return (a + b)%mod;
}
/**
* Subtract two numbers in modulo arithmetic.
* This function is safe for large numbers and won't overflow or underflow long.
*
* @param a
* @param b
* @param mod grater than 0
* @return (a-b)%mod
*/
public static long subtract(long a, long b, long mod) {
if(mod <= 0)
throw new IllegalArgumentException("Mod argument is not grater then 0");
return add(a, -b, mod);
}
/**
* Multiply two numbers in modulo arithmetic.
* This function is safe for large numbers and won't overflow or underflow long.
*
* Complexity O(log b)
*
* @param a
* @param b
* @param mod grater than 0
* @return (a*b)%mod
*/
public static long multiply(long a, long b, long mod) {
if(mod <= 0)
throw new IllegalArgumentException("Mod argument is not grater then 0");
a = modularAbs(a, mod);
b = modularAbs(b, mod);
if(b == 0) return 0;
return add(multiply(add(a, a, mod), b/2, mod), (b%2 == 1 ? a : 0), mod);
}
/**
* Calculate power in modulo arithmetic.
* This function is safe for large numbers and won't overflow or underflow long.
*
* Complexity O(log a * log b)
*
* @param a
* @param b integer grater or equal to zero
* @param mod grater than 0
* @return (a^b)%mod
*/
public static long pow(long a, long b, long mod) {
if(mod <= 0)
throw new IllegalArgumentException("Mod argument is not grater then 0");
if (b < 0)
throw new IllegalArgumentException("Exponent have to be grater or equal to zero");
a = modularAbs(a, mod);
if (a == 0 && b == 0)
throw new IllegalArgumentException("0^0 expression");
if (a == 0)
return 0;
long res = 1;
while(b > 0) {
if(b%2 == 1) res = multiply(res, a, mod);
a = multiply(a, a, mod);
b /= 2;
}
return res;
}
/**
* Divide two numbers in modulo arithmetic.
* This function is safe for large numbers and won't overflow or underflow long.
* b and mod have to be coprime.
*
* Complexity O(sqrt(mod))
*
* @param a
* @param b non zero
* @param mod grater than 0
* @return (a/b)%mod
*/
public static long divide(long a, long b, long mod) {
a = modularAbs(a, mod);
b = modularAbs(b, mod);
if(mod <= 0)
throw new IllegalArgumentException("Mod argument is not grater then 0");
if (b == 0)
throw new IllegalArgumentException("Dividing by zero");
if (GreatestCommonDivisor.gcdUsingRecursion(b, mod) != 1) {
throw new IllegalArgumentException("b and mod are not coprime");
}
if (a == 0) {
return 0;
}
if (b == 1) {
return a;
}
long reverted = pow(b, Coprimes.getNumberOfCoprimes(mod)-1, mod);
return multiply(reverted, a, mod);
}
}