pub struct Decimal { /* private fields */ }Expand description
An exact fixed-point decimal: mantissa × 10⁻ˢᶜᵃˡᵉ.
See the module documentation for why the type exists and what it
guarantees. Construct with Decimal::new or by parsing the digits:
use chronix_core::Decimal;
let register: Decimal = "1234.5678".parse().unwrap();
assert_eq!(register.mantissa(), 12_345_678);
assert_eq!(register.scale(), 4);
assert_eq!(register.to_string(), "1234.5678");
// Widening is exact; narrowing past a non-zero digit is refused.
assert_eq!(register.rescale(6).unwrap().to_string(), "1234.567800");
assert!(register.rescale(2).is_err());Implementations§
Source§impl Decimal
impl Decimal
Sourcepub const fn new(mantissa: i128, scale: u8) -> Result<Self, DecimalError>
pub const fn new(mantissa: i128, scale: u8) -> Result<Self, DecimalError>
Construct from an unscaled mantissa and a scale.
§Errors
DecimalError::ScaleTooLarge if scale > MAX_DECIMAL_SCALE, and
DecimalError::PrecisionOverflow if the mantissa needs more than
38 significant digits.
Sourcepub const fn zero(scale: u8) -> Result<Self, DecimalError>
pub const fn zero(scale: u8) -> Result<Self, DecimalError>
Sourcepub const fn abs(&self) -> Self
pub const fn abs(&self) -> Self
The absolute value, at the same scale.
Total: |mantissa| cannot overflow because the mantissa is bounded
by MAX_DECIMAL_MANTISSA, well inside i128::MIN.
Sourcepub fn rescale(&self, target: u8) -> Result<Self, DecimalError>
pub fn rescale(&self, target: u8) -> Result<Self, DecimalError>
Return the same value expressed at target scale.
Widening multiplies by a power of ten and is always exact. Narrowing
succeeds only when every digit it would drop is a zero — 1.500 to
scale 1 is 1.5, 1.55 to scale 1 is an error, never 1.6 and
never 1.5.
§Errors
DecimalError::ScaleTooLargeiftarget > MAX_DECIMAL_SCALE.DecimalError::InexactRescaleif narrowing would drop a non-zero digit.DecimalError::PrecisionOverflowif widening pushes the mantissa past 38 significant digits.
Sourcepub fn normalized(&self, min_scale: u8) -> Self
pub fn normalized(&self, min_scale: u8) -> Self
Drop trailing fractional zeros, down to min_scale.
1.2500 normalised to a minimum scale of 0 is 1.25; to a minimum
of 3 it is 1.250. Never changes the value.
Sourcepub fn checked_add(&self, other: &Self) -> Result<Self, DecimalError>
pub fn checked_add(&self, other: &Self) -> Result<Self, DecimalError>
Exact sum, at the wider of the two scales.
§Errors
DecimalError::Overflow if the result needs more than 38
significant digits.
Sourcepub fn checked_sub(&self, other: &Self) -> Result<Self, DecimalError>
pub fn checked_sub(&self, other: &Self) -> Result<Self, DecimalError>
Exact difference, at the wider of the two scales.
§Errors
DecimalError::Overflow if the result needs more than 38
significant digits.
Sourcepub fn to_f64_lossy(&self) -> f64
pub fn to_f64_lossy(&self) -> f64
The value as an f64 — lossy, and named so at every call site.
The only conversion to binary floating point this type offers. A settlement quantity must not travel this way; a chart of one may.
Sourcepub fn cmp_exact(&self, other: &Self) -> Ordering
pub fn cmp_exact(&self, other: &Self) -> Ordering
Compare against another decimal of any scale, exactly.
Aligning two mantissas at different scales can overflow i128 —
10³⁷ at scale 0 against anything at scale 38 does. An overflow is
not an error here but an answer: the side that cannot be represented
at the common scale is the side with the larger magnitude, because
the other one is representable there.
Trait Implementations§
impl Copy for Decimal
Source§impl<'de> Deserialize<'de> for Decimal
impl<'de> Deserialize<'de> for Decimal
Source§fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error>
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error>
impl Eq for Decimal
Source§impl From<Decimal> for FieldValue
impl From<Decimal> for FieldValue
Source§impl FromStr for Decimal
impl FromStr for Decimal
Source§fn from_str(s: &str) -> Result<Self, Self::Err>
fn from_str(s: &str) -> Result<Self, Self::Err>
Parse the digits themselves — never via f64.
Accepts an optional sign, digits with an optional fractional part,
and an optional decimal exponent (1.5e3). The scale is the number
of fractional digits less the exponent; a literal that lands on a
scale above MAX_DECIMAL_SCALE is accepted only if the excess
digits are trailing zeros that can be dropped without changing the
value.
Source§type Err = DecimalError
type Err = DecimalError
Source§impl Ord for Decimal
impl Ord for Decimal
1.21.0 (const: unstable) · Source§fn max(self, other: Self) -> Selfwhere
Self: Sized,
fn max(self, other: Self) -> Selfwhere
Self: Sized,
1.21.0 (const: unstable) · Source§fn min(self, other: Self) -> Selfwhere
Self: Sized,
fn min(self, other: Self) -> Selfwhere
Self: Sized,
Source§impl PartialOrd for Decimal
impl PartialOrd for Decimal
Source§impl Serialize for Decimal
impl Serialize for Decimal
Source§fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>
Exact in both directions: the digits as a string for JSON and any
other human-readable format, the (mantissa, scale) pair for
postcard and the rest of the binary ones.
A decimal must never reach JSON as a JSON number: serde_json
parses one back through f64, which is the loss this type exists to
prevent.