malachite_base/num/arithmetic/
mod_inverse.rs1use crate::num::arithmetic::traits::ModInverse;
14use crate::num::basic::signeds::PrimitiveSigned;
15use crate::num::basic::unsigneds::PrimitiveUnsigned;
16use crate::num::conversion::traits::WrappingFrom;
17use crate::rounding_modes::RoundingMode::*;
18
19pub_test! {mod_inverse_binary<
21 U: WrappingFrom<S> + PrimitiveUnsigned,
22 S: PrimitiveSigned + WrappingFrom<U>,
23>(
24 x: U,
25 m: U,
26) -> Option<U> {
27 assert_ne!(x, U::ZERO);
28 assert!(x < m, "x must be reduced mod m, but {x} >= {m}");
29 let mut u1 = S::ONE;
30 let mut v2 = S::ONE;
31 let mut u2 = S::ZERO;
32 let mut v1 = S::ZERO;
33 let mut u3 = m;
34 let mut v3 = x;
35 let mut d;
36 let mut t2;
37 let mut t1;
38 if (m & x).get_highest_bit() {
39 d = u3 - v3;
40 t2 = v2;
41 t1 = u2;
42 u2 = u1 - u2;
43 u1 = t1;
44 u3 = v3;
45 v2 = v1 - v2;
46 v1 = t2;
47 v3 = d;
48 }
49 while v3.get_bit(U::WIDTH - 2) {
50 d = u3 - v3;
51 if d < v3 {
52 t2 = v2;
54 t1 = u2;
55 u2 = u1 - u2;
56 u1 = t1;
57 u3 = v3;
58 v2 = v1 - v2;
59 v1 = t2;
60 v3 = d;
61 } else if d < (v3 << 1) {
62 t1 = u2;
64 u2 = u1 - (u2 << 1);
65 u1 = t1;
66 u3 = v3;
67 t2 = v2;
68 v2 = v1 - (v2 << 1);
69 v1 = t2;
70 v3 = d - u3;
71 } else {
72 t1 = u2;
74 u2 = u1 - S::wrapping_from(3) * u2;
75 u1 = t1;
76 u3 = v3;
77 t2 = v2;
78 v2 = v1 - S::wrapping_from(3) * v2;
79 v1 = t2;
80 v3 = d - (u3 << 1);
81 }
82 }
83 while v3 != U::ZERO {
84 d = u3 - v3;
85 if u3 < (v3 << 2) {
87 if d < v3 {
88 t2 = v2;
90 t1 = u2;
91 u2 = u1 - u2;
92 u1 = t1;
93 u3 = v3;
94 v2 = v1 - v2;
95 v1 = t2;
96 v3 = d;
97 } else if d < (v3 << 1) {
98 t1 = u2;
100 u2 = u1.wrapping_sub(u2 << 1);
101 u1 = t1;
102 u3 = v3;
103 t2 = v2;
104 v2 = v1.wrapping_sub(v2 << 1);
105 v1 = t2;
106 v3 = d - u3;
107 } else {
108 t1 = u2;
110 u2 = u1.wrapping_sub(S::wrapping_from(3).wrapping_mul(u2));
111 u1 = t1;
112 u3 = v3;
113 t2 = v2;
114 v2 = v1.wrapping_sub(S::wrapping_from(3).wrapping_mul(v2));
115 v1 = t2;
116 v3 = d.wrapping_sub(u3 << 1);
117 }
118 } else {
119 let (quot, rem) = u3.div_rem(v3);
120 t1 = u2;
121 u2 = u1.wrapping_sub(S::wrapping_from(quot).wrapping_mul(u2));
122 u1 = t1;
123 u3 = v3;
124 t2 = v2;
125 v2 = v1.wrapping_sub(S::wrapping_from(quot).wrapping_mul(v2));
126 v1 = t2;
127 v3 = rem;
128 }
129 }
130 if u3 != U::ONE {
131 return None;
132 }
133 let mut inverse = U::wrapping_from(v1);
134 if u1 <= S::ZERO {
135 inverse.wrapping_sub_assign(m);
136 }
137 let limit = (m >> 1u32).wrapping_neg();
138 if inverse < limit {
139 let k = (limit - inverse).div_round(m, Ceiling).0;
140 inverse.wrapping_add_assign(m.wrapping_mul(k));
141 }
142 Some(if inverse.get_highest_bit() {
143 inverse.wrapping_add(m)
144 } else {
145 inverse
146 })
147}}
148
149macro_rules! impl_mod_inverse {
150 ($u:ident, $s:ident) => {
151 impl ModInverse<$u> for $u {
152 type Output = $u;
153
154 #[inline]
175 fn mod_inverse(self, m: $u) -> Option<$u> {
176 mod_inverse_binary::<$u, $s>(self, m)
177 }
178 }
179 };
180}
181apply_to_unsigned_signed_pairs!(impl_mod_inverse);