use crate::Error; use num_traits::{FromPrimitive, Num, One, Signed, ToPrimitive, Zero}; #[cfg(feature = "diesel")] use diesel::sql_types::Numeric; 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, }; // Sign mask for the flags field. A value of zero in this bit indicates a // positive Decimal value, and a value of one in this bit indicates a // negative Decimal value. const SIGN_MASK: u32 = 0x8000_0000; const UNSIGN_MASK: u32 = 0x4FFF_FFFF; // Scale mask for the flags field. This byte in the flags field contains // the power of 10 to divide the Decimal value by. The scale byte must // contain a value between 0 and 28 inclusive. const SCALE_MASK: u32 = 0x00FF_0000; const U8_MASK: u32 = 0x0000_00FF; const U32_MASK: u64 = 0xFFFF_FFFF; // Number of bits scale is shifted by. const SCALE_SHIFT: u32 = 16; // Number of bits sign is shifted by. const SIGN_SHIFT: u32 = 31; // The maximum supported precision pub(crate) const MAX_PRECISION: u32 = 28; // 79,228,162,514,264,337,593,543,950,335 const MAX_I128_REPR: i128 = 0x0000_0000_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF; static ONE_INTERNAL_REPR: [u32; 3] = [1, 0, 0]; 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, }; // Fast access for 10^n where n is 0-9 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, ]; // Fast access for 10^n where n is 10-19 #[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, ]; /// `UnpackedDecimal` contains unpacked representation of `Decimal` where each component /// of decimal-format stored in it's own field #[derive(Clone, Copy, Debug)] pub struct UnpackedDecimal { pub is_negative: bool, pub scale: u32, pub hi: u32, pub mid: u32, pub lo: u32, } /// `Decimal` represents a 128 bit representation of a fixed-precision decimal number. /// The finite set of values of type `Decimal` are of the form m / 10e, /// where m is an integer such that -296 < m < 296, and e is an integer /// between 0 and 28 inclusive. #[derive(Clone, Copy)] #[cfg_attr(feature = "diesel", derive(FromSqlRow, AsExpression), sql_type = "Numeric")] pub struct Decimal { // Bits 0-15: unused // Bits 16-23: Contains "e", a value between 0-28 that indicates the scale // Bits 24-30: unused // Bit 31: the sign of the Decimal value, 0 meaning positive and 1 meaning negative. flags: u32, // The lo, mid, hi, and flags fields contain the representation of the // Decimal value as a 96-bit integer. hi: u32, lo: u32, mid: u32, } /// `RoundingStrategy` represents the different strategies that can be used by /// `round_dp_with_strategy`. /// /// `RoundingStrategy::BankersRounding` - Rounds toward the nearest even number, e.g. 6.5 -> 6, 7.5 -> 8 /// `RoundingStrategy::RoundHalfUp` - Rounds up if the value >= 5, otherwise rounds down, e.g. 6.5 -> 7, /// `RoundingStrategy::RoundHalfDown` - Rounds down if the value =< 5, otherwise rounds up, e.g. /// 6.5 -> 6, 6.51 -> 7 /// 1.4999999 -> 1 /// `RoundingStrategy::RoundDown` - Always round down. /// `RoundingStrategy::RoundUp` - Always round up. pub enum RoundingStrategy { BankersRounding, RoundHalfUp, RoundHalfDown, RoundDown, RoundUp, } #[allow(dead_code)] impl Decimal { /// Returns a `Decimal` with a 64 bit `m` representation and corresponding `e` scale. /// /// # Arguments /// /// * `num` - An i64 that represents the `m` portion of the decimal number /// * `scale` - A u32 representing the `e` portion of the decimal number. /// /// # Example /// /// ``` /// use rust_decimal::Decimal; /// /// let pi = Decimal::new(3141, 3); /// assert_eq!(pi.to_string(), "3.141"); /// ``` 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, } } /// Creates a `Decimal` using a 128 bit signed `m` representation and corresponding `e` scale. /// /// # Arguments /// /// * `num` - An i128 that represents the `m` portion of the decimal number /// * `scale` - A u32 representing the `e` portion of the decimal number. /// /// # Example /// /// ``` /// use rust_decimal::Decimal; /// /// let pi = Decimal::from_i128_with_scale(3141i128, 3); /// assert_eq!(pi.to_string(), "3.141"); /// ``` 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, } } /// Returns a `Decimal` using the instances constituent parts. /// /// # Arguments /// /// * `lo` - The low 32 bits of a 96-bit integer. /// * `mid` - The middle 32 bits of a 96-bit integer. /// * `hi` - The high 32 bits of a 96-bit integer. /// * `negative` - `true` to indicate a negative number. /// * `scale` - A power of 10 ranging from 0 to 28. /// /// # Example /// /// ``` /// use rust_decimal::Decimal; /// /// let pi = Decimal::from_parts(1102470952, 185874565, 1703060790, false, 28); /// assert_eq!(pi.to_string(), "3.1415926535897932384626433832"); /// ``` pub const fn from_parts(lo: u32, mid: u32, hi: u32, negative: bool, scale: u32) -> Decimal { Decimal { lo, mid, hi, flags: flags(negative, scale), } } /// Returns a `Result` which if successful contains the `Decimal` constitution of /// the scientific notation provided by `value`. /// /// # Arguments /// /// * `value` - The scientific notation of the `Decimal`. /// /// # Example /// /// ``` /// use rust_decimal::Decimal; /// /// let value = Decimal::from_scientific("9.7e-7").unwrap(); /// assert_eq!(value.to_string(), "0.00000097"); /// ``` pub fn from_scientific(value: &str) -> Result { 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) } /// Returns the scale of the decimal number, otherwise known as `e`. /// /// # Example /// /// ``` /// use rust_decimal::Decimal; /// /// let num = Decimal::new(1234, 3); /// assert_eq!(num.scale(), 3u32); /// ``` #[inline] pub const fn scale(&self) -> u32 { ((self.flags & SCALE_MASK) >> SCALE_SHIFT) as u32 } /// An optimized method for changing the sign of a decimal number. /// /// # Arguments /// /// * `positive`: true if the resulting decimal should be positive. /// /// # Example /// /// ``` /// use rust_decimal::Decimal; /// /// let mut one = Decimal::new(1, 0); /// one.set_sign(false); /// assert_eq!(one.to_string(), "-1"); /// ``` #[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); } /// An optimized method for changing the sign of a decimal number. /// /// # Arguments /// /// * `positive`: true if the resulting decimal should be positive. /// /// # Example /// /// ``` /// use rust_decimal::Decimal; /// /// let mut one = Decimal::new(1, 0); /// one.set_sign_positive(false); /// assert_eq!(one.to_string(), "-1"); /// ``` #[inline(always)] pub fn set_sign_positive(&mut self, positive: bool) { if positive { self.flags &= UNSIGN_MASK; } else { self.flags |= SIGN_MASK; } } /// An optimized method for changing the sign of a decimal number. /// /// # Arguments /// /// * `negative`: true if the resulting decimal should be negative. /// /// # Example /// /// ``` /// use rust_decimal::Decimal; /// /// let mut one = Decimal::new(1, 0); /// one.set_sign_negative(true); /// assert_eq!(one.to_string(), "-1"); /// ``` #[inline(always)] pub fn set_sign_negative(&mut self, negative: bool) { self.set_sign_positive(!negative); } /// An optimized method for changing the scale of a decimal number. /// /// # Arguments /// /// * `scale`: the new scale of the number /// /// # Example /// /// ``` /// use rust_decimal::Decimal; /// /// let mut one = Decimal::new(1, 0); /// one.set_scale(5); /// assert_eq!(one.to_string(), "0.00001"); /// ``` 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(()) } /// Modifies the `Decimal` to the given scale, attempting to do so without changing the /// underlying number itself. /// /// Note that setting the scale to something less then the current `Decimal`s scale will /// cause the newly created `Decimal` to have some rounding. /// Scales greater than the maximum precision supported by `Decimal` will be automatically /// rounded to `Decimal::MAX_PRECISION`. /// Rounding leverages the half up strategy. /// /// # Arguments /// * `scale`: The scale to use for the new `Decimal` number. /// /// # Example /// /// ``` /// use rust_decimal::Decimal; /// /// let mut number = Decimal::new(1_123, 3); /// number.rescale(6); /// assert_eq!(number, Decimal::new(1_123_000, 6)); /// let mut round = Decimal::new(145, 2); /// round.rescale(1); /// assert_eq!(round, Decimal::new(15, 1)); /// ``` 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); } /// Returns a serialized version of the decimal number. /// The resulting byte array will have the following representation: /// /// * Bytes 1-4: flags /// * Bytes 5-8: lo portion of `m` /// * Bytes 9-12: mid portion of `m` /// * Bytes 13-16: high portion of `m` 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, ] } /// Deserializes the given bytes into a decimal number. /// The deserialized byte representation must be 16 bytes and adhere to the followign convention: /// /// * Bytes 1-4: flags /// * Bytes 5-8: lo portion of `m` /// * Bytes 9-12: mid portion of `m` /// * Bytes 13-16: high portion of `m` 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, } } /// Returns `true` if the decimal is negative. #[deprecated(since = "0.6.3", note = "please use `is_sign_negative` instead")] pub fn is_negative(&self) -> bool { self.is_sign_negative() } /// Returns `true` if the decimal is positive. #[deprecated(since = "0.6.3", note = "please use `is_sign_positive` instead")] pub fn is_positive(&self) -> bool { self.is_sign_positive() } /// Returns `true` if the sign bit of the decimal is negative. #[inline(always)] pub const fn is_sign_negative(&self) -> bool { self.flags & SIGN_MASK > 0 } /// Returns `true` if the sign bit of the decimal is positive. #[inline(always)] pub const fn is_sign_positive(&self) -> bool { self.flags & SIGN_MASK == 0 } /// Returns the minimum possible number that `Decimal` can represent. pub const fn min_value() -> Decimal { MIN } /// Returns the maximum possible number that `Decimal` can represent. pub const fn max_value() -> Decimal { MAX } /// Returns a new `Decimal` integral with no fractional portion. /// This is a true truncation whereby no rounding is performed. /// /// # Example /// /// ``` /// use rust_decimal::Decimal; /// /// let pi = Decimal::new(3141, 3); /// let trunc = Decimal::new(3, 0); /// // note that it returns a decimal /// assert_eq!(pi.trunc(), trunc); /// ``` pub fn trunc(&self) -> Decimal { let mut scale = self.scale(); if scale == 0 { // Nothing to do return *self; } let mut working = [self.lo, self.mid, self.hi]; while scale > 0 { // We're removing precision, so we don't care about overflow if scale < 10 { div_by_u32(&mut working, POWERS_10[scale as usize]); break; } else { div_by_u32(&mut working, POWERS_10[9]); // Only 9 as this array starts with 1 scale -= 9; } } Decimal { lo: working[0], mid: working[1], hi: working[2], flags: flags(self.is_sign_negative(), 0), } } /// Returns a new `Decimal` representing the fractional portion of the number. /// /// # Example /// /// ``` /// use rust_decimal::Decimal; /// /// let pi = Decimal::new(3141, 3); /// let fract = Decimal::new(141, 3); /// // note that it returns a decimal /// assert_eq!(pi.fract(), fract); /// ``` pub fn fract(&self) -> Decimal { // This is essentially the original number minus the integral. // Could possibly be optimized in the future *self - self.trunc() } /// Computes the absolute value of `self`. /// /// # Example /// /// ``` /// use rust_decimal::Decimal; /// /// let num = Decimal::new(-3141, 3); /// assert_eq!(num.abs().to_string(), "3.141"); /// ``` pub fn abs(&self) -> Decimal { let mut me = *self; me.set_sign_positive(true); me } /// Returns the largest integer less than or equal to a number. /// /// # Example /// /// ``` /// use rust_decimal::Decimal; /// /// let num = Decimal::new(3641, 3); /// assert_eq!(num.floor().to_string(), "3"); /// ``` pub fn floor(&self) -> Decimal { let scale = self.scale(); if scale == 0 { // Nothing to do return *self; } // Opportunity for optimization here let floored = self.trunc(); if self.is_sign_negative() && !self.fract().is_zero() { floored - Decimal::one() } else { floored } } /// Returns the smallest integer greater than or equal to a number. /// /// # Example /// /// ``` /// use rust_decimal::Decimal; /// /// let num = Decimal::new(3141, 3); /// assert_eq!(num.ceil().to_string(), "4"); /// let num = Decimal::new(3, 0); /// assert_eq!(num.ceil().to_string(), "3"); /// ``` pub fn ceil(&self) -> Decimal { let scale = self.scale(); if scale == 0 { // Nothing to do return *self; } // Opportunity for optimization here if self.is_sign_positive() && !self.fract().is_zero() { self.trunc() + Decimal::one() } else { self.trunc() } } /// Returns the maximum of the two numbers. /// /// ``` /// use rust_decimal::Decimal; /// /// let x = Decimal::new(1, 0); /// let y = Decimal::new(2, 0); /// assert_eq!(y, x.max(y)); /// ``` pub fn max(self, other: Decimal) -> Decimal { if self < other { return other; } else { self } } /// Returns the minimum of the two numbers. /// /// ``` /// use rust_decimal::Decimal; /// /// let x = Decimal::new(1, 0); /// let y = Decimal::new(2, 0); /// assert_eq!(x, x.min(y)); /// ``` pub fn min(self, other: Decimal) -> Decimal { if self > other { return other; } else { self } } /// Strips any trailing zero's from a `Decimal` and converts -0 to 0. /// /// # Example /// /// ``` /// use rust_decimal::Decimal; /// /// let number = Decimal::new(3100, 3); /// // note that it returns a decimal, without the extra scale /// assert_eq!(number.normalize().to_string(), "3.1"); /// ``` pub fn normalize(&self) -> Decimal { if self.is_zero() { // Convert -0, -0.0*, or 0.0* to 0. return Decimal::zero(); } let mut scale = self.scale(); if scale == 0 { // Nothing to do 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), } } /// Returns a new `Decimal` number with no fractional portion (i.e. an integer). /// Rounding currently follows "Bankers Rounding" rules. e.g. 6.5 -> 6, 7.5 -> 8 /// /// # Example /// /// ``` /// use rust_decimal::Decimal; /// /// // Demonstrating bankers rounding... /// let number_down = Decimal::new(65, 1); /// let number_up = Decimal::new(75, 1); /// assert_eq!(number_down.round().to_string(), "6"); /// assert_eq!(number_up.round().to_string(), "8"); /// ``` pub fn round(&self) -> Decimal { self.round_dp(0) } /// Returns a new `Decimal` number with the specified number of decimal points for fractional /// portion. /// Rounding is performed using the provided [`RoundingStrategy`] /// /// # Arguments /// * `dp`: the number of decimal points to round to. /// * `strategy`: the [`RoundingStrategy`] to use. /// /// # Example /// /// ``` /// use rust_decimal::{Decimal, RoundingStrategy}; /// use std::str::FromStr; /// /// let tax = Decimal::from_str("3.4395").unwrap(); /// assert_eq!(tax.round_dp_with_strategy(2, RoundingStrategy::RoundHalfUp).to_string(), "3.44"); /// ``` pub fn round_dp_with_strategy(&self, dp: u32, strategy: RoundingStrategy) -> Decimal { // Short circuit for zero if self.is_zero() { return Decimal { lo: 0, mid: 0, hi: 0, flags: flags(self.is_sign_negative(), dp), }; } let old_scale = self.scale(); // return early if decimal has a smaller number of fractional places than dp // e.g. 2.51 rounded to 3 decimal places is 2.51 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; // Rescale to zero so it's easier to work with 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; } } // Do some midpoint rounding checks // We're actually doing two things here. // 1. Figuring out midpoint rounding when we're right on the boundary. e.g. 2.50000 // 2. Figuring out whether to add one or not e.g. 2.51 // For this, we need to figure out the fractional portion that is additional to // the rounded number. e.g. for 0.12345 rounding to 2dp we'd want 345. // We're doing the equivalent of losing precision (e.g. to get 0.12) // then increasing the precision back up to 0.12000 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]); // Only 9 as this array starts with 1 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]); // Only 9 as this array starts with 1 diff -= 9; } } let mut decimal_portion = [self.lo, self.mid, self.hi]; sub_internal(&mut decimal_portion, &offset); // If the decimal_portion is zero then we round based on the other data 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 => { // Doesn't matter about the decimal portion add_internal(&mut value, &ONE_INTERNAL_REPR); } _ => {} } } RoundingStrategy::RoundHalfDown => { if let Ordering::Greater = order { add_internal(&mut value, &ONE_INTERNAL_REPR); } } RoundingStrategy::RoundHalfUp => { // when Ordering::Equal, decimal_portion is 0.5 exactly // when Ordering::Greater, decimal_portion is > 0.5 match order { Ordering::Equal => { add_internal(&mut value, &ONE_INTERNAL_REPR); } Ordering::Greater => { // Doesn't matter about the decimal portion add_internal(&mut value, &ONE_INTERNAL_REPR); } _ => {} } } RoundingStrategy::RoundUp => { if !is_all_zero(&decimal_portion) { add_internal(&mut value, &ONE_INTERNAL_REPR); } } RoundingStrategy::RoundDown => (), } Decimal { lo: value[0], mid: value[1], hi: value[2], flags: flags(negative, dp), } } /// Returns a new `Decimal` number with the specified number of decimal points for fractional portion. /// Rounding currently follows "Bankers Rounding" rules. e.g. 6.5 -> 6, 7.5 -> 8 /// /// # Arguments /// * `dp`: the number of decimal points to round to. /// /// # Example /// /// ``` /// use rust_decimal::Decimal; /// use std::str::FromStr; /// /// let pi = Decimal::from_str("3.1415926535897932384626433832").unwrap(); /// assert_eq!(pi.round_dp(2).to_string(), "3.14"); /// ``` pub fn round_dp(&self, dp: u32) -> Decimal { self.round_dp_with_strategy(dp, RoundingStrategy::BankersRounding) } /// Convert `Decimal` to an internal representation of the underlying struct. This is useful /// for debugging the internal state of the object. /// /// # Important Disclaimer /// This is primarily intended for library maintainers. The internal representation of a /// `Decimal` is considered "unstable" for public use. /// /// # Example /// /// ``` /// use rust_decimal::Decimal; /// use std::str::FromStr; /// /// let pi = Decimal::from_str("3.1415926535897932384626433832").unwrap(); /// assert_eq!(format!("{:?}", pi), "3.1415926535897932384626433832"); /// assert_eq!(format!("{:?}", pi.unpack()), "UnpackedDecimal { \ /// is_negative: false, scale: 28, hi: 1703060790, mid: 185874565, lo: 1102470952 \ /// }"); /// ``` 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, } } /// Convert `Decimal` to an internal representation of the underlying struct. This is useful /// for debugging the internal state of the object. /// /// # Important Disclaimer /// This is primarily intended for library maintainers. The internal representation of a /// `Decimal` is considered "unstable" for public use. /// /// # Example /// /// ``` /// use rust_decimal::Decimal; /// use std::str::FromStr; /// /// let pi = Decimal::from_str("3.1415926535897932384626433832").unwrap(); /// assert_eq!(format!("{:?}", pi), "3.1415926535897932384626433832"); /// assert_eq!(format!("{:?}", pi.unpack()), "UnpackedDecimal { \ /// is_negative: false, scale: 28, hi: 1703060790, mid: 185874565, lo: 1102470952 \ /// }"); /// ``` #[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 { // 2^exponent2 = (10^exponent2)/(5^exponent2) // = (5^-exponent2)*(10^exponent2) let mut exponent5 = -exponent2; let mut exponent10 = exponent2; // Ultimately, we want this for the scale while exponent5 > 0 { // Check to see if the mantissa is divisible by 2 if bits[0] & 0x1 == 0 { exponent10 += 1; exponent5 -= 1; // We can divide by 2 without losing precision 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 { // The mantissa is NOT divisible by 2. Therefore the mantissa should // be multiplied by 5, unless the multiplication overflows. exponent5 -= 1; let mut temp = [bits[0], bits[1], bits[2]]; if mul_by_u32(&mut temp, 5) == 0 { // Multiplication succeeded without overflow, so copy result back bits[0] = temp[0]; bits[1] = temp[1]; bits[2] = temp[2]; } else { // Multiplication by 5 overflows. The mantissa should be divided // by 2, and therefore will lose significant digits. exponent10 += 1; // Shift right 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 }; } } } // In order to divide the value by 5, it is best to multiply by 2/10. // Therefore, exponent10 is decremented, and the mantissa should be multiplied by 2 while exponent5 < 0 { if bits[2] & SIGN_MASK == 0 { // No far left bit, the mantissa can withstand a shift-left without overflowing exponent10 -= 1; exponent5 += 1; shl_internal(bits, 1, 0); } else { // The mantissa would overflow if shifted. Therefore it should be // directly divided by 5. This will lose significant digits, unless // by chance the mantissa happens to be divisible by 5. exponent5 += 1; div_by_u32(bits, 5); } } // At this point, the mantissa has assimilated the exponent5, but // exponent10 might not be suitable for assignment. exponent10 must be // in the range [-MAX_PRECISION..0], so the mantissa must be scaled up or // down appropriately. while exponent10 > 0 { // In order to bring exponent10 down to 0, the mantissa should be // multiplied by 10 to compensate. If the exponent10 is too big, this // will cause the mantissa to overflow. if mul_by_u32(bits, 10) == 0 { exponent10 -= 1; } else { // Overflowed - return? return None; } } // In order to bring exponent up to -MAX_PRECISION, the mantissa should // be divided by 10 to compensate. If the exponent10 is too small, this // will cause the mantissa to underflow and become 0. while exponent10 < -(MAX_PRECISION as i32) { let rem10 = div_by_u32(bits, 10); exponent10 += 1; if is_all_zero(bits) { // Underflow, unable to keep dividing exponent10 = 0; } else if rem10 >= 5 { add_internal(bits, &ONE_INTERNAL_REPR); } } // This step is required in order to remove excess bits of precision from the // end of the bit representation, down to the precision guaranteed by the // floating point number if is64 { // Guaranteed to about 16 dp while exponent10 < 0 && (bits[2] != 0 || (bits[1] & 0xFFF0_0000) != 0) { let rem10 = div_by_u32(bits, 10); exponent10 += 1; if rem10 >= 5 { add_internal(bits, &ONE_INTERNAL_REPR); } } } else { // Guaranteed to about 7 dp 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); } } } // Remove multiples of 10 from the representation 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), }) } /// Checked addition. Computes `self + other`, returning `None` if overflow occurred. #[inline(always)] pub fn checked_add(self, other: Decimal) -> Option { // Convert to the same scale 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); // Add the items together 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); // -x + y // if x > y then it's negative (i.e. -2 + 1) 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 => { // -2 + 2 my[0] = 0; my[1] = 0; my[2] = 0; } } carry = 0; } // If we have a carry we underflowed. // We need to lose some significant digits (if possible) if carry > 0 { if final_scale == 0 { return None; } // Copy it over to a temp array for modification 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 we still have a carry bit then we overflowed if temp[3] > 0 { return None; } // Copy it back - we're done 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), }) } /// Checked subtraction. Computes `self - other`, returning `None` if overflow occurred. #[inline(always)] pub fn checked_sub(self, other: Decimal) -> Option { let negated_other = Decimal { lo: other.lo, mid: other.mid, hi: other.hi, flags: other.flags ^ SIGN_MASK, }; self.checked_add(negated_other) } /// Checked multiplication. Computes `self * other`, returning `None` if overflow occurred. #[inline] pub fn checked_mul(self, other: Decimal) -> Option { // Early exit if either is zero if self.is_zero() || other.is_zero() { return Some(Decimal::zero()); } // We are only resulting in a negative if we have mismatched signs let negative = self.is_sign_negative() ^ other.is_sign_negative(); // We get the scale of the result by adding the operands. This may be too big, however // we'll correct later let mut final_scale = self.scale() + other.scale(); // First of all, if ONLY the lo parts of both numbers is filled // then we can simply do a standard 64 bit calculation. It's a minor // optimization however prevents the need for long form multiplication if self.mid == 0 && self.hi == 0 && other.mid == 0 && other.hi == 0 { // Simply multiplication let mut u64_result = u64_to_array(u64::from(self.lo) * u64::from(other.lo)); // If we're above max precision then this is a very small number if final_scale > MAX_PRECISION { final_scale -= MAX_PRECISION; // If the number is above 19 then this will equate to zero. // This is because the max value in 64 bits is 1.84E19 if final_scale > 19 { return Some(Decimal::zero()); } let mut rem_lo = 0; let mut power; if final_scale > 9 { // Since 10^10 doesn't fit into u32, we divide by 10^10/4 // and multiply the next divisor by 4. 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]; } // Divide fits in 32 bits let rem_hi = div_by_u32(&mut u64_result, power); // Round the result. Since the divisor is a power of 10 // we check to see if the remainder is >= 1/2 divisor 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), }); } // We're using some of the high bits, so we essentially perform // long form multiplication. We compute the 9 partial products // into a 192 bit result array. // // [my-h][my-m][my-l] // x [ot-h][ot-m][ot-l] // -------------------------------------- // 1. [r-hi][r-lo] my-l * ot-l [0, 0] // 2. [r-hi][r-lo] my-l * ot-m [0, 1] // 3. [r-hi][r-lo] my-m * ot-l [1, 0] // 4. [r-hi][r-lo] my-m * ot-m [1, 1] // 5. [r-hi][r-lo] my-l * ot-h [0, 2] // 6. [r-hi][r-lo] my-h * ot-l [2, 0] // 7. [r-hi][r-lo] my-m * ot-h [1, 2] // 8. [r-hi][r-lo] my-h * ot-m [2, 1] // 9.[r-hi][r-lo] my-h * ot-h [2, 2] 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]; // We can perform a minor short circuit here. If the // high portions are both 0 then we can skip portions 5-9 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); // Get the index for the lo portion of the product for prod in product.iter_mut().skip(my_index + ot_index) { let (res, overflow) = add_part(rlo, *prod); *prod = res; // If we have something in rhi from before then promote that if rhi > 0 { // If we overflowed in the last add, add that with rhi 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 nothing to do next round then break out if rlo == 0 { break; } } } } // If our result has used up the high portion of the product // then we either have an overflow or an underflow situation // Overflow will occur if we can't scale it back, whereas underflow // with kick in rounding 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; } // Round up the carry if we need to 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 we're still above max precision then we'll try again to // reduce precision - we may be dealing with a limit of "0" if final_scale > MAX_PRECISION { // We're in an underflow situation // The easiest way to remove precision is to divide off the result while final_scale > MAX_PRECISION && !is_all_zero(&product) { div_by_u32(&mut product, 10); final_scale -= 1; } // If we're still at limit then we can't represent any // siginificant decimal digits and will return an integer only // Can also be invoked while representing 0. if final_scale > MAX_PRECISION { final_scale = 0; } } else if !(product[3] == 0 && product[4] == 0 && product[5] == 0) { // We're in an overflow situation - we're within our precision bounds // but still have bits in overflow return None; } Some(Decimal { lo: product[0], mid: product[1], hi: product[2], flags: flags(negative, final_scale), }) } /// Checked division. Computes `self / other`, returning `None` if `other == 0.0` or the /// division results in overflow. pub fn checked_div(self, other: Decimal) -> Option { 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; // We supply an extra overflow word for each of the dividend and the remainder 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, ); // Multiply the remainder by 10 let mut overflow = 0; for part in working_remainder.iter_mut() { let (lo, hi) = mul_part(*part, 10, overflow); *part = lo; overflow = hi; } // Copy temp remainder into the temp quotient section working_quotient.copy_from_slice(&working_remainder); remainder_scale += 1; working_scale = remainder_scale; if underflow || is_all_zero(&working_remainder) { break; } } // If we have a really big number try to adjust the scale to 0 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); // Mul 10 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 { // Overflow 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(); // Check for underflow let mut final_scale: u32 = quotient_scale as u32; if final_scale > MAX_PRECISION { let mut remainder = 0; // Division underflowed. We must remove some significant digits over using // an invalid scale. while final_scale > MAX_PRECISION && !is_all_zero("ient) { remainder = div_by_u32(&mut quotient, 10); final_scale -= 1; } if final_scale > MAX_PRECISION { // Result underflowed so set to zero 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), }) } /// Checked remainder. Computes `self % other`, returning `None` if `other == 0.0`. pub fn checked_rem(self, other: Decimal) -> Option { if other.is_zero() { return None; } if self.is_zero() { return Some(Decimal::zero()); } // Rescale so comparable 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); // Working is the remainder + the quotient // We use an aligned array since we'll be using it a lot. 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); // Round if necessary. This is for semantic correctness, but could feasibly be removed for // performance improvements. 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), }) } } impl Default for Decimal { fn default() -> Self { Self::zero() } } enum DivResult { Ok(Decimal), Overflow, DivByZero, } #[inline] const fn flags(neg: bool, scale: u32) -> u32 { (scale << SCALE_SHIFT) | ((neg as u32) << SIGN_SHIFT) } /// Rescales the given decimals to equivalent scales. /// It will firstly try to scale both the left and the right side to /// the maximum scale of left/right. If it is unable to do that it /// will try to reduce the accuracy of the other argument. /// e.g. with 1.23 and 2.345 it'll rescale the first arg to 1.230 #[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 { // Nothing to do 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); } } } /// Rescales the given decimal to new scale. /// e.g. with 1.23 and new scale 3 rescale the value to 1.230 #[inline(always)] fn rescale_internal(value: &mut [u32; 3], value_scale: &mut u32, new_scale: u32) { if *value_scale == new_scale { // Nothing to do return; } if is_all_zero(value) { *value_scale = new_scale; return; } if *value_scale > new_scale { let mut diff = *value_scale - new_scale; // Scaling further isn't possible since we got an overflow // In this case we need to reduce the accuracy of the "side to keep" // Now do the necessary rounding let mut remainder = 0; while diff > 0 { if is_all_zero(value) { *value_scale = new_scale; return; } diff -= 1; // Any remainder is discarded if diff > 0 still (i.e. lost precision) 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; } } // This method should only be used where copy from slice cannot be #[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 { // Overflow, by default, is anything in the high portion of by 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 { // Add quotient and the working (i.e. quotient = quotient + working) if is_all_zero(quotient) { // Quotient is zero so we can just copy the working quotient in directly // First, make sure they are both 96 bit. 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; } // We have ensured that our working is not zero so we should do the addition // If our two quotients are different then // try to scale down the one with the bigger scale let mut temp3 = [0u32, 0u32, 0u32]; let mut temp4 = [0u32, 0u32, 0u32, 0u32]; if *quotient_scale != *working_scale { // TODO: Remove necessity for temp (without performance impact) fn div_by_10(target: &mut [u32], temp: &mut [u32], scale: &mut i32, target_scale: i32) { // Copy to the temp array temp.copy_from_slice(target); // divide by 10 until target scale is reached 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 our two quotients are still different then // try to scale up the smaller scale if *quotient_scale != *working_scale { // TODO: Remove necessity for temp (without performance impact) 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; // Multiply by 10 until target scale reached or overflow while *scale < target_scale && overflow == 0 { overflow = mul_by_u32(temp, 10); if overflow == 0 { // Still no overflow *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 our two quotients are still different then // try to scale down the one with the bigger scale // (ultimately losing significant digits) if *quotient_scale != *working_scale { // TODO: Remove necessity for temp (without performance impact) fn div_by_10_lossy(target: &mut [u32], temp: &mut [u32], scale: &mut i32, target_scale: i32) { temp.copy_from_slice(target); // divide by 10 until target scale is reached 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 quotient or working are zero we have an underflow condition if is_all_zero(quotient) || is_all_zero(working_quotient) { // Underflow return true; } else { // Both numbers have the same scale and can be added. // We just need to know whether we can fit them in let mut underflow = false; let mut temp = [0u32, 0u32, 0u32]; while !underflow { temp.copy_from_slice(quotient); // Add the working quotient let overflow = add_internal(&mut temp, working_quotient); if overflow == 0 { // addition was successful quotient.copy_from_slice(&temp); break; } else { // addition overflowed - remove significant digits and try again div_by_u32(quotient, 10); *quotient_scale -= 1; div_by_u32(working_quotient, 10); *working_scale -= 1; // Check for underflow 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 { // The way this works is similar to long subtraction // Let's assume we're working with bytes for simpliciy in an example: // 257 - 8 = 249 // 0000_0001 0000_0001 - 0000_0000 0000_1000 = 0000_0000 1111_1001 // We start by doing the first byte... // Overflow = 0 // Left = 0000_0001 (1) // Right = 0000_1000 (8) // Firstly, we make sure the left and right are scaled up to twice the size // Left = 0000_0000 0000_0001 // Right = 0000_0000 0000_1000 // We then subtract right from left // Result = Left - Right = 1111_1111 1111_1001 // We subtract the overflow, which in this case is 0. // Because left < right (1 < 8) we invert the high part. // Lo = 1111_1001 // Hi = 1111_1111 -> 0000_0001 // Lo is the field, hi is the overflow. // We do the same for the second byte... // Overflow = 1 // Left = 0000_0001 // Right = 0000_0000 // Result = Left - Right = 0000_0000 0000_0001 // We subtract the overflow... // Result = 0000_0000 0000_0001 - 1 = 0 // And we invert the high, just because (invert 0 = 0). // So our result is: // 0000_0000 1111_1001 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) } // Returns overflow #[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 } // Returns overflow 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]) { // There are a couple of ways to do division on binary numbers: // 1. Using long division // 2. Using the complement method // ref: http://paulmason.me/dividing-binary-numbers-part-2/ // The complement method basically keeps trying to subtract the // divisor until it can't anymore and placing the rest in remainder. let mut complement = [ divisor[0] ^ 0xFFFF_FFFF, divisor[1] ^ 0xFFFF_FFFF, divisor[2] ^ 0xFFFF_FFFF, 0xFFFF_FFFF, ]; // Add one onto the complement add_internal(&mut complement, &[1u32]); // Make sure the remainder is 0 remainder.iter_mut().for_each(|x| *x = 0); // If we have nothing in our hi+ block then shift over till we do let mut blocks_to_process = 0; while blocks_to_process < 4 && quotient[3] == 0 { // Shift whole blocks to the "left" shl_internal(quotient, 32, 0); // Incremember the counter blocks_to_process += 1; } // Let's try and do the addition... let mut block = blocks_to_process << 5; let mut working = [0u32, 0u32, 0u32, 0u32]; while block < 128 { // << 1 for quotient AND remainder let carry = shl_internal(quotient, 1, 0); shl_internal(remainder, 1, carry); // Copy the remainder of working into sub working.copy_from_slice(remainder); // Add the remainder with the complement add_internal(&mut working, &complement); // Check for the significant bit - move over to the quotient // as necessary if (working[3] & 0x8000_0000) == 0 { remainder.copy_from_slice(&working); quotient[0] |= 1; } // Increment our pointer block += 1; } } // Returns remainder pub(crate) fn div_by_u32(bits: &mut [u32], divisor: u32) -> u32 { if divisor == 0 { // Divide by zero panic!("Internal error: divide by zero"); } else if divisor == 1 { // dividend remains unchanged 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; // Whole blocks first while shift >= 32 { // memcpy would be useful here for i in (1..bits.len()).rev() { bits[i] = bits[i - 1]; } bits[0] = 0; shift -= 32; } // Continue with the rest 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 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 = Decimal::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 Num for Decimal { type FromStrRadixErr = Error; fn from_str_radix(str: &str, radix: u32) -> Result { if str.is_empty() { return Err(Error::new("Invalid decimal: empty")); } if radix < 2 { return Err(Error::new("Unsupported radix < 2")); } if radix > 36 { // As per trait documentation return Err(Error::new("Unsupported radix > 36")); } let mut offset = 0; let mut len = str.len(); let bytes: Vec = str.bytes().collect(); let mut negative = false; // assume positive // handle the sign if bytes[offset] == b'-' { negative = true; // leading minus means negative offset += 1; len -= 1; } else if bytes[offset] == b'+' { // leading + allowed offset += 1; len -= 1; } // should now be at numeric part of the significand let mut digits_before_dot: i32 = -1; // digits before '.', -1 if no '.' let mut coeff = Vec::new(); // integer significand array // Supporting different radix 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') }; // Estimate the max precision. All in all, it needs to fit into 96 bits. // Rather than try to estimate, I've included the constants directly in here. We could, // perhaps, replace this with a formula if it's faster - though it does appear to be log2. let estimated_max_precision = match radix { 2 => 96, 3 => 61, 4 => 48, 5 => 42, 6 => 38, 7 => 35, 8 => 32, 9 => 31, 10 => 29, 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 the coefficient is longer than the max, exit early 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'_' => { // Must start with a number... 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 we exited before the end of the string then do some rounding if necessary 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'.' => { // Still an error if we have a second dp if digits_before_dot >= 0 { return Err(Error::new("Invalid decimal: two decimal points")); } 0 } _ => return Err(Error::new("Invalid decimal: unknown character")), }; // Round at midpoint 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; } } } // here when no characters left if coeff.is_empty() { return Err(Error::new("Invalid decimal: no digits found")); } let mut scale = if digits_before_dot >= 0 { // we had a decimal place so set the scale (coeff.len() as u32) - (digits_before_dot as u32) } else { 0 }; // Parse this using specified radix let mut data = [0u32, 0u32, 0u32]; let mut tmp = [0u32, 0u32, 0u32]; let len = coeff.len(); for (i, digit) in coeff.iter().enumerate() { // If the data is going to overflow then we should go into recovery mode tmp[0] = data[0]; tmp[1] = data[1]; tmp[2] = data[2]; let overflow = mul_by_u32(&mut tmp, radix); if overflow > 0 { // This means that we have more data to process, that we're not sure what to do with. // This may or may not be an issue - depending on whether we're past a decimal point // or not. 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_internal(&mut data, &ONE_INTERNAL_REPR); if carry > 0 { // Highly unlikely scenario which is more indicative of a bug return Err(Error::new("Invalid decimal: overflow when rounding")); } } // We're also one less digit so reduce the scale 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_internal(&mut data, &[*digit]); if carry > 0 { // Highly unlikely scenario which is more indicative of a bug 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 FromStr for Decimal { type Err = Error; fn from_str(value: &str) -> Result { Decimal::from_str_radix(value, 10) } } impl FromPrimitive for Decimal { fn from_i32(n: i32) -> Option { 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 { 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 { Some(Decimal { flags: 0, lo: n, mid: 0, hi: 0, }) } fn from_u64(n: u64) -> Option { Some(Decimal { flags: 0, lo: n as u32, mid: (n >> 32) as u32, hi: 0, }) } fn from_f32(n: f32) -> Option { // Handle the case if it is NaN, Infinity or -Infinity if !n.is_finite() { return None; } // It's a shame we can't use a union for this due to it being broken up by bits // i.e. 1/8/23 (sign, exponent, mantissa) // See https://en.wikipedia.org/wiki/IEEE_754-1985 // n = (sign*-1) * 2^exp * mantissa // Decimal of course stores this differently... 10^-exp * significand let raw = n.to_bits(); let positive = (raw >> 31) == 0; let biased_exponent = ((raw >> 23) & 0xFF) as i32; let mantissa = raw & 0x007F_FFFF; // Handle the special zero case if biased_exponent == 0 && mantissa == 0 { let mut zero = Decimal::zero(); if !positive { zero.set_sign_negative(true); } return Some(zero); } // Get the bits and exponent2 let mut exponent2 = biased_exponent - 127; let mut bits = [mantissa, 0u32, 0u32]; if biased_exponent == 0 { // Denormalized number - correct the exponent exponent2 += 1; } else { // Add extra hidden bit to mantissa bits[0] |= 0x0080_0000; } // The act of copying a mantissa as integer bits is equivalent to shifting // left the mantissa 23 bits. The exponent is reduced to compensate. exponent2 -= 23; // Convert to decimal Decimal::base2_to_decimal(&mut bits, exponent2, positive, false) } fn from_f64(n: f64) -> Option { // Handle the case if it is NaN, Infinity or -Infinity if !n.is_finite() { return None; } // It's a shame we can't use a union for this due to it being broken up by bits // i.e. 1/11/52 (sign, exponent, mantissa) // See https://en.wikipedia.org/wiki/IEEE_754-1985 // n = (sign*-1) * 2^exp * mantissa // Decimal of course stores this differently... 10^-exp * significand 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; // Handle the special zero case if biased_exponent == 0 && mantissa == 0 { let mut zero = Decimal::zero(); if !positive { zero.set_sign_negative(true); } return Some(zero); } // Get the bits and exponent2 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 { // Denormalized number - correct the exponent exponent2 += 1; } else { // Add extra hidden bit to mantissa bits[1] |= 0x0010_0000; } // The act of copying a mantissa as integer bits is equivalent to shifting // left the mantissa 52 bits. The exponent is reduced to compensate. exponent2 -= 52; // Convert to decimal Decimal::base2_to_decimal(&mut bits, exponent2, positive, true) } } impl ToPrimitive for Decimal { fn to_i64(&self) -> Option { let d = self.trunc(); // Quick overflow check if d.hi != 0 || (d.mid & 0x8000_0000) > 0 { // Overflow 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 { if self.is_sign_negative() { return None; } let d = self.trunc(); if d.hi != 0 { // Overflow return None; } Some((u64::from(d.mid) << 32) | u64::from(d.lo)) } fn to_f64(&self) -> Option { 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; // scale is at most 28, so this fits comfortably into a u128. 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); Some(sign * ((integral_part as f64) + frac_f64)) } } } impl fmt::Display for Decimal { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { // Get the scale - where we need to put the decimal point let mut scale = self.scale() as usize; // Convert to a string and manipulate that (neg at front, inject decimal) 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::(); 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::(); rep.push_str(&zeros[..]); } scale = n_dp; } let len = rep.len(); // Inject the decimal point if scale > 0 { // Must be a low fractional // TODO: Remove this condition as it's no longer possible for `scale > len` if scale > len { let mut new_rep = String::new(); let zeros = repeat("0").take(scale as usize - len).collect::(); 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() { // corner case for when we truncated everything in a low fractional 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 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 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 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 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 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(&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 { Some(self.cmp(other)) } } impl Ord for Decimal { fn cmp(&self, other: &Decimal) -> Ordering { // Quick exit if major differences let self_negative = self.is_sign_negative(); let other_negative = other.is_sign_negative(); if self_negative && !other_negative { if self.is_zero() && other.is_zero() { return Ordering::Equal; } return Ordering::Less; } else if !self_negative && other_negative { if self.is_zero() && other.is_zero() { return Ordering::Equal; } return Ordering::Greater; } // If we have 1.23 and 1.2345 then we have // 123 scale 2 and 12345 scale 4 // We need to convert the first to // 12300 scale 4 so we can compare equally let left: &Decimal; let right: &Decimal; if self_negative && other_negative { // Both are negative, so reverse cmp 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 { // Fast path for same 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); } // Rescale and compare 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>(iter: I) -> Self { let mut sum = Decimal::zero(); for i in iter { sum += i; } sum } } #[cfg(test)] mod test { // Tests on private methods. // // All public tests should go under `tests/`. 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", // Scale 28 "843.65000000", // Scale 8 "0.0872727272727272727272727", // 25 "843.6500000000000000000000000", // 25 ), ]; for &(left_raw, right_raw, expected_left, expected_right) in tests { // Left = the value to rescale // Right = the new scale we're scaling to // Expected = the expected left value after rescale 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); // Also test the transitive case 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", // Scale 8 25, // 25 "843.6500000000000000000000000", // 25 ), ( "843.65000000", // Scale 8 30, // 30 "843.6500000000000000000000000000", // 28 ), ]; 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); } } }