From 7a1814f3120a0e7ee67d6d2d52d39ea5216e472c Mon Sep 17 00:00:00 2001 From: Bart Massey Date: Mon, 9 Nov 2020 20:50:36 -0800 Subject: [PATCH] added BigUint::count_ones(), trailing_ones() closes issue #174 --- src/biguint.rs | 18 ++++++++++++++++++ tests/biguint.rs | 31 +++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/src/biguint.rs b/src/biguint.rs index c4a63f40..f20719a1 100644 --- a/src/biguint.rs +++ b/src/biguint.rs @@ -2689,6 +2689,24 @@ impl BigUint { let zeros: u64 = self.data[i].trailing_zeros().into(); Some(i as u64 * u64::from(big_digit::BITS) + zeros) } + + /// Returns the number of least-significant bits that are ones. + pub fn trailing_ones(&self) -> u64 { + if let Some(i) = self.data.iter().position(|&digit| !digit != 0) { + // XXX u64::trailing_ones() introduced in Rust 1.46, + // but we need to be compatible further back. + // Thanks to cuviper for this workaround. + let ones: u64 = (!self.data[i]).trailing_zeros().into(); + i as u64 * u64::from(big_digit::BITS) + ones + } else { + self.data.len() as u64 * u64::from(big_digit::BITS) + } + } + + /// Returns the number of one bits. + pub fn count_ones(&self) -> u64 { + self.data.iter().map(|&d| u64::from(d.count_ones())).sum() + } } fn plain_modpow(base: &BigUint, exp_data: &[BigDigit], modulus: &BigUint) -> BigUint { diff --git a/tests/biguint.rs b/tests/biguint.rs index 14c33daa..cc274954 100644 --- a/tests/biguint.rs +++ b/tests/biguint.rs @@ -1775,3 +1775,34 @@ fn test_pow() { check!(u128); check!(usize); } + +#[test] +fn test_trailing_zeros() { + assert!(BigUint::from(0u8).trailing_zeros().is_none()); + assert_eq!(BigUint::from(1u8).trailing_zeros().unwrap(), 0); + assert_eq!(BigUint::from(2u8).trailing_zeros().unwrap(), 1); + let x: BigUint = BigUint::one() << 128; + assert_eq!(x.trailing_zeros().unwrap(), 128); +} + +#[test] +fn test_trailing_ones() { + assert_eq!(BigUint::from(0u8).trailing_ones(), 0); + assert_eq!(BigUint::from(1u8).trailing_ones(), 1); + assert_eq!(BigUint::from(2u8).trailing_ones(), 0); + assert_eq!(BigUint::from(3u8).trailing_ones(), 2); + let x: BigUint = (BigUint::from(3u8) << 128) | BigUint::from(3u8); + assert_eq!(x.trailing_ones(), 2); + let x: BigUint = (BigUint::one() << 128) - BigUint::one(); + assert_eq!(x.trailing_ones(), 128); +} + +#[test] +fn test_count_ones() { + assert_eq!(BigUint::from(0u8).count_ones(), 0); + assert_eq!(BigUint::from(1u8).count_ones(), 1); + assert_eq!(BigUint::from(2u8).count_ones(), 1); + assert_eq!(BigUint::from(3u8).count_ones(), 2); + let x: BigUint = (BigUint::from(3u8) << 128) | BigUint::from(3u8); + assert_eq!(x.count_ones(), 4); +}