Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add nth root support for u256 and u128 types #862

Open
xgreenx opened this issue Oct 24, 2024 · 0 comments
Open

Add nth root support for u256 and u128 types #862

xgreenx opened this issue Oct 24, 2024 · 0 comments

Comments

@xgreenx
Copy link
Collaborator

xgreenx commented Oct 24, 2024

pub fn checked_nth_root(target: u64, nth_root: u64) -> Option<u64> {
if nth_root == 0 {
// Zeroth root is not defined
return None
}
if nth_root == 1 || target <= 1 {
// Corner cases
return Some(target)
}
if nth_root >= target || nth_root > 64 {
// For any root >= target, result always 1
// For any n>1, n**64 can never fit into u64
return Some(1)
}
let nth_root = u32::try_from(nth_root).expect("Never loses bits, checked above");
// Use floating point operation to get an approximation for the starting point.
// This is at most off by one in either direction.
#[cfg(feature = "std")]
let powf = f64::powf;
#[cfg(not(feature = "std"))]
let powf = libm::pow;
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
let guess = powf(target as f64, (nth_root as f64).recip()) as u64;
debug_assert!(guess != 0, "This should never occur for {{target, n}} > 1");
// Check if a value raised to nth_power is below the target value, handling overflow
// correctly
let is_nth_power_below_target = |v: u64| match v.checked_pow(nth_root) {
Some(pow) => target < pow,
None => true, // v**nth_root >= 2**64 and target < 2**64
};
// Compute guess**n to check if the guess is too large.
// Note that if guess == 1, then g1 == 1 as well, meaning that we will not return
// here.
if is_nth_power_below_target(guess) {
return Some(guess.saturating_sub(1))
}
// Check if the initial guess was correct
let guess_plus_one = guess.checked_add(1).expect(
"Guess cannot be u64::MAX, as we have taken a root > 2 of a value to get it",
);
if is_nth_power_below_target(guess_plus_one) {
return Some(guess)
}
// If not, then the value above must be the correct one.
Some(guess_plus_one)
}

We already implement this for u64, but are missing it for the other types

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant