Skip to content

Commit

Permalink
Speed up biguint::root_n #289
Browse files Browse the repository at this point in the history
  • Loading branch information
printfn committed May 4, 2024
1 parent bfbc865 commit 458aa72
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 5 deletions.
39 changes: 34 additions & 5 deletions core/src/num/biguint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,22 @@ const fn truncate(n: u128) -> u64 {
}

impl BigUint {
fn bits(&self) -> u64 {
match self {
Small(n) => u64::from(n.ilog2()) + 1,
Large(value) => {
for (i, v) in value.iter().enumerate().rev() {
if *v != 0 {
let bits_in_v = u64::from(v.ilog2()) + 1;
let bits_in_rest = u64::try_from(i).unwrap() * u64::from(usize::BITS);
return bits_in_v + bits_in_rest;
}
}
0
}
}
}

fn is_zero(&self) -> bool {
match self {
Small(n) => *n == 0,
Expand Down Expand Up @@ -193,21 +209,34 @@ impl BigUint {
if self == 0.into() || self == 1.into() || n == &Self::from(1) {
return Ok(Exact::new(self, true));
}
if n.value_len() > 1 {
return Err(FendError::OutOfRange {
value: Box::new(n.format(&FormatOptions::default(), int)?.value),
range: Range {
start: RangeBound::Closed(Box::new(1)),
end: RangeBound::Closed(Box::new(u64::MAX)),
},
});
}
let max_bits = self.bits() / n.get(0) + 1;
let mut low_guess = Self::from(1);
let mut high_guess = self.clone();
while high_guess.clone().sub(&low_guess) > 1.into() {
let mut high_guess = Small(1).lshift_n(&(max_bits + 1).into(), int)?;
let result = loop {
test_int(int)?;
let mut guess = low_guess.clone().add(&high_guess);
guess.rshift(int)?;

let res = Self::pow(&guess, n, int)?;
match res.cmp(&self) {
Ordering::Equal => return Ok(Exact::new(guess, true)),
Ordering::Equal => break Exact::new(guess, true),
Ordering::Greater => high_guess = guess,
Ordering::Less => low_guess = guess,
}
}
Ok(Exact::new(low_guess, false))
if high_guess.clone().sub(&low_guess) <= 1.into() {
break Exact::new(low_guess, false);
}
};
Ok(result)
}

fn pow_internal<I: Interrupt>(&self, mut exponent: u64, int: &I) -> FResult<Self> {
Expand Down
5 changes: 5 additions & 0 deletions core/tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1995,6 +1995,11 @@ fn exponents_28() {
test_eval("e^10", "approx. 22026.4657948067");
}

#[test]
fn exponents_29() {
test_eval("e^2.72", "approx. 15.1803222449");
}

#[test]
fn one_kg() {
test_eval("1kg", "1 kg");
Expand Down

0 comments on commit 458aa72

Please sign in to comment.