-
Notifications
You must be signed in to change notification settings - Fork 4.5k
Expand file tree
/
Copy pathModPowTest.java
More file actions
100 lines (86 loc) · 2.89 KB
/
ModPowTest.java
File metadata and controls
100 lines (86 loc) · 2.89 KB
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
package com.williamfiset.algorithms.math;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.math.BigInteger;
import java.util.concurrent.ThreadLocalRandom;
import org.junit.jupiter.api.*;
public class ModPowTest {
@Test
public void basicPositiveExponent() {
// 3^4 mod 1000000 = 81
assertThat(ModPow.modPow(3, 4, 1000000)).isEqualTo(81);
}
@Test
public void negativeBase() {
// (-45)^12345 mod 987654321
long expected =
BigInteger.valueOf(-45)
.modPow(BigInteger.valueOf(12345), BigInteger.valueOf(987654321))
.longValue();
assertThat(ModPow.modPow(-45, 12345, 987654321)).isEqualTo(expected);
}
@Test
public void negativeExponent() {
// 6^-66 mod 101 = 84
long expected =
BigInteger.valueOf(6)
.modPow(BigInteger.valueOf(-66), BigInteger.valueOf(101))
.longValue();
assertThat(ModPow.modPow(6, -66, 101)).isEqualTo(expected);
}
@Test
public void negativeBaseAndExponent() {
// (-5)^-7 mod 1009
long expected =
BigInteger.valueOf(-5)
.modPow(BigInteger.valueOf(-7), BigInteger.valueOf(1009))
.longValue();
assertThat(ModPow.modPow(-5, -7, 1009)).isEqualTo(expected);
}
@Test
public void exponentZero() {
assertThat(ModPow.modPow(123, 0, 7)).isEqualTo(1);
assertThat(ModPow.modPow(0, 0, 5)).isEqualTo(1);
}
@Test
public void baseZero() {
assertThat(ModPow.modPow(0, 10, 7)).isEqualTo(0);
}
@Test
public void modOne() {
// Anything mod 1 = 0
assertThat(ModPow.modPow(999, 999, 1)).isEqualTo(0);
}
@Test
public void largeValues() {
// Test with values that would overflow without safe multiplication
long a = 1_000_000_000L;
long n = 1_000_000_000L;
long mod = 999_999_937L;
long expected =
BigInteger.valueOf(a).modPow(BigInteger.valueOf(n), BigInteger.valueOf(mod)).longValue();
assertThat(ModPow.modPow(a, n, mod)).isEqualTo(expected);
}
@Test
public void modNonPositiveThrows() {
assertThrows(ArithmeticException.class, () -> ModPow.modPow(2, 3, 0));
assertThrows(ArithmeticException.class, () -> ModPow.modPow(2, 3, -5));
}
@Test
public void negativeExponentNotCoprime() {
// gcd(4, 8) = 4 ≠ 1, so no modular inverse
assertThrows(ArithmeticException.class, () -> ModPow.modPow(4, -1, 8));
}
@Test
public void matchesBigIntegerRandomized() {
ThreadLocalRandom rng = ThreadLocalRandom.current();
for (int i = 0; i < 500; i++) {
long a = rng.nextLong(-1_000_000_000L, 1_000_000_000L);
long n = rng.nextLong(0, 1_000_000_000L);
long mod = rng.nextLong(1, 1_000_000_000L);
long expected =
BigInteger.valueOf(a).modPow(BigInteger.valueOf(n), BigInteger.valueOf(mod)).longValue();
assertThat(ModPow.modPow(a, n, mod)).isEqualTo(expected);
}
}
}