Skip to content

Commit

Permalink
added BigUint::count_ones(), trailing_ones()
Browse files Browse the repository at this point in the history
closes issue rust-num#174
  • Loading branch information
BartMassey committed Nov 10, 2020
1 parent 38d6973 commit 7a1814f
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 0 deletions.
18 changes: 18 additions & 0 deletions src/biguint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
31 changes: 31 additions & 0 deletions tests/biguint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

0 comments on commit 7a1814f

Please sign in to comment.