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);