From 6e3c04a810ca0041bcc99bb297c9c2fa1b0da097 Mon Sep 17 00:00:00 2001 From: Andrew Kubera Date: Fri, 28 Jul 2023 14:23:56 -0400 Subject: [PATCH] Reimplement ten_to_the --- src/lib.rs | 47 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a1c23dc..9bd1170 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -102,27 +102,52 @@ mod parsing; pub mod rounding; pub use rounding::RoundingMode; -#[inline(always)] +/// Return 10^pow +/// +/// Try to calculate this with fewest number of allocations +/// fn ten_to_the(pow: u64) -> BigInt { if pow < 20 { - BigInt::from(10u64.pow(pow as u32)) - } else { - let (half, rem) = pow.div_rem(&16); + return BigInt::from(10u64.pow(pow as u32)); + } + + // linear case of 10^pow = 10^(19 * count + rem) + if pow < 590 { + let ten_to_nineteen = 10u64.pow(19); - let mut x = ten_to_the(half); + // count factors of 19 + let (count, rem) = pow.div_rem(&19); - for _ in 0..4 { - x = &x * &x; + let mut res = BigInt::from(ten_to_nineteen); + + for _ in 1..count { + res *= ten_to_nineteen; } - if rem == 0 { - x - } else { - x * ten_to_the(rem) + if rem != 0 { + res *= 10u64.pow(rem as u32); } + + return res; + } + + // use recursive algorithm where linear case might be too slow + let (quoteint, rem) = pow.div_rem(&16); + let x = ten_to_the(quoteint); + + let x2 = &x * &x; + let x4 = &x2 * &x2; + let x8 = &x4 * &x4; + let res = &x8 * &x8; + + if rem == 0 { + res + } else { + res * 10u64.pow(rem as u32) } } + #[inline(always)] fn count_decimal_digits(int: &BigInt) -> u64 { if int.is_zero() {