malachite_nz/integer/arithmetic/
shl_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::integer::Integer;
10use core::cmp::Ordering::{self, *};
11use core::ops::{Shl, ShlAssign};
12use malachite_base::num::arithmetic::traits::{
13    ShlRound, ShlRoundAssign, ShrRound, ShrRoundAssign, UnsignedAbs,
14};
15use malachite_base::num::basic::traits::Zero;
16use malachite_base::rounding_modes::RoundingMode;
17
18fn shl_round_signed_ref<'a, U, S: Copy + Ord + UnsignedAbs<Output = U> + Zero>(
19    x: &'a Integer,
20    bits: S,
21    rm: RoundingMode,
22) -> (Integer, Ordering)
23where
24    &'a Integer: Shl<U, Output = Integer> + ShrRound<U, Output = Integer>,
25{
26    if bits >= S::ZERO {
27        (x << bits.unsigned_abs(), Equal)
28    } else {
29        x.shr_round(bits.unsigned_abs(), rm)
30    }
31}
32
33fn shl_round_assign_i<U, S: Copy + Ord + UnsignedAbs<Output = U> + Zero>(
34    x: &mut Integer,
35    bits: S,
36    rm: RoundingMode,
37) -> Ordering
38where
39    Integer: ShlAssign<U> + ShrRoundAssign<U>,
40{
41    if bits >= S::ZERO {
42        *x <<= bits.unsigned_abs();
43        Equal
44    } else {
45        x.shr_round_assign(bits.unsigned_abs(), rm)
46    }
47}
48
49macro_rules! impl_shl_round_signed {
50    ($t:ident) => {
51        impl ShlRound<$t> for Integer {
52            type Output = Integer;
53
54            /// Left-shifts an [`Integer`] (multiplies or divides it by a power of 2), taking it by
55            /// value, and rounds according to the specified rounding mode. An [`Ordering`] is also
56            /// returned, indicating whether the returned value is less than, equal to, or greater
57            /// than the exact value. If `bits` is non-negative, then the returned [`Ordering`] is
58            /// always `Equal`, even if the higher bits of the result are lost.
59            ///
60            /// Passing `Floor` is equivalent to using `>>`. To test whether `Exact` can be passed,
61            /// use `bits > 0 || self.divisible_by_power_of_2(bits)`. Rounding might only be
62            /// necessary if `bits` is negative.
63            ///
64            /// Let $q = x2^k$, and let $g$ be the function that just returns the first element of
65            /// the pair, without the [`Ordering`]:
66            ///
67            /// $g(x, k, \mathrm{Down}) = g(x, y, \mathrm{Floor}) = \lfloor q \rfloor.$
68            ///
69            /// $g(x, k, \mathrm{Up}) = g(x, y, \mathrm{Ceiling}) = \lceil q \rceil.$
70            ///
71            /// $$
72            /// g(x, k, \mathrm{Nearest}) = \begin{cases}
73            ///     \lfloor q \rfloor & \text{if}
74            ///         \\quad q - \lfloor q \rfloor < \frac{1}{2}, \\\\
75            ///     \lceil q \rceil & \text{if}
76            ///         \\quad q - \lfloor q \rfloor > \frac{1}{2}, \\\\
77            ///     \lfloor q \rfloor & \text{if} \\quad q - \lfloor q \rfloor =
78            ///         \frac{1}{2} \\ \text{and} \\ \lfloor q \rfloor
79            ///     \\ \text{is even}, \\\\
80            ///     \lceil q \rceil &
81            ///     \text{if} \\quad q - \lfloor q \rfloor = \frac{1}{2} \\ \text{and}
82            ///         \\ \lfloor q \rfloor \\ \text{is odd}.
83            /// \end{cases}
84            /// $$
85            ///
86            /// $g(x, k, \mathrm{Exact}) = q$, but panics if $q \notin \N$.
87            ///
88            /// Then
89            ///
90            /// $f(x, k, r) = (g(x, k, r), \operatorname{cmp}(g(x, k, r), q))$.
91            ///
92            /// # Worst-case complexity
93            /// $T(n, m) = O(n + m)$
94            ///
95            /// $M(n, m) = O(n + m)$
96            ///
97            /// where $T$ is time, $M$ is additional memory, $n$ is `self.significant_bits()`, and
98            /// $m$ is `max(bits, 0)`.
99            ///
100            /// # Panics
101            /// Let $k$ be `bits`. Panics if $k$ is negative and `rm` is `Exact` but `self` is not
102            /// divisible by $2^{-k}$.
103            ///
104            /// # Examples
105            /// See [here](super::shl_round#shl_round).
106            #[inline]
107            fn shl_round(mut self, bits: $t, rm: RoundingMode) -> (Integer, Ordering) {
108                let o = self.shl_round_assign(bits, rm);
109                (self, o)
110            }
111        }
112
113        impl<'a> ShlRound<$t> for &Integer {
114            type Output = Integer;
115
116            /// Left-shifts an [`Integer`] (multiplies or divides it by a power of 2), taking it by
117            /// reference, and rounds according to the specified rounding mode. An [`Ordering`] is
118            /// also returned, indicating whether the returned value is less than, equal to, or
119            /// greater than the exact value. If `bits` is non-negative, then the returned
120            /// [`Ordering`] is always `Equal`, even if the higher bits of the result are lost.
121            ///
122            /// Passing `Floor` is equivalent to using `>>`. To test whether `Exact` can be passed,
123            /// use `bits > 0 || self.divisible_by_power_of_2(bits)`. Rounding might only be
124            /// necessary if `bits` is negative.
125            ///
126            /// Let $q = x2^k$, and let $g$ be the function that just returns the first element of
127            /// the pair, without the [`Ordering`]:
128            ///
129            /// $g(x, k, \mathrm{Down}) = g(x, y, \mathrm{Floor}) = \lfloor q \rfloor.$
130            ///
131            /// $g(x, k, \mathrm{Up}) = g(x, y, \mathrm{Ceiling}) = \lceil q \rceil.$
132            ///
133            /// $$
134            /// g(x, k, \mathrm{Nearest}) = \begin{cases}
135            ///     \lfloor q \rfloor & \text{if}
136            ///         \\quad q - \lfloor q \rfloor < \frac{1}{2}, \\\\
137            ///     \lceil q \rceil & \text{if}
138            ///         \\quad q - \lfloor q \rfloor > \frac{1}{2}, \\\\
139            ///     \lfloor q \rfloor & \text{if} \\quad q - \lfloor q \rfloor =
140            ///         \frac{1}{2} \\ \text{and} \\ \lfloor q \rfloor
141            ///     \\ \text{is even}, \\\\
142            ///     \lceil q \rceil &
143            ///     \text{if} \\quad q - \lfloor q \rfloor = \frac{1}{2} \\ \text{and}
144            ///         \\ \lfloor q \rfloor \\ \text{is odd}.
145            /// \end{cases}
146            /// $$
147            ///
148            /// $g(x, k, \mathrm{Exact}) = q$, but panics if $q \notin \N$.
149            ///
150            /// Then
151            ///
152            /// $f(x, k, r) = (g(x, k, r), \operatorname{cmp}(g(x, k, r), q))$.
153            ///
154            /// # Worst-case complexity
155            /// $T(n, m) = O(n + m)$
156            ///
157            /// $M(n, m) = O(n + m)$
158            ///
159            /// where $T$ is time, $M$ is additional memory, $n$ is `self.significant_bits()`, and
160            /// $m$ is `max(bits, 0)`.
161            ///
162            /// # Panics
163            /// Let $k$ be `bits`. Panics if $k$ is negative and `rm` is `Exact` but `self` is not
164            /// divisible by $2^{-k}$.
165            ///
166            /// # Examples
167            /// See [here](super::shl_round#shl_round).
168            #[inline]
169            fn shl_round(self, bits: $t, rm: RoundingMode) -> (Integer, Ordering) {
170                shl_round_signed_ref(self, bits, rm)
171            }
172        }
173
174        impl ShlRoundAssign<$t> for Integer {
175            /// Left-shifts an [`Integer`] (multiplies or divides it by a power of 2) and rounds
176            /// according to the specified rounding mode, in place. An [`Ordering`] is returned,
177            /// indicating whether the assigned value is less than, equal to, or greater than the
178            /// exact value.
179            ///
180            /// Passing `Floor` is equivalent to using `>>`. To test whether `Exact` can be passed,
181            /// use `bits > 0 || self.divisible_by_power_of_2(bits)`. Rounding might only be
182            /// necessary if `bits` is negative.
183            ///
184            /// See the [`ShlRound`] documentation for details.
185            ///
186            /// # Worst-case complexity
187            /// $T(n, m) = O(n + m)$
188            ///
189            /// $M(n, m) = O(n + m)$
190            ///
191            /// where $T$ is time, $M$ is additional memory, $n$ is `self.significant_bits()`, and
192            /// $m$ is `max(bits, 0)`.
193            ///
194            /// # Examples
195            /// See [here](super::shl_round#shl_round_assign).
196            #[inline]
197            fn shl_round_assign(&mut self, bits: $t, rm: RoundingMode) -> Ordering {
198                shl_round_assign_i(self, bits, rm)
199            }
200        }
201    };
202}
203apply_to_signeds!(impl_shl_round_signed);