1use crate::Uint;
2use core::ops::{
3 BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not, Shl, ShlAssign, Shr,
4 ShrAssign,
5};
6
7impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
8 #[must_use]
12 #[inline]
13 pub const fn bit(&self, index: usize) -> bool {
14 if index >= BITS {
15 return false;
16 }
17 let (limbs, bits) = (index / 64, index % 64);
18 self.limbs[limbs] & (1 << bits) != 0
19 }
20
21 #[inline]
23 pub fn set_bit(&mut self, index: usize, value: bool) {
24 if index >= BITS {
25 return;
26 }
27 let (limbs, bits) = (index / 64, index % 64);
28 if value {
29 self.limbs[limbs] |= 1 << bits;
30 } else {
31 self.limbs[limbs] &= !(1 << bits);
32 }
33 }
34
35 #[inline]
68 #[must_use]
69 #[track_caller]
70 pub const fn byte(&self, index: usize) -> u8 {
71 #[cfg(target_endian = "little")]
72 {
73 self.as_le_slice()[index]
74 }
75
76 #[cfg(target_endian = "big")]
77 #[allow(clippy::cast_possible_truncation)] {
79 (self.limbs[index / 8] >> ((index % 8) * 8)) as u8
80 }
81 }
82
83 #[inline]
87 #[must_use]
88 pub fn reverse_bits(mut self) -> Self {
89 self.limbs.reverse();
90 for limb in &mut self.limbs {
91 *limb = limb.reverse_bits();
92 }
93 if BITS % 64 != 0 {
94 self >>= 64 - BITS % 64;
95 }
96 self
97 }
98
99 #[inline]
102 #[must_use]
103 pub fn leading_zeros(&self) -> usize {
104 self.as_limbs()
105 .iter()
106 .rev()
107 .position(|&limb| limb != 0)
108 .map_or(BITS, |n| {
109 let fixed = Self::MASK.leading_zeros() as usize;
110 let skipped = n * 64;
111 let top = self.as_limbs()[LIMBS - n - 1].leading_zeros() as usize;
112 skipped + top - fixed
113 })
114 }
115
116 #[inline]
119 #[must_use]
120 pub fn leading_ones(&self) -> usize {
121 (self.not()).leading_zeros()
122 }
123
124 #[inline]
127 #[must_use]
128 pub fn trailing_zeros(&self) -> usize {
129 self.as_limbs()
130 .iter()
131 .position(|&limb| limb != 0)
132 .map_or(BITS, |n| {
133 n * 64 + self.as_limbs()[n].trailing_zeros() as usize
134 })
135 }
136
137 #[inline]
140 #[must_use]
141 pub fn trailing_ones(&self) -> usize {
142 self.as_limbs()
143 .iter()
144 .position(|&limb| limb != u64::MAX)
145 .map_or(BITS, |n| {
146 n * 64 + self.as_limbs()[n].trailing_ones() as usize
147 })
148 }
149
150 #[inline]
152 #[must_use]
153 pub fn count_ones(&self) -> usize {
154 self.as_limbs()
155 .iter()
156 .map(|limb| limb.count_ones() as usize)
157 .sum()
158 }
159
160 #[must_use]
162 #[inline]
163 pub fn count_zeros(&self) -> usize {
164 BITS - self.count_ones()
165 }
166
167 #[must_use]
169 #[inline]
170 pub fn bit_len(&self) -> usize {
171 BITS - self.leading_zeros()
172 }
173
174 #[must_use]
176 #[inline]
177 pub fn byte_len(&self) -> usize {
178 (self.bit_len() + 7) / 8
179 }
180
181 #[inline]
193 #[must_use]
194 pub fn most_significant_bits(&self) -> (u64, usize) {
195 let first_set_limb = self
196 .as_limbs()
197 .iter()
198 .rposition(|&limb| limb != 0)
199 .unwrap_or(0);
200 if first_set_limb == 0 {
201 (self.as_limbs().first().copied().unwrap_or(0), 0)
202 } else {
203 let hi = self.as_limbs()[first_set_limb];
204 let lo = self.as_limbs()[first_set_limb - 1];
205 let leading_zeros = hi.leading_zeros();
206 let bits = if leading_zeros > 0 {
207 (hi << leading_zeros) | (lo >> (64 - leading_zeros))
208 } else {
209 hi
210 };
211 let exponent = first_set_limb * 64 - leading_zeros as usize;
212 (bits, exponent)
213 }
214 }
215
216 #[inline(always)]
225 #[must_use]
226 pub fn checked_shl(self, rhs: usize) -> Option<Self> {
227 match self.overflowing_shl(rhs) {
228 (value, false) => Some(value),
229 _ => None,
230 }
231 }
232
233 #[inline(always)]
239 #[must_use]
240 pub fn saturating_shl(self, rhs: usize) -> Self {
241 match self.overflowing_shl(rhs) {
242 (value, false) => value,
243 _ => Self::MAX,
244 }
245 }
246
247 #[inline]
256 #[must_use]
257 pub fn overflowing_shl(mut self, rhs: usize) -> (Self, bool) {
258 let (limbs, bits) = (rhs / 64, rhs % 64);
259 if limbs >= LIMBS {
260 return (Self::ZERO, self != Self::ZERO);
261 }
262 if bits == 0 {
263 let mut overflow = false;
265 for i in (LIMBS - limbs)..LIMBS {
266 overflow |= self.limbs[i] != 0;
267 }
268 if self.limbs[LIMBS - limbs - 1] > Self::MASK {
269 overflow = true;
270 }
271
272 for i in (limbs..LIMBS).rev() {
274 assume!(i >= limbs && i - limbs < LIMBS);
275 self.limbs[i] = self.limbs[i - limbs];
276 }
277 self.limbs[..limbs].fill(0);
278 self.limbs[LIMBS - 1] &= Self::MASK;
279 return (self, overflow);
280 }
281
282 let mut overflow = false;
284 for i in (LIMBS - limbs)..LIMBS {
285 overflow |= self.limbs[i] != 0;
286 }
287 if self.limbs[LIMBS - limbs - 1] >> (64 - bits) != 0 {
288 overflow = true;
289 }
290 if self.limbs[LIMBS - limbs - 1] << bits > Self::MASK {
291 overflow = true;
292 }
293
294 for i in (limbs + 1..LIMBS).rev() {
296 assume!(i - limbs < LIMBS && i - limbs - 1 < LIMBS);
297 self.limbs[i] = self.limbs[i - limbs] << bits;
298 self.limbs[i] |= self.limbs[i - limbs - 1] >> (64 - bits);
299 }
300 self.limbs[limbs] = self.limbs[0] << bits;
301 self.limbs[..limbs].fill(0);
302 self.limbs[LIMBS - 1] &= Self::MASK;
303 (self, overflow)
304 }
305
306 #[inline(always)]
313 #[must_use]
314 pub fn wrapping_shl(self, rhs: usize) -> Self {
315 self.overflowing_shl(rhs).0
316 }
317
318 #[inline(always)]
330 #[must_use]
331 pub fn checked_shr(self, rhs: usize) -> Option<Self> {
332 match self.overflowing_shr(rhs) {
333 (value, false) => Some(value),
334 _ => None,
335 }
336 }
337
338 #[inline]
351 #[must_use]
352 pub fn overflowing_shr(mut self, rhs: usize) -> (Self, bool) {
353 let (limbs, bits) = (rhs / 64, rhs % 64);
354 if limbs >= LIMBS {
355 return (Self::ZERO, self != Self::ZERO);
356 }
357 if bits == 0 {
358 let mut overflow = false;
360 for i in 0..limbs {
361 overflow |= self.limbs[i] != 0;
362 }
363
364 for i in 0..(LIMBS - limbs) {
366 self.limbs[i] = self.limbs[i + limbs];
367 }
368 self.limbs[LIMBS - limbs..].fill(0);
369 return (self, overflow);
370 }
371
372 let overflow = self.limbs[LIMBS - limbs - 1] >> (bits - 1) & 1 != 0;
374
375 for i in 0..(LIMBS - limbs - 1) {
377 assume!(i + limbs < LIMBS && i + limbs + 1 < LIMBS);
378 self.limbs[i] = self.limbs[i + limbs] >> bits;
379 self.limbs[i] |= self.limbs[i + limbs + 1] << (64 - bits);
380 }
381 self.limbs[LIMBS - limbs - 1] = self.limbs[LIMBS - 1] >> bits;
382 self.limbs[LIMBS - limbs..].fill(0);
383 (self, overflow)
384 }
385
386 #[inline(always)]
396 #[must_use]
397 pub fn wrapping_shr(self, rhs: usize) -> Self {
398 self.overflowing_shr(rhs).0
399 }
400
401 #[inline]
403 #[must_use]
404 pub fn arithmetic_shr(self, rhs: usize) -> Self {
405 if BITS == 0 {
406 return Self::ZERO;
407 }
408 let sign = self.bit(BITS - 1);
409 let mut r = self >> rhs;
410 if sign {
411 r |= Self::MAX << BITS.saturating_sub(rhs);
412 }
413 r
414 }
415
416 #[inline]
419 #[must_use]
420 #[allow(clippy::missing_const_for_fn)] pub fn rotate_left(self, rhs: usize) -> Self {
422 if BITS == 0 {
423 return Self::ZERO;
424 }
425 let rhs = rhs % BITS;
426 self << rhs | self >> (BITS - rhs)
427 }
428
429 #[inline(always)]
432 #[must_use]
433 pub fn rotate_right(self, rhs: usize) -> Self {
434 if BITS == 0 {
435 return Self::ZERO;
436 }
437 let rhs = rhs % BITS;
438 self.rotate_left(BITS - rhs)
439 }
440}
441
442impl<const BITS: usize, const LIMBS: usize> Not for Uint<BITS, LIMBS> {
443 type Output = Self;
444
445 #[inline]
446 fn not(mut self) -> Self::Output {
447 if BITS == 0 {
448 return Self::ZERO;
449 }
450 for limb in &mut self.limbs {
451 *limb = u64::not(*limb);
452 }
453 self.limbs[LIMBS - 1] &= Self::MASK;
454 self
455 }
456}
457
458impl<const BITS: usize, const LIMBS: usize> Not for &Uint<BITS, LIMBS> {
459 type Output = Uint<BITS, LIMBS>;
460
461 #[inline]
462 fn not(self) -> Self::Output {
463 (*self).not()
464 }
465}
466
467macro_rules! impl_bit_op {
468 ($trait:ident, $fn:ident, $trait_assign:ident, $fn_assign:ident) => {
469 impl<const BITS: usize, const LIMBS: usize> $trait_assign<Uint<BITS, LIMBS>>
470 for Uint<BITS, LIMBS>
471 {
472 #[inline(always)]
473 fn $fn_assign(&mut self, rhs: Uint<BITS, LIMBS>) {
474 self.$fn_assign(&rhs);
475 }
476 }
477
478 impl<const BITS: usize, const LIMBS: usize> $trait_assign<&Uint<BITS, LIMBS>>
479 for Uint<BITS, LIMBS>
480 {
481 #[inline]
482 fn $fn_assign(&mut self, rhs: &Uint<BITS, LIMBS>) {
483 for i in 0..LIMBS {
484 u64::$fn_assign(&mut self.limbs[i], rhs.limbs[i]);
485 }
486 }
487 }
488
489 impl<const BITS: usize, const LIMBS: usize> $trait<Uint<BITS, LIMBS>>
490 for Uint<BITS, LIMBS>
491 {
492 type Output = Uint<BITS, LIMBS>;
493
494 #[inline(always)]
495 fn $fn(mut self, rhs: Uint<BITS, LIMBS>) -> Self::Output {
496 self.$fn_assign(rhs);
497 self
498 }
499 }
500
501 impl<const BITS: usize, const LIMBS: usize> $trait<&Uint<BITS, LIMBS>>
502 for Uint<BITS, LIMBS>
503 {
504 type Output = Uint<BITS, LIMBS>;
505
506 #[inline(always)]
507 fn $fn(mut self, rhs: &Uint<BITS, LIMBS>) -> Self::Output {
508 self.$fn_assign(rhs);
509 self
510 }
511 }
512
513 impl<const BITS: usize, const LIMBS: usize> $trait<Uint<BITS, LIMBS>>
514 for &Uint<BITS, LIMBS>
515 {
516 type Output = Uint<BITS, LIMBS>;
517
518 #[inline(always)]
519 fn $fn(self, mut rhs: Uint<BITS, LIMBS>) -> Self::Output {
520 rhs.$fn_assign(self);
521 rhs
522 }
523 }
524
525 impl<const BITS: usize, const LIMBS: usize> $trait<&Uint<BITS, LIMBS>>
526 for &Uint<BITS, LIMBS>
527 {
528 type Output = Uint<BITS, LIMBS>;
529
530 #[inline(always)]
531 fn $fn(self, rhs: &Uint<BITS, LIMBS>) -> Self::Output {
532 self.clone().$fn(rhs)
533 }
534 }
535 };
536}
537
538impl_bit_op!(BitOr, bitor, BitOrAssign, bitor_assign);
539impl_bit_op!(BitAnd, bitand, BitAndAssign, bitand_assign);
540impl_bit_op!(BitXor, bitxor, BitXorAssign, bitxor_assign);
541
542impl<const BITS: usize, const LIMBS: usize> Shl<Self> for Uint<BITS, LIMBS> {
543 type Output = Self;
544
545 #[inline(always)]
546 fn shl(self, rhs: Self) -> Self::Output {
547 if BITS == 0 {
549 return self;
550 }
551 #[allow(clippy::cast_possible_truncation)]
555 self.wrapping_shl(rhs.as_limbs()[0] as usize)
556 }
557}
558
559impl<const BITS: usize, const LIMBS: usize> Shl<&Self> for Uint<BITS, LIMBS> {
560 type Output = Self;
561
562 #[inline(always)]
563 fn shl(self, rhs: &Self) -> Self::Output {
564 self << *rhs
565 }
566}
567
568impl<const BITS: usize, const LIMBS: usize> Shr<Self> for Uint<BITS, LIMBS> {
569 type Output = Self;
570
571 #[inline(always)]
572 fn shr(self, rhs: Self) -> Self::Output {
573 if BITS == 0 {
575 return self;
576 }
577 #[allow(clippy::cast_possible_truncation)]
581 self.wrapping_shr(rhs.as_limbs()[0] as usize)
582 }
583}
584
585impl<const BITS: usize, const LIMBS: usize> Shr<&Self> for Uint<BITS, LIMBS> {
586 type Output = Self;
587
588 #[inline(always)]
589 fn shr(self, rhs: &Self) -> Self::Output {
590 self >> *rhs
591 }
592}
593
594impl<const BITS: usize, const LIMBS: usize> ShlAssign<Self> for Uint<BITS, LIMBS> {
595 #[inline(always)]
596 fn shl_assign(&mut self, rhs: Self) {
597 *self = *self << rhs;
598 }
599}
600
601impl<const BITS: usize, const LIMBS: usize> ShlAssign<&Self> for Uint<BITS, LIMBS> {
602 #[inline(always)]
603 fn shl_assign(&mut self, rhs: &Self) {
604 *self = *self << rhs;
605 }
606}
607
608impl<const BITS: usize, const LIMBS: usize> ShrAssign<Self> for Uint<BITS, LIMBS> {
609 #[inline(always)]
610 fn shr_assign(&mut self, rhs: Self) {
611 *self = *self >> rhs;
612 }
613}
614
615impl<const BITS: usize, const LIMBS: usize> ShrAssign<&Self> for Uint<BITS, LIMBS> {
616 #[inline(always)]
617 fn shr_assign(&mut self, rhs: &Self) {
618 *self = *self >> rhs;
619 }
620}
621
622macro_rules! impl_shift {
623 (@main $u:ty) => {
624 impl<const BITS: usize, const LIMBS: usize> Shl<$u> for Uint<BITS, LIMBS> {
625 type Output = Self;
626
627 #[inline(always)]
628 #[allow(clippy::cast_possible_truncation)]
629 fn shl(self, rhs: $u) -> Self::Output {
630 self.wrapping_shl(rhs as usize)
631 }
632 }
633
634 impl<const BITS: usize, const LIMBS: usize> Shr<$u> for Uint<BITS, LIMBS> {
635 type Output = Self;
636
637 #[inline(always)]
638 #[allow(clippy::cast_possible_truncation)]
639 fn shr(self, rhs: $u) -> Self::Output {
640 self.wrapping_shr(rhs as usize)
641 }
642 }
643 };
644
645 (@ref $u:ty) => {
646 impl<const BITS: usize, const LIMBS: usize> Shl<&$u> for Uint<BITS, LIMBS> {
647 type Output = Self;
648
649 #[inline(always)]
650 fn shl(self, rhs: &$u) -> Self::Output {
651 <Self>::shl(self, *rhs)
652 }
653 }
654
655 impl<const BITS: usize, const LIMBS: usize> Shr<&$u> for Uint<BITS, LIMBS> {
656 type Output = Self;
657
658 #[inline(always)]
659 fn shr(self, rhs: &$u) -> Self::Output {
660 <Self>::shr(self, *rhs)
661 }
662 }
663 };
664
665 (@assign $u:ty) => {
666 impl<const BITS: usize, const LIMBS: usize> ShlAssign<$u> for Uint<BITS, LIMBS> {
667 #[inline(always)]
668 fn shl_assign(&mut self, rhs: $u) {
669 *self = *self << rhs;
670 }
671 }
672
673 impl<const BITS: usize, const LIMBS: usize> ShrAssign<$u> for Uint<BITS, LIMBS> {
674 #[inline(always)]
675 fn shr_assign(&mut self, rhs: $u) {
676 *self = *self >> rhs;
677 }
678 }
679 };
680
681 ($u:ty) => {
682 impl_shift!(@main $u);
683 impl_shift!(@ref $u);
684 impl_shift!(@assign $u);
685 impl_shift!(@assign &$u);
686 };
687
688 ($u:ty, $($tail:ty),*) => {
689 impl_shift!($u);
690 impl_shift!($($tail),*);
691 };
692}
693
694impl_shift!(usize, u8, u16, u32, isize, i8, i16, i32);
695
696#[cfg(target_pointer_width = "64")]
698impl_shift!(u64, i64);
699
700#[cfg(test)]
701mod tests {
702 use super::*;
703 use crate::{aliases::U128, const_for, nlimbs};
704 use core::cmp::min;
705 use proptest::proptest;
706
707 #[test]
708 fn test_leading_zeros() {
709 assert_eq!(Uint::<0, 0>::ZERO.leading_zeros(), 0);
710 assert_eq!(Uint::<1, 1>::ZERO.leading_zeros(), 1);
711 assert_eq!(Uint::<1, 1>::from(1).leading_zeros(), 0);
712 const_for!(BITS in NON_ZERO {
713 const LIMBS: usize = nlimbs(BITS);
714 type U = Uint::<BITS, LIMBS>;
715 assert_eq!(U::ZERO.leading_zeros(), BITS);
716 assert_eq!(U::MAX.leading_zeros(), 0);
717 assert_eq!(U::from(1).leading_zeros(), BITS - 1);
718 proptest!(|(value: U)| {
719 let zeros = value.leading_zeros();
720 assert!(zeros <= BITS);
721 assert!(zeros < BITS || value == U::ZERO);
722 if zeros < BITS {
723 let (left, overflow) = value.overflowing_shl(zeros);
724 assert!(!overflow);
725 assert!(left.leading_zeros() == 0 || value == U::ZERO);
726 assert!(left.bit(BITS - 1));
727 assert_eq!(value >> (BITS - zeros), Uint::ZERO);
728 }
729 });
730 });
731 proptest!(|(value: u128)| {
732 let uint = U128::from(value);
733 assert_eq!(uint.leading_zeros(), value.leading_zeros() as usize);
734 });
735 }
736
737 #[test]
738 fn test_leading_ones() {
739 assert_eq!(Uint::<0, 0>::ZERO.leading_ones(), 0);
740 assert_eq!(Uint::<1, 1>::ZERO.leading_ones(), 0);
741 assert_eq!(Uint::<1, 1>::from(1).leading_ones(), 1);
742 }
743
744 #[test]
745 fn test_most_significant_bits() {
746 const_for!(BITS in NON_ZERO {
747 const LIMBS: usize = nlimbs(BITS);
748 type U = Uint::<BITS, LIMBS>;
749 proptest!(|(value: u64)| {
750 let value = if U::LIMBS <= 1 { value & U::MASK } else { value };
751 assert_eq!(U::from(value).most_significant_bits(), (value, 0));
752 });
753 });
754 proptest!(|(mut limbs: [u64; 2])| {
755 if limbs[1] == 0 {
756 limbs[1] = 1;
757 }
758 let (bits, exponent) = U128::from_limbs(limbs).most_significant_bits();
759 assert!(bits >= 1_u64 << 63);
760 assert_eq!(exponent, 64 - limbs[1].leading_zeros() as usize);
761 });
762 }
763
764 #[test]
765 fn test_checked_shl() {
766 assert_eq!(
767 Uint::<65, 2>::from_limbs([0x0010_0000_0000_0000, 0]).checked_shl(1),
768 Some(Uint::<65, 2>::from_limbs([0x0020_0000_0000_0000, 0]))
769 );
770 assert_eq!(
771 Uint::<127, 2>::from_limbs([0x0010_0000_0000_0000, 0]).checked_shl(64),
772 Some(Uint::<127, 2>::from_limbs([0, 0x0010_0000_0000_0000]))
773 );
774 }
775
776 #[test]
777 #[allow(clippy::cast_lossless, clippy::cast_possible_truncation)]
778 fn test_small() {
779 const_for!(BITS in [1, 2, 8, 16, 32, 63, 64] {
780 type U = Uint::<BITS, 1>;
781 proptest!(|(a: U, b: U)| {
782 assert_eq!(a | b, U::from_limbs([a.limbs[0] | b.limbs[0]]));
783 assert_eq!(a & b, U::from_limbs([a.limbs[0] & b.limbs[0]]));
784 assert_eq!(a ^ b, U::from_limbs([a.limbs[0] ^ b.limbs[0]]));
785 });
786 proptest!(|(a: U, s in 0..BITS)| {
787 assert_eq!(a << s, U::from_limbs([a.limbs[0] << s & U::MASK]));
788 assert_eq!(a >> s, U::from_limbs([a.limbs[0] >> s]));
789 });
790 });
791 proptest!(|(a: Uint::<32, 1>, s in 0_usize..=34)| {
792 assert_eq!(a.reverse_bits(), Uint::from((a.limbs[0] as u32).reverse_bits() as u64));
793 assert_eq!(a.rotate_left(s), Uint::from((a.limbs[0] as u32).rotate_left(s as u32) as u64));
794 assert_eq!(a.rotate_right(s), Uint::from((a.limbs[0] as u32).rotate_right(s as u32) as u64));
795 if s < 32 {
796 let arr_shifted = (((a.limbs[0] as i32) >> s) as u32) as u64;
797 assert_eq!(a.arithmetic_shr(s), Uint::from_limbs([arr_shifted]));
798 }
799 });
800 proptest!(|(a: Uint::<64, 1>, s in 0_usize..=66)| {
801 assert_eq!(a.reverse_bits(), Uint::from(a.limbs[0].reverse_bits()));
802 assert_eq!(a.rotate_left(s), Uint::from(a.limbs[0].rotate_left(s as u32)));
803 assert_eq!(a.rotate_right(s), Uint::from(a.limbs[0].rotate_right(s as u32)));
804 if s < 64 {
805 let arr_shifted = ((a.limbs[0] as i64) >> s) as u64;
806 assert_eq!(a.arithmetic_shr(s), Uint::from_limbs([arr_shifted]));
807 }
808 });
809 }
810
811 #[test]
812 fn test_shift_reverse() {
813 const_for!(BITS in SIZES {
814 const LIMBS: usize = nlimbs(BITS);
815 type U = Uint::<BITS, LIMBS>;
816 proptest!(|(value: U, shift in 0..=BITS + 2)| {
817 let left = (value << shift).reverse_bits();
818 let right = value.reverse_bits() >> shift;
819 assert_eq!(left, right);
820 });
821 });
822 }
823
824 #[test]
825 fn test_rotate() {
826 const_for!(BITS in SIZES {
827 const LIMBS: usize = nlimbs(BITS);
828 type U = Uint::<BITS, LIMBS>;
829 proptest!(|(value: U, shift in 0..=BITS + 2)| {
830 let rotated = value.rotate_left(shift).rotate_right(shift);
831 assert_eq!(value, rotated);
832 });
833 });
834 }
835
836 #[test]
837 fn test_arithmetic_shr() {
838 const_for!(BITS in SIZES {
839 const LIMBS: usize = nlimbs(BITS);
840 type U = Uint::<BITS, LIMBS>;
841 proptest!(|(value: U, shift in 0..=BITS + 2)| {
842 let shifted = value.arithmetic_shr(shift);
843 dbg!(value, shifted, shift);
844 assert_eq!(shifted.leading_ones(), match value.leading_ones() {
845 0 => 0,
846 n => min(BITS, n + shift)
847 });
848 });
849 });
850 }
851
852 #[test]
853 fn test_overflowing_shr() {
854 assert_eq!(
857 Uint::<64, 1>::from_limbs([40u64]).overflowing_shr(1),
858 (Uint::<64, 1>::from(20), false)
859 );
860
861 assert_eq!(
864 Uint::<64, 1>::from_limbs([41u64]).overflowing_shr(1),
865 (Uint::<64, 1>::from(20), true)
866 );
867
868 assert_eq!(
871 Uint::<65, 2>::from_limbs([0x0010_0000_0000_0000, 0]).overflowing_shr(1),
872 (Uint::<65, 2>::from_limbs([0x0080_0000_0000_000, 0]), false)
873 );
874
875 assert_eq!(
879 Uint::<256, 4>::MAX.overflowing_shr(65),
880 (
881 Uint::<256, 4>::from_str_radix(
882 "7fffffffffffffffffffffffffffffffffffffffffffffff",
883 16
884 )
885 .unwrap(),
886 true
887 )
888 );
889 assert_eq!(
892 Uint::<4096, 64>::from_str_radix("3ffffffffffffffffffffffffffffc00000000", 16,)
893 .unwrap()
894 .overflowing_shr(34),
895 (
896 Uint::<4096, 64>::from_str_radix("fffffffffffffffffffffffffffff", 16).unwrap(),
897 false
898 )
899 );
900 assert_eq!(
903 Uint::<4096, 64>::from_str_radix(
904 "fffffffffffffffffffffffffffff0000000000000000000000000",
905 16,
906 )
907 .unwrap()
908 .overflowing_shr(100),
909 (
910 Uint::<4096, 64>::from_str_radix("fffffffffffffffffffffffffffff", 16).unwrap(),
911 false
912 )
913 );
914 assert_eq!(
917 Uint::<4096, 64>::from_str_radix(
918 "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0bdbfe",
919 16,
920 )
921 .unwrap()
922 .overflowing_shr(1),
923 (
924 Uint::<4096, 64>::from_str_radix(
925 "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff85edff",
926 16
927 )
928 .unwrap(),
929 false
930 )
931 );
932 assert_eq!(
935 Uint::<4096, 64>::from_str_radix(
936 "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
937 16,
938 )
939 .unwrap()
940 .overflowing_shr(1000),
941 (
942 Uint::<4096, 64>::from_str_radix(
943 "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
944 16
945 )
946 .unwrap(),
947 false
948 )
949 );
950 assert_eq!(
953 Uint::<4096, 64>::MAX
954 .overflowing_shr(34),
955 (
956 Uint::<4096, 64>::from_str_radix(
957 "3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
958 16
959 )
960 .unwrap(),
961 true
962 )
963 );
964 }
965}