summaryrefslogtreecommitdiffstats
path: root/third_party/rust/rust_decimal/src/decimal.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/rust_decimal/src/decimal.rs')
-rw-r--r--third_party/rust/rust_decimal/src/decimal.rs2578
1 files changed, 2578 insertions, 0 deletions
diff --git a/third_party/rust/rust_decimal/src/decimal.rs b/third_party/rust/rust_decimal/src/decimal.rs
new file mode 100644
index 0000000000..e98f7b4e4e
--- /dev/null
+++ b/third_party/rust/rust_decimal/src/decimal.rs
@@ -0,0 +1,2578 @@
+use crate::constants::{
+ MAX_I128_REPR, MAX_PRECISION_U32, 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::{Product, Sum},
+ ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign},
+ str::FromStr,
+};
+
+// Diesel configuration
+#[cfg(feature = "diesel2")]
+use diesel::deserialize::FromSqlRow;
+#[cfg(feature = "diesel2")]
+use diesel::expression::AsExpression;
+#[cfg(any(feature = "diesel1", feature = "diesel2"))]
+use diesel::sql_types::Numeric;
+
+#[allow(unused_imports)] // It's not actually dead code below, but the compiler thinks it is.
+#[cfg(not(feature = "std"))]
+use num_traits::float::FloatCore;
+use num_traits::{FromPrimitive, Num, One, Signed, ToPrimitive, Zero};
+#[cfg(feature = "rkyv")]
+use rkyv::{Archive, Deserialize, Serialize};
+
+/// The smallest value that can be represented by this decimal type.
+const MIN: Decimal = Decimal {
+ flags: 2_147_483_648,
+ lo: 4_294_967_295,
+ mid: 4_294_967_295,
+ hi: 4_294_967_295,
+};
+
+/// The largest value that can be represented by this decimal type.
+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,
+};
+const TWO: Decimal = Decimal {
+ flags: 0,
+ lo: 2,
+ mid: 0,
+ hi: 0,
+};
+const TEN: Decimal = Decimal {
+ flags: 0,
+ lo: 10,
+ mid: 0,
+ hi: 0,
+};
+const ONE_HUNDRED: Decimal = Decimal {
+ flags: 0,
+ lo: 100,
+ mid: 0,
+ hi: 0,
+};
+const ONE_THOUSAND: Decimal = Decimal {
+ flags: 0,
+ lo: 1000,
+ mid: 0,
+ hi: 0,
+};
+const NEGATIVE_ONE: Decimal = Decimal {
+ flags: 2147483648,
+ lo: 1,
+ mid: 0,
+ hi: 0,
+};
+
+/// `UnpackedDecimal` contains unpacked representation of `Decimal` where each component
+/// of decimal-format stored in it's own field
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub struct UnpackedDecimal {
+ pub 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 / 10<sup>e</sup>,
+/// where m is an integer such that -2<sup>96</sup> < m < 2<sup>96</sup>, and e is an integer
+/// between 0 and 28 inclusive.
+#[derive(Clone, Copy)]
+#[cfg_attr(
+ all(feature = "diesel1", not(feature = "diesel2")),
+ derive(FromSqlRow, AsExpression),
+ sql_type = "Numeric"
+)]
+#[cfg_attr(feature = "diesel2", derive(FromSqlRow, AsExpression), diesel(sql_type = Numeric))]
+#[cfg_attr(feature = "c-repr", repr(C))]
+#[cfg_attr(
+ feature = "borsh",
+ derive(borsh::BorshDeserialize, borsh::BorshSerialize, borsh::BorshSchema)
+)]
+#[cfg_attr(
+ feature = "rkyv",
+ derive(Archive, Deserialize, Serialize),
+ archive(compare(PartialEq)),
+ archive_attr(derive(Clone, Copy, Debug))
+)]
+#[cfg_attr(feature = "rkyv-safe", archive_attr(derive(bytecheck::CheckBytes)))]
+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 rounding strategies that can be used by
+/// `round_dp_with_strategy`.
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub enum RoundingStrategy {
+ /// When a number is halfway between two others, it is rounded toward the nearest even number.
+ /// Also known as "Bankers Rounding".
+ /// e.g.
+ /// 6.5 -> 6, 7.5 -> 8
+ MidpointNearestEven,
+ /// When a number is halfway between two others, it is rounded toward the nearest number that
+ /// is away from zero. e.g. 6.4 -> 6, 6.5 -> 7, -6.5 -> -7
+ MidpointAwayFromZero,
+ /// When a number is halfway between two others, it is rounded toward the nearest number that
+ /// is toward zero. e.g. 6.4 -> 6, 6.5 -> 6, -6.5 -> -6
+ MidpointTowardZero,
+ /// The number is always rounded toward zero. e.g. -6.8 -> -6, 6.8 -> 6
+ ToZero,
+ /// The number is always rounded away from zero. e.g. -6.8 -> -7, 6.8 -> 7
+ AwayFromZero,
+ /// The number is always rounded towards negative infinity. e.g. 6.8 -> 6, -6.8 -> -7
+ ToNegativeInfinity,
+ /// The number is always rounded towards positive infinity. e.g. 6.8 -> 7, -6.8 -> -6
+ ToPositiveInfinity,
+
+ /// When a number is halfway between two others, it is rounded toward the nearest even number.
+ /// e.g.
+ /// 6.5 -> 6, 7.5 -> 8
+ #[deprecated(since = "1.11.0", note = "Please use RoundingStrategy::MidpointNearestEven instead")]
+ BankersRounding,
+ /// Rounds up if the value >= 5, otherwise rounds down, e.g. 6.5 -> 7
+ #[deprecated(since = "1.11.0", note = "Please use RoundingStrategy::MidpointAwayFromZero instead")]
+ RoundHalfUp,
+ /// Rounds down if the value =< 5, otherwise rounds up, e.g. 6.5 -> 6, 6.51 -> 7 1.4999999 -> 1
+ #[deprecated(since = "1.11.0", note = "Please use RoundingStrategy::MidpointTowardZero instead")]
+ RoundHalfDown,
+ /// Always round down.
+ #[deprecated(since = "1.11.0", note = "Please use RoundingStrategy::ToZero instead")]
+ RoundDown,
+ /// Always round up.
+ #[deprecated(since = "1.11.0", note = "Please use RoundingStrategy::AwayFromZero instead")]
+ RoundUp,
+}
+
+#[allow(dead_code)]
+impl Decimal {
+ /// The smallest value that can be represented by this decimal type.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ /// ```
+ /// # use rust_decimal::Decimal;
+ /// # use rust_decimal_macros::dec;
+ /// assert_eq!(Decimal::MIN, dec!(-79_228_162_514_264_337_593_543_950_335));
+ /// ```
+ pub const MIN: Decimal = MIN;
+ /// The largest value that can be represented by this decimal type.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ /// ```
+ /// # use rust_decimal::Decimal;
+ /// # use rust_decimal_macros::dec;
+ /// assert_eq!(Decimal::MAX, dec!(79_228_162_514_264_337_593_543_950_335));
+ /// ```
+ pub const MAX: Decimal = MAX;
+ /// A constant representing 0.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ /// ```
+ /// # use rust_decimal::Decimal;
+ /// # use rust_decimal_macros::dec;
+ /// assert_eq!(Decimal::ZERO, dec!(0));
+ /// ```
+ pub const ZERO: Decimal = ZERO;
+ /// A constant representing 1.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ /// ```
+ /// # use rust_decimal::Decimal;
+ /// # use rust_decimal_macros::dec;
+ /// assert_eq!(Decimal::ONE, dec!(1));
+ /// ```
+ pub const ONE: Decimal = ONE;
+ /// A constant representing -1.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ /// ```
+ /// # use rust_decimal::Decimal;
+ /// # use rust_decimal_macros::dec;
+ /// assert_eq!(Decimal::NEGATIVE_ONE, dec!(-1));
+ /// ```
+ pub const NEGATIVE_ONE: Decimal = NEGATIVE_ONE;
+ /// A constant representing 2.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ /// ```
+ /// # use rust_decimal::Decimal;
+ /// # use rust_decimal_macros::dec;
+ /// assert_eq!(Decimal::TWO, dec!(2));
+ /// ```
+ pub const TWO: Decimal = TWO;
+ /// A constant representing 10.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ /// ```
+ /// # use rust_decimal::Decimal;
+ /// # use rust_decimal_macros::dec;
+ /// assert_eq!(Decimal::TEN, dec!(10));
+ /// ```
+ pub const TEN: Decimal = TEN;
+ /// A constant representing 100.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ /// ```
+ /// # use rust_decimal::Decimal;
+ /// # use rust_decimal_macros::dec;
+ /// assert_eq!(Decimal::ONE_HUNDRED, dec!(100));
+ /// ```
+ pub const ONE_HUNDRED: Decimal = ONE_HUNDRED;
+ /// A constant representing 1000.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ /// ```
+ /// # use rust_decimal::Decimal;
+ /// # use rust_decimal_macros::dec;
+ /// assert_eq!(Decimal::ONE_THOUSAND, dec!(1000));
+ /// ```
+ pub const ONE_THOUSAND: Decimal = ONE_THOUSAND;
+
+ /// A constant representing π as 3.1415926535897932384626433833
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ /// ```
+ /// # use rust_decimal::Decimal;
+ /// # use rust_decimal_macros::dec;
+ /// assert_eq!(Decimal::PI, dec!(3.1415926535897932384626433833));
+ /// ```
+ #[cfg(feature = "maths")]
+ pub const PI: Decimal = Decimal {
+ flags: 1835008,
+ lo: 1102470953,
+ mid: 185874565,
+ hi: 1703060790,
+ };
+ /// A constant representing π/2 as 1.5707963267948966192313216916
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ /// ```
+ /// # use rust_decimal::Decimal;
+ /// # use rust_decimal_macros::dec;
+ /// assert_eq!(Decimal::HALF_PI, dec!(1.5707963267948966192313216916));
+ /// ```
+ #[cfg(feature = "maths")]
+ pub const HALF_PI: Decimal = Decimal {
+ flags: 1835008,
+ lo: 2698719124,
+ mid: 92937282,
+ hi: 851530395,
+ };
+ /// A constant representing π/4 as 0.7853981633974483096156608458
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ /// ```
+ /// # use rust_decimal::Decimal;
+ /// # use rust_decimal_macros::dec;
+ /// assert_eq!(Decimal::QUARTER_PI, dec!(0.7853981633974483096156608458));
+ /// ```
+ #[cfg(feature = "maths")]
+ pub const QUARTER_PI: Decimal = Decimal {
+ flags: 1835008,
+ lo: 1349359562,
+ mid: 2193952289,
+ hi: 425765197,
+ };
+ /// A constant representing 2π as 6.2831853071795864769252867666
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ /// ```
+ /// # use rust_decimal::Decimal;
+ /// # use rust_decimal_macros::dec;
+ /// assert_eq!(Decimal::TWO_PI, dec!(6.2831853071795864769252867666));
+ /// ```
+ #[cfg(feature = "maths")]
+ pub const TWO_PI: Decimal = Decimal {
+ flags: 1835008,
+ lo: 2204941906,
+ mid: 371749130,
+ hi: 3406121580,
+ };
+ /// A constant representing Euler's number (e) as 2.7182818284590452353602874714
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ /// ```
+ /// # use rust_decimal::Decimal;
+ /// # use rust_decimal_macros::dec;
+ /// assert_eq!(Decimal::E, dec!(2.7182818284590452353602874714));
+ /// ```
+ #[cfg(feature = "maths")]
+ pub const E: Decimal = Decimal {
+ flags: 1835008,
+ lo: 2239425882,
+ mid: 3958169141,
+ hi: 1473583531,
+ };
+ /// A constant representing the inverse of Euler's number (1/e) as 0.3678794411714423215955237702
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ /// ```
+ /// # use rust_decimal::Decimal;
+ /// # use rust_decimal_macros::dec;
+ /// assert_eq!(Decimal::E_INVERSE, dec!(0.3678794411714423215955237702));
+ /// ```
+ #[cfg(feature = "maths")]
+ pub const E_INVERSE: Decimal = Decimal {
+ flags: 1835008,
+ lo: 2384059206,
+ mid: 2857938002,
+ hi: 199427844,
+ };
+
+ /// 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.
+ ///
+ /// # Panics
+ ///
+ /// This function panics if `scale` is > 28.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use rust_decimal::Decimal;
+ /// #
+ /// let pi = Decimal::new(3141, 3);
+ /// assert_eq!(pi.to_string(), "3.141");
+ /// ```
+ #[must_use]
+ pub fn new(num: i64, scale: u32) -> Decimal {
+ match Self::try_new(num, scale) {
+ Err(e) => panic!("{}", e),
+ Ok(d) => d,
+ }
+ }
+
+ /// Checked version of `Decimal::new`. Will return `Err` instead of panicking at run-time.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// # use rust_decimal::Decimal;
+ /// #
+ /// let max = Decimal::try_new(i64::MAX, u32::MAX);
+ /// assert!(max.is_err());
+ /// ```
+ pub const fn try_new(num: i64, scale: u32) -> crate::Result<Decimal> {
+ if scale > MAX_PRECISION_U32 {
+ return Err(Error::ScaleExceedsMaximumPrecision(scale));
+ }
+ let flags: u32 = scale << SCALE_SHIFT;
+ if num < 0 {
+ let pos_num = num.wrapping_neg() as u64;
+ return Ok(Decimal {
+ flags: flags | SIGN_MASK,
+ hi: 0,
+ lo: (pos_num & U32_MASK) as u32,
+ mid: ((pos_num >> 32) & U32_MASK) as u32,
+ });
+ }
+ Ok(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.
+ ///
+ /// # Panics
+ ///
+ /// This function panics if `scale` is > 28 or if `num` exceeds the maximum supported 96 bits.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// # use rust_decimal::Decimal;
+ /// #
+ /// let pi = Decimal::from_i128_with_scale(3141i128, 3);
+ /// assert_eq!(pi.to_string(), "3.141");
+ /// ```
+ #[must_use]
+ pub fn from_i128_with_scale(num: i128, scale: u32) -> Decimal {
+ match Self::try_from_i128_with_scale(num, scale) {
+ Ok(d) => d,
+ Err(e) => panic!("{}", e),
+ }
+ }
+
+ /// Checked version of `Decimal::from_i128_with_scale`. Will return `Err` instead
+ /// of panicking at run-time.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// # use rust_decimal::Decimal;
+ /// #
+ /// let max = Decimal::try_from_i128_with_scale(i128::MAX, u32::MAX);
+ /// assert!(max.is_err());
+ /// ```
+ pub const fn try_from_i128_with_scale(num: i128, scale: u32) -> crate::Result<Decimal> {
+ if scale > MAX_PRECISION_U32 {
+ return Err(Error::ScaleExceedsMaximumPrecision(scale));
+ }
+ let mut neg = false;
+ let mut wrapped = num;
+ if num > MAX_I128_REPR {
+ return Err(Error::ExceedsMaximumPossibleValue);
+ } else if num < -MAX_I128_REPR {
+ return Err(Error::LessThanMinimumPossibleValue);
+ } else if num < 0 {
+ neg = true;
+ wrapped = -num;
+ }
+ let flags: u32 = flags(neg, scale);
+ Ok(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.
+ ///
+ /// # Caution: Undefined behavior
+ ///
+ /// While a scale greater than 28 can be passed in, it will be automatically capped by this
+ /// function at the maximum precision. The library opts towards this functionality as opposed
+ /// to a panic to ensure that the function can be treated as constant. This may lead to
+ /// undefined behavior in downstream applications and should be treated with caution.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use rust_decimal::Decimal;
+ /// #
+ /// let pi = Decimal::from_parts(1102470952, 185874565, 1703060790, false, 28);
+ /// assert_eq!(pi.to_string(), "3.1415926535897932384626433832");
+ /// ```
+ #[must_use]
+ 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_U32 + 1),
+ ),
+ }
+ }
+
+ #[must_use]
+ 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 { flags, hi, lo, mid }
+ }
+ }
+
+ /// 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;
+ /// #
+ /// # fn main() -> Result<(), rust_decimal::Error> {
+ /// let value = Decimal::from_scientific("9.7e-7")?;
+ /// assert_eq!(value.to_string(), "0.00000097");
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn from_scientific(value: &str) -> Result<Decimal, Error> {
+ const ERROR_MESSAGE: &str = "Failed to parse";
+
+ let mut split = value.splitn(2, |c| c == 'e' || c == 'E');
+
+ let base = split.next().ok_or_else(|| Error::from(ERROR_MESSAGE))?;
+ let exp = split.next().ok_or_else(|| Error::from(ERROR_MESSAGE))?;
+
+ 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::from(ERROR_MESSAGE))?;
+ ret.set_scale(current_scale + exp)?;
+ } else {
+ let exp: u32 = exp.parse().map_err(|_| Error::from(ERROR_MESSAGE))?;
+ if exp <= current_scale {
+ ret.set_scale(current_scale - exp)?;
+ } else if exp > 0 {
+ use crate::constants::BIG_POWERS_10;
+
+ // This is a case whereby the mantissa needs to be larger to be correctly
+ // represented within the decimal type. A good example is 1.2E10. At this point,
+ // we've parsed 1.2 as the base and 10 as the exponent. To represent this within a
+ // Decimal type we effectively store the mantissa as 12,000,000,000 and scale as
+ // zero.
+ if exp > MAX_PRECISION_U32 {
+ return Err(Error::ScaleExceedsMaximumPrecision(exp));
+ }
+ let mut exp = exp as usize;
+ // Max two iterations. If exp is 1 then it needs to index position 0 of the array.
+ while exp > 0 {
+ let pow;
+ if exp >= BIG_POWERS_10.len() {
+ pow = BIG_POWERS_10[BIG_POWERS_10.len() - 1];
+ exp -= BIG_POWERS_10.len();
+ } else {
+ pow = BIG_POWERS_10[exp - 1];
+ exp = 0;
+ }
+
+ let pow = Decimal {
+ flags: 0,
+ lo: pow as u32,
+ mid: (pow >> 32) as u32,
+ hi: 0,
+ };
+ match ret.checked_mul(pow) {
+ Some(r) => ret = r,
+ None => return Err(Error::ExceedsMaximumPossibleValue),
+ };
+ }
+ ret.normalize_assign();
+ }
+ }
+ Ok(ret)
+ }
+
+ /// Converts a string slice in a given base to a decimal.
+ ///
+ /// The string is expected to be an optional + sign followed by digits.
+ /// Digits are a subset of these characters, depending on radix, and will return an error if outside
+ /// the expected range:
+ ///
+ /// * 0-9
+ /// * a-z
+ /// * A-Z
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// # use rust_decimal::prelude::*;
+ /// #
+ /// # fn main() -> Result<(), rust_decimal::Error> {
+ /// assert_eq!(Decimal::from_str_radix("A", 16)?.to_string(), "10");
+ /// # Ok(())
+ /// # }
+ /// ```
+ 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)
+ }
+ }
+
+ /// Parses a string slice into a decimal. If the value underflows and cannot be represented with the
+ /// given scale then this will return an error.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// # use rust_decimal::prelude::*;
+ /// # use rust_decimal::Error;
+ /// #
+ /// # fn main() -> Result<(), rust_decimal::Error> {
+ /// assert_eq!(Decimal::from_str_exact("0.001")?.to_string(), "0.001");
+ /// assert_eq!(Decimal::from_str_exact("0.00000_00000_00000_00000_00000_001")?.to_string(), "0.0000000000000000000000000001");
+ /// assert_eq!(Decimal::from_str_exact("0.00000_00000_00000_00000_00000_0001"), Err(Error::Underflow));
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn from_str_exact(str: &str) -> Result<Self, crate::Error> {
+ crate::str::parse_str_radix_10_exact(str)
+ }
+
+ /// 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]
+ #[must_use]
+ pub const fn scale(&self) -> u32 {
+ ((self.flags & SCALE_MASK) >> SCALE_SHIFT) as u32
+ }
+
+ /// Returns the mantissa of the decimal number.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use rust_decimal::prelude::*;
+ /// use rust_decimal_macros::dec;
+ ///
+ /// let num = dec!(-1.2345678);
+ /// assert_eq!(num.mantissa(), -12345678i128);
+ /// assert_eq!(num.scale(), 7);
+ /// ```
+ #[must_use]
+ 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
+ }
+ }
+
+ /// Returns true if this Decimal number is equivalent to zero.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use rust_decimal::prelude::*;
+ /// #
+ /// let num = Decimal::ZERO;
+ /// assert!(num.is_zero());
+ /// ```
+ #[must_use]
+ pub const fn is_zero(&self) -> bool {
+ self.lo == 0 && self.mid == 0 && self.hi == 0
+ }
+
+ /// 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::ONE;
+ /// 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::ONE;
+ /// 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::ONE;
+ /// 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;
+ /// #
+ /// # fn main() -> Result<(), rust_decimal::Error> {
+ /// let mut one = Decimal::ONE;
+ /// one.set_scale(5)?;
+ /// assert_eq!(one.to_string(), "0.00001");
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn set_scale(&mut self, scale: u32) -> Result<(), Error> {
+ if scale > MAX_PRECISION_U32 {
+ return Err(Error::ScaleExceedsMaximumPrecision(scale));
+ }
+ self.flags = (scale << SCALE_SHIFT) | (self.flags & SIGN_MASK);
+ Ok(())
+ }
+
+ /// Modifies the `Decimal` towards the desired scale, attempting to do so without changing the
+ /// underlying number itself.
+ ///
+ /// Setting the scale to something less then the current `Decimal`s scale will
+ /// cause the newly created `Decimal` to perform rounding using the `MidpointAwayFromZero` strategy.
+ ///
+ /// Scales greater than the maximum precision that can be represented by `Decimal` will be
+ /// automatically rounded to either `Decimal::MAX_PRECISION` or the maximum precision that can
+ /// be represented with the given mantissa.
+ ///
+ /// # Arguments
+ /// * `scale`: The desired scale to use for the new `Decimal` number.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use rust_decimal::prelude::*;
+ /// use rust_decimal_macros::dec;
+ ///
+ /// // Rescaling to a higher scale preserves the value
+ /// let mut number = dec!(1.123);
+ /// assert_eq!(number.scale(), 3);
+ /// number.rescale(6);
+ /// assert_eq!(number.to_string(), "1.123000");
+ /// assert_eq!(number.scale(), 6);
+ ///
+ /// // Rescaling to a lower scale forces the number to be rounded
+ /// let mut number = dec!(1.45);
+ /// assert_eq!(number.scale(), 2);
+ /// number.rescale(1);
+ /// assert_eq!(number.to_string(), "1.5");
+ /// assert_eq!(number.scale(), 1);
+ ///
+ /// // This function never fails. Consequently, if a scale is provided that is unable to be
+ /// // represented using the given mantissa, then the maximum possible scale is used.
+ /// let mut number = dec!(11.76470588235294);
+ /// assert_eq!(number.scale(), 14);
+ /// number.rescale(28);
+ /// // A scale of 28 cannot be represented given this mantissa, however it was able to represent
+ /// // a number with a scale of 27
+ /// assert_eq!(number.to_string(), "11.764705882352940000000000000");
+ /// assert_eq!(number.scale(), 27);
+ /// ```
+ 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);
+ }
+
+ /// 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`
+ #[must_use]
+ 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 following 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`
+ #[must_use]
+ pub fn deserialize(bytes: [u8; 16]) -> Decimal {
+ // We can bound flags by a bitwise mask to correspond to:
+ // 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.
+ let mut raw = Decimal {
+ flags: ((bytes[0] as u32) | (bytes[1] as u32) << 8 | (bytes[2] as u32) << 16 | (bytes[3] as u32) << 24)
+ & 0x801F_0000,
+ 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,
+ };
+ // Scale must be bound to maximum precision. Only two values can be greater than this
+ if raw.scale() > MAX_PRECISION_U32 {
+ let mut bits = raw.mantissa_array3();
+ let remainder = match raw.scale() {
+ 29 => crate::ops::array::div_by_1x(&mut bits, 1),
+ 30 => crate::ops::array::div_by_1x(&mut bits, 2),
+ 31 => crate::ops::array::div_by_1x(&mut bits, 3),
+ _ => 0,
+ };
+ if remainder >= 5 {
+ ops::array::add_one_internal(&mut bits);
+ }
+ raw.lo = bits[0];
+ raw.mid = bits[1];
+ raw.hi = bits[2];
+ raw.flags = flags(raw.is_sign_negative(), MAX_PRECISION_U32);
+ }
+ raw
+ }
+
+ /// Returns `true` if the decimal is negative.
+ #[deprecated(since = "0.6.3", note = "please use `is_sign_negative` instead")]
+ #[must_use]
+ 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")]
+ #[must_use]
+ pub fn is_positive(&self) -> bool {
+ self.is_sign_positive()
+ }
+
+ /// Returns `true` if the sign bit of the decimal is negative.
+ ///
+ /// # Example
+ /// ```
+ /// # use rust_decimal::prelude::*;
+ /// #
+ /// assert_eq!(true, Decimal::new(-1, 0).is_sign_negative());
+ /// assert_eq!(false, Decimal::new(1, 0).is_sign_negative());
+ /// ```
+ #[inline(always)]
+ #[must_use]
+ pub const fn is_sign_negative(&self) -> bool {
+ self.flags & SIGN_MASK > 0
+ }
+
+ /// Returns `true` if the sign bit of the decimal is positive.
+ ///
+ /// # Example
+ /// ```
+ /// # use rust_decimal::prelude::*;
+ /// #
+ /// assert_eq!(false, Decimal::new(-1, 0).is_sign_positive());
+ /// assert_eq!(true, Decimal::new(1, 0).is_sign_positive());
+ /// ```
+ #[inline(always)]
+ #[must_use]
+ pub const fn is_sign_positive(&self) -> bool {
+ self.flags & SIGN_MASK == 0
+ }
+
+ /// Returns the minimum possible number that `Decimal` can represent.
+ #[deprecated(since = "1.12.0", note = "Use the associated constant Decimal::MIN")]
+ #[must_use]
+ pub const fn min_value() -> Decimal {
+ MIN
+ }
+
+ /// Returns the maximum possible number that `Decimal` can represent.
+ #[deprecated(since = "1.12.0", note = "Use the associated constant Decimal::MAX")]
+ #[must_use]
+ 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);
+ /// ```
+ #[must_use]
+ 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 {
+ ops::array::div_by_u32(&mut working, POWERS_10[scale as usize]);
+ break;
+ } else {
+ ops::array::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);
+ /// ```
+ #[must_use]
+ 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");
+ /// ```
+ #[must_use]
+ 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");
+ /// ```
+ #[must_use]
+ 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 - 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");
+ /// ```
+ #[must_use]
+ 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() + 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));
+ /// ```
+ #[must_use]
+ pub fn max(self, other: Decimal) -> Decimal {
+ if self < other {
+ 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));
+ /// ```
+ #[must_use]
+ pub fn min(self, other: Decimal) -> Decimal {
+ if self > other {
+ other
+ } else {
+ self
+ }
+ }
+
+ /// Strips any trailing zero's from a `Decimal` and converts -0 to 0.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use rust_decimal::prelude::*;
+ /// # fn main() -> Result<(), rust_decimal::Error> {
+ /// let number = Decimal::from_str("3.100")?;
+ /// assert_eq!(number.normalize().to_string(), "3.1");
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[must_use]
+ pub fn normalize(&self) -> Decimal {
+ let mut result = *self;
+ result.normalize_assign();
+ result
+ }
+
+ /// An in place version of `normalize`. Strips any trailing zero's from a `Decimal` and converts -0 to 0.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use rust_decimal::prelude::*;
+ /// # fn main() -> Result<(), rust_decimal::Error> {
+ /// let mut number = Decimal::from_str("3.100")?;
+ /// assert_eq!(number.to_string(), "3.100");
+ /// number.normalize_assign();
+ /// assert_eq!(number.to_string(), "3.1");
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn normalize_assign(&mut self) {
+ if self.is_zero() {
+ self.flags = 0;
+ return;
+ }
+
+ let mut scale = self.scale();
+ if scale == 0 {
+ return;
+ }
+
+ let mut result = self.mantissa_array3();
+ let mut working = self.mantissa_array3();
+ while scale > 0 {
+ if ops::array::div_by_u32(&mut working, 10) > 0 {
+ break;
+ }
+ scale -= 1;
+ result.copy_from_slice(&working);
+ }
+ self.lo = result[0];
+ self.mid = result[1];
+ self.hi = result[2];
+ self.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");
+ /// ```
+ #[must_use]
+ 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 rust_decimal_macros::dec;
+ /// #
+ /// let tax = dec!(3.4395);
+ /// assert_eq!(tax.round_dp_with_strategy(2, RoundingStrategy::MidpointAwayFromZero).to_string(), "3.44");
+ /// ```
+ #[must_use]
+ 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 {
+ 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;
+ }
+ }
+
+ // 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 {
+ ops::array::div_by_u32(&mut offset, POWERS_10[diff as usize]);
+ break;
+ } else {
+ ops::array::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 {
+ ops::array::mul_by_u32(&mut offset, POWERS_10[diff as usize]);
+ break;
+ } else {
+ ops::array::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];
+ ops::array::sub_by_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) {
+ 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 => {
+ // Doesn't matter about the decimal portion
+ 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 => {
+ // when Ordering::Equal, decimal_portion is 0.5 exactly
+ // when Ordering::Greater, decimal_portion is > 0.5
+ match order {
+ Ordering::Equal => {
+ ops::array::add_one_internal(&mut value);
+ }
+ Ordering::Greater => {
+ // Doesn't matter about the decimal portion
+ 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::from_parts(value[0], value[1], value[2], 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 rust_decimal_macros::dec;
+ /// #
+ /// let pi = dec!(3.1415926535897932384626433832);
+ /// assert_eq!(pi.round_dp(2).to_string(), "3.14");
+ /// ```
+ #[must_use]
+ pub fn round_dp(&self, dp: u32) -> Decimal {
+ self.round_dp_with_strategy(dp, RoundingStrategy::MidpointNearestEven)
+ }
+
+ /// Returns `Some(Decimal)` number rounded to the specified number of significant digits. If
+ /// the resulting number is unable to be represented by the `Decimal` number then `None` will
+ /// be returned.
+ /// When the number of significant figures of the `Decimal` being rounded is greater than the requested
+ /// number of significant digits then rounding will be performed using `MidpointNearestEven` strategy.
+ ///
+ /// # Arguments
+ /// * `digits`: the number of significant digits to round to.
+ ///
+ /// # Remarks
+ /// A significant figure is determined using the following rules:
+ /// 1. Non-zero digits are always significant.
+ /// 2. Zeros between non-zero digits are always significant.
+ /// 3. Leading zeros are never significant.
+ /// 4. Trailing zeros are only significant if the number contains a decimal point.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use rust_decimal::Decimal;
+ /// use rust_decimal_macros::dec;
+ ///
+ /// let value = dec!(305.459);
+ /// assert_eq!(value.round_sf(0), Some(dec!(0)));
+ /// assert_eq!(value.round_sf(1), Some(dec!(300)));
+ /// assert_eq!(value.round_sf(2), Some(dec!(310)));
+ /// assert_eq!(value.round_sf(3), Some(dec!(305)));
+ /// assert_eq!(value.round_sf(4), Some(dec!(305.5)));
+ /// assert_eq!(value.round_sf(5), Some(dec!(305.46)));
+ /// assert_eq!(value.round_sf(6), Some(dec!(305.459)));
+ /// assert_eq!(value.round_sf(7), Some(dec!(305.4590)));
+ /// assert_eq!(Decimal::MAX.round_sf(1), None);
+ ///
+ /// let value = dec!(0.012301);
+ /// assert_eq!(value.round_sf(3), Some(dec!(0.0123)));
+ /// ```
+ #[must_use]
+ pub fn round_sf(&self, digits: u32) -> Option<Decimal> {
+ self.round_sf_with_strategy(digits, RoundingStrategy::MidpointNearestEven)
+ }
+
+ /// Returns `Some(Decimal)` number rounded to the specified number of significant digits. If
+ /// the resulting number is unable to be represented by the `Decimal` number then `None` will
+ /// be returned.
+ /// When the number of significant figures of the `Decimal` being rounded is greater than the requested
+ /// number of significant digits then rounding will be performed using the provided [RoundingStrategy].
+ ///
+ /// # Arguments
+ /// * `digits`: the number of significant digits to round to.
+ /// * `strategy`: if required, the rounding strategy to use.
+ ///
+ /// # Remarks
+ /// A significant figure is determined using the following rules:
+ /// 1. Non-zero digits are always significant.
+ /// 2. Zeros between non-zero digits are always significant.
+ /// 3. Leading zeros are never significant.
+ /// 4. Trailing zeros are only significant if the number contains a decimal point.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use rust_decimal::{Decimal, RoundingStrategy};
+ /// use rust_decimal_macros::dec;
+ ///
+ /// let value = dec!(305.459);
+ /// assert_eq!(value.round_sf_with_strategy(0, RoundingStrategy::ToZero), Some(dec!(0)));
+ /// assert_eq!(value.round_sf_with_strategy(1, RoundingStrategy::ToZero), Some(dec!(300)));
+ /// assert_eq!(value.round_sf_with_strategy(2, RoundingStrategy::ToZero), Some(dec!(300)));
+ /// assert_eq!(value.round_sf_with_strategy(3, RoundingStrategy::ToZero), Some(dec!(305)));
+ /// assert_eq!(value.round_sf_with_strategy(4, RoundingStrategy::ToZero), Some(dec!(305.4)));
+ /// assert_eq!(value.round_sf_with_strategy(5, RoundingStrategy::ToZero), Some(dec!(305.45)));
+ /// assert_eq!(value.round_sf_with_strategy(6, RoundingStrategy::ToZero), Some(dec!(305.459)));
+ /// assert_eq!(value.round_sf_with_strategy(7, RoundingStrategy::ToZero), Some(dec!(305.4590)));
+ /// assert_eq!(Decimal::MAX.round_sf_with_strategy(1, RoundingStrategy::ToZero), Some(dec!(70000000000000000000000000000)));
+ ///
+ /// let value = dec!(0.012301);
+ /// assert_eq!(value.round_sf_with_strategy(3, RoundingStrategy::AwayFromZero), Some(dec!(0.0124)));
+ /// ```
+ #[must_use]
+ pub fn round_sf_with_strategy(&self, digits: u32, strategy: RoundingStrategy) -> Option<Decimal> {
+ if self.is_zero() || digits == 0 {
+ return Some(Decimal::ZERO);
+ }
+
+ // We start by grabbing the mantissa and figuring out how many significant figures it is
+ // made up of. We do this by just dividing by 10 and checking remainders - effectively
+ // we're performing a naive log10.
+ let mut working = self.mantissa_array3();
+ let mut mantissa_sf = 0;
+ while !ops::array::is_all_zero(&working) {
+ let _remainder = ops::array::div_by_u32(&mut working, 10u32);
+ mantissa_sf += 1;
+ if working[2] == 0 && working[1] == 0 && working[0] == 1 {
+ mantissa_sf += 1;
+ break;
+ }
+ }
+ let scale = self.scale();
+
+ match digits.cmp(&mantissa_sf) {
+ Ordering::Greater => {
+ // If we're requesting a higher number of significant figures, we rescale
+ let mut array = [self.lo, self.mid, self.hi];
+ let mut value_scale = scale;
+ ops::array::rescale_internal(&mut array, &mut value_scale, scale + digits - mantissa_sf);
+ Some(Decimal {
+ lo: array[0],
+ mid: array[1],
+ hi: array[2],
+ flags: flags(self.is_sign_negative(), value_scale),
+ })
+ }
+ Ordering::Less => {
+ // We're requesting a lower number of significant digits.
+ let diff = mantissa_sf - digits;
+ // If the diff is greater than the scale we're focused on the integral. Otherwise, we can
+ // just round.
+ if diff > scale {
+ use crate::constants::BIG_POWERS_10;
+ // We need to adjust the integral portion. This also should be rounded, consequently
+ // we reduce the number down, round it, and then scale back up.
+ // E.g. If we have 305.459 scaling to a sf of 2 - we first reduce the number
+ // down to 30.5459, round it to 31 and then scale it back up to 310.
+ // Likewise, if we have 12301 scaling to a sf of 3 - we first reduce the number
+ // down to 123.01, round it to 123 and then scale it back up to 12300.
+ let mut num = *self;
+ let mut exp = (diff - scale) as usize;
+ while exp > 0 {
+ let pow;
+ if exp >= BIG_POWERS_10.len() {
+ pow = Decimal::from(BIG_POWERS_10[BIG_POWERS_10.len() - 1]);
+ exp -= BIG_POWERS_10.len();
+ } else {
+ pow = Decimal::from(BIG_POWERS_10[exp - 1]);
+ exp = 0;
+ }
+ num = num.checked_div(pow)?;
+ }
+ let mut num = num.round_dp_with_strategy(0, strategy).trunc();
+ let mut exp = (mantissa_sf - digits - scale) as usize;
+ while exp > 0 {
+ let pow;
+ if exp >= BIG_POWERS_10.len() {
+ pow = Decimal::from(BIG_POWERS_10[BIG_POWERS_10.len() - 1]);
+ exp -= BIG_POWERS_10.len();
+ } else {
+ pow = Decimal::from(BIG_POWERS_10[exp - 1]);
+ exp = 0;
+ }
+ num = num.checked_mul(pow)?;
+ }
+ Some(num)
+ } else {
+ Some(self.round_dp_with_strategy(scale - diff, strategy))
+ }
+ }
+ Ordering::Equal => {
+ // Case where significant figures = requested significant digits.
+ Some(*self)
+ }
+ }
+ }
+
+ /// 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 rust_decimal_macros::dec;
+ ///
+ /// let pi = dec!(3.1415926535897932384626433832);
+ /// assert_eq!(format!("{:?}", pi), "3.1415926535897932384626433832");
+ /// assert_eq!(format!("{:?}", pi.unpack()), "UnpackedDecimal { \
+ /// negative: false, scale: 28, hi: 1703060790, mid: 185874565, lo: 1102470952 \
+ /// }");
+ /// ```
+ #[must_use]
+ 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]
+ }
+
+ /// Parses a 32-bit float into a Decimal number whilst retaining any non-guaranteed precision.
+ ///
+ /// Typically when a float is parsed in Rust Decimal, any excess bits (after ~7.22 decimal points for
+ /// f32 as per IEEE-754) are removed due to any digits following this are considered an approximation
+ /// at best. This function bypasses this additional step and retains these excess bits.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use rust_decimal::prelude::*;
+ /// #
+ /// // Usually floats are parsed leveraging float guarantees. i.e. 0.1_f32 => 0.1
+ /// assert_eq!("0.1", Decimal::from_f32(0.1_f32).unwrap().to_string());
+ ///
+ /// // Sometimes, we may want to represent the approximation exactly.
+ /// assert_eq!("0.100000001490116119384765625", Decimal::from_f32_retain(0.1_f32).unwrap().to_string());
+ /// ```
+ pub fn from_f32_retain(n: f32) -> Option<Self> {
+ from_f32(n, false)
+ }
+
+ /// Parses a 64-bit float into a Decimal number whilst retaining any non-guaranteed precision.
+ ///
+ /// Typically when a float is parsed in Rust Decimal, any excess bits (after ~15.95 decimal points for
+ /// f64 as per IEEE-754) are removed due to any digits following this are considered an approximation
+ /// at best. This function bypasses this additional step and retains these excess bits.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use rust_decimal::prelude::*;
+ /// #
+ /// // Usually floats are parsed leveraging float guarantees. i.e. 0.1_f64 => 0.1
+ /// assert_eq!("0.1", Decimal::from_f64(0.1_f64).unwrap().to_string());
+ ///
+ /// // Sometimes, we may want to represent the approximation exactly.
+ /// assert_eq!("0.1000000000000000055511151231", Decimal::from_f64_retain(0.1_f64).unwrap().to_string());
+ /// ```
+ pub fn from_f64_retain(n: f64) -> Option<Self> {
+ from_f64(n, false)
+ }
+}
+
+impl Default for Decimal {
+ /// Returns the default value for a `Decimal` (equivalent to `Decimal::ZERO`). [Read more]
+ ///
+ /// [Read more]: core::default::Default#tymethod.default
+ #[inline]
+ 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! integer_docs {
+ ( true ) => {
+ " by truncating and returning the integer component"
+ };
+ ( false ) => {
+ ""
+ };
+}
+
+// #[doc] attributes are formatted poorly with rustfmt so skip for now.
+// See https://github.com/rust-lang/rustfmt/issues/5062 for more information.
+#[rustfmt::skip]
+macro_rules! impl_try_from_decimal {
+ ($TInto:ty, $conversion_fn:path, $additional_docs:expr) => {
+ #[doc = concat!(
+ "Try to convert a `Decimal` to `",
+ stringify!($TInto),
+ "`",
+ $additional_docs,
+ ".\n\nCan fail if the `Decimal` is out of range for `",
+ stringify!($TInto),
+ "`.",
+ )]
+ impl TryFrom<Decimal> for $TInto {
+ type Error = crate::Error;
+
+ #[inline]
+ fn try_from(t: Decimal) -> Result<Self, Error> {
+ $conversion_fn(&t).ok_or_else(|| Error::ConversionTo(stringify!($TInto).into()))
+ }
+ }
+ };
+}
+
+impl_try_from_decimal!(f32, Decimal::to_f32, integer_docs!(false));
+impl_try_from_decimal!(f64, Decimal::to_f64, integer_docs!(false));
+impl_try_from_decimal!(isize, Decimal::to_isize, integer_docs!(true));
+impl_try_from_decimal!(i8, Decimal::to_i8, integer_docs!(true));
+impl_try_from_decimal!(i16, Decimal::to_i16, integer_docs!(true));
+impl_try_from_decimal!(i32, Decimal::to_i32, integer_docs!(true));
+impl_try_from_decimal!(i64, Decimal::to_i64, integer_docs!(true));
+impl_try_from_decimal!(i128, Decimal::to_i128, integer_docs!(true));
+impl_try_from_decimal!(usize, Decimal::to_usize, integer_docs!(true));
+impl_try_from_decimal!(u8, Decimal::to_u8, integer_docs!(true));
+impl_try_from_decimal!(u16, Decimal::to_u16, integer_docs!(true));
+impl_try_from_decimal!(u32, Decimal::to_u32, integer_docs!(true));
+impl_try_from_decimal!(u64, Decimal::to_u64, integer_docs!(true));
+impl_try_from_decimal!(u128, Decimal::to_u128, integer_docs!(true));
+
+// #[doc] attributes are formatted poorly with rustfmt so skip for now.
+// See https://github.com/rust-lang/rustfmt/issues/5062 for more information.
+#[rustfmt::skip]
+macro_rules! impl_try_from_primitive {
+ ($TFrom:ty, $conversion_fn:path $(, $err:expr)?) => {
+ #[doc = concat!(
+ "Try to convert a `",
+ stringify!($TFrom),
+ "` into a `Decimal`.\n\nCan fail if the value is out of range for `Decimal`."
+ )]
+ impl TryFrom<$TFrom> for Decimal {
+ type Error = crate::Error;
+
+ #[inline]
+ fn try_from(t: $TFrom) -> Result<Self, Error> {
+ $conversion_fn(t) $( .ok_or_else(|| $err) )?
+ }
+ }
+ };
+}
+
+impl_try_from_primitive!(f32, Self::from_f32, Error::ConversionTo("Decimal".into()));
+impl_try_from_primitive!(f64, Self::from_f64, Error::ConversionTo("Decimal".into()));
+impl_try_from_primitive!(&str, core::str::FromStr::from_str);
+
+macro_rules! impl_from {
+ ($T:ty, $from_ty:path) => {
+ ///
+ /// Conversion to `Decimal`.
+ ///
+ 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);
+
+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 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;
+ };
+ // Check if we overflow
+ 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> {
+ // Check if we overflow
+ 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> {
+ // By default, we remove excess bits. This allows 0.1_f64 == dec!(0.1).
+ from_f32(n, true)
+ }
+
+ fn from_f64(n: f64) -> Option<Decimal> {
+ // By default, we remove excess bits. This allows 0.1_f64 == dec!(0.1).
+ from_f64(n, true)
+ }
+}
+
+#[inline]
+fn from_f64(n: f64, remove_excess_bits: bool) -> Option<Decimal> {
+ // 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 = 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
+ base2_to_decimal(&mut bits, exponent2, positive, true, remove_excess_bits)
+}
+
+#[inline]
+fn from_f32(n: f32, remove_excess_bits: bool) -> Option<Decimal> {
+ // 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 = 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
+ base2_to_decimal(&mut bits, exponent2, positive, false, remove_excess_bits)
+}
+
+fn base2_to_decimal(
+ bits: &mut [u32; 3],
+ exponent2: i32,
+ positive: bool,
+ is64: bool,
+ remove_excess_bits: bool,
+) -> Option<Decimal> {
+ // 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 ops::array::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;
+ ops::array::shl1_internal(bits, 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;
+ ops::array::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 ops::array::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_U32 as i32) {
+ let rem10 = ops::array::div_by_u32(bits, 10);
+ exponent10 += 1;
+ if ops::array::is_all_zero(bits) {
+ // Underflow, unable to keep dividing
+ exponent10 = 0;
+ } else if rem10 >= 5 {
+ ops::array::add_one_internal(bits);
+ }
+ }
+
+ if remove_excess_bits {
+ // 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 (see IEEE-754).
+ if is64 {
+ // Guaranteed to approx 15/16 dp
+ 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 {
+ // Guaranteed to about 7/8 dp
+ 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);
+ }
+ }
+ }
+
+ // Remove multiples of 10 from the representation
+ 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),
+ })
+}
+
+impl ToPrimitive for Decimal {
+ fn to_i64(&self) -> Option<i64> {
+ let d = self.trunc();
+ // If it is in the hi bit then it is a clear overflow.
+ if d.hi != 0 {
+ // Overflow
+ return None;
+ }
+ let negative = self.is_sign_negative();
+
+ // A bit more convoluted in terms of checking when it comes to the hi bit due to twos-complement
+ if d.mid & 0x8000_0000 > 0 {
+ if negative && d.mid == 0x8000_0000 && d.lo == 0 {
+ // We do this because below we try to convert the i64 to a positive first - of which
+ // doesn't fit into an i64.
+ return Some(i64::MIN);
+ }
+ return None;
+ }
+
+ let raw: i64 = (i64::from(d.mid) << 32) | i64::from(d.lo);
+ if negative {
+ Some(raw.neg())
+ } 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 {
+ // Overflow
+ 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 {
+ // If scale is zero, we are storing a 96-bit integer value, that would
+ // always fit into i128, which in turn is always representable as f64,
+ // albeit with loss of precision for values outside of -2^53..2^53 range.
+ let integer = self.to_i128();
+ integer.map(|i| i as f64)
+ } 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);
+ let value = sign * ((integral_part as f64) + frac_f64);
+ let round_to = 10f64.powi(self.scale() as i32);
+ Some((value * round_to).round() / round_to)
+ }
+ }
+}
+
+impl fmt::Display for Decimal {
+ fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ let (rep, additional) = crate::str::to_str_internal(self, false, f.precision());
+ if let Some(additional) = additional {
+ let value = [rep.as_str(), "0".repeat(additional).as_str()].concat();
+ f.pad_integral(self.is_sign_positive(), "", value.as_str())
+ } else {
+ 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,
+ }
+ }
+}
+
+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)
+ }
+}
+
+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)
+ }
+}
+
+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)
+ }
+}
+
+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)
+ }
+}
+
+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 Product for Decimal {
+ /// Panics if out-of-bounds
+ fn product<I: Iterator<Item = Decimal>>(iter: I) -> Self {
+ let mut product = ONE;
+ for i in iter {
+ product *= i;
+ }
+ product
+ }
+}
+
+impl<'a> Product<&'a Decimal> for Decimal {
+ /// Panics if out-of-bounds
+ fn product<I: Iterator<Item = &'a Decimal>>(iter: I) -> Self {
+ let mut product = ONE;
+ for i in iter {
+ product *= i;
+ }
+ product
+ }
+}
+
+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
+ }
+}