bigdecimal/arithmetic/
mod.rsuse crate::*;
use num_traits::CheckedSub;
pub(crate) mod addition;
pub(crate) mod sqrt;
pub(crate) mod cbrt;
pub(crate) mod inverse;
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_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 count_decimal_digits(int: &BigInt) -> u64 {
count_decimal_digits_uint(int.magnitude())
}
pub(crate) fn count_decimal_digits_uint(uint: &BigUint) -> u64 {
if uint.is_zero() {
return 1;
}
let mut digits = (uint.bits() as f64 / LOG2_10) as u64;
let mut num = ten_to_the_uint(digits);
while *uint >= num {
num *= 10u8;
digits += 1;
}
digits
}
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(a: usize, b: usize) -> (Ordering, usize) {
use stdlib::cmp::Ordering::*;
match a.cmp(&b) {
Less => (Less, b - a),
Greater => (Greater, a - b),
Equal => (Equal, 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);
}