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