use crate::{Arbi, BitCount, Digit};
impl Arbi {
pub fn trailing_ones(&self) -> Option<BitCount> {
if !self.is_negative() {
let first_nonmax =
self.vec.iter().position(|&digit| digit != Digit::MAX);
if let Some(idx) = first_nonmax {
Some(
self.vec[idx].trailing_ones() as BitCount
+ idx as BitCount * Digit::BITS as BitCount,
)
} else {
Some(self.size() as BitCount * Digit::BITS as BitCount)
}
} else {
if self.vec[0].trailing_zeros() != 0 {
return Some(0);
} else if self.vec[0] == 1 && self.size() == 1 {
return None; }
let mut digit = self.vec[0].wrapping_sub(1);
let mut idx = 0;
if digit == 0 {
idx = 1;
while idx < self.size() {
digit = self.vec[idx];
if digit != 0 {
break;
}
idx += 1;
}
}
Some(
digit.trailing_zeros() as BitCount
+ idx as BitCount * Digit::BITS as BitCount,
)
}
}
}
#[cfg(test)]
mod tests {
use crate::util::test::{get_seedable_rng, get_uniform_die, Distribution};
use crate::{Arbi, Assign};
use crate::{BitCount, DDigit, Digit, QDigit, SDDigit, SDigit, SQDigit};
macro_rules! test_uniform_die {
($die:expr, $rng:expr, unsigned) => {{
let val = $die.sample($rng);
let arbi = Arbi::from(val);
assert_eq!(
arbi.trailing_ones(),
Some(BitCount::from(val.trailing_ones()))
);
}};
($die:expr, $rng:expr) => {{
let val = $die.sample($rng);
let arbi = Arbi::from(val);
assert_eq!(
arbi.trailing_ones(),
if val == -1 {
None
} else {
Some(BitCount::from(val.trailing_ones()))
}
);
}};
}
#[test]
fn test_smoke() {
let (mut rng, _) = get_seedable_rng();
let die_d = get_uniform_die(Digit::MIN, Digit::MAX);
let die_dd = get_uniform_die(Digit::MAX as DDigit + 1, DDigit::MAX);
let die_qd = get_uniform_die(DDigit::MAX as QDigit + 1, QDigit::MAX);
let die_sd = get_uniform_die(SDigit::MIN, SDigit::MAX);
let die_sdd = get_uniform_die(SDDigit::MIN, SDDigit::MAX);
let die_sqd = get_uniform_die(SQDigit::MIN, SQDigit::MAX);
for _ in 0..i16::MAX {
test_uniform_die!(die_d, &mut rng, unsigned);
test_uniform_die!(die_dd, &mut rng, unsigned);
test_uniform_die!(die_qd, &mut rng, unsigned);
test_uniform_die!(die_sd, &mut rng);
test_uniform_die!(die_sdd, &mut rng);
test_uniform_die!(die_sqd, &mut rng);
}
}
#[test]
fn test_ones_sequence_positive() {
for j in 1..u128::BITS {
let ones = (1u128 << j) - 1;
let arbi = Arbi::from(ones);
assert_eq!(arbi.trailing_ones(), Some(BitCount::from(j)));
let zeros = !ones;
let arbi = Arbi::from(zeros);
assert_eq!(arbi.trailing_ones(), Some(0));
}
let arbi = Arbi::from(u128::MAX);
assert_eq!(arbi.trailing_ones(), Some(BitCount::from(u128::BITS)));
}
#[test]
fn test_ones_sequence_negative() {
assert_eq!((-2i128).trailing_ones(), 0);
assert_eq!(Arbi::from(-2i128).trailing_ones(), Some(0));
for j in 1..=126 {
let val = (-1i128 << j) ^ i128::MAX;
let arbi = Arbi::from(val);
assert_eq!(arbi.trailing_ones(), Some(j));
assert_eq!(
arbi.trailing_ones(),
Some(BitCount::from(val.trailing_ones()))
);
}
assert_eq!((-1i128).trailing_ones(), 128);
assert_eq!(Arbi::from(-1i128).trailing_ones(), None);
}
#[test]
fn test_special_nonnegative() {
let zero = Arbi::zero();
assert_eq!(
zero.trailing_ones(),
Some(BitCount::from(0_u32.trailing_ones()))
);
let mut a = Arbi::from(Digit::MAX - 1);
assert_eq!(
a.trailing_ones(),
Some(BitCount::from((Digit::MAX - 1).trailing_ones()))
);
a.assign(Digit::MAX);
assert_eq!(
a.trailing_ones(),
Some(BitCount::from(Digit::MAX.trailing_ones()))
);
a += 1;
assert_eq!(
a.trailing_ones(),
Some(BitCount::from((Digit::MAX as DDigit + 1).trailing_ones()))
);
a.assign(DDigit::MAX - 1);
assert_eq!(
a.trailing_ones(),
Some(BitCount::from((DDigit::MAX - 1).trailing_ones()))
);
a.assign(DDigit::MAX);
assert_eq!(
a.trailing_ones(),
Some(BitCount::from(DDigit::MAX.trailing_ones()))
);
a.assign(DDigit::MAX as QDigit + 1);
assert_eq!(
a.trailing_ones(),
Some(BitCount::from((DDigit::MAX as QDigit + 1).trailing_ones()))
);
}
}