use crate::Error;
use alloc::{string::String, vec::Vec};
use arrayvec::{ArrayString, ArrayVec};
use core::{
cmp::{Ordering::Equal, *},
fmt,
hash::{Hash, Hasher},
iter::Sum,
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign},
str::FromStr,
};
#[cfg(feature = "diesel")]
use diesel::sql_types::Numeric;
#[allow(unused_imports)]
#[cfg(not(feature = "std"))]
use num_traits::float::FloatCore;
use num_traits::{
CheckedAdd, CheckedDiv, CheckedMul, CheckedRem, CheckedSub, FromPrimitive, Num, One, Signed, ToPrimitive, Zero,
};
const SIGN_MASK: u32 = 0x8000_0000;
const UNSIGN_MASK: u32 = 0x4FFF_FFFF;
const SCALE_MASK: u32 = 0x00FF_0000;
const U8_MASK: u32 = 0x0000_00FF;
const U32_MASK: u64 = 0xFFFF_FFFF;
const SCALE_SHIFT: u32 = 16;
const SIGN_SHIFT: u32 = 31;
const MAX_STR_BUFFER_SIZE: usize = 32;
pub(crate) const MAX_PRECISION: u32 = 28;
#[cfg(not(feature = "legacy-ops"))]
const MAX_PRECISION_I32: i32 = 28;
const MAX_I128_REPR: i128 = 0x0000_0000_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF;
const MIN: Decimal = Decimal {
flags: 2_147_483_648,
lo: 4_294_967_295,
mid: 4_294_967_295,
hi: 4_294_967_295,
};
const MAX: Decimal = Decimal {
flags: 0,
lo: 4_294_967_295,
mid: 4_294_967_295,
hi: 4_294_967_295,
};
pub(crate) const ONE: Decimal = Decimal {
flags: 0,
lo: 1,
mid: 0,
hi: 0,
};
const POWERS_10: [u32; 10] = [
1,
10,
100,
1_000,
10_000,
100_000,
1_000_000,
10_000_000,
100_000_000,
1_000_000_000,
];
#[allow(dead_code)]
const BIG_POWERS_10: [u64; 10] = [
10_000_000_000,
100_000_000_000,
1_000_000_000_000,
10_000_000_000_000,
100_000_000_000_000,
1_000_000_000_000_000,
10_000_000_000_000_000,
100_000_000_000_000_000,
1_000_000_000_000_000_000,
10_000_000_000_000_000_000,
];
#[derive(Clone, Copy, Debug)]
pub struct UnpackedDecimal {
pub is_negative: bool,
pub scale: u32,
pub hi: u32,
pub mid: u32,
pub lo: u32,
}
#[derive(Clone, Copy)]
#[cfg_attr(feature = "diesel", derive(FromSqlRow, AsExpression), sql_type = "Numeric")]
pub struct Decimal {
flags: u32,
hi: u32,
lo: u32,
mid: u32,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum RoundingStrategy {
MidpointNearestEven,
MidpointAwayFromZero,
MidpointTowardZero,
ToZero,
AwayFromZero,
ToNegativeInfinity,
ToPositiveInfinity,
#[deprecated(since = "1.11.0", note = "Please use RoundingStrategy::MidpointNearestEven instead")]
BankersRounding,
#[deprecated(since = "1.11.0", note = "Please use RoundingStrategy::MidpointAwayFromZero instead")]
RoundHalfUp,
#[deprecated(since = "1.11.0", note = "Please use RoundingStrategy::MidpointTowardZero instead")]
RoundHalfDown,
#[deprecated(since = "1.11.0", note = "Please use RoundingStrategy::ToZero instead")]
RoundDown,
#[deprecated(since = "1.11.0", note = "Please use RoundingStrategy::AwayFromZero instead")]
RoundUp,
}
#[allow(dead_code)]
impl Decimal {
pub fn new(num: i64, scale: u32) -> Decimal {
if scale > MAX_PRECISION {
panic!(
"Scale exceeds the maximum precision allowed: {} > {}",
scale, MAX_PRECISION
);
}
let flags: u32 = scale << SCALE_SHIFT;
if num < 0 {
let pos_num = num.wrapping_neg() as u64;
return Decimal {
flags: flags | SIGN_MASK,
hi: 0,
lo: (pos_num & U32_MASK) as u32,
mid: ((pos_num >> 32) & U32_MASK) as u32,
};
}
Decimal {
flags,
hi: 0,
lo: (num as u64 & U32_MASK) as u32,
mid: ((num as u64 >> 32) & U32_MASK) as u32,
}
}
pub fn from_i128_with_scale(num: i128, scale: u32) -> Decimal {
if scale > MAX_PRECISION {
panic!(
"Scale exceeds the maximum precision allowed: {} > {}",
scale, MAX_PRECISION
);
}
let mut neg = false;
let mut wrapped = num;
if num > MAX_I128_REPR {
panic!("Number exceeds maximum value that can be represented");
} else if num < -MAX_I128_REPR {
panic!("Number less than minimum value that can be represented");
} else if num < 0 {
neg = true;
wrapped = -num;
}
let flags: u32 = flags(neg, scale);
Decimal {
flags,
lo: (wrapped as u64 & U32_MASK) as u32,
mid: ((wrapped as u64 >> 32) & U32_MASK) as u32,
hi: ((wrapped as u128 >> 64) as u64 & U32_MASK) as u32,
}
}
pub const fn from_parts(lo: u32, mid: u32, hi: u32, negative: bool, scale: u32) -> Decimal {
Decimal {
lo,
mid,
hi,
flags: flags(negative, scale % (MAX_PRECISION + 1)),
}
}
pub(crate) const fn from_parts_raw(lo: u32, mid: u32, hi: u32, flags: u32) -> Decimal {
Decimal { lo, mid, hi, flags }
}
pub fn from_scientific(value: &str) -> Result<Decimal, Error> {
let err = Error::new("Failed to parse");
let mut split = value.splitn(2, |c| c == 'e' || c == 'E');
let base = split.next().ok_or_else(|| err.clone())?;
let exp = split.next().ok_or_else(|| err.clone())?;
let mut ret = Decimal::from_str(base)?;
let current_scale = ret.scale();
if exp.starts_with('-') {
let exp: u32 = exp[1..].parse().map_err(move |_| err)?;
ret.set_scale(current_scale + exp)?;
} else {
let exp: u32 = exp.parse().map_err(move |_| err)?;
if exp <= current_scale {
ret.set_scale(current_scale - exp)?;
} else {
ret *= Decimal::from_i64(10_i64.pow(exp)).unwrap();
ret = ret.normalize();
}
}
Ok(ret)
}
#[inline]
pub const fn scale(&self) -> u32 {
((self.flags & SCALE_MASK) >> SCALE_SHIFT) as u32
}
pub const fn mantissa(&self) -> i128 {
let raw = (self.lo as i128) | ((self.mid as i128) << 32) | ((self.hi as i128) << 64);
if self.is_sign_negative() {
-raw
} else {
raw
}
}
#[deprecated(since = "1.4.0", note = "please use `set_sign_positive` instead")]
pub fn set_sign(&mut self, positive: bool) {
self.set_sign_positive(positive);
}
#[inline(always)]
pub fn set_sign_positive(&mut self, positive: bool) {
if positive {
self.flags &= UNSIGN_MASK;
} else {
self.flags |= SIGN_MASK;
}
}
#[inline(always)]
pub fn set_sign_negative(&mut self, negative: bool) {
self.set_sign_positive(!negative);
}
pub fn set_scale(&mut self, scale: u32) -> Result<(), Error> {
if scale > MAX_PRECISION {
return Err(Error::new("Scale exceeds maximum precision"));
}
self.flags = (scale << SCALE_SHIFT) | (self.flags & SIGN_MASK);
Ok(())
}
pub fn rescale(&mut self, scale: u32) {
let mut array = [self.lo, self.mid, self.hi];
let mut value_scale = self.scale();
rescale_internal(&mut array, &mut value_scale, scale);
self.lo = array[0];
self.mid = array[1];
self.hi = array[2];
self.flags = flags(self.is_sign_negative(), value_scale);
}
pub const fn serialize(&self) -> [u8; 16] {
[
(self.flags & U8_MASK) as u8,
((self.flags >> 8) & U8_MASK) as u8,
((self.flags >> 16) & U8_MASK) as u8,
((self.flags >> 24) & U8_MASK) as u8,
(self.lo & U8_MASK) as u8,
((self.lo >> 8) & U8_MASK) as u8,
((self.lo >> 16) & U8_MASK) as u8,
((self.lo >> 24) & U8_MASK) as u8,
(self.mid & U8_MASK) as u8,
((self.mid >> 8) & U8_MASK) as u8,
((self.mid >> 16) & U8_MASK) as u8,
((self.mid >> 24) & U8_MASK) as u8,
(self.hi & U8_MASK) as u8,
((self.hi >> 8) & U8_MASK) as u8,
((self.hi >> 16) & U8_MASK) as u8,
((self.hi >> 24) & U8_MASK) as u8,
]
}
pub const fn deserialize(bytes: [u8; 16]) -> Decimal {
Decimal {
flags: (bytes[0] as u32) | (bytes[1] as u32) << 8 | (bytes[2] as u32) << 16 | (bytes[3] as u32) << 24,
lo: (bytes[4] as u32) | (bytes[5] as u32) << 8 | (bytes[6] as u32) << 16 | (bytes[7] as u32) << 24,
mid: (bytes[8] as u32) | (bytes[9] as u32) << 8 | (bytes[10] as u32) << 16 | (bytes[11] as u32) << 24,
hi: (bytes[12] as u32) | (bytes[13] as u32) << 8 | (bytes[14] as u32) << 16 | (bytes[15] as u32) << 24,
}
}
#[deprecated(since = "0.6.3", note = "please use `is_sign_negative` instead")]
pub fn is_negative(&self) -> bool {
self.is_sign_negative()
}
#[deprecated(since = "0.6.3", note = "please use `is_sign_positive` instead")]
pub fn is_positive(&self) -> bool {
self.is_sign_positive()
}
#[inline(always)]
pub const fn is_sign_negative(&self) -> bool {
self.flags & SIGN_MASK > 0
}
#[inline(always)]
pub const fn is_sign_positive(&self) -> bool {
self.flags & SIGN_MASK == 0
}
pub const fn min_value() -> Decimal {
MIN
}
pub const fn max_value() -> Decimal {
MAX
}
pub fn trunc(&self) -> Decimal {
let mut scale = self.scale();
if scale == 0 {
return *self;
}
let mut working = [self.lo, self.mid, self.hi];
while scale > 0 {
if scale < 10 {
div_by_u32(&mut working, POWERS_10[scale as usize]);
break;
} else {
div_by_u32(&mut working, POWERS_10[9]);
scale -= 9;
}
}
Decimal {
lo: working[0],
mid: working[1],
hi: working[2],
flags: flags(self.is_sign_negative(), 0),
}
}
pub fn fract(&self) -> Decimal {
*self - self.trunc()
}
pub fn abs(&self) -> Decimal {
let mut me = *self;
me.set_sign_positive(true);
me
}
pub fn floor(&self) -> Decimal {
let scale = self.scale();
if scale == 0 {
return *self;
}
let floored = self.trunc();
if self.is_sign_negative() && !self.fract().is_zero() {
floored - ONE
} else {
floored
}
}
pub fn ceil(&self) -> Decimal {
let scale = self.scale();
if scale == 0 {
return *self;
}
if self.is_sign_positive() && !self.fract().is_zero() {
self.trunc() + ONE
} else {
self.trunc()
}
}
pub fn max(self, other: Decimal) -> Decimal {
if self < other {
other
} else {
self
}
}
pub fn min(self, other: Decimal) -> Decimal {
if self > other {
other
} else {
self
}
}
pub fn normalize(&self) -> Decimal {
if self.is_zero() {
return Decimal::zero();
}
let mut scale = self.scale();
if scale == 0 {
return *self;
}
let mut result = [self.lo, self.mid, self.hi];
let mut working = [self.lo, self.mid, self.hi];
while scale > 0 {
if div_by_u32(&mut working, 10) > 0 {
break;
}
scale -= 1;
result.copy_from_slice(&working);
}
Decimal {
lo: result[0],
mid: result[1],
hi: result[2],
flags: flags(self.is_sign_negative(), scale),
}
}
pub fn round(&self) -> Decimal {
self.round_dp(0)
}
pub fn round_dp_with_strategy(&self, dp: u32, strategy: RoundingStrategy) -> Decimal {
if self.is_zero() {
return Decimal {
lo: 0,
mid: 0,
hi: 0,
flags: flags(self.is_sign_negative(), dp),
};
}
let old_scale = self.scale();
if old_scale <= dp {
return *self;
}
let mut value = [self.lo, self.mid, self.hi];
let mut value_scale = self.scale();
let negative = self.is_sign_negative();
value_scale -= dp;
while value_scale > 0 {
if value_scale < 10 {
div_by_u32(&mut value, POWERS_10[value_scale as usize]);
value_scale = 0;
} else {
div_by_u32(&mut value, POWERS_10[9]);
value_scale -= 9;
}
}
let mut offset = [self.lo, self.mid, self.hi];
let mut diff = old_scale - dp;
while diff > 0 {
if diff < 10 {
div_by_u32(&mut offset, POWERS_10[diff as usize]);
break;
} else {
div_by_u32(&mut offset, POWERS_10[9]);
diff -= 9;
}
}
let mut diff = old_scale - dp;
while diff > 0 {
if diff < 10 {
mul_by_u32(&mut offset, POWERS_10[diff as usize]);
break;
} else {
mul_by_u32(&mut offset, POWERS_10[9]);
diff -= 9;
}
}
let mut decimal_portion = [self.lo, self.mid, self.hi];
sub_by_internal(&mut decimal_portion, &offset);
let mut cap = [5, 0, 0];
for _ in 0..(old_scale - dp - 1) {
mul_by_u32(&mut cap, 10);
}
let order = cmp_internal(&decimal_portion, &cap);
#[allow(deprecated)]
match strategy {
RoundingStrategy::BankersRounding | RoundingStrategy::MidpointNearestEven => {
match order {
Ordering::Equal => {
if (value[0] & 1) == 1 {
add_one_internal(&mut value);
}
}
Ordering::Greater => {
add_one_internal(&mut value);
}
_ => {}
}
}
RoundingStrategy::RoundHalfDown | RoundingStrategy::MidpointTowardZero => {
if let Ordering::Greater = order {
add_one_internal(&mut value);
}
}
RoundingStrategy::RoundHalfUp | RoundingStrategy::MidpointAwayFromZero => {
match order {
Ordering::Equal => {
add_one_internal(&mut value);
}
Ordering::Greater => {
add_one_internal(&mut value);
}
_ => {}
}
}
RoundingStrategy::RoundUp | RoundingStrategy::AwayFromZero => {
if !is_all_zero(&decimal_portion) {
add_one_internal(&mut value);
}
}
RoundingStrategy::ToPositiveInfinity => {
if !negative && !is_all_zero(&decimal_portion) {
add_one_internal(&mut value);
}
}
RoundingStrategy::ToNegativeInfinity => {
if negative && !is_all_zero(&decimal_portion) {
add_one_internal(&mut value);
}
}
RoundingStrategy::RoundDown | RoundingStrategy::ToZero => (),
}
Decimal {
lo: value[0],
mid: value[1],
hi: value[2],
flags: flags(negative, dp),
}
}
pub fn round_dp(&self, dp: u32) -> Decimal {
self.round_dp_with_strategy(dp, RoundingStrategy::MidpointNearestEven)
}
pub const fn unpack(&self) -> UnpackedDecimal {
UnpackedDecimal {
is_negative: self.is_sign_negative(),
scale: self.scale(),
hi: self.hi,
lo: self.lo,
mid: self.mid,
}
}
#[inline(always)]
pub(crate) const fn mantissa_array3(&self) -> [u32; 3] {
[self.lo, self.mid, self.hi]
}
#[inline(always)]
pub(crate) const fn mantissa_array4(&self) -> [u32; 4] {
[self.lo, self.mid, self.hi, 0]
}
fn base2_to_decimal(bits: &mut [u32; 3], exponent2: i32, positive: bool, is64: bool) -> Option<Self> {
let mut exponent5 = -exponent2;
let mut exponent10 = exponent2;
while exponent5 > 0 {
if bits[0] & 0x1 == 0 {
exponent10 += 1;
exponent5 -= 1;
let hi_carry = bits[2] & 0x1 == 1;
bits[2] >>= 1;
let mid_carry = bits[1] & 0x1 == 1;
bits[1] = (bits[1] >> 1) | if hi_carry { SIGN_MASK } else { 0 };
bits[0] = (bits[0] >> 1) | if mid_carry { SIGN_MASK } else { 0 };
} else {
exponent5 -= 1;
let mut temp = [bits[0], bits[1], bits[2]];
if mul_by_u32(&mut temp, 5) == 0 {
bits[0] = temp[0];
bits[1] = temp[1];
bits[2] = temp[2];
} else {
exponent10 += 1;
let hi_carry = bits[2] & 0x1 == 1;
bits[2] >>= 1;
let mid_carry = bits[1] & 0x1 == 1;
bits[1] = (bits[1] >> 1) | if hi_carry { SIGN_MASK } else { 0 };
bits[0] = (bits[0] >> 1) | if mid_carry { SIGN_MASK } else { 0 };
}
}
}
while exponent5 < 0 {
if bits[2] & SIGN_MASK == 0 {
exponent10 -= 1;
exponent5 += 1;
shl1_internal(bits, 0);
} else {
exponent5 += 1;
div_by_u32(bits, 5);
}
}
while exponent10 > 0 {
if mul_by_u32(bits, 10) == 0 {
exponent10 -= 1;
} else {
return None;
}
}
while exponent10 < -(MAX_PRECISION as i32) {
let rem10 = div_by_u32(bits, 10);
exponent10 += 1;
if is_all_zero(bits) {
exponent10 = 0;
} else if rem10 >= 5 {
add_one_internal(bits);
}
}
if is64 {
while exponent10 < 0 && (bits[2] != 0 || (bits[1] & 0xFFF0_0000) != 0) {
let rem10 = div_by_u32(bits, 10);
exponent10 += 1;
if rem10 >= 5 {
add_one_internal(bits);
}
}
} else {
while exponent10 < 0
&& (bits[2] != 0 || bits[1] != 0 || (bits[2] == 0 && bits[1] == 0 && (bits[0] & 0xFF00_0000) != 0))
{
let rem10 = div_by_u32(bits, 10);
exponent10 += 1;
if rem10 >= 5 {
add_one_internal(bits);
}
}
}
while exponent10 < 0 {
let mut temp = [bits[0], bits[1], bits[2]];
let remainder = div_by_u32(&mut temp, 10);
if remainder == 0 {
exponent10 += 1;
bits[0] = temp[0];
bits[1] = temp[1];
bits[2] = temp[2];
} else {
break;
}
}
Some(Decimal {
lo: bits[0],
mid: bits[1],
hi: bits[2],
flags: flags(!positive, -exponent10 as u32),
})
}
#[inline(always)]
pub fn checked_add(self, other: Decimal) -> Option<Decimal> {
let mut my = [self.lo, self.mid, self.hi];
let mut my_scale = self.scale();
let mut ot = [other.lo, other.mid, other.hi];
let mut other_scale = other.scale();
rescale_to_maximum_scale(&mut my, &mut my_scale, &mut ot, &mut other_scale);
let mut final_scale = my_scale.max(other_scale);
let my_negative = self.is_sign_negative();
let other_negative = other.is_sign_negative();
let mut negative = false;
let carry;
if !(my_negative ^ other_negative) {
negative = my_negative;
carry = add_by_internal3(&mut my, &ot);
} else {
let cmp = cmp_internal(&my, &ot);
match cmp {
Ordering::Less => {
negative = other_negative;
sub_by_internal3(&mut ot, &my);
my[0] = ot[0];
my[1] = ot[1];
my[2] = ot[2];
}
Ordering::Greater => {
negative = my_negative;
sub_by_internal3(&mut my, &ot);
}
Ordering::Equal => {
my[0] = 0;
my[1] = 0;
my[2] = 0;
}
}
carry = 0;
}
if carry > 0 {
if final_scale == 0 {
return None;
}
let mut temp = [my[0], my[1], my[2], carry];
while final_scale > 0 && temp[3] != 0 {
div_by_u32(&mut temp, 10);
final_scale -= 1;
}
if temp[3] > 0 {
return None;
}
my[0] = temp[0];
my[1] = temp[1];
my[2] = temp[2];
}
Some(Decimal {
lo: my[0],
mid: my[1],
hi: my[2],
flags: flags(negative, final_scale),
})
}
#[inline(always)]
pub fn checked_sub(self, other: Decimal) -> Option<Decimal> {
let negated_other = Decimal {
lo: other.lo,
mid: other.mid,
hi: other.hi,
flags: other.flags ^ SIGN_MASK,
};
self.checked_add(negated_other)
}
#[inline]
pub fn checked_mul(self, other: Decimal) -> Option<Decimal> {
if self.is_zero() || other.is_zero() {
return Some(Decimal::zero());
}
let negative = self.is_sign_negative() ^ other.is_sign_negative();
let mut final_scale = self.scale() + other.scale();
if self.mid == 0 && self.hi == 0 && other.mid == 0 && other.hi == 0 {
let mut u64_result = u64_to_array(u64::from(self.lo) * u64::from(other.lo));
if final_scale > MAX_PRECISION {
final_scale -= MAX_PRECISION;
if final_scale > 19 {
return Some(Decimal::zero());
}
let mut rem_lo = 0;
let mut power;
if final_scale > 9 {
rem_lo = div_by_u32(&mut u64_result, 2_500_000_000);
power = POWERS_10[final_scale as usize - 10] << 2;
} else {
power = POWERS_10[final_scale as usize];
}
let rem_hi = div_by_u32(&mut u64_result, power);
power >>= 1;
if rem_hi >= power && (rem_hi > power || (rem_lo | (u64_result[0] & 0x1)) != 0) {
u64_result[0] += 1;
}
final_scale = MAX_PRECISION;
}
return Some(Decimal {
lo: u64_result[0],
mid: u64_result[1],
hi: 0,
flags: flags(negative, final_scale),
});
}
let my = [self.lo, self.mid, self.hi];
let ot = [other.lo, other.mid, other.hi];
let mut product = [0u32, 0u32, 0u32, 0u32, 0u32, 0u32];
let to = if my[2] == 0 && ot[2] == 0 { 2 } else { 3 };
for my_index in 0..to {
for ot_index in 0..to {
let (mut rlo, mut rhi) = mul_part(my[my_index], ot[ot_index], 0);
for prod in product.iter_mut().skip(my_index + ot_index) {
let (res, overflow) = add_part(rlo, *prod);
*prod = res;
if rhi > 0 {
if overflow > 0 {
let (nlo, nhi) = add_part(rhi, overflow);
rlo = nlo;
rhi = nhi;
} else {
rlo = rhi;
rhi = 0;
}
} else if overflow > 0 {
rlo = overflow;
rhi = 0;
} else {
break;
}
if rlo == 0 {
break;
}
}
}
}
let mut remainder = 0;
while final_scale > 0 && (product[3] != 0 || product[4] != 0 || product[5] != 0) {
remainder = div_by_u32(&mut product, 10u32);
final_scale -= 1;
}
if remainder >= 5 {
for part in product.iter_mut() {
if remainder == 0 {
break;
}
let digit: u64 = u64::from(*part) + 1;
remainder = if digit > 0xFFFF_FFFF { 1 } else { 0 };
*part = (digit & 0xFFFF_FFFF) as u32;
}
}
if final_scale > MAX_PRECISION {
while final_scale > MAX_PRECISION && !is_all_zero(&product) {
div_by_u32(&mut product, 10);
final_scale -= 1;
}
if final_scale > MAX_PRECISION {
final_scale = 0;
}
} else if !(product[3] == 0 && product[4] == 0 && product[5] == 0) {
return None;
}
Some(Decimal {
lo: product[0],
mid: product[1],
hi: product[2],
flags: flags(negative, final_scale),
})
}
pub fn checked_div(self, other: Decimal) -> Option<Decimal> {
match ops::div_impl(&self, &other) {
DivResult::Ok(quot) => Some(quot),
DivResult::Overflow => None,
DivResult::DivByZero => None,
}
}
pub fn checked_rem(self, other: Decimal) -> Option<Decimal> {
if other.is_zero() {
return None;
}
if self.is_zero() {
return Some(Decimal::zero());
}
let initial_scale = self.scale();
let mut quotient = [self.lo, self.mid, self.hi];
let mut quotient_scale = initial_scale;
let mut divisor = [other.lo, other.mid, other.hi];
let mut divisor_scale = other.scale();
rescale_to_maximum_scale(&mut quotient, &mut quotient_scale, &mut divisor, &mut divisor_scale);
let mut working_quotient = [quotient[0], quotient[1], quotient[2], 0u32];
let mut working_remainder = [0u32, 0u32, 0u32, 0u32];
div_internal(&mut working_quotient, &mut working_remainder, &divisor);
if quotient_scale > initial_scale {
let mut working = [
working_remainder[0],
working_remainder[1],
working_remainder[2],
working_remainder[3],
];
while quotient_scale > initial_scale {
if div_by_u32(&mut working, 10) > 0 {
break;
}
quotient_scale -= 1;
working_remainder.copy_from_slice(&working);
}
}
Some(Decimal {
lo: working_remainder[0],
mid: working_remainder[1],
hi: working_remainder[2],
flags: flags(self.is_sign_negative(), quotient_scale),
})
}
pub fn from_str_radix(str: &str, radix: u32) -> Result<Self, crate::Error> {
if radix == 10 {
parse_str_radix_10(str)
} else {
parse_str_radix_n(str, radix)
}
}
}
impl Default for Decimal {
fn default() -> Self {
Self::zero()
}
}
pub(crate) enum DivResult {
Ok(Decimal),
Overflow,
DivByZero,
}
#[inline]
const fn flags(neg: bool, scale: u32) -> u32 {
(scale << SCALE_SHIFT) | ((neg as u32) << SIGN_SHIFT)
}
#[inline(always)]
fn rescale_to_maximum_scale(left: &mut [u32; 3], left_scale: &mut u32, right: &mut [u32; 3], right_scale: &mut u32) {
if left_scale == right_scale {
return;
}
if is_all_zero(left) {
*left_scale = *right_scale;
return;
} else if is_all_zero(right) {
*right_scale = *left_scale;
return;
}
if left_scale > right_scale {
rescale_internal(right, right_scale, *left_scale);
if right_scale != left_scale {
rescale_internal(left, left_scale, *right_scale);
}
} else {
rescale_internal(left, left_scale, *right_scale);
if right_scale != left_scale {
rescale_internal(right, right_scale, *left_scale);
}
}
}
#[inline(always)]
fn rescale_internal(value: &mut [u32; 3], value_scale: &mut u32, new_scale: u32) {
if *value_scale == new_scale {
return;
}
if is_all_zero(value) {
*value_scale = new_scale;
return;
}
if *value_scale > new_scale {
let mut diff = *value_scale - new_scale;
let mut remainder = 0;
while diff > 0 {
if is_all_zero(value) {
*value_scale = new_scale;
return;
}
diff -= 1;
remainder = div_by_10(value);
}
if remainder >= 5 {
for part in value.iter_mut() {
let digit = u64::from(*part) + 1u64;
remainder = if digit > 0xFFFF_FFFF { 1 } else { 0 };
*part = (digit & 0xFFFF_FFFF) as u32;
if remainder == 0 {
break;
}
}
}
*value_scale = new_scale;
} else {
let mut diff = new_scale - *value_scale;
let mut working = [value[0], value[1], value[2]];
while diff > 0 && mul_by_10(&mut working) == 0 {
value.copy_from_slice(&working);
diff -= 1;
}
*value_scale = new_scale - diff;
}
}
#[inline]
const fn u64_to_array(value: u64) -> [u32; 2] {
[(value & U32_MASK) as u32, (value >> 32 & U32_MASK) as u32]
}
fn add_by_internal(value: &mut [u32], by: &[u32]) -> u32 {
let mut carry: u64 = 0;
let vl = value.len();
let bl = by.len();
if vl >= bl {
let mut sum: u64;
for i in 0..bl {
sum = u64::from(value[i]) + u64::from(by[i]) + carry;
value[i] = (sum & U32_MASK) as u32;
carry = sum >> 32;
}
if vl > bl && carry > 0 {
for i in value.iter_mut().skip(bl) {
sum = u64::from(*i) + carry;
*i = (sum & U32_MASK) as u32;
carry = sum >> 32;
if carry == 0 {
break;
}
}
}
} else if vl + 1 == bl {
let mut sum: u64;
for i in 0..vl {
sum = u64::from(value[i]) + u64::from(by[i]) + carry;
value[i] = (sum & U32_MASK) as u32;
carry = sum >> 32;
}
if by[vl] > 0 {
carry += u64::from(by[vl]);
}
} else {
panic!("Internal error: add using incompatible length arrays. {} <- {}", vl, bl);
}
carry as u32
}
#[inline]
fn add_one_internal(value: &mut [u32]) -> u32 {
let mut carry: u64 = 1;
let mut sum: u64;
for i in value.iter_mut() {
sum = (*i as u64) + carry;
*i = (sum & U32_MASK) as u32;
carry = sum >> 32;
}
carry as u32
}
#[inline]
fn add_one_internal4(value: &mut [u32; 4]) -> u32 {
let mut carry: u64 = 1;
let mut sum: u64;
for i in value.iter_mut() {
sum = (*i as u64) + carry;
*i = (sum & U32_MASK) as u32;
carry = sum >> 32;
}
carry as u32
}
#[inline]
fn add_by_internal3(value: &mut [u32; 3], by: &[u32; 3]) -> u32 {
let mut carry: u32 = 0;
let bl = by.len();
for i in 0..bl {
let res1 = value[i].overflowing_add(by[i]);
let res2 = res1.0.overflowing_add(carry);
value[i] = res2.0;
carry = (res1.1 | res2.1) as u32;
}
carry
}
#[inline]
fn add_part(left: u32, right: u32) -> (u32, u32) {
let added = u64::from(left) + u64::from(right);
((added & U32_MASK) as u32, (added >> 32 & U32_MASK) as u32)
}
#[inline(always)]
fn sub_by_internal3(value: &mut [u32; 3], by: &[u32; 3]) {
let mut overflow = 0;
let vl = value.len();
for i in 0..vl {
let part = (0x1_0000_0000u64 + u64::from(value[i])) - (u64::from(by[i]) + overflow);
value[i] = part as u32;
overflow = 1 - (part >> 32);
}
}
fn sub_by_internal(value: &mut [u32], by: &[u32]) -> u32 {
let mut overflow = 0;
let vl = value.len();
let bl = by.len();
for i in 0..vl {
if i >= bl {
break;
}
let (lo, hi) = sub_part(value[i], by[i], overflow);
value[i] = lo;
overflow = hi;
}
overflow
}
fn sub_part(left: u32, right: u32, overflow: u32) -> (u32, u32) {
let part = 0x1_0000_0000u64 + u64::from(left) - (u64::from(right) + u64::from(overflow));
let lo = part as u32;
let hi = 1 - ((part >> 32) as u32);
(lo, hi)
}
#[inline]
fn mul_by_10(bits: &mut [u32; 3]) -> u32 {
let mut overflow = 0u64;
for b in bits.iter_mut() {
let result = u64::from(*b) * 10u64 + overflow;
let hi = (result >> 32) & U32_MASK;
let lo = (result & U32_MASK) as u32;
*b = lo;
overflow = hi;
}
overflow as u32
}
pub(crate) fn mul_by_u32(bits: &mut [u32], m: u32) -> u32 {
let mut overflow = 0;
for b in bits.iter_mut() {
let (lo, hi) = mul_part(*b, m, overflow);
*b = lo;
overflow = hi;
}
overflow
}
fn mul_part(left: u32, right: u32, high: u32) -> (u32, u32) {
let result = u64::from(left) * u64::from(right) + u64::from(high);
let hi = ((result >> 32) & U32_MASK) as u32;
let lo = (result & U32_MASK) as u32;
(lo, hi)
}
fn div_internal(quotient: &mut [u32; 4], remainder: &mut [u32; 4], divisor: &[u32; 3]) {
let mut complement = [
divisor[0] ^ 0xFFFF_FFFF,
divisor[1] ^ 0xFFFF_FFFF,
divisor[2] ^ 0xFFFF_FFFF,
0xFFFF_FFFF,
];
add_one_internal4(&mut complement);
remainder.iter_mut().for_each(|x| *x = 0);
let mut blocks_to_process = 0;
while blocks_to_process < 4 && quotient[3] == 0 {
quotient[3] = quotient[2];
quotient[2] = quotient[1];
quotient[1] = quotient[0];
quotient[0] = 0;
blocks_to_process += 1;
}
let mut block = blocks_to_process << 5;
let mut working = [0u32, 0u32, 0u32, 0u32];
while block < 128 {
let carry = shl1_internal(quotient, 0);
shl1_internal(remainder, carry);
working.copy_from_slice(remainder);
add_by_internal(&mut working, &complement);
if (working[3] & 0x8000_0000) == 0 {
remainder.copy_from_slice(&working);
quotient[0] |= 1;
}
block += 1;
}
}
#[cfg(feature = "legacy-ops")]
mod ops {
use super::*;
pub(crate) fn div_impl(d1: &Decimal, d2: &Decimal) -> DivResult {
if d2.is_zero() {
return DivResult::DivByZero;
}
if d1.is_zero() {
return DivResult::Ok(Decimal::zero());
}
let dividend = [d1.lo, d1.mid, d1.hi];
let divisor = [d2.lo, d2.mid, d2.hi];
let mut quotient = [0u32, 0u32, 0u32];
let mut quotient_scale: i32 = d1.scale() as i32 - d2.scale() as i32;
let mut working_quotient = [dividend[0], dividend[1], dividend[2], 0u32];
let mut working_remainder = [0u32, 0u32, 0u32, 0u32];
let mut working_scale = quotient_scale;
let mut remainder_scale = quotient_scale;
let mut underflow;
loop {
div_internal(&mut working_quotient, &mut working_remainder, &divisor);
underflow = add_with_scale_internal(
&mut quotient,
&mut quotient_scale,
&mut working_quotient,
&mut working_scale,
);
let mut overflow = 0;
for part in working_remainder.iter_mut() {
let (lo, hi) = mul_part(*part, 10, overflow);
*part = lo;
overflow = hi;
}
working_quotient.copy_from_slice(&working_remainder);
remainder_scale += 1;
working_scale = remainder_scale;
if underflow || is_all_zero(&working_remainder) {
break;
}
}
while quotient_scale < 0 {
copy_array_diff_lengths(&mut working_quotient, "ient);
working_quotient[3] = 0;
working_remainder.iter_mut().for_each(|x| *x = 0);
let mut overflow = 0;
for part in &mut working_quotient {
let (lo, hi) = mul_part(*part, 10, overflow);
*part = lo;
overflow = hi;
}
for part in &mut working_remainder {
let (lo, hi) = mul_part(*part, 10, overflow);
*part = lo;
overflow = hi;
}
if working_quotient[3] == 0 && is_all_zero(&working_remainder) {
quotient_scale += 1;
quotient[0] = working_quotient[0];
quotient[1] = working_quotient[1];
quotient[2] = working_quotient[2];
} else {
return DivResult::Overflow;
}
}
if quotient_scale > 255 {
quotient[0] = 0;
quotient[1] = 0;
quotient[2] = 0;
quotient_scale = 0;
}
let mut quotient_negative = d1.is_sign_negative() ^ d2.is_sign_negative();
let mut final_scale: u32 = quotient_scale as u32;
if final_scale > MAX_PRECISION {
let mut remainder = 0;
while final_scale > MAX_PRECISION && !is_all_zero("ient) {
remainder = div_by_u32(&mut quotient, 10);
final_scale -= 1;
}
if final_scale > MAX_PRECISION {
final_scale = 0;
quotient_negative = false;
} else if remainder >= 5 {
for part in &mut quotient {
if remainder == 0 {
break;
}
let digit: u64 = u64::from(*part) + 1;
remainder = if digit > 0xFFFF_FFFF { 1 } else { 0 };
*part = (digit & 0xFFFF_FFFF) as u32;
}
}
}
DivResult::Ok(Decimal {
lo: quotient[0],
mid: quotient[1],
hi: quotient[2],
flags: flags(quotient_negative, final_scale),
})
}
#[inline]
fn copy_array_diff_lengths(into: &mut [u32], from: &[u32]) {
for i in 0..into.len() {
if i >= from.len() {
break;
}
into[i] = from[i];
}
}
fn add_with_scale_internal(
quotient: &mut [u32; 3],
quotient_scale: &mut i32,
working_quotient: &mut [u32; 4],
working_scale: &mut i32,
) -> bool {
if is_all_zero(quotient) {
while working_quotient[3] != 0 {
div_by_u32(working_quotient, 10);
*working_scale -= 1;
}
copy_array_diff_lengths(quotient, working_quotient);
*quotient_scale = *working_scale;
return false;
}
if is_all_zero(working_quotient) {
return false;
}
let mut temp3 = [0u32, 0u32, 0u32];
let mut temp4 = [0u32, 0u32, 0u32, 0u32];
if *quotient_scale != *working_scale {
fn div_by_10(target: &mut [u32], temp: &mut [u32], scale: &mut i32, target_scale: i32) {
temp.copy_from_slice(target);
while *scale > target_scale {
let remainder = div_by_u32(temp, 10);
if remainder == 0 {
*scale -= 1;
target.copy_from_slice(&temp);
} else {
break;
}
}
}
if *quotient_scale < *working_scale {
div_by_10(working_quotient, &mut temp4, working_scale, *quotient_scale);
} else {
div_by_10(quotient, &mut temp3, quotient_scale, *working_scale);
}
}
if *quotient_scale != *working_scale {
fn mul_by_10(target: &mut [u32], temp: &mut [u32], scale: &mut i32, target_scale: i32) {
temp.copy_from_slice(target);
let mut overflow = 0;
while *scale < target_scale && overflow == 0 {
overflow = mul_by_u32(temp, 10);
if overflow == 0 {
*scale += 1;
target.copy_from_slice(&temp);
}
}
}
if *quotient_scale > *working_scale {
mul_by_10(working_quotient, &mut temp4, working_scale, *quotient_scale);
} else {
mul_by_10(quotient, &mut temp3, quotient_scale, *working_scale);
}
}
if *quotient_scale != *working_scale {
fn div_by_10_lossy(target: &mut [u32], temp: &mut [u32], scale: &mut i32, target_scale: i32) {
temp.copy_from_slice(target);
while *scale > target_scale {
div_by_u32(temp, 10);
*scale -= 1;
target.copy_from_slice(&temp);
}
}
if *quotient_scale < *working_scale {
div_by_10_lossy(working_quotient, &mut temp4, working_scale, *quotient_scale);
} else {
div_by_10_lossy(quotient, &mut temp3, quotient_scale, *working_scale);
}
}
if is_all_zero(quotient) || is_all_zero(working_quotient) {
return true;
} else {
let mut underflow = false;
let mut temp = [0u32, 0u32, 0u32];
while !underflow {
temp.copy_from_slice(quotient);
let overflow = add_by_internal(&mut temp, working_quotient);
if overflow == 0 {
quotient.copy_from_slice(&temp);
break;
} else {
div_by_u32(quotient, 10);
*quotient_scale -= 1;
div_by_u32(working_quotient, 10);
*working_scale -= 1;
underflow = is_all_zero(quotient) || is_all_zero(working_quotient);
}
}
if underflow {
return true;
}
}
false
}
}
#[cfg(not(feature = "legacy-ops"))]
mod ops {
use super::*;
use core::ops::BitXor;
static POWER_OVERFLOW_VALUES: [Dec12; 8] = [
Dec12 {
hi: 429496729,
mid: 2576980377,
lo: 2576980377,
},
Dec12 {
hi: 42949672,
mid: 4123168604,
lo: 687194767,
},
Dec12 {
hi: 4294967,
mid: 1271310319,
lo: 2645699854,
},
Dec12 {
hi: 429496,
mid: 3133608139,
lo: 694066715,
},
Dec12 {
hi: 42949,
mid: 2890341191,
lo: 2216890319,
},
Dec12 {
hi: 4294,
mid: 4154504685,
lo: 2369172679,
},
Dec12 {
hi: 429,
mid: 2133437386,
lo: 4102387834,
},
Dec12 {
hi: 42,
mid: 4078814305,
lo: 410238783,
},
];
struct Dec12 {
lo: u32,
mid: u32,
hi: u32,
}
impl Dec12 {
const fn new(value: &Decimal) -> Self {
Dec12 {
lo: value.lo,
mid: value.mid,
hi: value.hi,
}
}
const fn low64(&self) -> u64 {
((self.mid as u64) << 32) | (self.lo as u64)
}
fn set_low64(&mut self, value: u64) {
self.mid = (value >> 32) as u32;
self.lo = value as u32;
}
const fn high64(&self) -> u64 {
((self.hi as u64) << 32) | (self.mid as u64)
}
fn set_high64(&mut self, value: u64) {
self.hi = (value >> 32) as u32;
self.mid = value as u32;
}
fn add32(&mut self, value: u32) -> Result<(), DivError> {
let value = value as u64;
let new = self.low64().wrapping_add(value);
self.set_low64(new);
if new < value {
self.hi = self.hi.wrapping_add(1);
if self.hi == 0 {
return Err(DivError::Overflow);
}
}
Ok(())
}
fn div32(&mut self, divisor: u32) -> u32 {
let divisor64 = divisor as u64;
if self.hi != 0 {
let mut temp = self.high64();
let q64 = temp / divisor64;
self.set_high64(q64);
temp = ((temp - q64 * divisor64) << 32) | (self.lo as u64);
if temp == 0 {
return 0;
}
let q32 = (temp / divisor64) as u32;
self.lo = q32;
((temp as u32).wrapping_sub(q32.wrapping_mul(divisor))) as u32
} else {
let low64 = self.low64();
if low64 == 0 {
return 0;
}
let quotient = low64 / divisor64;
self.set_low64(quotient);
(low64.wrapping_sub(quotient.wrapping_mul(divisor64))) as u32
}
}
fn div32_const(&mut self, pow: u32) -> bool {
let pow64 = pow as u64;
let high64 = self.high64();
let lo = self.lo as u64;
let div64: u64 = high64 / pow64;
let div = ((((high64 - div64 * pow64) << 32) + lo) / pow64) as u32;
if self.lo == div.wrapping_mul(pow) {
self.set_high64(div64);
self.lo = div;
true
} else {
false
}
}
}
struct Dec16 {
lo: u32,
mid: u32,
hi: u32,
overflow: u32,
}
impl Dec16 {
const fn zero() -> Self {
Dec16 {
lo: 0,
mid: 0,
hi: 0,
overflow: 0,
}
}
const fn low64(&self) -> u64 {
((self.mid as u64) << 32) | (self.lo as u64)
}
fn set_low64(&mut self, value: u64) {
self.mid = (value >> 32) as u32;
self.lo = value as u32;
}
const fn mid64(&self) -> u64 {
((self.hi as u64) << 32) | (self.mid as u64)
}
fn set_mid64(&mut self, value: u64) {
self.hi = (value >> 32) as u32;
self.mid = value as u32;
}
const fn high64(&self) -> u64 {
((self.overflow as u64) << 32) | (self.hi as u64)
}
fn set_high64(&mut self, value: u64) {
self.overflow = (value >> 32) as u32;
self.hi = value as u32;
}
fn partial_divide_64(&mut self, divisor: u64) -> u32 {
debug_assert!(divisor > self.mid64());
if self.hi == 0 {
let low64 = self.low64();
if low64 < divisor {
return 0;
}
let quotient = low64 / divisor;
self.set_low64(low64 - (quotient * divisor));
return quotient as u32;
}
let divisor_hi32 = (divisor >> 32) as u32;
if self.hi >= divisor_hi32 {
let mut low64 = self.low64();
low64 = low64 - (divisor << 32) + divisor;
let mut quotient = u32::MAX;
loop {
if low64 < divisor {
break;
}
quotient -= 1;
low64 += divisor;
}
self.set_low64(low64);
return quotient;
}
let mid64 = self.mid64();
let divisor_hi32_64 = divisor_hi32 as u64;
if mid64 < divisor_hi32_64 as u64 {
return 0;
}
let mut quotient = mid64 / divisor_hi32_64;
let mut remainder = self.lo as u64 | ((mid64 - quotient * divisor_hi32_64) << 32);
let product = quotient * (divisor & 0xFFFF_FFFF);
remainder = remainder.wrapping_sub(product);
if remainder > product.bitxor(u64::max_value()) {
loop {
quotient = quotient.wrapping_sub(1);
remainder = remainder.wrapping_add(divisor);
if remainder < divisor {
break;
}
}
}
self.set_low64(remainder);
quotient as u32
}
fn partial_divide_96(&mut self, divisor: &Dec12) -> u32 {
let dividend = self.high64();
let divisor_hi = divisor.hi;
if dividend < divisor_hi as u64 {
return 0;
}
let mut quo = (dividend / divisor_hi as u64) as u32;
let mut remainder = (dividend as u32).wrapping_sub(quo.wrapping_mul(divisor_hi));
let mut prod1 = quo as u64 * divisor.lo as u64;
let mut prod2 = quo as u64 * divisor.mid as u64;
prod2 += prod1 >> 32;
prod1 = (prod1 & 0xFFFF_FFFF) | (prod2 << 32);
prod2 >>= 32;
let mut num = self.low64();
num = num.wrapping_sub(prod1);
remainder = remainder.wrapping_sub(prod2 as u32);
if num > prod1.bitxor(u64::MAX) {
remainder = remainder.wrapping_sub(1);
if remainder < (prod2 as u32).bitxor(u32::MAX) {
self.set_low64(num);
self.hi = remainder;
return quo;
}
} else if remainder <= (prod2 as u32).bitxor(u32::MAX) {
self.set_low64(num);
self.hi = remainder;
return quo;
}
prod1 = divisor.low64();
loop {
quo = quo.wrapping_sub(1);
num = num.wrapping_add(prod1);
remainder = remainder.wrapping_add(divisor_hi);
if num < prod1 {
let tmp = remainder;
remainder += 1;
if tmp < divisor_hi {
break;
}
}
if remainder < divisor_hi {
break;
}
}
self.set_low64(num);
self.hi = remainder;
quo
}
}
enum DivError {
Overflow,
}
pub(crate) fn div_impl(dividend: &Decimal, divisor: &Decimal) -> DivResult {
if divisor.is_zero() {
return DivResult::DivByZero;
}
if dividend.is_zero() {
return DivResult::Ok(Decimal::zero());
}
let mut scale = (dividend.scale() as i32) - (divisor.scale() as i32);
let sign_negative = dividend.is_sign_negative() ^ divisor.is_sign_negative();
let mut require_unscale = false;
let mut quotient = Dec12::new(÷nd);
let divisor = Dec12::new(&divisor);
if divisor.hi | divisor.mid == 0 {
let divisor32 = divisor.lo;
let mut remainder = quotient.div32(divisor32);
let mut power_scale = 0;
loop {
if remainder == 0 {
if scale >= 0 {
break;
}
power_scale = 9usize.min((-scale) as usize);
} else {
require_unscale = true;
let will_overflow = if scale == MAX_PRECISION_I32 {
true
} else {
if let Ok(s) = find_scale("ient, scale) {
power_scale = s;
} else {
return DivResult::Overflow;
}
power_scale == 0
};
if will_overflow {
let tmp = remainder << 1;
let round = if tmp < remainder {
true
} else {
if tmp >= divisor32 {
tmp > divisor32 || (quotient.lo & 0x1) > 0
} else {
false
}
};
if round {
if let Ok(new_scale) = round_up(&mut quotient, scale) {
scale = new_scale;
} else {
return DivResult::Overflow;
}
}
break;
}
}
let power = POWERS_10[power_scale];
scale += power_scale as i32;
let overflow = increase_scale(&mut quotient, power as u64);
if overflow > 0 {
return DivResult::Overflow;
}
let remainder_scaled = (remainder as u64) * (power as u64);
let remainder_quotient = (remainder_scaled / (divisor32 as u64)) as u32;
remainder = (remainder_scaled - remainder_quotient as u64 * divisor32 as u64) as u32;
if let Err(DivError::Overflow) = quotient.add32(remainder_quotient) {
if let Ok(adj) = unscale_from_overflow(&mut quotient, scale, remainder != 0) {
scale = adj;
} else {
return DivResult::Overflow;
}
break;
}
}
} else {
let mut power_scale = if divisor.hi == 0 {
divisor.mid.leading_zeros()
} else {
divisor.hi.leading_zeros()
} as usize;
let mut remainder = Dec16::zero();
remainder.set_low64(quotient.low64() << power_scale);
let tmp_high = ((quotient.mid as u64) + ((quotient.hi as u64) << 32)) >> (32 - power_scale);
remainder.set_high64(tmp_high);
let divisor64 = divisor.low64() << power_scale;
if divisor.hi == 0 {
quotient.hi = 0;
let rem_lo = remainder.lo;
remainder.lo = remainder.mid;
remainder.mid = remainder.hi;
remainder.hi = remainder.overflow;
quotient.mid = remainder.partial_divide_64(divisor64);
remainder.hi = remainder.mid;
remainder.mid = remainder.lo;
remainder.lo = rem_lo;
quotient.lo = remainder.partial_divide_64(divisor64);
loop {
let rem_low64 = remainder.low64();
if rem_low64 == 0 {
if scale >= 0 {
break;
}
power_scale = 9usize.min((-scale) as usize);
} else {
require_unscale = true;
let will_overflow = if scale == MAX_PRECISION_I32 {
true
} else {
if let Ok(s) = find_scale("ient, scale) {
power_scale = s;
} else {
return DivResult::Overflow;
}
power_scale == 0
};
if will_overflow {
let mut tmp = remainder.low64();
let round = if (tmp as i64) < 0 {
true
} else {
tmp <<= 1;
if tmp > divisor64 {
true
} else {
tmp == divisor64 && quotient.lo & 0x1 != 0
}
};
if round {
if let Ok(new_scale) = round_up(&mut quotient, scale) {
scale = new_scale;
} else {
return DivResult::Overflow;
}
}
break;
}
}
let power = POWERS_10[power_scale];
scale += power_scale as i32;
let overflow = increase_scale(&mut quotient, power as u64);
if overflow > 0 {
return DivResult::Overflow;
}
increase_scale64(&mut remainder, power as u64);
let tmp = remainder.partial_divide_64(divisor64);
if let Err(DivError::Overflow) = quotient.add32(tmp) {
if let Ok(adj) = unscale_from_overflow(&mut quotient, scale, remainder.low64() != 0) {
scale = adj;
} else {
return DivResult::Overflow;
}
break;
}
}
} else {
let divisor_mid = divisor.mid;
let divisor_hi = divisor.hi;
let mut divisor = divisor;
divisor.set_low64(divisor64);
divisor.hi = ((divisor_mid as u64 + ((divisor_hi as u64) << 32)) >> (32 - power_scale)) as u32;
let quo = remainder.partial_divide_96(&divisor);
quotient.set_low64(quo as u64);
quotient.hi = 0;
loop {
let mut rem_low64 = remainder.low64();
if rem_low64 == 0 && remainder.hi == 0 {
if scale >= 0 {
break;
}
power_scale = 9usize.min((-scale) as usize);
} else {
require_unscale = true;
let will_overflow = if scale == MAX_PRECISION_I32 {
true
} else {
if let Ok(s) = find_scale("ient, scale) {
power_scale = s;
} else {
return DivResult::Overflow;
}
power_scale == 0
};
if will_overflow {
let round = if (remainder.hi as i32) < 0 {
true
} else {
let tmp = remainder.mid >> 31;
rem_low64 <<= 1;
remainder.set_low64(rem_low64);
remainder.hi = (remainder.hi << 1) + tmp;
if remainder.hi > divisor.hi {
true
} else if remainder.hi == divisor.hi {
let divisor_low64 = divisor.low64();
if rem_low64 > divisor_low64 {
true
} else {
rem_low64 == divisor_low64 && (quotient.lo & 1) != 0
}
} else {
false
}
};
if round {
if let Ok(new_scale) = round_up(&mut quotient, scale) {
scale = new_scale;
} else {
return DivResult::Overflow;
}
}
break;
}
}
let power = POWERS_10[power_scale];
scale += power_scale as i32;
let overflow = increase_scale(&mut quotient, power as u64);
if overflow > 0 {
return DivResult::Overflow;
}
let mut tmp_remainder = Dec12 {
lo: remainder.lo,
mid: remainder.mid,
hi: remainder.hi,
};
let overflow = increase_scale(&mut tmp_remainder, power as u64);
remainder.lo = tmp_remainder.lo;
remainder.mid = tmp_remainder.mid;
remainder.hi = tmp_remainder.hi;
remainder.overflow = overflow;
let tmp = remainder.partial_divide_96(&divisor);
if let Err(DivError::Overflow) = quotient.add32(tmp) {
if let Ok(adj) =
unscale_from_overflow(&mut quotient, scale, (remainder.low64() | remainder.high64()) != 0)
{
scale = adj;
} else {
return DivResult::Overflow;
}
break;
}
}
}
}
if require_unscale {
scale = unscale(&mut quotient, scale);
}
DivResult::Ok(Decimal {
lo: quotient.lo,
mid: quotient.mid,
hi: quotient.hi,
flags: flags(sign_negative, scale as u32),
})
}
fn increase_scale(num: &mut Dec12, power: u64) -> u32 {
let mut tmp = (num.lo as u64) * power;
num.lo = tmp as u32;
tmp >>= 32;
tmp += (num.mid as u64) * power;
num.mid = tmp as u32;
tmp >>= 32;
tmp += (num.hi as u64) * power;
num.hi = tmp as u32;
(tmp >> 32) as u32
}
fn increase_scale64(num: &mut Dec16, power: u64) {
let mut tmp = (num.lo as u64) * power;
num.lo = tmp as u32;
tmp >>= 32;
tmp += (num.mid as u64) * power;
num.set_mid64(tmp)
}
fn unscale_from_overflow(num: &mut Dec12, scale: i32, sticky: bool) -> Result<i32, DivError> {
let scale = scale - 1;
if scale < 0 {
return Err(DivError::Overflow);
}
const HIGH_BIT: u64 = 0x1_0000_0000;
num.hi = (HIGH_BIT / 10) as u32;
let mut tmp = ((HIGH_BIT % 10) << 32) + (num.mid as u64);
let mut val = (tmp / 10) as u32;
num.mid = val;
tmp = ((tmp - (val as u64) * 10) << 32) + (num.lo as u64);
val = (tmp / 10) as u32;
num.lo = val;
let remainder = (tmp - (val as u64) * 10) as u32;
if remainder > 5 || (remainder == 5 && (sticky || num.lo & 0x1 > 0)) {
let _ = num.add32(1);
}
Ok(scale)
}
fn find_scale(num: &Dec12, scale: i32) -> Result<usize, DivError> {
const OVERFLOW_MAX_9_HI: u32 = 4;
const OVERFLOW_MAX_8_HI: u32 = 42;
const OVERFLOW_MAX_7_HI: u32 = 429;
const OVERFLOW_MAX_6_HI: u32 = 4294;
const OVERFLOW_MAX_5_HI: u32 = 42949;
const OVERFLOW_MAX_4_HI: u32 = 429496;
const OVERFLOW_MAX_3_HI: u32 = 4294967;
const OVERFLOW_MAX_2_HI: u32 = 42949672;
const OVERFLOW_MAX_1_HI: u32 = 429496729;
const OVERFLOW_MAX_9_LOW64: u64 = 5441186219426131129;
let hi = num.hi;
let low64 = num.low64();
let mut x = 0usize;
if hi > OVERFLOW_MAX_1_HI {
if scale < 0 {
return Err(DivError::Overflow);
}
return Ok(x);
}
if scale > MAX_PRECISION_I32 - 9 {
x = (MAX_PRECISION_I32 - scale) as usize;
if hi < POWER_OVERFLOW_VALUES[x - 1].hi {
if x as i32 + scale < 0 {
return Err(DivError::Overflow);
}
return Ok(x);
}
} else if hi < OVERFLOW_MAX_9_HI || hi == OVERFLOW_MAX_9_HI && low64 <= OVERFLOW_MAX_9_LOW64 {
return Ok(9);
}
x = if hi > OVERFLOW_MAX_5_HI {
if hi > OVERFLOW_MAX_3_HI {
if hi > OVERFLOW_MAX_2_HI {
1
} else {
2
}
} else {
if hi > OVERFLOW_MAX_4_HI {
3
} else {
4
}
}
} else {
if hi > OVERFLOW_MAX_7_HI {
if hi > OVERFLOW_MAX_6_HI {
5
} else {
6
}
} else {
if hi > OVERFLOW_MAX_8_HI {
7
} else {
8
}
}
};
if hi == POWER_OVERFLOW_VALUES[x - 1].hi && low64 > POWER_OVERFLOW_VALUES[x - 1].low64() {
x -= 1;
}
if x as i32 + scale < 0 {
Err(DivError::Overflow)
} else {
Ok(x)
}
}
#[inline]
fn round_up(num: &mut Dec12, scale: i32) -> Result<i32, DivError> {
let low64 = num.low64().wrapping_add(1);
num.set_low64(low64);
if low64 != 0 {
return Ok(scale);
}
let hi = num.hi.wrapping_add(1);
num.hi = hi;
if hi != 0 {
return Ok(scale);
}
unscale_from_overflow(num, scale, true)
}
fn unscale(num: &mut Dec12, scale: i32) -> i32 {
let mut scale = scale;
while num.lo == 0 && scale >= 8 && num.div32_const(100000000) {
scale -= 8;
}
if (num.lo & 0xF) == 0 && scale >= 4 && num.div32_const(10000) {
scale -= 4;
}
if (num.lo & 0x3) == 0 && scale >= 2 && num.div32_const(100) {
scale -= 2;
}
if (num.lo & 0x1) == 0 && scale >= 1 && num.div32_const(10) {
scale -= 1;
}
scale
}
}
pub(crate) fn div_by_u32(bits: &mut [u32], divisor: u32) -> u32 {
if divisor == 0 {
panic!("Internal error: divide by zero");
} else if divisor == 1 {
0
} else {
let mut remainder = 0u32;
let divisor = u64::from(divisor);
for part in bits.iter_mut().rev() {
let temp = (u64::from(remainder) << 32) + u64::from(*part);
remainder = (temp % divisor) as u32;
*part = (temp / divisor) as u32;
}
remainder
}
}
fn div_by_10(bits: &mut [u32; 3]) -> u32 {
let mut remainder = 0u32;
let divisor = 10u64;
for part in bits.iter_mut().rev() {
let temp = (u64::from(remainder) << 32) + u64::from(*part);
remainder = (temp % divisor) as u32;
*part = (temp / divisor) as u32;
}
remainder
}
#[inline]
fn shl1_internal(bits: &mut [u32], carry: u32) -> u32 {
let mut carry = carry;
for part in bits.iter_mut() {
let b = *part >> 31;
*part = (*part << 1) | carry;
carry = b;
}
carry
}
#[inline]
fn cmp_internal(left: &[u32; 3], right: &[u32; 3]) -> Ordering {
let left_hi: u32 = left[2];
let right_hi: u32 = right[2];
let left_lo: u64 = u64::from(left[1]) << 32 | u64::from(left[0]);
let right_lo: u64 = u64::from(right[1]) << 32 | u64::from(right[0]);
if left_hi < right_hi || (left_hi <= right_hi && left_lo < right_lo) {
Ordering::Less
} else if left_hi == right_hi && left_lo == right_lo {
Ordering::Equal
} else {
Ordering::Greater
}
}
#[inline]
pub(crate) fn is_all_zero(bits: &[u32]) -> bool {
bits.iter().all(|b| *b == 0)
}
macro_rules! impl_from {
($T:ty, $from_ty:path) => {
impl core::convert::From<$T> for Decimal {
#[inline]
fn from(t: $T) -> Self {
$from_ty(t).unwrap()
}
}
};
}
impl_from!(isize, FromPrimitive::from_isize);
impl_from!(i8, FromPrimitive::from_i8);
impl_from!(i16, FromPrimitive::from_i16);
impl_from!(i32, FromPrimitive::from_i32);
impl_from!(i64, FromPrimitive::from_i64);
impl_from!(usize, FromPrimitive::from_usize);
impl_from!(u8, FromPrimitive::from_u8);
impl_from!(u16, FromPrimitive::from_u16);
impl_from!(u32, FromPrimitive::from_u32);
impl_from!(u64, FromPrimitive::from_u64);
impl_from!(i128, FromPrimitive::from_i128);
impl_from!(u128, FromPrimitive::from_u128);
macro_rules! forward_val_val_binop {
(impl $imp:ident for $res:ty, $method:ident) => {
impl $imp<$res> for $res {
type Output = $res;
#[inline]
fn $method(self, other: $res) -> $res {
(&self).$method(&other)
}
}
};
}
macro_rules! forward_ref_val_binop {
(impl $imp:ident for $res:ty, $method:ident) => {
impl<'a> $imp<$res> for &'a $res {
type Output = $res;
#[inline]
fn $method(self, other: $res) -> $res {
self.$method(&other)
}
}
};
}
macro_rules! forward_val_ref_binop {
(impl $imp:ident for $res:ty, $method:ident) => {
impl<'a> $imp<&'a $res> for $res {
type Output = $res;
#[inline]
fn $method(self, other: &$res) -> $res {
(&self).$method(other)
}
}
};
}
macro_rules! forward_all_binop {
(impl $imp:ident for $res:ty, $method:ident) => {
forward_val_val_binop!(impl $imp for $res, $method);
forward_ref_val_binop!(impl $imp for $res, $method);
forward_val_ref_binop!(impl $imp for $res, $method);
};
}
impl Zero for Decimal {
fn zero() -> Decimal {
Decimal {
flags: 0,
hi: 0,
lo: 0,
mid: 0,
}
}
fn is_zero(&self) -> bool {
self.lo.is_zero() && self.mid.is_zero() && self.hi.is_zero()
}
}
impl One for Decimal {
fn one() -> Decimal {
ONE
}
}
impl Signed for Decimal {
fn abs(&self) -> Self {
self.abs()
}
fn abs_sub(&self, other: &Self) -> Self {
if self <= other {
Decimal::zero()
} else {
self.abs()
}
}
fn signum(&self) -> Self {
if self.is_zero() {
Decimal::zero()
} else {
let mut value = ONE;
if self.is_sign_negative() {
value.set_sign_negative(true);
}
value
}
}
fn is_positive(&self) -> bool {
self.is_sign_positive()
}
fn is_negative(&self) -> bool {
self.is_sign_negative()
}
}
impl CheckedAdd for Decimal {
#[inline]
fn checked_add(&self, v: &Decimal) -> Option<Decimal> {
Decimal::checked_add(*self, *v)
}
}
impl CheckedSub for Decimal {
#[inline]
fn checked_sub(&self, v: &Decimal) -> Option<Decimal> {
Decimal::checked_sub(*self, *v)
}
}
impl CheckedMul for Decimal {
#[inline]
fn checked_mul(&self, v: &Decimal) -> Option<Decimal> {
Decimal::checked_mul(*self, *v)
}
}
impl CheckedDiv for Decimal {
#[inline]
fn checked_div(&self, v: &Decimal) -> Option<Decimal> {
Decimal::checked_div(*self, *v)
}
}
impl CheckedRem for Decimal {
#[inline]
fn checked_rem(&self, v: &Decimal) -> Option<Decimal> {
Decimal::checked_rem(*self, *v)
}
}
fn parse_str_radix_10(str: &str) -> Result<Decimal, crate::Error> {
if str.is_empty() {
return Err(Error::new("Invalid decimal: empty"));
}
let mut offset = 0;
let mut len = str.len();
let bytes = str.as_bytes();
let mut negative = false;
if bytes[offset] == b'-' {
negative = true;
offset += 1;
len -= 1;
} else if bytes[offset] == b'+' {
offset += 1;
len -= 1;
}
let mut digits_before_dot: i32 = -1;
let mut coeff = ArrayVec::<[_; MAX_STR_BUFFER_SIZE]>::new();
let mut maybe_round = false;
while len > 0 {
let b = bytes[offset];
match b {
b'0'..=b'9' => {
coeff.push(u32::from(b - b'0'));
offset += 1;
len -= 1;
if coeff.len() as u32 > 28 {
maybe_round = true;
break;
}
}
b'.' => {
if digits_before_dot >= 0 {
return Err(Error::new("Invalid decimal: two decimal points"));
}
digits_before_dot = coeff.len() as i32;
offset += 1;
len -= 1;
}
b'_' => {
if coeff.is_empty() {
return Err(Error::new("Invalid decimal: must start lead with a number"));
}
offset += 1;
len -= 1;
}
_ => return Err(Error::new("Invalid decimal: unknown character")),
}
}
if maybe_round && offset < bytes.len() {
let next_byte = bytes[offset];
let digit = match next_byte {
b'0'..=b'9' => u32::from(next_byte - b'0'),
b'_' => 0,
b'.' => {
if digits_before_dot >= 0 {
return Err(Error::new("Invalid decimal: two decimal points"));
}
0
}
_ => return Err(Error::new("Invalid decimal: unknown character")),
};
if digit >= 5 {
let mut index = coeff.len() - 1;
loop {
let new_digit = coeff[index] + 1;
if new_digit <= 9 {
coeff[index] = new_digit;
break;
} else {
coeff[index] = 0;
if index == 0 {
coeff.insert(0, 1u32);
digits_before_dot += 1;
coeff.pop();
break;
}
}
index -= 1;
}
}
}
if coeff.is_empty() {
return Err(Error::new("Invalid decimal: no digits found"));
}
let mut scale = if digits_before_dot >= 0 {
(coeff.len() as u32) - (digits_before_dot as u32)
} else {
0
};
let mut data = [0u32, 0u32, 0u32];
let mut tmp = [0u32, 0u32, 0u32];
let len = coeff.len();
for (i, digit) in coeff.iter().enumerate() {
tmp[0] = data[0];
tmp[1] = data[1];
tmp[2] = data[2];
let overflow = mul_by_10(&mut tmp);
if overflow > 0 {
if (i as i32) < digits_before_dot && i + 1 < len {
return Err(Error::new("Invalid decimal: overflow from too many digits"));
}
if *digit >= 5 {
let carry = add_one_internal(&mut data);
if carry > 0 {
return Err(Error::new("Invalid decimal: overflow when rounding"));
}
}
let diff = (len - i) as u32;
if diff > scale {
return Err(Error::new("Invalid decimal: overflow from scale mismatch"));
}
scale -= diff;
break;
} else {
data[0] = tmp[0];
data[1] = tmp[1];
data[2] = tmp[2];
let carry = add_by_internal(&mut data, &[*digit]);
if carry > 0 {
return Err(Error::new("Invalid decimal: overflow from carry"));
}
}
}
Ok(Decimal {
lo: data[0],
mid: data[1],
hi: data[2],
flags: flags(negative, scale),
})
}
pub fn parse_str_radix_n(str: &str, radix: u32) -> Result<Decimal, crate::Error> {
if str.is_empty() {
return Err(Error::new("Invalid decimal: empty"));
}
if radix < 2 {
return Err(Error::new("Unsupported radix < 2"));
}
if radix > 36 {
return Err(Error::new("Unsupported radix > 36"));
}
let mut offset = 0;
let mut len = str.len();
let bytes = str.as_bytes();
let mut negative = false;
if bytes[offset] == b'-' {
negative = true;
offset += 1;
len -= 1;
} else if bytes[offset] == b'+' {
offset += 1;
len -= 1;
}
let mut digits_before_dot: i32 = -1;
let mut coeff = ArrayVec::<[_; 96]>::new();
let (max_n, max_alpha_lower, max_alpha_upper) = if radix <= 10 {
(b'0' + (radix - 1) as u8, 0, 0)
} else {
let adj = (radix - 11) as u8;
(b'9', adj + b'a', adj + b'A')
};
let estimated_max_precision = match radix {
2 => 96,
3 => 61,
4 => 48,
5 => 42,
6 => 38,
7 => 35,
8 => 32,
9 => 31,
10 => 28,
11 => 28,
12 => 27,
13 => 26,
14 => 26,
15 => 25,
16 => 24,
17 => 24,
18 => 24,
19 => 23,
20 => 23,
21 => 22,
22 => 22,
23 => 22,
24 => 21,
25 => 21,
26 => 21,
27 => 21,
28 => 20,
29 => 20,
30 => 20,
31 => 20,
32 => 20,
33 => 20,
34 => 19,
35 => 19,
36 => 19,
_ => return Err(Error::new("Unsupported radix")),
};
let mut maybe_round = false;
while len > 0 {
let b = bytes[offset];
match b {
b'0'..=b'9' => {
if b > max_n {
return Err(Error::new("Invalid decimal: invalid character"));
}
coeff.push(u32::from(b - b'0'));
offset += 1;
len -= 1;
if coeff.len() as u32 > estimated_max_precision {
maybe_round = true;
break;
}
}
b'a'..=b'z' => {
if b > max_alpha_lower {
return Err(Error::new("Invalid decimal: invalid character"));
}
coeff.push(u32::from(b - b'a') + 10);
offset += 1;
len -= 1;
if coeff.len() as u32 > estimated_max_precision {
maybe_round = true;
break;
}
}
b'A'..=b'Z' => {
if b > max_alpha_upper {
return Err(Error::new("Invalid decimal: invalid character"));
}
coeff.push(u32::from(b - b'A') + 10);
offset += 1;
len -= 1;
if coeff.len() as u32 > estimated_max_precision {
maybe_round = true;
break;
}
}
b'.' => {
if digits_before_dot >= 0 {
return Err(Error::new("Invalid decimal: two decimal points"));
}
digits_before_dot = coeff.len() as i32;
offset += 1;
len -= 1;
}
b'_' => {
if coeff.is_empty() {
return Err(Error::new("Invalid decimal: must start lead with a number"));
}
offset += 1;
len -= 1;
}
_ => return Err(Error::new("Invalid decimal: unknown character")),
}
}
if maybe_round && offset < bytes.len() {
let next_byte = bytes[offset];
let digit = match next_byte {
b'0'..=b'9' => {
if next_byte > max_n {
return Err(Error::new("Invalid decimal: invalid character"));
}
u32::from(next_byte - b'0')
}
b'a'..=b'z' => {
if next_byte > max_alpha_lower {
return Err(Error::new("Invalid decimal: invalid character"));
}
u32::from(next_byte - b'a') + 10
}
b'A'..=b'Z' => {
if next_byte > max_alpha_upper {
return Err(Error::new("Invalid decimal: invalid character"));
}
u32::from(next_byte - b'A') + 10
}
b'_' => 0,
b'.' => {
if digits_before_dot >= 0 {
return Err(Error::new("Invalid decimal: two decimal points"));
}
0
}
_ => return Err(Error::new("Invalid decimal: unknown character")),
};
let midpoint = if radix & 0x1 == 1 { radix / 2 } else { (radix + 1) / 2 };
if digit >= midpoint {
let mut index = coeff.len() - 1;
loop {
let new_digit = coeff[index] + 1;
if new_digit <= 9 {
coeff[index] = new_digit;
break;
} else {
coeff[index] = 0;
if index == 0 {
coeff.insert(0, 1u32);
digits_before_dot += 1;
coeff.pop();
break;
}
}
index -= 1;
}
}
}
if coeff.is_empty() {
return Err(Error::new("Invalid decimal: no digits found"));
}
let mut scale = if digits_before_dot >= 0 {
(coeff.len() as u32) - (digits_before_dot as u32)
} else {
0
};
let mut data = [0u32, 0u32, 0u32];
let mut tmp = [0u32, 0u32, 0u32];
let len = coeff.len();
for (i, digit) in coeff.iter().enumerate() {
tmp[0] = data[0];
tmp[1] = data[1];
tmp[2] = data[2];
let overflow = mul_by_u32(&mut tmp, radix);
if overflow > 0 {
if (i as i32) < digits_before_dot && i + 1 < len {
return Err(Error::new("Invalid decimal: overflow from too many digits"));
}
if *digit >= 5 {
let carry = add_one_internal(&mut data);
if carry > 0 {
return Err(Error::new("Invalid decimal: overflow when rounding"));
}
}
let diff = (len - i) as u32;
if diff > scale {
return Err(Error::new("Invalid decimal: overflow from scale mismatch"));
}
scale -= diff;
break;
} else {
data[0] = tmp[0];
data[1] = tmp[1];
data[2] = tmp[2];
let carry = add_by_internal(&mut data, &[*digit]);
if carry > 0 {
return Err(Error::new("Invalid decimal: overflow from carry"));
}
}
}
Ok(Decimal {
lo: data[0],
mid: data[1],
hi: data[2],
flags: flags(negative, scale),
})
}
impl Num for Decimal {
type FromStrRadixErr = Error;
fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
Decimal::from_str_radix(str, radix)
}
}
impl FromStr for Decimal {
type Err = Error;
fn from_str(value: &str) -> Result<Decimal, Self::Err> {
parse_str_radix_10(value)
}
}
impl FromPrimitive for Decimal {
fn from_i32(n: i32) -> Option<Decimal> {
let flags: u32;
let value_copy: i64;
if n >= 0 {
flags = 0;
value_copy = n as i64;
} else {
flags = SIGN_MASK;
value_copy = -(n as i64);
}
Some(Decimal {
flags,
lo: value_copy as u32,
mid: 0,
hi: 0,
})
}
fn from_i64(n: i64) -> Option<Decimal> {
let flags: u32;
let value_copy: i128;
if n >= 0 {
flags = 0;
value_copy = n as i128;
} else {
flags = SIGN_MASK;
value_copy = -(n as i128);
}
Some(Decimal {
flags,
lo: value_copy as u32,
mid: (value_copy >> 32) as u32,
hi: 0,
})
}
fn from_i128(n: i128) -> Option<Decimal> {
let flags;
let unsigned;
if n >= 0 {
unsigned = n as u128;
flags = 0;
} else {
unsigned = -n as u128;
flags = SIGN_MASK;
};
if unsigned >> 96 != 0 {
return None;
}
Some(Decimal {
flags,
lo: unsigned as u32,
mid: (unsigned >> 32) as u32,
hi: (unsigned >> 64) as u32,
})
}
fn from_u32(n: u32) -> Option<Decimal> {
Some(Decimal {
flags: 0,
lo: n,
mid: 0,
hi: 0,
})
}
fn from_u64(n: u64) -> Option<Decimal> {
Some(Decimal {
flags: 0,
lo: n as u32,
mid: (n >> 32) as u32,
hi: 0,
})
}
fn from_u128(n: u128) -> Option<Decimal> {
if n >> 96 != 0 {
return None;
}
Some(Decimal {
flags: 0,
lo: n as u32,
mid: (n >> 32) as u32,
hi: (n >> 64) as u32,
})
}
fn from_f32(n: f32) -> Option<Decimal> {
if !n.is_finite() {
return None;
}
let raw = n.to_bits();
let positive = (raw >> 31) == 0;
let biased_exponent = ((raw >> 23) & 0xFF) as i32;
let mantissa = raw & 0x007F_FFFF;
if biased_exponent == 0 && mantissa == 0 {
let mut zero = Decimal::zero();
if !positive {
zero.set_sign_negative(true);
}
return Some(zero);
}
let mut exponent2 = biased_exponent - 127;
let mut bits = [mantissa, 0u32, 0u32];
if biased_exponent == 0 {
exponent2 += 1;
} else {
bits[0] |= 0x0080_0000;
}
exponent2 -= 23;
Decimal::base2_to_decimal(&mut bits, exponent2, positive, false)
}
fn from_f64(n: f64) -> Option<Decimal> {
if !n.is_finite() {
return None;
}
let raw = n.to_bits();
let positive = (raw >> 63) == 0;
let biased_exponent = ((raw >> 52) & 0x7FF) as i32;
let mantissa = raw & 0x000F_FFFF_FFFF_FFFF;
if biased_exponent == 0 && mantissa == 0 {
let mut zero = Decimal::zero();
if !positive {
zero.set_sign_negative(true);
}
return Some(zero);
}
let mut exponent2 = biased_exponent - 1023;
let mut bits = [
(mantissa & 0xFFFF_FFFF) as u32,
((mantissa >> 32) & 0xFFFF_FFFF) as u32,
0u32,
];
if biased_exponent == 0 {
exponent2 += 1;
} else {
bits[1] |= 0x0010_0000;
}
exponent2 -= 52;
Decimal::base2_to_decimal(&mut bits, exponent2, positive, true)
}
}
impl ToPrimitive for Decimal {
fn to_i64(&self) -> Option<i64> {
let d = self.trunc();
if d.hi != 0 || (d.mid & 0x8000_0000) > 0 {
return None;
}
let raw: i64 = (i64::from(d.mid) << 32) | i64::from(d.lo);
if self.is_sign_negative() {
Some(-raw)
} else {
Some(raw)
}
}
fn to_i128(&self) -> Option<i128> {
let d = self.trunc();
let raw: i128 = ((i128::from(d.hi) << 64) | i128::from(d.mid) << 32) | i128::from(d.lo);
if self.is_sign_negative() {
Some(-raw)
} else {
Some(raw)
}
}
fn to_u64(&self) -> Option<u64> {
if self.is_sign_negative() {
return None;
}
let d = self.trunc();
if d.hi != 0 {
return None;
}
Some((u64::from(d.mid) << 32) | u64::from(d.lo))
}
fn to_u128(&self) -> Option<u128> {
if self.is_sign_negative() {
return None;
}
let d = self.trunc();
Some((u128::from(d.hi) << 64) | (u128::from(d.mid) << 32) | u128::from(d.lo))
}
fn to_f64(&self) -> Option<f64> {
if self.scale() == 0 {
let integer = self.to_i64();
match integer {
Some(i) => Some(i as f64),
None => None,
}
} else {
let sign: f64 = if self.is_sign_negative() { -1.0 } else { 1.0 };
let mut mantissa: u128 = self.lo.into();
mantissa |= (self.mid as u128) << 32;
mantissa |= (self.hi as u128) << 64;
let scale = self.scale();
let precision: u128 = 10_u128.pow(scale);
let integral_part = mantissa / precision;
let frac_part = mantissa % precision;
let frac_f64 = (frac_part as f64) / (precision as f64);
let value = sign * ((integral_part as f64) + frac_f64);
let round_to = 10f64.powi(self.scale() as i32);
Some(value * round_to / round_to)
}
}
}
impl core::convert::TryFrom<f32> for Decimal {
type Error = crate::Error;
fn try_from(value: f32) -> Result<Self, Error> {
Self::from_f32(value).ok_or_else(|| Error::new("Failed to convert to Decimal"))
}
}
impl core::convert::TryFrom<f64> for Decimal {
type Error = crate::Error;
fn try_from(value: f64) -> Result<Self, Error> {
Self::from_f64(value).ok_or_else(|| Error::new("Failed to convert to Decimal"))
}
}
impl core::convert::TryFrom<Decimal> for f32 {
type Error = crate::Error;
fn try_from(value: Decimal) -> Result<Self, Self::Error> {
Decimal::to_f32(&value).ok_or_else(|| Error::new("Failed to convert to f32"))
}
}
impl core::convert::TryFrom<Decimal> for f64 {
type Error = crate::Error;
fn try_from(value: Decimal) -> Result<Self, Self::Error> {
Decimal::to_f64(&value).ok_or_else(|| Error::new("Failed to convert to f64"))
}
}
pub(crate) fn to_str_internal(
value: &Decimal,
append_sign: bool,
precision: Option<usize>,
) -> ArrayString<[u8; MAX_STR_BUFFER_SIZE]> {
let scale = value.scale() as usize;
let mut chars = ArrayVec::<[_; MAX_STR_BUFFER_SIZE]>::new();
let mut working = [value.lo, value.mid, value.hi];
while !is_all_zero(&working) {
let remainder = div_by_u32(&mut working, 10u32);
chars.push(char::from(b'0' + remainder as u8));
}
while scale > chars.len() {
chars.push('0');
}
let prec = match precision {
Some(prec) => prec,
None => scale,
};
let len = chars.len();
let whole_len = len - scale;
let mut rep = ArrayString::new();
if append_sign && value.is_sign_negative() {
rep.push('-');
}
for i in 0..whole_len + prec {
if i == len - scale {
if i == 0 {
rep.push('0');
}
rep.push('.');
}
if i >= len {
rep.push('0');
} else {
let c = chars[len - i - 1];
rep.push(c);
}
}
if rep.is_empty() {
rep.push('0');
}
rep
}
impl fmt::Display for Decimal {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let rep = to_str_internal(self, false, f.precision());
f.pad_integral(self.is_sign_positive(), "", rep.as_str())
}
}
impl fmt::Debug for Decimal {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fmt::Display::fmt(self, f)
}
}
fn fmt_scientific_notation(value: &Decimal, exponent_symbol: &str, f: &mut fmt::Formatter<'_>) -> fmt::Result {
#[cfg(not(feature = "std"))]
use alloc::string::ToString;
let mut exponent = -(value.scale() as isize);
let mut chars = Vec::new();
let mut working = [value.lo, value.mid, value.hi];
while !is_all_zero(&working) {
let remainder = div_by_u32(&mut working, 10u32);
chars.push(char::from(b'0' + remainder as u8));
}
let len = chars.len();
let mut rep;
if len > 1 {
if chars.iter().take(len - 1).all(|c| *c == '0') {
rep = chars.iter().skip(len - 1).collect::<String>();
} else {
chars.insert(len - 1, '.');
rep = chars.iter().rev().collect::<String>();
}
exponent += (len - 1) as isize;
} else {
rep = chars.iter().collect::<String>();
}
rep.push_str(exponent_symbol);
rep.push_str(&exponent.to_string());
f.pad_integral(value.is_sign_positive(), "", &rep)
}
impl fmt::LowerExp for Decimal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt_scientific_notation(self, "e", f)
}
}
impl fmt::UpperExp for Decimal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt_scientific_notation(self, "E", f)
}
}
impl Neg for Decimal {
type Output = Decimal;
fn neg(self) -> Decimal {
let mut copy = self;
copy.set_sign_negative(self.is_sign_positive());
copy
}
}
impl<'a> Neg for &'a Decimal {
type Output = Decimal;
fn neg(self) -> Decimal {
Decimal {
flags: flags(!self.is_sign_negative(), self.scale()),
hi: self.hi,
lo: self.lo,
mid: self.mid,
}
}
}
forward_all_binop!(impl Add for Decimal, add);
impl<'a, 'b> Add<&'b Decimal> for &'a Decimal {
type Output = Decimal;
#[inline(always)]
fn add(self, other: &Decimal) -> Decimal {
match self.checked_add(other) {
Some(sum) => sum,
None => panic!("Addition overflowed"),
}
}
}
impl AddAssign for Decimal {
fn add_assign(&mut self, other: Decimal) {
let result = self.add(other);
self.lo = result.lo;
self.mid = result.mid;
self.hi = result.hi;
self.flags = result.flags;
}
}
impl<'a> AddAssign<&'a Decimal> for Decimal {
fn add_assign(&mut self, other: &'a Decimal) {
Decimal::add_assign(self, *other)
}
}
impl<'a> AddAssign<Decimal> for &'a mut Decimal {
fn add_assign(&mut self, other: Decimal) {
Decimal::add_assign(*self, other)
}
}
impl<'a> AddAssign<&'a Decimal> for &'a mut Decimal {
fn add_assign(&mut self, other: &'a Decimal) {
Decimal::add_assign(*self, *other)
}
}
forward_all_binop!(impl Sub for Decimal, sub);
impl<'a, 'b> Sub<&'b Decimal> for &'a Decimal {
type Output = Decimal;
#[inline(always)]
fn sub(self, other: &Decimal) -> Decimal {
match self.checked_sub(other) {
Some(diff) => diff,
None => panic!("Subtraction overflowed"),
}
}
}
impl SubAssign for Decimal {
fn sub_assign(&mut self, other: Decimal) {
let result = self.sub(other);
self.lo = result.lo;
self.mid = result.mid;
self.hi = result.hi;
self.flags = result.flags;
}
}
impl<'a> SubAssign<&'a Decimal> for Decimal {
fn sub_assign(&mut self, other: &'a Decimal) {
Decimal::sub_assign(self, *other)
}
}
impl<'a> SubAssign<Decimal> for &'a mut Decimal {
fn sub_assign(&mut self, other: Decimal) {
Decimal::sub_assign(*self, other)
}
}
impl<'a> SubAssign<&'a Decimal> for &'a mut Decimal {
fn sub_assign(&mut self, other: &'a Decimal) {
Decimal::sub_assign(*self, *other)
}
}
forward_all_binop!(impl Mul for Decimal, mul);
impl<'a, 'b> Mul<&'b Decimal> for &'a Decimal {
type Output = Decimal;
#[inline]
fn mul(self, other: &Decimal) -> Decimal {
match self.checked_mul(other) {
Some(prod) => prod,
None => panic!("Multiplication overflowed"),
}
}
}
impl MulAssign for Decimal {
fn mul_assign(&mut self, other: Decimal) {
let result = self.mul(other);
self.lo = result.lo;
self.mid = result.mid;
self.hi = result.hi;
self.flags = result.flags;
}
}
impl<'a> MulAssign<&'a Decimal> for Decimal {
fn mul_assign(&mut self, other: &'a Decimal) {
Decimal::mul_assign(self, *other)
}
}
impl<'a> MulAssign<Decimal> for &'a mut Decimal {
fn mul_assign(&mut self, other: Decimal) {
Decimal::mul_assign(*self, other)
}
}
impl<'a> MulAssign<&'a Decimal> for &'a mut Decimal {
fn mul_assign(&mut self, other: &'a Decimal) {
Decimal::mul_assign(*self, *other)
}
}
forward_all_binop!(impl Div for Decimal, div);
impl<'a, 'b> Div<&'b Decimal> for &'a Decimal {
type Output = Decimal;
fn div(self, other: &Decimal) -> Decimal {
match ops::div_impl(&self, other) {
DivResult::Ok(quot) => quot,
DivResult::Overflow => panic!("Division overflowed"),
DivResult::DivByZero => panic!("Division by zero"),
}
}
}
impl DivAssign for Decimal {
fn div_assign(&mut self, other: Decimal) {
let result = self.div(other);
self.lo = result.lo;
self.mid = result.mid;
self.hi = result.hi;
self.flags = result.flags;
}
}
impl<'a> DivAssign<&'a Decimal> for Decimal {
fn div_assign(&mut self, other: &'a Decimal) {
Decimal::div_assign(self, *other)
}
}
impl<'a> DivAssign<Decimal> for &'a mut Decimal {
fn div_assign(&mut self, other: Decimal) {
Decimal::div_assign(*self, other)
}
}
impl<'a> DivAssign<&'a Decimal> for &'a mut Decimal {
fn div_assign(&mut self, other: &'a Decimal) {
Decimal::div_assign(*self, *other)
}
}
forward_all_binop!(impl Rem for Decimal, rem);
impl<'a, 'b> Rem<&'b Decimal> for &'a Decimal {
type Output = Decimal;
#[inline]
fn rem(self, other: &Decimal) -> Decimal {
match self.checked_rem(other) {
Some(rem) => rem,
None => panic!("Division by zero"),
}
}
}
impl RemAssign for Decimal {
fn rem_assign(&mut self, other: Decimal) {
let result = self.rem(other);
self.lo = result.lo;
self.mid = result.mid;
self.hi = result.hi;
self.flags = result.flags;
}
}
impl<'a> RemAssign<&'a Decimal> for Decimal {
fn rem_assign(&mut self, other: &'a Decimal) {
Decimal::rem_assign(self, *other)
}
}
impl<'a> RemAssign<Decimal> for &'a mut Decimal {
fn rem_assign(&mut self, other: Decimal) {
Decimal::rem_assign(*self, other)
}
}
impl<'a> RemAssign<&'a Decimal> for &'a mut Decimal {
fn rem_assign(&mut self, other: &'a Decimal) {
Decimal::rem_assign(*self, *other)
}
}
impl PartialEq for Decimal {
#[inline]
fn eq(&self, other: &Decimal) -> bool {
self.cmp(other) == Equal
}
}
impl Eq for Decimal {}
impl Hash for Decimal {
fn hash<H: Hasher>(&self, state: &mut H) {
let n = self.normalize();
n.lo.hash(state);
n.mid.hash(state);
n.hi.hash(state);
n.flags.hash(state);
}
}
impl PartialOrd for Decimal {
#[inline]
fn partial_cmp(&self, other: &Decimal) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Decimal {
fn cmp(&self, other: &Decimal) -> Ordering {
if self.is_zero() && other.is_zero() {
return Ordering::Equal;
}
let self_negative = self.is_sign_negative();
let other_negative = other.is_sign_negative();
if self_negative && !other_negative {
return Ordering::Less;
} else if !self_negative && other_negative {
return Ordering::Greater;
}
let left: &Decimal;
let right: &Decimal;
if self_negative && other_negative {
left = other;
right = self;
} else {
left = self;
right = other;
}
let mut left_scale = left.scale();
let mut right_scale = right.scale();
if left_scale == right_scale {
if left.hi != right.hi {
return left.hi.cmp(&right.hi);
}
if left.mid != right.mid {
return left.mid.cmp(&right.mid);
}
return left.lo.cmp(&right.lo);
}
let mut left_raw = [left.lo, left.mid, left.hi];
let mut right_raw = [right.lo, right.mid, right.hi];
rescale_to_maximum_scale(&mut left_raw, &mut left_scale, &mut right_raw, &mut right_scale);
cmp_internal(&left_raw, &right_raw)
}
}
impl Sum for Decimal {
fn sum<I: Iterator<Item = Decimal>>(iter: I) -> Self {
let mut sum = Decimal::zero();
for i in iter {
sum += i;
}
sum
}
}
impl<'a> Sum<&'a Decimal> for Decimal {
fn sum<I: Iterator<Item = &'a Decimal>>(iter: I) -> Self {
let mut sum = Decimal::zero();
for i in iter {
sum += i;
}
sum
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn it_can_rescale_to_maximum_scale() {
fn extract(value: &str) -> ([u32; 3], u32) {
let v = Decimal::from_str(value).unwrap();
([v.lo, v.mid, v.hi], v.scale())
}
let tests = &[
("1", "1", "1", "1"),
("1", "1.0", "1.0", "1.0"),
("1", "1.00000", "1.00000", "1.00000"),
("1", "1.0000000000", "1.0000000000", "1.0000000000"),
(
"1",
"1.00000000000000000000",
"1.00000000000000000000",
"1.00000000000000000000",
),
("1.1", "1.1", "1.1", "1.1"),
("1.1", "1.10000", "1.10000", "1.10000"),
("1.1", "1.1000000000", "1.1000000000", "1.1000000000"),
(
"1.1",
"1.10000000000000000000",
"1.10000000000000000000",
"1.10000000000000000000",
),
(
"0.6386554621848739495798319328",
"11.815126050420168067226890757",
"0.638655462184873949579831933",
"11.815126050420168067226890757",
),
(
"0.0872727272727272727272727272",
"843.65000000",
"0.0872727272727272727272727",
"843.6500000000000000000000000",
),
];
for &(left_raw, right_raw, expected_left, expected_right) in tests {
let (expected_left, expected_lscale) = extract(expected_left);
let (expected_right, expected_rscale) = extract(expected_right);
let (mut left, mut left_scale) = extract(left_raw);
let (mut right, mut right_scale) = extract(right_raw);
rescale_to_maximum_scale(&mut left, &mut left_scale, &mut right, &mut right_scale);
assert_eq!(left, expected_left);
assert_eq!(left_scale, expected_lscale);
assert_eq!(right, expected_right);
assert_eq!(right_scale, expected_rscale);
let (mut left, mut left_scale) = extract(left_raw);
let (mut right, mut right_scale) = extract(right_raw);
rescale_to_maximum_scale(&mut right, &mut right_scale, &mut left, &mut left_scale);
assert_eq!(left, expected_left);
assert_eq!(left_scale, expected_lscale);
assert_eq!(right, expected_right);
assert_eq!(right_scale, expected_rscale);
}
}
#[test]
fn it_can_rescale_internal() {
fn extract(value: &str) -> ([u32; 3], u32) {
let v = Decimal::from_str(value).unwrap();
([v.lo, v.mid, v.hi], v.scale())
}
let tests = &[
("1", 0, "1"),
("1", 1, "1.0"),
("1", 5, "1.00000"),
("1", 10, "1.0000000000"),
("1", 20, "1.00000000000000000000"),
("0.6386554621848739495798319328", 27, "0.638655462184873949579831933"),
(
"843.65000000",
25,
"843.6500000000000000000000000",
),
(
"843.65000000",
30,
"843.6500000000000000000000000000",
),
];
for &(value_raw, new_scale, expected_value) in tests {
let (expected_value, _) = extract(expected_value);
let (mut value, mut value_scale) = extract(value_raw);
rescale_internal(&mut value, &mut value_scale, new_scale);
assert_eq!(value, expected_value);
}
}
#[test]
fn test_shl1_internal() {
struct TestCase {
given: [u32; 3],
given_carry: u32,
expected: [u32; 3],
expected_carry: u32,
}
let tests = [
TestCase {
given: [1, 0, 0],
given_carry: 0,
expected: [2, 0, 0],
expected_carry: 0,
},
TestCase {
given: [1, 0, 2147483648],
given_carry: 1,
expected: [3, 0, 0],
expected_carry: 1,
},
];
for case in &tests {
let mut test = [case.given[0], case.given[1], case.given[2]];
let carry = shl1_internal(&mut test, case.given_carry);
assert_eq!(
test, case.expected,
"Bits: {:?} << 1 | {}",
case.given, case.given_carry
);
assert_eq!(
carry, case.expected_carry,
"Carry: {:?} << 1 | {}",
case.given, case.given_carry
)
}
}
}