Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  decimal.rs   Sprache: unbekannt

 
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]
--> --------------------

--> maximum size reached

--> --------------------

[ Dauer der Verarbeitung: 0.44 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge