use crate::*;
use num_traits::CheckedSub;
use num_traits::AsPrimitive;
pub(crate) mod decimal;
pub(crate) mod addition;
pub(crate) mod multiplication;
pub(crate) mod modulo;
pub(crate) mod sqrt;
pub(crate) mod cbrt;
pub(crate) mod inverse;
pub(crate) mod pow;
pub(crate) use self::decimal::{
count_digits_bigint as count_decimal_digits,
count_digits_biguint as count_decimal_digits_uint,
};
#[cfg(not(feature = "std"))]
mod funcs {
pub fn exp2(x: f64) -> f64 {
libm::exp2(x)
}
pub fn log10(x: f64) -> f64 {
libm::log10(x)
}
}
#[cfg(feature = "std")]
mod funcs {
pub fn exp2(x: f64) -> f64 {
x.exp2()
}
pub fn log10(x: f64) -> f64 {
x.log10()
}
}
pub(crate) use self::funcs::*;
pub(crate) fn ten_to_the(pow: u64) -> BigInt {
ten_to_the_uint(pow).into()
}
pub(crate) fn ten_to_the_u64(pow: u8) -> u64 {
debug_assert!(pow < 20);
10u64.pow(pow as u32)
}
pub(crate) fn ten_to_the_t<T>(pow: u8) -> T
where
T: From<u8> + num_traits::Pow<u8, Output = T>
{
debug_assert!((pow as f64) < stdlib::mem::size_of::<T>() as f64 * 8.0 / LOG2_10);
T::from(10u8).pow(pow)
}
pub(crate) fn ten_to_the_uint(pow: u64) -> BigUint {
if pow < 20 {
return BigUint::from(10u64.pow(pow as u32));
}
if pow < 590 {
let ten_to_nineteen = 10u64.pow(19);
let (count, rem) = pow.div_rem(&19);
let mut res = BigUint::from(ten_to_nineteen);
for _ in 1..count {
res *= ten_to_nineteen;
}
if rem != 0 {
res *= 10u64.pow(rem as u32);
}
return res;
}
let (quotient, rem) = pow.div_rem(&16);
let x = ten_to_the_uint(quotient);
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)
}
}
pub(crate) fn multiply_by_ten_to_the_uint<T, P>(n: &mut T, pow: P)
where
T: MulAssign<u64> + MulAssign<BigUint>,
P: ToPrimitive,
{
let pow = pow.to_u64().expect("exponent overflow error");
if pow < 20 {
*n *= 10u64.pow(pow as u32);
} else {
*n *= ten_to_the_uint(pow);
}
}
pub(crate) fn diff<T>(a: T, b: T) -> (Ordering, u64)
where
T: ToPrimitive + CheckedSub + stdlib::cmp::Ord,
{
use stdlib::cmp::Ordering::*;
let (ord, diff) = checked_diff(a, b);
(ord, diff.expect("subtraction overflow"))
}
pub(crate) fn checked_diff<T>(a: T, b: T) -> (Ordering, Option<u64>)
where
T: ToPrimitive + CheckedSub + stdlib::cmp::Ord,
{
use stdlib::cmp::Ordering::*;
let _try_subtracting = |x: T, y: T| x.checked_sub(&y).and_then(|diff| diff.to_u64());
match a.cmp(&b) {
Less => (Less, _try_subtracting(b, a)),
Greater => (Greater, _try_subtracting(a, b)),
Equal => (Equal, Some(0)),
}
}
#[allow(dead_code)]
pub(crate) fn diff_usize<T>(a: T, b: T) -> (Ordering, usize)
where
T: AsPrimitive<usize> + stdlib::ops::Sub<Output = T> + stdlib::cmp::Ord,
{
use stdlib::cmp::Ordering::*;
match a.cmp(&b) {
Less => (Less, (b - a).as_()),
Greater => (Greater, (a - b).as_()),
Equal => (Equal, 0),
}
}
#[cfg(rustc_1_60)]
#[allow(clippy::incompatible_msrv)]
#[allow(dead_code)]
pub(crate) fn abs_diff(x: i64, y: i64) -> u64 {
x.abs_diff(y)
}
#[cfg(not(rustc_1_60))]
#[allow(dead_code)]
pub(crate) fn abs_diff(x: i64, y: i64) -> u64 {
(x as i128 - y as i128).to_u64().unwrap_or(0)
}
pub(crate) fn add_carry(n: u8, carry: &mut u8) -> u8 {
let s = n + *carry;
if s < 10 {
*carry = 0;
s
} else {
debug_assert!(s < 20);
*carry = 1;
s - 10
}
}
pub(crate) fn store_carry(n: u8, carry: &mut u8) -> u8 {
if n < 10 {
n
} else {
debug_assert!(n < 20);
debug_assert_eq!(carry, &0);
*carry = 1;
n - 10
}
}
pub(crate) fn extend_adding_with_carry<D: Iterator<Item = u8>>(
dest: &mut Vec<u8>,
mut digits: D,
carry: &mut u8,
) {
while *carry != 0 {
match digits.next() {
Some(d) => {
dest.push(add_carry(d, carry))
}
None => {
return;
}
}
}
dest.extend(digits);
}