use crate::constants::{
MAX_I128_REPR, MAX_PRECISION, POWERS_10, SCALE_MASK, SCALE_SHIFT, SIGN_MASK, SIGN_SHIFT, U32_MASK, U8_MASK,
UNSIGN_MASK,
};
use crate::ops;
use crate::Error;
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 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,
};
const ZERO: Decimal = Decimal {
flags: 0,
lo: 0,
mid: 0,
hi: 0,
};
const ONE: Decimal = Decimal {
flags: 0,
lo: 1,
mid: 0,
hi: 0,
};
#[derive(Clone, Copy, Debug)]
pub struct UnpackedDecimal {
pub 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 const MIN: Decimal = MIN;
pub const MAX: Decimal = MAX;
pub const ZERO: Decimal = ZERO;
pub const ONE: Decimal = ONE;
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(
if lo == 0 && mid == 0 && hi == 0 {
false
} else {
negative
},
scale % (MAX_PRECISION + 1),
),
}
}
pub(crate) const fn from_parts_raw(lo: u32, mid: u32, hi: u32, flags: u32) -> Decimal {
if lo == 0 && mid == 0 && hi == 0 {
Decimal {
lo,
mid,
hi,
flags: flags & SCALE_MASK,
}
} else {
Decimal { lo, mid, hi, flags }
}
}
pub fn from_scientific(value: &str) -> Result<Decimal, Error> {
let err_msg = "Failed to parse";
let mut split = value.splitn(2, |c| c == 'e' || c == 'E');
let base = split.next().ok_or_else(|| Error::new(err_msg))?;
let exp = split.next().ok_or_else(|| Error::new(err_msg))?;
let mut ret = Decimal::from_str(base)?;
let current_scale = ret.scale();
if let Some(stripped) = exp.strip_prefix('-') {
let exp: u32 = stripped.parse().map_err(|_| Error::new(err_msg))?;
ret.set_scale(current_scale + exp)?;
} else {
let exp: u32 = exp.parse().map_err(|_| Error::new(err_msg))?;
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
}
}
pub const fn is_zero(&self) -> bool {
self.lo == 0 && self.mid == 0 && self.hi == 0
}
#[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();
ops::array::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
}
#[deprecated(since = "1.12.0", note = "Use the associated constant Decimal::MIN")]
pub const fn min_value() -> Decimal {
MIN
}
#[deprecated(since = "1.12.0", note = "Use the associated constant Decimal::MAX")]
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 {
ops::array::div_by_u32(&mut working, POWERS_10[scale as usize]);
break;
} else {
ops::array::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 ops::array::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 {
ops::array::div_by_u32(&mut value, POWERS_10[value_scale as usize]);
value_scale = 0;
} else {
ops::array::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 {
ops::array::div_by_u32(&mut offset, POWERS_10[diff as usize]);
break;
} else {
ops::array::div_by_u32(&mut offset, POWERS_10[9]);
diff -= 9;
}
}
let mut diff = old_scale - dp;
while diff > 0 {
if diff < 10 {
ops::array::mul_by_u32(&mut offset, POWERS_10[diff as usize]);
break;
} else {
ops::array::mul_by_u32(&mut offset, POWERS_10[9]);
diff -= 9;
}
}
let mut decimal_portion = [self.lo, self.mid, self.hi];
ops::array::sub_by_internal(&mut decimal_portion, &offset);
let mut cap = [5, 0, 0];
for _ in 0..(old_scale - dp - 1) {
ops::array::mul_by_u32(&mut cap, 10);
}
let order = ops::array::cmp_internal(&decimal_portion, &cap);
#[allow(deprecated)]
match strategy {
RoundingStrategy::BankersRounding | RoundingStrategy::MidpointNearestEven => {
match order {
Ordering::Equal => {
if (value[0] & 1) == 1 {
ops::array::add_one_internal(&mut value);
}
}
Ordering::Greater => {
ops::array::add_one_internal(&mut value);
}
_ => {}
}
}
RoundingStrategy::RoundHalfDown | RoundingStrategy::MidpointTowardZero => {
if let Ordering::Greater = order {
ops::array::add_one_internal(&mut value);
}
}
RoundingStrategy::RoundHalfUp | RoundingStrategy::MidpointAwayFromZero => {
match order {
Ordering::Equal => {
ops::array::add_one_internal(&mut value);
}
Ordering::Greater => {
ops::array::add_one_internal(&mut value);
}
_ => {}
}
}
RoundingStrategy::RoundUp | RoundingStrategy::AwayFromZero => {
if !ops::array::is_all_zero(&decimal_portion) {
ops::array::add_one_internal(&mut value);
}
}
RoundingStrategy::ToPositiveInfinity => {
if !negative && !ops::array::is_all_zero(&decimal_portion) {
ops::array::add_one_internal(&mut value);
}
}
RoundingStrategy::ToNegativeInfinity => {
if negative && !ops::array::is_all_zero(&decimal_portion) {
ops::array::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 {
negative: self.is_sign_negative(),
scale: self.scale(),
hi: self.hi,
lo: self.lo,
mid: self.mid,
}
}
#[inline(always)]
pub(crate) const fn lo(&self) -> u32 {
self.lo
}
#[inline(always)]
pub(crate) const fn mid(&self) -> u32 {
self.mid
}
#[inline(always)]
pub(crate) const fn hi(&self) -> u32 {
self.hi
}
#[inline(always)]
pub(crate) const fn flags(&self) -> u32 {
self.flags
}
#[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 ops::array::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;
ops::array::shl1_internal(bits, 0);
} else {
exponent5 += 1;
ops::array::div_by_u32(bits, 5);
}
}
while exponent10 > 0 {
if ops::array::mul_by_u32(bits, 10) == 0 {
exponent10 -= 1;
} else {
return None;
}
}
while exponent10 < -(MAX_PRECISION as i32) {
let rem10 = ops::array::div_by_u32(bits, 10);
exponent10 += 1;
if ops::array::is_all_zero(bits) {
exponent10 = 0;
} else if rem10 >= 5 {
ops::array::add_one_internal(bits);
}
}
if is64 {
while exponent10 < 0 && (bits[2] != 0 || (bits[1] & 0xFFF0_0000) != 0) {
let rem10 = ops::array::div_by_u32(bits, 10);
exponent10 += 1;
if rem10 >= 5 {
ops::array::add_one_internal(bits);
}
}
} else {
while exponent10 < 0 && ((bits[0] & 0xFF00_0000) != 0 || bits[1] != 0 || bits[2] != 0) {
let rem10 = ops::array::div_by_u32(bits, 10);
exponent10 += 1;
if rem10 >= 5 {
ops::array::add_one_internal(bits);
}
}
}
while exponent10 < 0 {
let mut temp = [bits[0], bits[1], bits[2]];
let remainder = ops::array::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> {
match ops::add_impl(&self, &other) {
CalculationResult::Ok(result) => Some(result),
CalculationResult::Overflow => None,
_ => None,
}
}
#[inline(always)]
pub fn checked_sub(self, other: Decimal) -> Option<Decimal> {
match ops::sub_impl(&self, &other) {
CalculationResult::Ok(result) => Some(result),
CalculationResult::Overflow => None,
_ => None,
}
}
#[inline]
pub fn checked_mul(self, other: Decimal) -> Option<Decimal> {
match ops::mul_impl(&self, &other) {
CalculationResult::Ok(result) => Some(result),
CalculationResult::Overflow => None,
_ => None,
}
}
pub fn checked_div(self, other: Decimal) -> Option<Decimal> {
match ops::div_impl(&self, &other) {
CalculationResult::Ok(quot) => Some(quot),
CalculationResult::Overflow => None,
CalculationResult::DivByZero => None,
}
}
pub fn checked_rem(self, other: Decimal) -> Option<Decimal> {
match ops::rem_impl(&self, &other) {
CalculationResult::Ok(quot) => Some(quot),
CalculationResult::Overflow => None,
CalculationResult::DivByZero => None,
}
}
pub fn from_str_radix(str: &str, radix: u32) -> Result<Self, crate::Error> {
if radix == 10 {
crate::str::parse_str_radix_10(str)
} else {
crate::str::parse_str_radix_n(str, radix)
}
}
}
impl Default for Decimal {
fn default() -> Self {
ZERO
}
}
pub(crate) enum CalculationResult {
Ok(Decimal),
Overflow,
DivByZero,
}
#[inline]
const fn flags(neg: bool, scale: u32) -> u32 {
(scale << SCALE_SHIFT) | ((neg as u32) << SIGN_SHIFT)
}
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 {
ZERO
}
fn is_zero(&self) -> bool {
self.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 {
ZERO
} else {
self.abs()
}
}
fn signum(&self) -> Self {
if self.is_zero() {
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)
}
}
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> {
crate::str::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 = 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 = 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"))
}
}
impl fmt::Display for Decimal {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let rep = crate::str::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)
}
}
impl fmt::LowerExp for Decimal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
crate::str::fmt_scientific_notation(self, "e", f)
}
}
impl fmt::UpperExp for Decimal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
crate::str::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 ops::add_impl(&self, other) {
CalculationResult::Ok(sum) => sum,
_ => 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 ops::sub_impl(&self, other) {
CalculationResult::Ok(sum) => sum,
_ => 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 ops::mul_impl(&self, other) {
CalculationResult::Ok(prod) => prod,
_ => 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) {
CalculationResult::Ok(quot) => quot,
CalculationResult::Overflow => panic!("Division overflowed"),
CalculationResult::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 ops::rem_impl(&self, other) {
CalculationResult::Ok(rem) => rem,
CalculationResult::Overflow => panic!("Division overflowed"),
CalculationResult::DivByZero => 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 {
ops::cmp_impl(self, other)
}
}
impl Sum for Decimal {
fn sum<I: Iterator<Item = Decimal>>(iter: I) -> Self {
let mut sum = 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 = ZERO;
for i in iter {
sum += i;
}
sum
}
}