1use num_traits::{
2 ConstOne, ConstZero, NumCast, PrimInt, Signed, Unsigned, WrappingAdd, WrappingMul, WrappingNeg,
3 WrappingSub,
4};
5use std::ops::{AddAssign, BitAnd, MulAssign};
6
7pub const fn size_of_bits<T>() -> usize {
8 std::mem::size_of::<T>() * 8
9}
10
11pub fn bit_width_mask<T>(bit_width: usize) -> T
12where
13 T: PrimInt + ConstOne,
14{
15 if bit_width < size_of_bits::<T>() {
16 (T::ONE << bit_width) - T::ONE
17 } else {
18 !(T::ONE)
19 }
20}
21
22pub trait UIntTypes:
25 PrimInt + Unsigned + ConstOne + ConstZero + WrappingAdd + WrappingSub + Copy
26{
27 fn mul_mod(a: Self, b: Self, m: Self) -> Self;
33}
34
35pub fn mul_mod_generic<T>(a: T, b: T, m: T) -> T
63where
64 T: UIntTypes,
65{
66 let mut a_work: T = a;
67 let mut b_work: T = b;
68 let mut result: T = T::ZERO;
69
70 if b_work >= m {
71 if m > T::max_value() / (T::ONE + T::ONE) {
72 b_work = b_work.wrapping_sub(&m);
73 } else {
74 b_work = b_work % m;
75 }
76 }
77
78 while a_work != T::ZERO {
79 if a_work & T::ONE != T::ZERO {
80 if b_work >= m - result {
81 result = result.wrapping_sub(&m);
82 }
83 result = result.wrapping_add(&b_work);
84 }
85 a_work = a_work >> 1;
86
87 let mut temp_b = b_work;
88 if b_work >= m - temp_b {
89 temp_b = temp_b.wrapping_sub(&m);
90 }
91 b_work = b_work.wrapping_add(&temp_b);
92 }
93 result
94}
95
96impl UIntTypes for u8 {
97 fn mul_mod(a: Self, b: Self, m: Self) -> Self {
99 ((a as u16) * (b as u16) % (m as u16)) as u8
100 }
101}
102impl UIntTypes for u16 {
103 fn mul_mod(a: Self, b: Self, m: Self) -> Self {
105 ((a as u32) * (b as u32) % (m as u32)) as u16
106 }
107}
108impl UIntTypes for u32 {
109 fn mul_mod(a: Self, b: Self, m: Self) -> Self {
111 ((a as u64) * (b as u64) % (m as u64)) as u32
112 }
113}
114impl UIntTypes for u64 {
115 fn mul_mod(a: Self, b: Self, m: Self) -> Self {
117 ((a as u128) * (b as u128) % (m as u128)) as u64
118 }
119}
120impl UIntTypes for u128 {
121 fn mul_mod(a: Self, b: Self, m: Self) -> Self {
123 mul_mod_generic::<Self>(a, b, m)
124 }
125}
126impl UIntTypes for usize {
127 fn mul_mod(a: Self, b: Self, m: Self) -> Self {
129 mul_mod_generic::<Self>(a, b, m)
130 }
131}
132
133pub fn mul_mod<T>(a: T, b: T, m: T) -> T
134where
135 T: UIntTypes,
136{
137 T::mul_mod(a, b, m)
138}
139
140pub trait IntTypes:
145 PrimInt + NumCast + ConstZero + ConstOne + WrappingAdd + WrappingNeg + Copy
146{
147 type SignedType: PrimInt + Signed + ConstZero + ConstOne + Copy + NumCast;
148 type UnsignedType: PrimInt + Unsigned + ConstZero + ConstOne + Copy + NumCast + WrappingNeg;
149 type OtherSignType: PrimInt + ConstOne + ConstZero + Copy + NumCast;
150
151 fn abs_as_unsigned(a: Self) -> Self::UnsignedType;
157}
158
159pub fn abs_as_unsigned_generic<T>(a: T) -> T::UnsignedType
167where
168 T: IntTypes,
169{
170 if a < T::ZERO {
171 let result: Option<T::UnsignedType> = NumCast::from(a.wrapping_neg());
173 if result.is_some() {
174 result.unwrap()
176 } else {
177 let result_minus_1: Option<T::UnsignedType> =
180 NumCast::from((a + T::ONE).wrapping_neg());
181 result_minus_1.unwrap_or(T::UnsignedType::ZERO) + T::UnsignedType::ONE
182 }
183 } else {
184 let result: Option<T::UnsignedType> = NumCast::from(a);
186 result.unwrap_or(T::UnsignedType::ZERO)
187 }
188}
189
190impl IntTypes for i8 {
191 type SignedType = i8;
192 type UnsignedType = u8;
193 type OtherSignType = u8;
194 fn abs_as_unsigned(a: Self) -> Self::UnsignedType {
195 abs_as_unsigned_generic::<Self>(a)
196 }
197}
198impl IntTypes for i16 {
199 type SignedType = i16;
200 type UnsignedType = u16;
201 type OtherSignType = u16;
202 fn abs_as_unsigned(a: Self) -> Self::UnsignedType {
203 abs_as_unsigned_generic::<Self>(a)
204 }
205}
206impl IntTypes for i32 {
207 type SignedType = i32;
208 type UnsignedType = u32;
209 type OtherSignType = u32;
210 fn abs_as_unsigned(a: Self) -> Self::UnsignedType {
211 abs_as_unsigned_generic::<Self>(a)
212 }
213}
214impl IntTypes for i64 {
215 type SignedType = i64;
216 type UnsignedType = u64;
217 type OtherSignType = u64;
218 fn abs_as_unsigned(a: Self) -> Self::UnsignedType {
219 abs_as_unsigned_generic::<Self>(a)
220 }
221}
222impl IntTypes for i128 {
223 type SignedType = i128;
224 type UnsignedType = u128;
225 type OtherSignType = u128;
226 fn abs_as_unsigned(a: Self) -> Self::UnsignedType {
227 abs_as_unsigned_generic::<Self>(a)
228 }
229}
230impl IntTypes for isize {
231 type SignedType = isize;
232 type UnsignedType = usize;
233 type OtherSignType = usize;
234 fn abs_as_unsigned(a: Self) -> Self::UnsignedType {
235 abs_as_unsigned_generic::<Self>(a)
236 }
237}
238impl IntTypes for u8 {
239 type SignedType = i8;
240 type UnsignedType = u8;
241 type OtherSignType = i8;
242 fn abs_as_unsigned(a: Self) -> Self::UnsignedType {
243 a
244 }
245}
246impl IntTypes for u16 {
247 type SignedType = i16;
248 type UnsignedType = u16;
249 type OtherSignType = i16;
250 fn abs_as_unsigned(a: Self) -> Self::UnsignedType {
251 a
252 }
253}
254impl IntTypes for u32 {
255 type SignedType = i32;
256 type UnsignedType = u32;
257 type OtherSignType = i32;
258 fn abs_as_unsigned(a: Self) -> Self::UnsignedType {
259 a
260 }
261}
262impl IntTypes for u64 {
263 type SignedType = i64;
264 type UnsignedType = u64;
265 type OtherSignType = i64;
266 fn abs_as_unsigned(a: Self) -> Self::UnsignedType {
267 a
268 }
269}
270impl IntTypes for u128 {
271 type SignedType = i128;
272 type UnsignedType = u128;
273 type OtherSignType = i128;
274 fn abs_as_unsigned(a: Self) -> Self::UnsignedType {
275 a
276 }
277}
278impl IntTypes for usize {
279 type SignedType = isize;
280 type UnsignedType = usize;
281 type OtherSignType = isize;
282 fn abs_as_unsigned(a: Self) -> Self::UnsignedType {
283 a
284 }
285}
286
287pub fn abs_as_unsigned<T>(a: T) -> T::UnsignedType
295where
296 T: IntTypes,
297{
298 IntTypes::abs_as_unsigned(a)
299}
300
301pub fn modulo<A, M>(a: A, m: M) -> M
320where
321 A: IntTypes,
322 M: PrimInt + Unsigned + ConstZero + Copy + NumCast,
323{
324 if a >= A::ZERO {
325 let a_opt: Option<M> = NumCast::from(a);
327 if a_opt.is_some() {
328 a_opt.unwrap() % m
330 } else {
331 let m_opt: Option<A> = NumCast::from(m);
333 let result_a = a % m_opt.unwrap();
334 let result_m: Option<M> = NumCast::from(result_a);
335 result_m.unwrap()
336 }
337 } else {
338 let a_abs = abs_as_unsigned(a);
340 let a_abs_opt: Option<M> = NumCast::from(a_abs);
341 if a_abs_opt.is_some() {
342 m - (a_abs_opt.unwrap() % m)
344 } else {
345 let m_opt: Option<A::UnsignedType> = NumCast::from(m);
347 let m_s = m_opt.unwrap();
348 let result_a = m_s - (a_abs % m_s);
349 let result_m: Option<M> = NumCast::from(result_a);
350 result_m.unwrap()
351 }
352 }
353}
354
355pub fn wrapping_pow<T, N>(base: T, n: N) -> T
365where
366 T: PrimInt + Unsigned + WrappingMul + WrappingSub + ConstOne,
367 N: PrimInt + Unsigned + ConstOne + ConstZero + BitAnd,
368{
369 let mut result: T = T::ONE;
370 let mut temp_exp = base;
371 let mut n_work: N = n;
372
373 loop {
374 if n_work & N::ONE != N::ZERO {
375 result = result.wrapping_mul(&temp_exp);
376 }
377 n_work = n_work >> 1;
378 if n_work == N::ZERO {
379 break;
380 }
381 temp_exp = temp_exp.wrapping_mul(&temp_exp);
382 }
383 result
384}
385
386pub fn pow_mod<T, N>(base: T, n: N, m: T) -> T
399where
400 T: UIntTypes,
401 N: PrimInt + Unsigned + ConstOne + ConstZero + BitAnd,
402{
403 let mut result: T = T::ONE;
404 let mut temp_exp = base;
405 let mut n_work: N = n;
406
407 loop {
408 if n_work & N::ONE != N::ZERO {
409 result = mul_mod(result, temp_exp, m);
410 }
411 n_work = n_work >> 1;
412 if n_work == N::ZERO {
413 break;
414 }
415 temp_exp = mul_mod(temp_exp, temp_exp, m);
416 }
417 result
418}
419
420pub fn wrapping_geom_series<T, N>(r: T, n: N) -> T
445where
446 T: PrimInt
447 + Unsigned
448 + ConstOne
449 + ConstZero
450 + WrappingMul
451 + WrappingAdd
452 + WrappingSub
453 + AddAssign
454 + MulAssign,
455 N: PrimInt + Unsigned + ConstOne + ConstZero + BitAnd,
456{
457 let mut temp_r = r;
458 let mut mult = T::ONE;
459 let mut result = T::ZERO;
460
461 if n == N::ZERO {
462 return T::ZERO;
463 }
464
465 let mut n_work = n;
466 while n_work > N::ONE {
467 if n_work & N::ONE != N::ZERO {
468 result = wrapping_pow(temp_r, n_work - N::ONE)
469 .wrapping_mul(&mult)
470 .wrapping_add(&result);
471 }
472 mult = (T::ONE.wrapping_add(&temp_r)).wrapping_mul(&mult);
473 temp_r = temp_r.wrapping_mul(&temp_r);
474 n_work = n_work >> 1;
475 }
476 result = result.wrapping_add(&mult);
477 result
478}