mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-31 06:22:00 +00:00
Rollup merge of #92747 - swenson:bignum-bit-length-optimization, r=scottmcm
Simplification of BigNum::bit_length As indicated in the comment, the BigNum::bit_length function could be optimized by using CLZ, which is often a single instruction instead a loop. I think the code is also simpler now without the loop. I added some additional tests for Big8x3 and Big32x40 to ensure that there were no regressions.
This commit is contained in:
commit
f511360fd2
@ -158,24 +158,15 @@ macro_rules! define_bignum {
|
||||
/// Returns the number of bits necessary to represent this value. Note that zero
|
||||
/// is considered to need 0 bits.
|
||||
pub fn bit_length(&self) -> usize {
|
||||
// Skip over the most significant digits which are zero.
|
||||
let digits = self.digits();
|
||||
let zeros = digits.iter().rev().take_while(|&&x| x == 0).count();
|
||||
let end = digits.len() - zeros;
|
||||
let nonzero = &digits[..end];
|
||||
|
||||
if nonzero.is_empty() {
|
||||
// There are no non-zero digits, i.e., the number is zero.
|
||||
return 0;
|
||||
}
|
||||
// This could be optimized with leading_zeros() and bit shifts, but that's
|
||||
// probably not worth the hassle.
|
||||
let digitbits = <$ty>::BITS as usize;
|
||||
let mut i = nonzero.len() * digitbits - 1;
|
||||
while self.get_bit(i) == 0 {
|
||||
i -= 1;
|
||||
let digits = self.digits();
|
||||
// Find the most significant non-zero digit.
|
||||
let msd = digits.iter().rposition(|&x| x != 0);
|
||||
match msd {
|
||||
Some(msd) => msd * digitbits + digits[msd].log2() as usize + 1,
|
||||
// There are no non-zero digits, i.e., the number is zero.
|
||||
_ => 0,
|
||||
}
|
||||
i + 1
|
||||
}
|
||||
|
||||
/// Adds `other` to itself and returns its own mutable reference.
|
||||
|
@ -1,4 +1,5 @@
|
||||
use core::num::bignum::tests::Big8x3 as Big;
|
||||
use core::num::bignum::Big32x40;
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
@ -215,6 +216,16 @@ fn test_get_bit_out_of_range() {
|
||||
|
||||
#[test]
|
||||
fn test_bit_length() {
|
||||
for i in 0..8 * 3 {
|
||||
// 010000...000
|
||||
assert_eq!(Big::from_small(1).mul_pow2(i).bit_length(), i + 1);
|
||||
}
|
||||
for i in 1..8 * 3 - 1 {
|
||||
// 010000...001
|
||||
assert_eq!(Big::from_small(1).mul_pow2(i).add(&Big::from_small(1)).bit_length(), i + 1);
|
||||
// 110000...000
|
||||
assert_eq!(Big::from_small(3).mul_pow2(i).bit_length(), i + 2);
|
||||
}
|
||||
assert_eq!(Big::from_small(0).bit_length(), 0);
|
||||
assert_eq!(Big::from_small(1).bit_length(), 1);
|
||||
assert_eq!(Big::from_small(5).bit_length(), 3);
|
||||
@ -223,6 +234,30 @@ fn test_bit_length() {
|
||||
assert_eq!(Big::from_u64(0xffffff).bit_length(), 24);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bit_length_32x40() {
|
||||
for i in 0..32 * 40 {
|
||||
// 010000...000
|
||||
assert_eq!(Big32x40::from_small(1).mul_pow2(i).bit_length(), i + 1);
|
||||
}
|
||||
for i in 1..32 * 40 - 1 {
|
||||
// 010000...001
|
||||
assert_eq!(
|
||||
Big32x40::from_small(1).mul_pow2(i).add(&Big32x40::from_small(1)).bit_length(),
|
||||
i + 1
|
||||
);
|
||||
// 110000...000
|
||||
assert_eq!(Big32x40::from_small(3).mul_pow2(i).bit_length(), i + 2);
|
||||
}
|
||||
assert_eq!(Big32x40::from_small(0).bit_length(), 0);
|
||||
assert_eq!(Big32x40::from_small(1).bit_length(), 1);
|
||||
assert_eq!(Big32x40::from_small(5).bit_length(), 3);
|
||||
assert_eq!(Big32x40::from_small(0x18).bit_length(), 5);
|
||||
assert_eq!(Big32x40::from_u64(0x4073).bit_length(), 15);
|
||||
assert_eq!(Big32x40::from_u64(0xffffff).bit_length(), 24);
|
||||
assert_eq!(Big32x40::from_u64(0xffffffffffffffff).bit_length(), 64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ord() {
|
||||
assert!(Big::from_u64(0) < Big::from_u64(0xffffff));
|
||||
|
Loading…
Reference in New Issue
Block a user