Skip to main content

cosmwasm_std/math/
decimal256.rs

1use core::cmp::Ordering;
2use core::fmt::{self, Write};
3use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Sub, SubAssign};
4use core::str::FromStr;
5use serde::{de, ser, Deserialize, Deserializer, Serialize};
6
7use crate::errors::{
8    CheckedFromRatioError, CheckedMultiplyRatioError, DivideByZeroError, ErrorKind, OverflowError,
9    OverflowOperation, RoundUpOverflowError, StdError,
10};
11use crate::forward_ref::{forward_ref_binop, forward_ref_op_assign};
12use crate::{Decimal, SignedDecimal, SignedDecimal256, __internal::forward_ref_partial_eq};
13
14use super::Fraction;
15use super::Isqrt;
16use super::{Uint256, Uint512};
17
18/// A fixed-point decimal value with 18 fractional digits, i.e. Decimal256(1_000_000_000_000_000_000) == 1.0
19///
20/// The greatest possible value that can be represented is 115792089237316195423570985008687907853269984665640564039457.584007913129639935 = (2^256 - 1) / 10^18
21#[derive(
22    Copy,
23    Clone,
24    Default,
25    PartialEq,
26    Eq,
27    PartialOrd,
28    Ord,
29    schemars::JsonSchema,
30    cw_schema::Schemaifier,
31)]
32#[schemaifier(type = cw_schema::NodeType::Decimal { precision: 256, signed: false })]
33pub struct Decimal256(#[schemars(with = "String")] Uint256);
34
35forward_ref_partial_eq!(Decimal256, Decimal256);
36
37#[derive(Debug, PartialEq, Eq, thiserror::Error)]
38#[error("Decimal256 range exceeded")]
39pub struct Decimal256RangeExceeded;
40
41impl Decimal256 {
42    const DECIMAL_FRACTIONAL: Uint256 = // 1*10**18
43        Uint256::new(1_000_000_000_000_000_000);
44    const DECIMAL_FRACTIONAL_SQUARED: Uint256 = // 1*10**36
45        Uint256::new(1_000_000_000_000_000_000_000_000_000_000_000_000);
46
47    /// The number of decimal places. Since decimal types are fixed-point rather than
48    /// floating-point, this is a constant.
49    pub const DECIMAL_PLACES: u32 = 18;
50    /// The largest value that can be represented by this decimal type.
51    pub const MAX: Self = Self(Uint256::MAX);
52    /// The smallest value that can be represented by this decimal type.
53    pub const MIN: Self = Self(Uint256::MIN);
54
55    /// Creates a Decimal256 from Uint256
56    /// This is equivalent to `Decimal256::from_atomics(value, 18)` but usable in a const context.
57    ///
58    /// ## Examples
59    ///
60    /// ```
61    /// # use cosmwasm_std::{Uint256, Decimal256};
62    /// let atoms = Uint256::new(141_183_460_469_231_731_687_303_715_884_105_727_125);
63    /// let value = Decimal256::new(atoms);
64    /// assert_eq!(value.to_string(), "141183460469231731687.303715884105727125");
65    /// ```
66    #[inline]
67    #[must_use]
68    pub const fn new(value: Uint256) -> Self {
69        Self(value)
70    }
71
72    /// Creates a Decimal256 from u128
73    /// This is equivalent to `Decimal256::from_atomics(value, 18)` but usable in a const context.
74    #[deprecated(
75        since = "3.0.0",
76        note = "Use Decimal256::new(Uint256::new(value)) instead"
77    )]
78    pub const fn raw(value: u128) -> Self {
79        Self(Uint256::new(value))
80    }
81
82    /// Create a 1.0 Decimal256
83    #[inline]
84    pub const fn one() -> Self {
85        Self(Self::DECIMAL_FRACTIONAL)
86    }
87
88    /// Create a 0.0 Decimal256
89    #[inline]
90    pub const fn zero() -> Self {
91        Self(Uint256::zero())
92    }
93
94    /// Convert x% into Decimal256
95    ///
96    /// ## Examples
97    ///
98    /// ```
99    /// # use std::str::FromStr;
100    /// # use cosmwasm_std::Decimal256;
101    /// const HALF: Decimal256 = Decimal256::percent(50);
102    ///
103    /// assert_eq!(HALF, Decimal256::from_str("0.5").unwrap());
104    /// ```
105    pub const fn percent(x: u64) -> Self {
106        // multiplication does not overflow since `u64::MAX` * 10**16 is well in u128 range
107        let atomics = (x as u128) * 10_000_000_000_000_000;
108        Self(Uint256::new(atomics))
109    }
110
111    /// Convert permille (x/1000) into Decimal256
112    ///
113    /// ## Examples
114    ///
115    /// ```
116    /// # use std::str::FromStr;
117    /// # use cosmwasm_std::Decimal256;
118    /// const HALF: Decimal256 = Decimal256::permille(500);
119    ///
120    /// assert_eq!(HALF, Decimal256::from_str("0.5").unwrap());
121    /// ```
122    pub const fn permille(x: u64) -> Self {
123        // multiplication does not overflow since `u64::MAX` * 10**15 is well in u128 range
124        let atomics = (x as u128) * 1_000_000_000_000_000;
125        Self(Uint256::new(atomics))
126    }
127
128    /// Convert basis points (x/10000) into Decimal256
129    ///
130    /// ## Examples
131    ///
132    /// ```
133    /// # use std::str::FromStr;
134    /// # use cosmwasm_std::Decimal256;
135    /// const TWO_BPS: Decimal256 = Decimal256::bps(2);
136    /// const HALF: Decimal256 = Decimal256::bps(5000);
137    ///
138    /// assert_eq!(TWO_BPS, Decimal256::from_str("0.0002").unwrap());
139    /// assert_eq!(HALF, Decimal256::from_str("0.5").unwrap());
140    /// ```
141    pub const fn bps(x: u64) -> Self {
142        // multiplication does not overflow since `u64::MAX` * 10**14 is well in u128 range
143        let atomics = (x as u128) * 100_000_000_000_000;
144        Self(Uint256::new(atomics))
145    }
146
147    /// Creates a decimal from a number of atomic units and the number
148    /// of decimal places. The inputs will be converted internally to form
149    /// a decimal with 18 decimal places. So the input 123 and 2 will create
150    /// the decimal 1.23.
151    ///
152    /// Using 18 decimal places is slightly more efficient than other values
153    /// as no internal conversion is necessary.
154    ///
155    /// ## Examples
156    ///
157    /// ```
158    /// # use cosmwasm_std::{Decimal256, Uint256};
159    /// let a = Decimal256::from_atomics(1234u64, 3).unwrap();
160    /// assert_eq!(a.to_string(), "1.234");
161    ///
162    /// let a = Decimal256::from_atomics(1234u128, 0).unwrap();
163    /// assert_eq!(a.to_string(), "1234");
164    ///
165    /// let a = Decimal256::from_atomics(1u64, 18).unwrap();
166    /// assert_eq!(a.to_string(), "0.000000000000000001");
167    ///
168    /// let a = Decimal256::from_atomics(Uint256::MAX, 18).unwrap();
169    /// assert_eq!(a, Decimal256::MAX);
170    /// ```
171    pub fn from_atomics(
172        atomics: impl Into<Uint256>,
173        decimal_places: u32,
174    ) -> Result<Self, Decimal256RangeExceeded> {
175        let atomics = atomics.into();
176        const TEN: Uint256 = Uint256::from_be_bytes([
177            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
178            0, 0, 10,
179        ]);
180        Ok(match decimal_places.cmp(&Self::DECIMAL_PLACES) {
181            Ordering::Less => {
182                let digits = (Self::DECIMAL_PLACES) - decimal_places; // No overflow because decimal_places < DECIMAL_PLACES
183                let factor = TEN.checked_pow(digits).unwrap(); // Safe because digits <= 17
184                Self(
185                    atomics
186                        .checked_mul(factor)
187                        .map_err(|_| Decimal256RangeExceeded)?,
188                )
189            }
190            Ordering::Equal => Self(atomics),
191            Ordering::Greater => {
192                let digits = decimal_places - (Self::DECIMAL_PLACES); // No overflow because decimal_places > DECIMAL_PLACES
193                if atomics.is_zero() || digits > atomics.ilog10() {
194                    // In this case `10^digits > atomics`, so the division truncates to zero.
195                    Self(Uint256::zero())
196                } else {
197                    // `digits <= ilog10(atomics)` guarantees `10^digits` fits in Uint256.
198                    let factor = TEN.checked_pow(digits).unwrap();
199                    Self(atomics.checked_div(factor).unwrap()) // Safe because factor cannot be zero
200                }
201            }
202        })
203    }
204
205    /// Returns the ratio (numerator / denominator) as a Decimal256
206    pub fn from_ratio(numerator: impl Into<Uint256>, denominator: impl Into<Uint256>) -> Self {
207        match Decimal256::checked_from_ratio(numerator, denominator) {
208            Ok(value) => value,
209            Err(CheckedFromRatioError::DivideByZero) => {
210                panic!("Denominator must not be zero")
211            }
212            Err(CheckedFromRatioError::Overflow) => panic!("Multiplication overflow"),
213        }
214    }
215
216    /// Returns the ratio (numerator / denominator) as a Decimal256
217    pub fn checked_from_ratio(
218        numerator: impl Into<Uint256>,
219        denominator: impl Into<Uint256>,
220    ) -> Result<Self, CheckedFromRatioError> {
221        let numerator: Uint256 = numerator.into();
222        let denominator: Uint256 = denominator.into();
223        match numerator.checked_multiply_ratio(Self::DECIMAL_FRACTIONAL, denominator) {
224            Ok(ratio) => {
225                // numerator * DECIMAL_FRACTIONAL / denominator
226                Ok(Self(ratio))
227            }
228            Err(CheckedMultiplyRatioError::Overflow) => Err(CheckedFromRatioError::Overflow),
229            Err(CheckedMultiplyRatioError::DivideByZero) => {
230                Err(CheckedFromRatioError::DivideByZero)
231            }
232        }
233    }
234
235    #[must_use]
236    pub const fn is_zero(&self) -> bool {
237        self.0.is_zero()
238    }
239
240    /// A decimal is an integer of atomic units plus a number that specifies the
241    /// position of the decimal dot. So any decimal can be expressed as two numbers.
242    ///
243    /// ## Examples
244    ///
245    /// ```
246    /// # use cosmwasm_std::{Decimal256, Uint256};
247    /// # use core::str::FromStr;
248    /// // Value with whole and fractional part
249    /// let a = Decimal256::from_str("1.234").unwrap();
250    /// assert_eq!(a.decimal_places(), 18);
251    /// assert_eq!(a.atomics(), Uint256::from(1234000000000000000u128));
252    ///
253    /// // Smallest possible value
254    /// let b = Decimal256::from_str("0.000000000000000001").unwrap();
255    /// assert_eq!(b.decimal_places(), 18);
256    /// assert_eq!(b.atomics(), Uint256::from(1u128));
257    /// ```
258    #[must_use]
259    #[inline]
260    pub const fn atomics(&self) -> Uint256 {
261        self.0
262    }
263
264    /// The number of decimal places. This is a constant value for now
265    /// but this could potentially change as the type evolves.
266    ///
267    /// See also [`Decimal256::atomics()`].
268    #[must_use]
269    #[inline]
270    pub const fn decimal_places(&self) -> u32 {
271        Self::DECIMAL_PLACES
272    }
273
274    /// Rounds value down after decimal places.
275    #[must_use = "this returns the result of the operation, without modifying the original"]
276    pub fn floor(&self) -> Self {
277        Self((self.0 / Self::DECIMAL_FRACTIONAL) * Self::DECIMAL_FRACTIONAL)
278    }
279
280    /// Rounds value up after decimal places. Panics on overflow.
281    #[must_use = "this returns the result of the operation, without modifying the original"]
282    pub fn ceil(&self) -> Self {
283        match self.checked_ceil() {
284            Ok(value) => value,
285            Err(_) => panic!("attempt to ceil with overflow"),
286        }
287    }
288
289    /// Rounds value up after decimal places. Returns OverflowError on overflow.
290    pub fn checked_ceil(&self) -> Result<Self, RoundUpOverflowError> {
291        let floor = self.floor();
292        if floor == self {
293            Ok(floor)
294        } else {
295            floor
296                .checked_add(Decimal256::one())
297                .map_err(|_| RoundUpOverflowError)
298        }
299    }
300
301    pub fn checked_add(self, other: Self) -> Result<Self, OverflowError> {
302        self.0
303            .checked_add(other.0)
304            .map(Self)
305            .map_err(|_| OverflowError::new(OverflowOperation::Add))
306    }
307
308    pub fn checked_sub(self, other: Self) -> Result<Self, OverflowError> {
309        self.0
310            .checked_sub(other.0)
311            .map(Self)
312            .map_err(|_| OverflowError::new(OverflowOperation::Sub))
313    }
314
315    /// Multiplies one `Decimal256` by another, returning an `OverflowError` if an overflow occurred.
316    pub fn checked_mul(self, other: Self) -> Result<Self, OverflowError> {
317        let result_as_uint512 = self.numerator().full_mul(other.numerator())
318            / Uint512::from_uint256(Self::DECIMAL_FRACTIONAL); // from_uint128 is a const method and should be "free"
319        result_as_uint512
320            .try_into()
321            .map(Self)
322            .map_err(|_| OverflowError::new(OverflowOperation::Mul))
323    }
324
325    /// Raises a value to the power of `exp`, panics if an overflow occurred.
326    #[must_use = "this returns the result of the operation, without modifying the original"]
327    pub fn pow(self, exp: u32) -> Self {
328        match self.checked_pow(exp) {
329            Ok(value) => value,
330            Err(_) => panic!("Multiplication overflow"),
331        }
332    }
333
334    /// Raises a value to the power of `exp`, returning an `OverflowError` if an overflow occurred.
335    pub fn checked_pow(self, exp: u32) -> Result<Self, OverflowError> {
336        // This uses the exponentiation by squaring algorithm:
337        // https://en.wikipedia.org/wiki/Exponentiation_by_squaring#Basic_method
338
339        fn inner(mut x: Decimal256, mut n: u32) -> Result<Decimal256, OverflowError> {
340            if n == 0 {
341                return Ok(Decimal256::one());
342            }
343
344            let mut y = Decimal256::one();
345
346            while n > 1 {
347                if n % 2 == 0 {
348                    x = x.checked_mul(x)?;
349                    n /= 2;
350                } else {
351                    y = x.checked_mul(y)?;
352                    x = x.checked_mul(x)?;
353                    n = (n - 1) / 2;
354                }
355            }
356
357            Ok(x * y)
358        }
359
360        inner(self, exp).map_err(|_| OverflowError::new(OverflowOperation::Pow))
361    }
362
363    pub fn checked_div(self, other: Self) -> Result<Self, CheckedFromRatioError> {
364        Decimal256::checked_from_ratio(self.numerator(), other.numerator())
365    }
366
367    pub fn checked_rem(self, other: Self) -> Result<Self, DivideByZeroError> {
368        self.0
369            .checked_rem(other.0)
370            .map(Self)
371            .map_err(|_| DivideByZeroError)
372    }
373
374    /// Returns the approximate square root as a Decimal256.
375    ///
376    /// This should not overflow or panic.
377    #[must_use = "this returns the result of the operation, without modifying the original"]
378    pub fn sqrt(&self) -> Self {
379        // The max precision is `9 - log10(self.0) / 2`.
380        // We can optimize the previous loop by using `ilog10` to directly calculate the precision.
381        if self.0.is_zero() {
382            // value is 0, so we can use any precision, let's use the max one
383            return self.sqrt_with_precision(Self::DECIMAL_PLACES / 2).unwrap();
384        }
385
386        // 77 is the max `ilog10` value for Uint256
387        // 9 is the max precision (DECIMAL_PLACES / 2)
388        let precision_guess = (77 - self.0.ilog10()) / 2;
389        let precision = core::cmp::min(precision_guess, Self::DECIMAL_PLACES / 2);
390
391        // The estimate using ilog10 might determine a precision that causes overflow for
392        // high mantissas (e.g. 4e75). In that case, we need to lower the precision by 1.
393        // We know that precision-1 is always safe because it reduces the exponent by 2.
394        self.sqrt_with_precision(precision)
395            .or_else(|| self.sqrt_with_precision(precision - 1))
396            .unwrap()
397    }
398
399    /// Lower precision means more aggressive rounding, but less risk of overflow.
400    /// Precision *must* be a number between 0 and 9 (inclusive).
401    ///
402    /// Returns `None` if the internal multiplication overflows.
403    #[must_use = "this returns the result of the operation, without modifying the original"]
404    fn sqrt_with_precision(&self, precision: u32) -> Option<Self> {
405        let inner_mul = Uint256::from(100u128).pow(precision);
406        self.0.checked_mul(inner_mul).ok().map(|inner| {
407            let outer_mul = Uint256::from(10u128).pow(Self::DECIMAL_PLACES / 2 - precision);
408            Self(inner.isqrt().checked_mul(outer_mul).unwrap())
409        })
410    }
411
412    #[must_use = "this returns the result of the operation, without modifying the original"]
413    pub fn abs_diff(self, other: Self) -> Self {
414        if self < other {
415            other - self
416        } else {
417            self - other
418        }
419    }
420
421    #[must_use = "this returns the result of the operation, without modifying the original"]
422    pub fn saturating_add(self, other: Self) -> Self {
423        self.checked_add(other).unwrap_or(Self::MAX)
424    }
425
426    #[must_use = "this returns the result of the operation, without modifying the original"]
427    pub fn saturating_sub(self, other: Self) -> Self {
428        self.checked_sub(other).unwrap_or_else(|_| Self::zero())
429    }
430
431    #[must_use = "this returns the result of the operation, without modifying the original"]
432    pub fn saturating_mul(self, other: Self) -> Self {
433        self.checked_mul(other).unwrap_or(Self::MAX)
434    }
435
436    #[must_use = "this returns the result of the operation, without modifying the original"]
437    pub fn saturating_pow(self, exp: u32) -> Self {
438        self.checked_pow(exp).unwrap_or(Self::MAX)
439    }
440
441    /// Converts this decimal to an unsigned integer by truncating
442    /// the fractional part, e.g. 22.5 becomes 22.
443    ///
444    /// ## Examples
445    ///
446    /// ```
447    /// use core::str::FromStr;
448    /// use cosmwasm_std::{Decimal256, Uint256};
449    ///
450    /// let d = Decimal256::from_str("12.345").unwrap();
451    /// assert_eq!(d.to_uint_floor(), Uint256::from(12u64));
452    ///
453    /// let d = Decimal256::from_str("12.999").unwrap();
454    /// assert_eq!(d.to_uint_floor(), Uint256::from(12u64));
455    ///
456    /// let d = Decimal256::from_str("75.0").unwrap();
457    /// assert_eq!(d.to_uint_floor(), Uint256::from(75u64));
458    /// ```
459    #[must_use = "this returns the result of the operation, without modifying the original"]
460    pub fn to_uint_floor(self) -> Uint256 {
461        self.0 / Self::DECIMAL_FRACTIONAL
462    }
463
464    /// Converts this decimal to an unsigned integer by rounding up
465    /// to the next integer, e.g. 22.3 becomes 23.
466    ///
467    /// ## Examples
468    ///
469    /// ```
470    /// use core::str::FromStr;
471    /// use cosmwasm_std::{Decimal256, Uint256};
472    ///
473    /// let d = Decimal256::from_str("12.345").unwrap();
474    /// assert_eq!(d.to_uint_ceil(), Uint256::from(13u64));
475    ///
476    /// let d = Decimal256::from_str("12.999").unwrap();
477    /// assert_eq!(d.to_uint_ceil(), Uint256::from(13u64));
478    ///
479    /// let d = Decimal256::from_str("75.0").unwrap();
480    /// assert_eq!(d.to_uint_ceil(), Uint256::from(75u64));
481    /// ```
482    #[must_use = "this returns the result of the operation, without modifying the original"]
483    pub fn to_uint_ceil(self) -> Uint256 {
484        // Using `q = 1 + ((x - 1) / y); // if x != 0` with unsigned integers x, y, q
485        // from https://stackoverflow.com/a/2745086/2013738. We know `x + y` CAN overflow.
486        let x = self.0;
487        let y = Self::DECIMAL_FRACTIONAL;
488        if x.is_zero() {
489            Uint256::zero()
490        } else {
491            Uint256::one() + ((x - Uint256::one()) / y)
492        }
493    }
494}
495
496impl Fraction<Uint256> for Decimal256 {
497    #[inline]
498    fn numerator(&self) -> Uint256 {
499        self.0
500    }
501
502    #[inline]
503    fn denominator(&self) -> Uint256 {
504        Self::DECIMAL_FRACTIONAL
505    }
506
507    /// Returns the multiplicative inverse `1/d` for decimal `d`.
508    ///
509    /// If `d` is zero, none is returned.
510    fn inv(&self) -> Option<Self> {
511        if self.is_zero() {
512            None
513        } else {
514            // Let self be p/q with p = self.0 and q = DECIMAL_FRACTIONAL.
515            // Now we calculate the inverse a/b = q/p such that b = DECIMAL_FRACTIONAL. Then
516            // `a = DECIMAL_FRACTIONAL*DECIMAL_FRACTIONAL / self.0`.
517            Some(Self(Self::DECIMAL_FRACTIONAL_SQUARED / self.0))
518        }
519    }
520}
521
522impl From<Decimal> for Decimal256 {
523    fn from(input: Decimal) -> Self {
524        // Unwrap is safe because Decimal256 and Decimal have the same decimal places.
525        // Every Decimal value can be stored in Decimal256.
526        Decimal256::from_atomics(input.atomics(), input.decimal_places()).unwrap()
527    }
528}
529
530impl TryFrom<SignedDecimal> for Decimal256 {
531    type Error = Decimal256RangeExceeded;
532
533    fn try_from(value: SignedDecimal) -> Result<Self, Self::Error> {
534        value
535            .atomics()
536            .try_into()
537            .map(Decimal256)
538            .map_err(|_| Decimal256RangeExceeded)
539    }
540}
541
542impl TryFrom<SignedDecimal256> for Decimal256 {
543    type Error = Decimal256RangeExceeded;
544
545    fn try_from(value: SignedDecimal256) -> Result<Self, Self::Error> {
546        value
547            .atomics()
548            .try_into()
549            .map(Decimal256)
550            .map_err(|_| Decimal256RangeExceeded)
551    }
552}
553
554impl FromStr for Decimal256 {
555    type Err = StdError;
556
557    /// Converts the decimal string to a Decimal256
558    /// Possible inputs: "1.23", "1", "000012", "1.123000000"
559    /// Disallowed: "", ".23"
560    ///
561    /// This never performs any kind of rounding.
562    /// More than DECIMAL_PLACES fractional digits, even zeros, result in an error.
563    fn from_str(input: &str) -> Result<Self, Self::Err> {
564        let mut parts_iter = input.split('.');
565
566        let whole_part = parts_iter.next().unwrap(); // split always returns at least one element
567        let whole = whole_part.parse::<Uint256>()?;
568        let mut atomics = whole.checked_mul(Self::DECIMAL_FRACTIONAL)?;
569
570        if let Some(fractional_part) = parts_iter.next() {
571            let fractional = fractional_part.parse::<Uint256>()?;
572            let exp = Self::DECIMAL_PLACES
573                .checked_sub(fractional_part.len() as u32)
574                .ok_or_else(|| {
575                    StdError::msg(format_args!(
576                        "Cannot parse more than {} fractional digits",
577                        Self::DECIMAL_PLACES
578                    ))
579                })?;
580            debug_assert!(exp <= Self::DECIMAL_PLACES);
581            let fractional_factor = Uint256::from(10u128).pow(exp);
582            atomics = atomics.checked_add(
583                // The inner multiplication can't overflow because
584                // fractional < 10^DECIMAL_PLACES && fractional_factor <= 10^DECIMAL_PLACES
585                fractional.checked_mul(fractional_factor).unwrap(),
586            )?;
587        }
588
589        if parts_iter.next().is_some() {
590            return Err(StdError::msg("Unexpected number of dots").with_kind(ErrorKind::Parsing));
591        }
592
593        Ok(Self(atomics))
594    }
595}
596
597impl fmt::Display for Decimal256 {
598    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
599        let whole = (self.0) / Self::DECIMAL_FRACTIONAL;
600        let fractional = self.0.checked_rem(Self::DECIMAL_FRACTIONAL).unwrap();
601
602        if fractional.is_zero() {
603            write!(f, "{whole}")
604        } else {
605            let fractional_string = format!(
606                "{:0>padding$}",
607                fractional,
608                padding = Self::DECIMAL_PLACES as usize
609            );
610            f.write_str(&whole.to_string())?;
611            f.write_char('.')?;
612            f.write_str(fractional_string.trim_end_matches('0'))?;
613            Ok(())
614        }
615    }
616}
617
618impl fmt::Debug for Decimal256 {
619    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
620        write!(f, "Decimal256({self})")
621    }
622}
623
624impl Add for Decimal256 {
625    type Output = Self;
626
627    fn add(self, other: Self) -> Self {
628        Self(self.0 + other.0)
629    }
630}
631forward_ref_binop!(impl Add, add for Decimal256, Decimal256);
632
633impl AddAssign for Decimal256 {
634    fn add_assign(&mut self, rhs: Decimal256) {
635        *self = *self + rhs;
636    }
637}
638forward_ref_op_assign!(impl AddAssign, add_assign for Decimal256, Decimal256);
639
640impl Sub for Decimal256 {
641    type Output = Self;
642
643    fn sub(self, other: Self) -> Self {
644        Self(self.0 - other.0)
645    }
646}
647forward_ref_binop!(impl Sub, sub for Decimal256, Decimal256);
648
649impl SubAssign for Decimal256 {
650    fn sub_assign(&mut self, rhs: Decimal256) {
651        *self = *self - rhs;
652    }
653}
654forward_ref_op_assign!(impl SubAssign, sub_assign for Decimal256, Decimal256);
655
656impl Mul for Decimal256 {
657    type Output = Self;
658
659    #[allow(clippy::suspicious_arithmetic_impl)]
660    fn mul(self, other: Self) -> Self {
661        // Decimals are fractions. We can multiply two decimals a and b
662        // via
663        //       (a.numerator() * b.numerator()) / (a.denominator() * b.denominator())
664        //     = (a.numerator() * b.numerator()) / a.denominator() / b.denominator()
665
666        let result_as_uint512 = self.numerator().full_mul(other.numerator())
667            / Uint512::from_uint256(Self::DECIMAL_FRACTIONAL); // from_uint256 is a const method and should be "free"
668        match result_as_uint512.try_into() {
669            Ok(result) => Self(result),
670            Err(_) => panic!("attempt to multiply with overflow"),
671        }
672    }
673}
674forward_ref_binop!(impl Mul, mul for Decimal256, Decimal256);
675
676impl MulAssign for Decimal256 {
677    fn mul_assign(&mut self, rhs: Self) {
678        *self = *self * rhs;
679    }
680}
681forward_ref_op_assign!(impl MulAssign, mul_assign for Decimal256, Decimal256);
682
683impl Div for Decimal256 {
684    type Output = Self;
685
686    fn div(self, other: Self) -> Self {
687        match Decimal256::checked_from_ratio(self.numerator(), other.numerator()) {
688            Ok(ratio) => ratio,
689            Err(CheckedFromRatioError::DivideByZero) => {
690                panic!("Division failed - denominator must not be zero")
691            }
692            Err(CheckedFromRatioError::Overflow) => {
693                panic!("Division failed - multiplication overflow")
694            }
695        }
696    }
697}
698forward_ref_binop!(impl Div, div for Decimal256, Decimal256);
699
700impl DivAssign for Decimal256 {
701    fn div_assign(&mut self, rhs: Decimal256) {
702        *self = *self / rhs;
703    }
704}
705forward_ref_op_assign!(impl DivAssign, div_assign for Decimal256, Decimal256);
706
707impl Div<Uint256> for Decimal256 {
708    type Output = Self;
709
710    fn div(self, rhs: Uint256) -> Self::Output {
711        Self(self.0 / rhs)
712    }
713}
714
715impl DivAssign<Uint256> for Decimal256 {
716    fn div_assign(&mut self, rhs: Uint256) {
717        self.0 /= rhs;
718    }
719}
720
721impl Rem for Decimal256 {
722    type Output = Self;
723
724    /// # Panics
725    ///
726    /// This operation will panic if `rhs` is zero
727    #[inline]
728    fn rem(self, rhs: Self) -> Self {
729        Self(self.0.rem(rhs.0))
730    }
731}
732forward_ref_binop!(impl Rem, rem for Decimal256, Decimal256);
733
734impl RemAssign<Decimal256> for Decimal256 {
735    fn rem_assign(&mut self, rhs: Decimal256) {
736        *self = *self % rhs;
737    }
738}
739forward_ref_op_assign!(impl RemAssign, rem_assign for Decimal256, Decimal256);
740
741impl<A> core::iter::Sum<A> for Decimal256
742where
743    Self: Add<A, Output = Self>,
744{
745    fn sum<I: Iterator<Item = A>>(iter: I) -> Self {
746        iter.fold(Self::zero(), Add::add)
747    }
748}
749
750/// Serializes as a decimal string
751impl Serialize for Decimal256 {
752    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
753    where
754        S: ser::Serializer,
755    {
756        serializer.serialize_str(&self.to_string())
757    }
758}
759
760/// Deserializes as a base64 string
761impl<'de> Deserialize<'de> for Decimal256 {
762    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
763    where
764        D: Deserializer<'de>,
765    {
766        deserializer.deserialize_str(Decimal256Visitor)
767    }
768}
769
770struct Decimal256Visitor;
771
772impl de::Visitor<'_> for Decimal256Visitor {
773    type Value = Decimal256;
774
775    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
776        formatter.write_str("string-encoded decimal")
777    }
778
779    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
780    where
781        E: de::Error,
782    {
783        match Self::Value::from_str(v) {
784            Ok(d) => Ok(d),
785            Err(e) => Err(E::custom(format_args!("Error parsing decimal '{v}': {e}"))),
786        }
787    }
788}