malachite_base/num/arithmetic/
shr_round.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::{ShrRound, ShrRoundAssign, UnsignedAbs};
10use crate::num::basic::integers::PrimitiveInt;
11use crate::num::basic::signeds::PrimitiveSigned;
12use crate::num::basic::unsigneds::PrimitiveUnsigned;
13use crate::num::conversion::traits::WrappingFrom;
14use crate::rounding_modes::RoundingMode::{self, *};
15use core::cmp::Ordering::{self, *};
16use core::ops::{Shl, ShlAssign, Shr, ShrAssign};
17
18fn shr_round_unsigned_unsigned<
19    T: PrimitiveUnsigned + Shl<U, Output = T> + Shr<U, Output = T>,
20    U: PrimitiveUnsigned,
21>(
22    x: T,
23    bits: U,
24    rm: RoundingMode,
25) -> (T, Ordering) {
26    if bits == U::ZERO || x == T::ZERO {
27        return (x, Equal);
28    }
29    let width = U::wrapping_from(T::WIDTH);
30    match rm {
31        Down | Floor if bits >= width => (T::ZERO, Less),
32        Down | Floor => {
33            let shifted = x >> bits;
34            (shifted, if shifted << bits == x { Equal } else { Less })
35        }
36        Up | Ceiling if bits >= width => (T::ONE, Greater),
37        Up | Ceiling => {
38            let shifted = x >> bits;
39            if shifted << bits == x {
40                (shifted, Equal)
41            } else {
42                (shifted + T::ONE, Greater)
43            }
44        }
45        Nearest if bits == width && x > T::power_of_2(T::WIDTH - 1) => (T::ONE, Greater),
46        Nearest if bits >= width => (T::ZERO, Less),
47        Nearest => {
48            let bm1 = bits - U::ONE;
49            let mostly_shifted = x >> bm1;
50            let bm1_zeros = mostly_shifted << bm1 == x;
51            if mostly_shifted.even() {
52                // round down
53                (mostly_shifted >> 1, if bm1_zeros { Equal } else { Less })
54            } else if !bm1_zeros {
55                // round up
56                ((mostly_shifted >> 1) + T::ONE, Greater)
57            } else {
58                // result is half-integer; round to even
59                let shifted: T = mostly_shifted >> 1;
60                if shifted.even() {
61                    (shifted, Less)
62                } else {
63                    (shifted + T::ONE, Greater)
64                }
65            }
66        }
67        Exact if bits >= width => {
68            panic!("Right shift is not exact: {x} >> {bits}");
69        }
70        Exact => {
71            let shifted = x >> bits;
72            assert!(
73                shifted << bits == x,
74                "Right shift is not exact: {x} >> {bits}"
75            );
76            (shifted, Equal)
77        }
78    }
79}
80
81fn shr_round_assign_unsigned_unsigned<
82    T: PrimitiveUnsigned + Shl<U, Output = T> + ShrAssign<U>,
83    U: PrimitiveUnsigned,
84>(
85    x: &mut T,
86    bits: U,
87    rm: RoundingMode,
88) -> Ordering {
89    if bits == U::ZERO || *x == T::ZERO {
90        return Equal;
91    }
92    let width = U::wrapping_from(T::WIDTH);
93    match rm {
94        Down | Floor if bits >= width => {
95            *x = T::ZERO;
96            Less
97        }
98        Down | Floor => {
99            let original = *x;
100            *x >>= bits;
101            if *x << bits == original { Equal } else { Less }
102        }
103        Up | Ceiling if bits >= width => {
104            *x = T::ONE;
105            Greater
106        }
107        Up | Ceiling => {
108            let original = *x;
109            *x >>= bits;
110            if *x << bits == original {
111                Equal
112            } else {
113                *x += T::ONE;
114                Greater
115            }
116        }
117        Nearest if bits == width && *x > T::power_of_2(T::WIDTH - 1) => {
118            *x = T::ONE;
119            Greater
120        }
121        Nearest if bits >= width => {
122            *x = T::ZERO;
123            Less
124        }
125        Nearest => {
126            let original = *x;
127            let bm1 = bits - U::ONE;
128            *x >>= bm1;
129            let bm1_zeros = *x << bm1 == original;
130            let old_x = *x;
131            *x >>= 1;
132            if old_x.even() {
133                // round down
134                if bm1_zeros { Equal } else { Less }
135            } else if !bm1_zeros {
136                // round up
137                *x += T::ONE;
138                Greater
139            } else {
140                // result is half-integer; round to even
141                if x.even() {
142                    Less
143                } else {
144                    *x += T::ONE;
145                    Greater
146                }
147            }
148        }
149        Exact if bits >= width => {
150            panic!("Right shift is not exact: {} >>= {}", *x, bits);
151        }
152        Exact => {
153            let original = *x;
154            *x >>= bits;
155            assert!(
156                *x << bits == original,
157                "Right shift is not exact: {original} >>= {bits}"
158            );
159            Equal
160        }
161    }
162}
163
164macro_rules! impl_shr_round_unsigned_unsigned {
165    ($t:ident) => {
166        macro_rules! impl_shr_round_unsigned_unsigned_inner {
167            ($u:ident) => {
168                impl ShrRound<$u> for $t {
169                    type Output = $t;
170
171                    /// Shifts a number right (divides it by a power of 2) and rounds according to
172                    /// the specified rounding mode. An [`Ordering`] is also returned, indicating
173                    /// whether the returned value is less than, equal to, or greater than the exact
174                    /// value.
175                    ///
176                    /// Passing `Floor` or `Down` is equivalent to using `>>`. To test whether
177                    /// `Exact` can be passed, use `self.divisible_by_power_of_2(bits)`.
178                    ///
179                    /// Let $q = \frac{x}{2^k}$, and let $g$ be the function that just returns the
180                    /// first element of the pair, without the [`Ordering`]:
181                    ///
182                    /// $g(x, k, \mathrm{Down}) = g(x, y, \mathrm{Floor}) = \lfloor q \rfloor.$
183                    ///
184                    /// $g(x, k, \mathrm{Up}) = g(x, y, \mathrm{Ceiling}) = \lceil q \rceil.$
185                    ///
186                    /// $$
187                    /// g(x, k, \mathrm{Nearest}) = \begin{cases}
188                    ///     \lfloor q \rfloor & \text{if}
189                    ///         \\quad q - \lfloor q \rfloor < \frac{1}{2}, \\\\
190                    ///     \lceil q \rceil & \text{if}
191                    ///         \\quad q - \lfloor q \rfloor > \frac{1}{2}, \\\\
192                    ///     \lfloor q \rfloor & \text{if} \\quad q - \lfloor q \rfloor =
193                    ///         \frac{1}{2} \\ \text{and} \\ \lfloor q \rfloor
194                    ///     \\ \text{is even}, \\\\
195                    ///     \lceil q \rceil &
196                    ///     \text{if} \\quad q - \lfloor q \rfloor = \frac{1}{2} \\ \text{and}
197                    ///         \\ \lfloor q \rfloor \\ \text{is odd}.
198                    /// \end{cases}
199                    /// $$
200                    ///
201                    /// $g(x, k, \mathrm{Exact}) = q$, but panics if $q \notin \N$.
202                    ///
203                    /// Then
204                    ///
205                    /// $f(x, k, r) = (g(x, k, r), \operatorname{cmp}(g(x, k, r), q))$.
206                    ///
207                    /// # Worst-case complexity
208                    /// Constant time and additional memory.
209                    ///
210                    /// # Panics
211                    /// Panics if `rm` is `Exact` but `self` is not divisible by $2^b$.
212                    ///
213                    /// # Examples
214                    /// See [here](super::shr_round#shr_round).
215                    #[inline]
216                    fn shr_round(self, bits: $u, rm: RoundingMode) -> ($t, Ordering) {
217                        shr_round_unsigned_unsigned(self, bits, rm)
218                    }
219                }
220
221                impl ShrRoundAssign<$u> for $t {
222                    /// Shifts a number right (divides it by a power of 2) and rounds according to
223                    /// the specified rounding mode, in place. An [`Ordering`] is returned,
224                    /// indicating whether the assigned value is less than, equal to, or greater
225                    /// than the exact value.
226                    ///
227                    /// Passing `Floor` or `Down` is equivalent to using `>>`. To test whether
228                    /// `Exact` can be passed, use `self.divisible_by_power_of_2(bits)`.
229                    ///
230                    /// See the [`ShrRound`] documentation for details.
231                    ///
232                    /// # Worst-case complexity
233                    /// Constant time and additional memory.
234                    ///
235                    /// # Panics
236                    /// Panics if `rm` is `Exact` but `self` is not divisible by $2^b$.
237                    ///
238                    /// # Examples
239                    /// See [here](super::shr_round#shr_round_assign).
240                    #[inline]
241                    fn shr_round_assign(&mut self, bits: $u, rm: RoundingMode) -> Ordering {
242                        shr_round_assign_unsigned_unsigned(self, bits, rm)
243                    }
244                }
245            };
246        }
247        apply_to_unsigneds!(impl_shr_round_unsigned_unsigned_inner);
248    };
249}
250apply_to_unsigneds!(impl_shr_round_unsigned_unsigned);
251
252fn shr_round_signed_unsigned<
253    U: PrimitiveUnsigned + ShrRound<B, Output = U>,
254    S: PrimitiveSigned + UnsignedAbs<Output = U> + WrappingFrom<U>,
255    B,
256>(
257    x: S,
258    bits: B,
259    rm: RoundingMode,
260) -> (S, Ordering) {
261    let abs = x.unsigned_abs();
262    if x >= S::ZERO {
263        let (abs_shifted, o) = abs.shr_round(bits, rm);
264        (S::wrapping_from(abs_shifted), o)
265    } else {
266        let (abs_shifted, o) = abs.shr_round(bits, -rm);
267        (
268            if abs_shifted == U::ZERO {
269                S::ZERO
270            } else if abs_shifted == S::MIN.unsigned_abs() {
271                S::MIN
272            } else {
273                -S::wrapping_from(abs_shifted)
274            },
275            o.reverse(),
276        )
277    }
278}
279
280macro_rules! impl_shr_round_signed_unsigned {
281    ($t:ident) => {
282        macro_rules! impl_shr_round_signed_unsigned_inner {
283            ($u:ident) => {
284                impl ShrRound<$u> for $t {
285                    type Output = $t;
286
287                    /// Shifts a number right (divides it by a power of 2) and rounds according to
288                    /// the specified rounding mode. An [`Ordering`] is also returned, indicating
289                    /// whether the returned value is less than, equal to, or greater than the exact
290                    /// value.
291                    ///
292                    /// Passing `Floor` or `Down` is equivalent to using `>>`. To test whether
293                    /// `Exact` can be passed, use `self.divisible_by_power_of_2(bits)`.
294                    ///
295                    /// Let $q = \frac{x}{2^k}$, and let $g$ be the function that just returns the
296                    /// first element of the pair, without the [`Ordering`]:
297                    ///
298                    /// $g(x, k, \mathrm{Down}) = g(x, y, \mathrm{Floor}) = \lfloor q \rfloor.$
299                    ///
300                    /// $g(x, k, \mathrm{Up}) = g(x, y, \mathrm{Ceiling}) = \lceil q \rceil.$
301                    ///
302                    /// $$
303                    /// g(x, k, \mathrm{Nearest}) = \begin{cases}
304                    ///     \lfloor q \rfloor & \text{if}
305                    ///         \\quad q - \lfloor q \rfloor < \frac{1}{2}, \\\\
306                    ///     \lceil q \rceil & \text{if}
307                    ///         \\quad q - \lfloor q \rfloor > \frac{1}{2}, \\\\
308                    ///     \lfloor q \rfloor & \text{if} \\quad q - \lfloor q \rfloor =
309                    ///         \frac{1}{2} \\ \text{and} \\ \lfloor q \rfloor
310                    ///     \\ \text{is even}, \\\\
311                    ///     \lceil q \rceil &
312                    ///     \text{if} \\quad q - \lfloor q \rfloor = \frac{1}{2} \\ \text{and}
313                    ///         \\ \lfloor q \rfloor \\ \text{is odd}.
314                    /// \end{cases}
315                    /// $$
316                    ///
317                    /// $g(x, k, \mathrm{Exact}) = q$, but panics if $q \notin \N$.
318                    ///
319                    /// Then
320                    ///
321                    /// $f(x, k, r) = (g(x, k, r), \operatorname{cmp}(g(x, k, r), q))$.
322                    ///
323                    /// # Worst-case complexity
324                    /// Constant time and additional memory.
325                    ///
326                    /// # Panics
327                    /// Panics if `rm` is `Exact` but `self` is not divisible by $2^b$.
328                    ///
329                    /// # Examples
330                    /// See [here](super::shr_round#shr_round).
331                    #[inline]
332                    fn shr_round(self, bits: $u, rm: RoundingMode) -> ($t, Ordering) {
333                        shr_round_signed_unsigned(self, bits, rm)
334                    }
335                }
336
337                impl ShrRoundAssign<$u> for $t {
338                    /// Shifts a number right (divides it by a power of 2) and rounds according to
339                    /// the specified rounding mode, in place. An [`Ordering`] isreturned,
340                    /// indicating whether the assigned value is less than, equal to, or greater
341                    /// than the exact value.
342                    ///
343                    /// Passing `Floor` or `Down` is equivalent to using `>>`. To test whether
344                    /// `Exact` can be passed, use `self.divisible_by_power_of_2(bits)`.
345                    ///
346                    /// # Worst-case complexity
347                    /// Constant time and additional memory.
348                    ///
349                    /// # Panics
350                    /// Panics if `rm` is `Exact` but `self` is not divisible by $2^b$.
351                    ///
352                    /// # Examples
353                    /// See [here](super::shr_round#shr_round_assign).
354                    #[inline]
355                    fn shr_round_assign(&mut self, bits: $u, rm: RoundingMode) -> Ordering {
356                        let o;
357                        (*self, o) = self.shr_round(bits, rm);
358                        o
359                    }
360                }
361            };
362        }
363        apply_to_unsigneds!(impl_shr_round_signed_unsigned_inner);
364    };
365}
366apply_to_signeds!(impl_shr_round_signed_unsigned);
367
368fn shr_round_primitive_signed<
369    T: PrimitiveInt + Shl<U, Output = T> + ShrRound<U, Output = T>,
370    U: PrimitiveUnsigned,
371    S: PrimitiveSigned + UnsignedAbs<Output = U>,
372>(
373    x: T,
374    bits: S,
375    rm: RoundingMode,
376) -> (T, Ordering) {
377    if bits >= S::ZERO {
378        x.shr_round(bits.unsigned_abs(), rm)
379    } else {
380        let abs = bits.unsigned_abs();
381        (
382            if abs >= U::wrapping_from(T::WIDTH) {
383                T::ZERO
384            } else {
385                x << bits.unsigned_abs()
386            },
387            Equal,
388        )
389    }
390}
391
392fn shr_round_assign_primitive_signed<
393    T: PrimitiveInt + ShlAssign<U> + ShrRoundAssign<U>,
394    U: PrimitiveUnsigned,
395    S: PrimitiveSigned + UnsignedAbs<Output = U>,
396>(
397    x: &mut T,
398    bits: S,
399    rm: RoundingMode,
400) -> Ordering {
401    if bits >= S::ZERO {
402        x.shr_round_assign(bits.unsigned_abs(), rm)
403    } else {
404        let abs = bits.unsigned_abs();
405        if abs >= U::wrapping_from(T::WIDTH) {
406            *x = T::ZERO;
407        } else {
408            *x <<= bits.unsigned_abs();
409        }
410        Equal
411    }
412}
413
414macro_rules! impl_shr_round_primitive_signed {
415    ($t:ident) => {
416        macro_rules! impl_shr_round_primitive_signed_inner {
417            ($u:ident) => {
418                impl ShrRound<$u> for $t {
419                    type Output = $t;
420
421                    /// Shifts a number right (divides it by a power of 2) and rounds according to
422                    /// the specified rounding mode. An [`Ordering`] is also returned, indicating
423                    /// whether the returned value is less than, equal to, or greater than the exact
424                    /// value. If `bits` is negative, then the returned [`Ordering`] is always
425                    /// `Equal`, even if the higher bits of the result are lost.
426                    ///
427                    /// Passing `Floor` or `Down` is equivalent to using `>>`. To test whether
428                    /// `Exact` can be passed, use `self.divisible_by_power_of_2(bits)`. Rounding
429                    /// might only be necessary if `bits` is non-negative.
430                    ///
431                    /// Let $q = \frac{x}{2^k}$, and let $g$ be the function that just returns the
432                    /// first element of the pair, without the [`Ordering`]:
433                    ///
434                    /// $g(x, k, \mathrm{Down}) = \operatorname{sgn}(q) \lfloor |q| \rfloor.$
435                    ///
436                    /// $g(x, k, \mathrm{Up}) = \operatorname{sgn}(q) \lceil |q| \rceil.$
437                    ///
438                    /// $g(x, k, \mathrm{Floor}) = \lfloor q \rfloor.$
439                    ///
440                    /// $g(x, k, \mathrm{Ceiling}) = \lceil q \rceil.$
441                    ///
442                    /// $$
443                    /// g(x, k, \mathrm{Nearest}) = \begin{cases}
444                    ///     \lfloor q \rfloor & \text{if}
445                    ///         \\quad q - \lfloor q \rfloor < \frac{1}{2}, \\\\
446                    ///     \lceil q \rceil & \text{if}
447                    ///         \\quad q - \lfloor q \rfloor > \frac{1}{2}, \\\\
448                    ///     \lfloor q \rfloor & \text{if} \\quad q - \lfloor q \rfloor =
449                    ///         \frac{1}{2} \\ \text{and} \\ \lfloor q \rfloor
450                    ///     \\ \text{is even}, \\\\
451                    ///     \lceil q \rceil &
452                    ///     \text{if} \\quad q - \lfloor q \rfloor = \frac{1}{2} \\ \text{and}
453                    ///         \\ \lfloor q \rfloor \\ \text{is odd}.
454                    /// \end{cases}
455                    /// $$
456                    ///
457                    /// $g(x, k, \mathrm{Exact}) = q$, but panics if $q \notin \Z$.
458                    ///
459                    /// Then
460                    ///
461                    /// $f(x, k, r) = (g(x, k, r), \operatorname{cmp}(g(x, k, r), q))$.
462                    ///
463                    /// # Worst-case complexity
464                    /// Constant time and additional memory.
465                    ///
466                    /// # Panics
467                    /// Panics if `bits` is positive and `rm` is `Exact` but `self` is not divisible
468                    /// by $2^b$.
469                    ///
470                    /// # Examples
471                    /// See [here](super::shr_round#shr_round).
472                    #[inline]
473                    fn shr_round(self, bits: $u, rm: RoundingMode) -> ($t, Ordering) {
474                        shr_round_primitive_signed(self, bits, rm)
475                    }
476                }
477
478                impl ShrRoundAssign<$u> for $t {
479                    /// Shifts a number right (divides it by a power of 2) and rounds according to
480                    /// the specified rounding mode, in place. An [`Ordering`] is returned,
481                    /// indicating whether the assigned value is less than, equal to, or greater
482                    /// than the exact value. If `bits` is negative, then the returned [`Ordering`]
483                    /// is always `Equal`, even if the higher bits of the result are lost.
484                    ///
485                    /// Passing `Floor` or `Down` is equivalent to using `>>`. To test whether
486                    /// `Exact` can be passed, use `self.divisible_by_power_of_2(bits)`. Rounding
487                    /// might only be necessary if `bits` is non-negative.
488                    ///
489                    /// See the [`ShrRound`] documentation for details.
490                    ///
491                    /// # Worst-case complexity
492                    /// Constant time and additional memory.
493                    ///
494                    /// # Panics
495                    /// Panics if `bits` is positive and `rm` is `Exact` but `self` is not divisible
496                    /// by $2^b$.
497                    ///
498                    /// # Examples
499                    /// See [here](super::shr_round#shr_round_assign).
500                    #[inline]
501                    fn shr_round_assign(&mut self, bits: $u, rm: RoundingMode) -> Ordering {
502                        shr_round_assign_primitive_signed(self, bits, rm)
503                    }
504                }
505            };
506        }
507        apply_to_signeds!(impl_shr_round_primitive_signed_inner);
508    };
509}
510apply_to_primitive_ints!(impl_shr_round_primitive_signed);