1#[inline]
5pub fn mod_reduce(a: i64, modulus: u64) -> u64 {
6 let m = modulus as i64;
7 let r = a % m;
8 if r < 0 { (r + m) as u64 } else { r as u64 }
9}
10
11#[inline]
13pub fn center(a: u64, modulus: u64) -> i64 {
14 let a = a % modulus;
15 if a > modulus / 2 {
16 a as i64 - modulus as i64
17 } else {
18 a as i64
19 }
20}
21
22#[inline]
24pub fn mod_add(a: u64, b: u64, modulus: u64) -> u64 {
25 ((a as u128 + b as u128) % modulus as u128) as u64
26}
27
28#[inline]
30pub fn mod_sub(a: u64, b: u64, modulus: u64) -> u64 {
31 if a >= b {
32 (a - b) % modulus
33 } else {
34 modulus - ((b - a) % modulus)
35 }
36}
37
38#[inline]
40pub fn mod_mul(a: u64, b: u64, modulus: u64) -> u64 {
41 ((a as u128 * b as u128) % modulus as u128) as u64
42}
43
44#[inline]
46pub fn mod_neg(a: u64, modulus: u64) -> u64 {
47 if a == 0 { 0 } else { modulus - (a % modulus) }
48}
49
50pub fn mod_pow(mut base: u64, mut exp: u64, modulus: u64) -> u64 {
52 let mut result: u128 = 1;
53 let m = modulus as u128;
54 base %= modulus;
55 let mut b = base as u128;
56 while exp > 0 {
57 if exp & 1 == 1 {
58 result = (result * b) % m;
59 }
60 exp >>= 1;
61 b = (b * b) % m;
62 }
63 result as u64
64}
65
66pub fn mod_inv(a: u64, modulus: u64) -> u64 {
68 mod_pow(a, modulus - 2, modulus)
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74
75 #[test]
76 fn test_mod_reduce_positive() {
77 assert_eq!(mod_reduce(7, 5), 2);
78 }
79
80 #[test]
81 fn test_mod_reduce_negative() {
82 assert_eq!(mod_reduce(-3, 5), 2);
83 }
84
85 #[test]
86 fn test_center() {
87 assert_eq!(center(1, 7), 1);
88 assert_eq!(center(6, 7), -1);
89 assert_eq!(center(3, 7), 3); assert_eq!(center(4, 7), -3); }
92
93 #[test]
94 fn test_mod_arithmetic() {
95 let q = 97;
96 assert_eq!(mod_add(50, 60, q), 13);
97 assert_eq!(mod_sub(10, 30, q), 77);
98 assert_eq!(mod_mul(50, 50, q), (2500 % 97));
99 assert_eq!(mod_neg(10, q), 87);
100 }
101
102 #[test]
103 fn test_mod_pow() {
104 assert_eq!(mod_pow(2, 10, 1024), 0); assert_eq!(mod_pow(3, 4, 97), 81 % 97);
106 }
107
108 #[test]
109 fn test_mod_inv() {
110 let q = 97u64;
111 for a in 1..q {
112 let inv = mod_inv(a, q);
113 assert_eq!(mod_mul(a, inv, q), 1, "inverse failed for {a}");
114 }
115 }
116}