cfx_math/nth_root/
inv.rs

1use cfx_types::U256;
2use std::ops::{Shl, Shr};
3use typenum::Unsigned;
4
5use super::{nth_root, NthRoot, RootDegree, RootInvParams};
6
7pub fn nth_inv_root<N: RootDegree, P: Unsigned>(input: U256) -> U256
8where (N, P): RootInvParams {
9    if input.is_zero() {
10        return U256::MAX;
11    }
12    let min_bits = N::USIZE * P::USIZE + 1;
13
14    let bits = input.bits();
15    let ideal_bits = min_bits + (bits - 1) % N::USIZE;
16
17    let adjusted_input =
18        rotate_right(input, bits as isize - ideal_bits as isize);
19    let back_rotate = (bits as isize - ideal_bits as isize) / N::ISIZE;
20
21    let root = nth_root::<N, _>(adjusted_input);
22    let root_bits = root.bits();
23
24    if root_bits + P::USIZE <= 64 {
25        rotate_right(U256::from(u64::MAX / root.low_u64()), back_rotate - 192)
26    } else if root_bits + P::USIZE <= 128 {
27        rotate_right(U256::from(u128::MAX / root.low_u128()), back_rotate - 128)
28    } else {
29        rotate_right(U256::MAX / root, back_rotate)
30    }
31}
32
33#[inline]
34fn rotate_right<I: Shr<usize, Output = I> + Shl<usize, Output = I>>(
35    input: I, bits: isize,
36) -> I {
37    if bits >= 0 {
38        input >> bits as usize
39    } else {
40        input << (-bits) as usize
41    }
42}