use crate::Error;
use num::{FromPrimitive, One, ToPrimitive, Zero};
#[cfg(not(feature = "const_fn"))]
use lazy_static::lazy_static;
use std::{
cmp::{Ordering::Equal, *},
fmt,
hash::{Hash, Hasher},
iter::{repeat, Sum},
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign},
str::FromStr,
};
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_PRECISION: u32 = 28;
static ONE_INTERNAL_REPR: [u32; 3] = [1, 0, 0];
#[cfg(not(feature = "const_fn"))]
lazy_static! {
static ref MIN: Decimal = Decimal {
flags: 2_147_483_648,
lo: 4_294_967_295,
mid: 4_294_967_295,
hi: 4_294_967_295
};
static ref MAX: Decimal = Decimal {
flags: 0,
lo: 4_294_967_295,
mid: 4_294_967_295,
hi: 4_294_967_295
};
}
#[cfg(feature = "const_fn")]
const MIN: Decimal = Decimal {
flags: 2_147_483_648,
lo: 4_294_967_295,
mid: 4_294_967_295,
hi: 4_294_967_295,
};
#[cfg(feature = "const_fn")]
const MAX: Decimal = Decimal {
flags: 0,
lo: 4_294_967_295,
mid: 4_294_967_295,
hi: 4_294_967_295,
};
static 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)]
static 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)]
pub struct Decimal {
flags: u32,
hi: u32,
lo: u32,
mid: u32,
}
pub enum RoundingStrategy {
BankersRounding,
RoundHalfUp,
RoundHalfDown,
}
#[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 {
return Decimal {
flags: flags | SIGN_MASK,
hi: 0,
lo: (num.abs() as u64 & U32_MASK) as u32,
mid: ((num.abs() as u64 >> 32) & U32_MASK) as u32,
};
}
Decimal {
flags: flags,
hi: 0,
lo: (num as u64 & U32_MASK) as u32,
mid: ((num as u64 >> 32) & U32_MASK) as u32,
}
}
#[cfg(feature = "const_fn")]
pub const fn from_parts(lo: u32, mid: u32, hi: u32, negative: bool, scale: u32) -> Decimal {
Decimal {
lo: lo,
mid: mid,
hi: hi,
flags: flags(negative, scale),
}
}
#[cfg(not(feature = "const_fn"))]
pub fn from_parts(lo: u32, mid: u32, hi: u32, negative: bool, scale: u32) -> Decimal {
Decimal {
lo: lo,
mid: mid,
hi: hi,
flags: flags(negative, scale),
}
}
pub fn from_scientific(value: &str) -> Result<Decimal, Error> {
let err = Error::new("Failed to parse");
let mut split = value.splitn(2, 'e');
let base = split.next().ok_or(err.clone())?;
let mut scale = split.next().ok_or(err.clone())?.to_string();
let mut ret = Decimal::from_str(base)?;
if scale.contains('-') {
scale.remove(0);
let scale: u32 = scale.as_str().parse().map_err(move |_| err.clone())?;
let current_scale = ret.scale();
ret.set_scale(current_scale + scale)?;
} else {
if scale.contains('+') {
scale.remove(0);
}
let pow: u32 = scale.as_str().parse().map_err(move |_| err.clone())?;
ret *= Decimal::from_i64(10_i64.pow(pow)).unwrap();
ret = ret.normalize();
}
Ok(ret)
}
#[inline]
#[cfg(feature = "const_fn")]
pub const fn scale(&self) -> u32 {
((self.flags & SCALE_MASK) >> SCALE_SHIFT) as u32
}
#[inline]
#[cfg(not(feature = "const_fn"))]
pub fn scale(&self) -> u32 {
((self.flags & SCALE_MASK) >> SCALE_SHIFT) as u32
}
pub fn set_sign(&mut self, positive: bool) {
if positive {
self.flags &= UNSIGN_MASK;
} else {
self.flags |= SIGN_MASK;
}
}
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(())
}
#[cfg(feature = "const_fn")]
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,
]
}
#[cfg(not(feature = "const_fn"))]
pub 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,
]
}
#[cfg(feature = "const_fn")]
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,
}
}
#[cfg(not(feature = "const_fn"))]
pub 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)]
#[cfg(feature = "const_fn")]
pub const fn is_sign_negative(&self) -> bool {
self.flags & SIGN_MASK > 0
}
#[inline(always)]
#[cfg(not(feature = "const_fn"))]
pub fn is_sign_negative(&self) -> bool {
self.flags & SIGN_MASK > 0
}
#[inline(always)]
#[cfg(feature = "const_fn")]
pub const fn is_sign_positive(&self) -> bool {
self.flags & SIGN_MASK == 0
}
#[inline(always)]
#[cfg(not(feature = "const_fn"))]
pub fn is_sign_positive(&self) -> bool {
self.flags & SIGN_MASK == 0
}
#[cfg(feature = "const_fn")]
pub const fn min_value() -> Decimal {
MIN
}
#[cfg(not(feature = "const_fn"))]
pub fn min_value() -> Decimal {
*MIN
}
#[cfg(feature = "const_fn")]
pub const fn max_value() -> Decimal {
MAX
}
#[cfg(not(feature = "const_fn"))]
pub 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(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 - Decimal::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() + Decimal::one()
} else {
self.trunc()
}
}
pub fn normalize(&self) -> Decimal {
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_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);
match strategy {
RoundingStrategy::BankersRounding => {
match order {
Ordering::Equal => {
if (value[0] & 1) == 1 {
add_internal(&mut value, &ONE_INTERNAL_REPR);
}
}
Ordering::Greater => {
add_internal(&mut value, &ONE_INTERNAL_REPR);
}
_ => {}
}
}
RoundingStrategy::RoundHalfDown => match order {
Ordering::Greater => {
add_internal(&mut value, &ONE_INTERNAL_REPR);
}
_ => {}
},
RoundingStrategy::RoundHalfUp => {
match order {
Ordering::Equal => {
add_internal(&mut value, &ONE_INTERNAL_REPR);
}
Ordering::Greater => {
add_internal(&mut value, &ONE_INTERNAL_REPR);
}
_ => {}
}
}
}
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::BankersRounding)
}
#[cfg(feature = "const_fn")]
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,
}
}
#[cfg(not(feature = "const_fn"))]
pub 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) fn mantissa_array3(&self) -> [u32; 3] {
[self.lo, self.mid, self.hi]
}
#[inline(always)]
pub(crate) 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;
shl_internal(bits, 1, 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_internal(bits, &ONE_INTERNAL_REPR);
}
}
if is64 {
while exponent10 < 0 && (bits[2] != 0 || (bits[1] & 0xFFE0_0000) != 0) {
let rem10 = div_by_u32(bits, 10);
exponent10 += 1;
if rem10 >= 5 {
add_internal(bits, &ONE_INTERNAL_REPR);
}
}
} 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_internal(bits, &ONE_INTERNAL_REPR);
}
}
}
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(&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 = add3_internal(&mut my, &ot);
} else {
let cmp = cmp_internal(&my, &ot);
match cmp {
Ordering::Less => {
negative = other_negative;
sub3_internal(&mut ot, &my);
my[0] = ot[0];
my[1] = ot[1];
my[2] = ot[2];
}
Ordering::Greater => {
negative = my_negative;
sub3_internal(&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, 2500000000);
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 self.div_impl(other) {
DivResult::Ok(quot) => Some(quot),
DivResult::Overflow => None,
DivResult::DivByZero => None,
}
}
fn div_impl(self, other: Decimal) -> DivResult {
if other.is_zero() {
return DivResult::DivByZero;
}
if self.is_zero() {
return DivResult::Ok(Decimal::zero());
}
let dividend = [self.lo, self.mid, self.hi];
let divisor = [other.lo, other.mid, other.hi];
let mut quotient = [0u32, 0u32, 0u32];
let mut quotient_scale: i32 = self.scale() as i32 - other.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 = self.is_sign_negative() ^ other.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),
})
}
pub fn checked_rem(self, other: Decimal) -> Option<Decimal> {
if other.is_zero() {
return None;
}
if self.is_zero() {
return Some(Decimal::zero());
}
let mut working_quotient = [self.lo, self.mid, self.hi, 0u32];
let mut working_remainder = [0u32, 0u32, 0u32, 0u32];
let divisor = [other.lo, other.mid, other.hi];
div_internal(&mut working_quotient, &mut working_remainder, &divisor);
Some(Decimal {
lo: working_remainder[0],
mid: working_remainder[1],
hi: working_remainder[2],
flags: if self.is_sign_negative() { SIGN_MASK } else { 0 },
})
}
}
impl Default for Decimal {
fn default() -> Self {
Self::zero()
}
}
enum DivResult {
Ok(Decimal),
Overflow,
DivByZero,
}
#[inline]
#[cfg(feature = "const_fn")]
const fn flags(neg: bool, scale: u32) -> u32 {
(scale << SCALE_SHIFT) | ((neg as u32) << SIGN_SHIFT)
}
#[inline]
#[cfg(not(feature = "const_fn"))]
fn flags(neg: bool, scale: u32) -> u32 {
(scale << SCALE_SHIFT) | ((neg as u32) << SIGN_SHIFT)
}
#[inline(always)]
fn rescale(left: &mut [u32; 3], left_scale: &mut u32, right: &mut [u32; 3], right_scale: &mut u32) {
if left_scale == right_scale {
return;
}
enum Target {
Left,
Right,
}
let target;
let mut diff;
let my;
let other;
if left_scale > right_scale {
diff = *left_scale - *right_scale;
my = right;
other = left;
target = Target::Left;
} else {
diff = *right_scale - *left_scale;
my = left;
other = right;
target = Target::Right;
};
let mut working = [my[0], my[1], my[2]];
while diff > 0 && mul_by_10(&mut working) == 0 {
my.copy_from_slice(&working);
diff -= 1;
}
match target {
Target::Left => *right_scale = *left_scale,
Target::Right => *left_scale = *right_scale,
}
if diff == 0 {
return;
}
let mut remainder = 0;
while diff > 0 && !is_all_zero(other) {
diff -= 1;
*left_scale -= 1;
*right_scale -= 1;
remainder = div_by_10(other);
}
if remainder >= 5 {
for part in other.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;
}
}
}
}
#[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];
}
}
#[inline]
fn u64_to_array(value: u64) -> [u32; 2] {
[(value & U32_MASK) as u32, (value >> 32 & U32_MASK) as u32]
}
fn add_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 add3_internal(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
}
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_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
}
#[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 sub3_internal(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_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_internal(&mut complement, &[1u32]);
remainder.iter_mut().for_each(|x| *x = 0);
let mut blocks_to_process = 0;
while blocks_to_process < 4 && quotient[3] == 0 {
shl_internal(quotient, 32, 0);
blocks_to_process += 1;
}
let mut block = blocks_to_process << 5;
let mut working = [0u32, 0u32, 0u32, 0u32];
while block < 128 {
let carry = shl_internal(quotient, 1, 0);
shl_internal(remainder, 1, carry);
working.copy_from_slice(remainder);
add_internal(&mut working, &complement);
if (working[3] & 0x8000_0000) == 0 {
remainder.copy_from_slice(&working);
quotient[0] |= 1;
}
block += 1;
}
}
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 shl_internal(bits: &mut [u32], shift: u32, carry: u32) -> u32 {
let mut shift = shift;
while shift >= 32 {
for i in (1..bits.len()).rev() {
bits[i] = bits[i - 1];
}
bits[0] = 0;
shift -= 32;
}
if shift > 0 {
let mut carry = carry;
for part in bits.iter_mut() {
let b = *part >> (32 - shift);
*part = (*part << shift) | carry;
carry = b;
}
carry
} else {
0
}
}
#[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 From<$T> for Decimal {
#[inline]
fn from(t: $T) -> Decimal {
$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);
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 {
Decimal {
flags: 0,
hi: 0,
lo: 1,
mid: 0,
}
}
}
impl FromStr for Decimal {
type Err = Error;
fn from_str(value: &str) -> Result<Decimal, Self::Err> {
if value.is_empty() {
return Err(Error::new("Invalid decimal: empty"));
}
let mut offset = 0;
let mut len = value.len();
let bytes: Vec<u8> = value.bytes().collect();
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 = Vec::new();
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 > MAX_PRECISION {
if offset < bytes.len() {
let next_byte = bytes[offset];
match next_byte {
b'0'...b'9' => {
let digit = u32::from(next_byte - b'0');
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;
}
}
}
b'_' => {}
b'.' => {
if digits_before_dot >= 0 {
return Err(Error::new("Invalid decimal: two decimal points"));
}
}
_ => return Err(Error::new("Invalid decimal: unknown character")),
}
}
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 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, 10u32);
if overflow > 0 {
if i + 1 < len {
return Err(Error::new("Invalid decimal: overflow from too many digits"));
}
if *digit >= 5 {
let carry = add_internal(&mut data, &ONE_INTERNAL_REPR);
if carry > 0 {
return Err(Error::new("Invalid decimal: overflow when rounding"));
}
}
scale -= (len - i) as u32;
break;
} else {
data[0] = tmp[0];
data[1] = tmp[1];
data[2] = tmp[2];
let carry = add_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 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_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_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(false);
}
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(false);
}
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_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_f64(&self) -> Option<f64> {
if self.scale() == 0 {
let integer = self.to_i64();
match integer {
Some(i) => Some(i as f64),
None => None,
}
} else {
match self.to_string().parse::<f64>() {
Ok(s) => Some(s),
Err(_) => None,
}
}
}
}
impl fmt::Display for Decimal {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let mut scale = self.scale() as usize;
let mut chars = Vec::new();
let mut working = [self.lo, self.mid, self.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 mut rep = chars.iter().rev().collect::<String>();
let len = rep.len();
if let Some(n_dp) = f.precision() {
if n_dp < scale {
rep.truncate(len - scale + n_dp)
} else {
let zeros = repeat("0").take(n_dp - scale).collect::<String>();
rep.push_str(&zeros[..]);
}
scale = n_dp;
}
let len = rep.len();
if scale > 0 {
if scale > len {
let mut new_rep = String::new();
let zeros = repeat("0").take(scale as usize - len).collect::<String>();
new_rep.push_str("0.");
new_rep.push_str(&zeros[..]);
new_rep.push_str(&rep[..]);
rep = new_rep;
} else if scale == len {
rep.insert(0, '.');
rep.insert(0, '0');
} else {
rep.insert(len - scale as usize, '.');
}
} else if rep.is_empty() {
rep.insert(0, '0');
}
f.pad_integral(self.is_sign_positive(), "", &rep)
}
}
impl fmt::Debug for Decimal {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fmt::Display::fmt(self, f)
}
}
impl Neg for Decimal {
type Output = Decimal;
fn neg(self) -> Decimal {
-&self
}
}
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 self.div_impl(*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) {
self.lo.hash(state);
self.mid.hash(state);
self.hi.hash(state);
self.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 {
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(&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;
}
return sum;
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn it_can_rescale() {
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(&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(&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);
}
}
}