malachite_base/num/arithmetic/mod_shr.rs
1// Copyright © 2025 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::num::arithmetic::traits::{ModShl, ModShlAssign, ModShr, ModShrAssign, UnsignedAbs};
10use crate::num::basic::signeds::PrimitiveSigned;
11use crate::num::basic::unsigneds::PrimitiveUnsigned;
12use core::ops::{Shr, ShrAssign};
13
14fn mod_shr_signed<
15 T: ModShl<U, T, Output = T> + PrimitiveUnsigned + Shr<U, Output = T>,
16 U: PrimitiveUnsigned,
17 S: PrimitiveSigned + UnsignedAbs<Output = U>,
18>(
19 x: T,
20 other: S,
21 m: T,
22) -> T {
23 assert!(x < m, "x must be reduced mod m, but {x} >= {m}");
24 let other_abs = other.unsigned_abs();
25 if other >= S::ZERO {
26 let width = U::wrapping_from(T::WIDTH);
27 if width != U::ZERO && other_abs >= width {
28 T::ZERO
29 } else {
30 x >> other_abs
31 }
32 } else {
33 x.mod_shl(other_abs, m)
34 }
35}
36
37fn mod_shr_assign_signed<
38 T: ModShlAssign<U, T> + PrimitiveUnsigned + ShrAssign<U>,
39 U: PrimitiveUnsigned,
40 S: PrimitiveSigned + UnsignedAbs<Output = U>,
41>(
42 x: &mut T,
43 other: S,
44 m: T,
45) {
46 assert!(*x < m, "x must be reduced mod m, but {x} >= {m}");
47 let other_abs = other.unsigned_abs();
48 if other >= S::ZERO {
49 let width = U::wrapping_from(T::WIDTH);
50 if width != U::ZERO && other_abs >= width {
51 *x = T::ZERO;
52 } else {
53 *x >>= other_abs;
54 }
55 } else {
56 x.mod_shl_assign(other_abs, m);
57 }
58}
59
60macro_rules! impl_mod_shr_signed {
61 ($t:ident) => {
62 macro_rules! impl_mod_shr_signed_inner {
63 ($u:ident) => {
64 impl ModShr<$u, $t> for $t {
65 type Output = $t;
66
67 /// Right-shifts a number (divides it by a power of 2) modulo a number $m$. The
68 /// number must be already reduced modulo $m$.
69 ///
70 /// $f(x, n, m) = y$, where $x, y < m$ and $\lfloor 2^{-n}x \rfloor \equiv y
71 /// \mod m$.
72 ///
73 /// # Worst-case complexity
74 /// $T(n) = O(n)$
75 ///
76 /// $M(n) = O(1)$
77 ///
78 /// where $T$ is time, $M$ is additional memory, and $n$ is
79 /// `other.significant_bits()`.
80 ///
81 /// # Panics
82 /// Panics if `self` is greater than or equal to `m`.
83 ///
84 /// # Examples
85 /// See [here](super::mod_shr#mod_shr).
86 #[inline]
87 fn mod_shr(self, other: $u, m: $t) -> $t {
88 mod_shr_signed(self, other, m)
89 }
90 }
91
92 impl ModShrAssign<$u, $t> for $t {
93 /// Right-shifts a number (divides it by a power of 2) modulo a number $m$, in
94 /// place. The number must be already reduced modulo $m$.
95 ///
96 /// $x \gets y$, where $x, y < m$ and $\lfloor 2^{-n}x \rfloor \equiv y \mod m$.
97 ///
98 /// # Worst-case complexity
99 /// $T(n) = O(n)$
100 ///
101 /// $M(n) = O(1)$
102 ///
103 /// where $T$ is time, $M$ is additional memory, and $n$ is
104 /// `other.significant_bits()`.
105 ///
106 /// # Panics
107 /// Panics if `self` is greater than or equal to `m`.
108 ///
109 /// # Examples
110 /// See [here](super::mod_shr#mod_shr).
111 #[inline]
112 fn mod_shr_assign(&mut self, other: $u, m: $t) {
113 mod_shr_assign_signed(self, other, m)
114 }
115 }
116 };
117 }
118 apply_to_signeds!(impl_mod_shr_signed_inner);
119 };
120}
121apply_to_unsigneds!(impl_mod_shr_signed);