Skip to main content

cosmwasm_std/math/
signed_decimal.rs

1use alloc::string::ToString;
2use core::cmp::Ordering;
3use core::fmt::{self, Write};
4use core::ops::{
5    Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign,
6};
7use core::str::FromStr;
8use serde::{de, ser, Deserialize, Deserializer, Serialize};
9
10use crate::errors::{
11    CheckedFromRatioError, CheckedMultiplyRatioError, DivideByZeroError, ErrorKind, OverflowError,
12    OverflowOperation, RoundDownOverflowError, RoundUpOverflowError, StdError,
13};
14use crate::forward_ref::{forward_ref_binop, forward_ref_op_assign};
15use crate::{Decimal, Decimal256, Int256, SignedDecimal256, __internal::forward_ref_partial_eq};
16
17use super::Fraction;
18use super::Int128;
19
20/// A signed fixed-point decimal value with 18 fractional digits, i.e. SignedDecimal(1_000_000_000_000_000_000) == 1.0
21///
22/// The greatest possible value that can be represented is 170141183460469231731.687303715884105727 (which is (2^127 - 1) / 10^18)
23/// and the smallest is -170141183460469231731.687303715884105728 (which is -2^127 / 10^18).
24#[derive(
25    Copy,
26    Clone,
27    Default,
28    PartialEq,
29    Eq,
30    PartialOrd,
31    Ord,
32    schemars::JsonSchema,
33    cw_schema::Schemaifier,
34)]
35#[schemaifier(type = cw_schema::NodeType::Decimal { precision: 128, signed: true })]
36pub struct SignedDecimal(#[schemars(with = "String")] Int128);
37
38forward_ref_partial_eq!(SignedDecimal, SignedDecimal);
39
40#[derive(Debug, PartialEq, Eq, thiserror::Error)]
41#[error("SignedDecimal range exceeded")]
42pub struct SignedDecimalRangeExceeded;
43
44impl SignedDecimal {
45    const DECIMAL_FRACTIONAL: Int128 = Int128::new(1_000_000_000_000_000_000i128); // 1*10**18
46    const DECIMAL_FRACTIONAL_SQUARED: Int128 =
47        Int128::new(1_000_000_000_000_000_000_000_000_000_000_000_000i128); // (1*10**18)**2 = 1*10**36
48
49    /// The number of decimal places. Since decimal types are fixed-point rather than
50    /// floating-point, this is a constant.
51    pub const DECIMAL_PLACES: u32 = 18; // This needs to be an even number.
52
53    /// The largest value that can be represented by this signed decimal type.
54    ///
55    /// # Examples
56    ///
57    /// ```
58    /// # use cosmwasm_std::SignedDecimal;
59    /// assert_eq!(SignedDecimal::MAX.to_string(), "170141183460469231731.687303715884105727");
60    /// ```
61    pub const MAX: Self = Self(Int128::MAX);
62
63    /// The smallest value that can be represented by this signed decimal type.
64    ///
65    /// # Examples
66    ///
67    /// ```
68    /// # use cosmwasm_std::SignedDecimal;
69    /// assert_eq!(SignedDecimal::MIN.to_string(), "-170141183460469231731.687303715884105728");
70    /// ```
71    pub const MIN: Self = Self(Int128::MIN);
72
73    /// Creates a SignedDecimal(value)
74    /// This is equivalent to `SignedDecimal::from_atomics(value, 18)` but usable in a const context.
75    ///
76    /// # Examples
77    ///
78    /// ```
79    /// # use cosmwasm_std::{SignedDecimal, Int128};
80    /// assert_eq!(SignedDecimal::new(Int128::one()).to_string(), "0.000000000000000001");
81    ///
82    /// let atoms = Int128::new(-141_183_460_469_231_731_687_303_715_884_105_727_125);
83    /// let value = SignedDecimal::new(atoms);
84    /// assert_eq!(value.to_string(), "-141183460469231731687.303715884105727125");
85    /// ```
86    #[inline]
87    #[must_use]
88    pub const fn new(value: Int128) -> Self {
89        Self(value)
90    }
91
92    /// Creates a SignedDecimal(Int128(value))
93    /// This is equivalent to `SignedDecimal::from_atomics(value, 18)` but usable in a const context.
94    ///
95    /// # Examples
96    ///
97    /// ```
98    /// # use cosmwasm_std::SignedDecimal;
99    /// assert_eq!(SignedDecimal::raw(1234i128).to_string(), "0.000000000000001234");
100    /// ```
101    #[deprecated(
102        since = "3.0.0",
103        note = "Use SignedDecimal::new(Int128::new(value)) instead"
104    )]
105    pub const fn raw(value: i128) -> Self {
106        Self(Int128::new(value))
107    }
108
109    /// Create a 1.0 SignedDecimal
110    #[inline]
111    pub const fn one() -> Self {
112        Self(Self::DECIMAL_FRACTIONAL)
113    }
114
115    /// Create a -1.0 SignedDecimal
116    #[inline]
117    pub const fn negative_one() -> Self {
118        Self(Int128::new(-Self::DECIMAL_FRACTIONAL.i128()))
119    }
120
121    /// Create a 0.0 SignedDecimal
122    #[inline]
123    pub const fn zero() -> Self {
124        Self(Int128::zero())
125    }
126
127    /// Convert x% into SignedDecimal
128    pub fn percent(x: i64) -> Self {
129        Self(((x as i128) * 10_000_000_000_000_000).into())
130    }
131
132    /// Convert permille (x/1000) into SignedDecimal
133    pub fn permille(x: i64) -> Self {
134        Self(((x as i128) * 1_000_000_000_000_000).into())
135    }
136
137    /// Convert basis points (x/10000) into SignedDecimal
138    pub fn bps(x: i64) -> Self {
139        Self(((x as i128) * 100_000_000_000_000).into())
140    }
141
142    /// Creates a signed decimal from a number of atomic units and the number
143    /// of decimal places. The inputs will be converted internally to form
144    /// a signed decimal with 18 decimal places. So the input 123 and 2 will create
145    /// the decimal 1.23.
146    ///
147    /// Using 18 decimal places is slightly more efficient than other values
148    /// as no internal conversion is necessary.
149    ///
150    /// ## Examples
151    ///
152    /// ```
153    /// # use cosmwasm_std::{SignedDecimal, Int128};
154    /// let a = SignedDecimal::from_atomics(Int128::new(1234), 3).unwrap();
155    /// assert_eq!(a.to_string(), "1.234");
156    ///
157    /// let a = SignedDecimal::from_atomics(1234i128, 0).unwrap();
158    /// assert_eq!(a.to_string(), "1234");
159    ///
160    /// let a = SignedDecimal::from_atomics(1i64, 18).unwrap();
161    /// assert_eq!(a.to_string(), "0.000000000000000001");
162    ///
163    /// let a = SignedDecimal::from_atomics(-1i64, 18).unwrap();
164    /// assert_eq!(a.to_string(), "-0.000000000000000001");
165    /// ```
166    pub fn from_atomics(
167        atomics: impl Into<Int128>,
168        decimal_places: u32,
169    ) -> Result<Self, SignedDecimalRangeExceeded> {
170        let atomics = atomics.into();
171        const TEN: Int128 = Int128::new(10);
172        Ok(match decimal_places.cmp(&(Self::DECIMAL_PLACES)) {
173            Ordering::Less => {
174                let digits = (Self::DECIMAL_PLACES) - decimal_places; // No overflow because decimal_places < DECIMAL_PLACES
175                let factor = TEN.checked_pow(digits).unwrap(); // Safe because digits <= 17
176                Self(
177                    atomics
178                        .checked_mul(factor)
179                        .map_err(|_| SignedDecimalRangeExceeded)?,
180                )
181            }
182            Ordering::Equal => Self(atomics),
183            Ordering::Greater => {
184                let digits = decimal_places - (Self::DECIMAL_PLACES); // No overflow because decimal_places > DECIMAL_PLACES
185                if atomics.is_zero() || digits > atomics.unsigned_abs().ilog10() {
186                    // In this case `10^digits > |atomics|`, so the division truncates to zero.
187                    Self(Int128::zero())
188                } else {
189                    // `digits <= ilog10(|atomics|)` guarantees `10^digits` fits in Int128.
190                    let factor = TEN.checked_pow(digits).unwrap();
191                    Self(atomics.checked_div(factor).unwrap()) // Safe because factor cannot be zero
192                }
193            }
194        })
195    }
196
197    /// Returns the ratio (numerator / denominator) as a SignedDecimal
198    ///
199    /// # Examples
200    ///
201    /// ```
202    /// # use cosmwasm_std::SignedDecimal;
203    /// assert_eq!(
204    ///     SignedDecimal::from_ratio(1, 3).to_string(),
205    ///     "0.333333333333333333"
206    /// );
207    /// ```
208    pub fn from_ratio(numerator: impl Into<Int128>, denominator: impl Into<Int128>) -> Self {
209        match SignedDecimal::checked_from_ratio(numerator, denominator) {
210            Ok(value) => value,
211            Err(CheckedFromRatioError::DivideByZero) => {
212                panic!("Denominator must not be zero")
213            }
214            Err(CheckedFromRatioError::Overflow) => panic!("Multiplication overflow"),
215        }
216    }
217
218    /// Returns the ratio (numerator / denominator) as a SignedDecimal
219    ///
220    /// # Examples
221    ///
222    /// ```
223    /// # use cosmwasm_std::{SignedDecimal, CheckedFromRatioError};
224    /// assert_eq!(
225    ///     SignedDecimal::checked_from_ratio(1, 3).unwrap().to_string(),
226    ///     "0.333333333333333333"
227    /// );
228    /// assert_eq!(
229    ///     SignedDecimal::checked_from_ratio(1, 0),
230    ///     Err(CheckedFromRatioError::DivideByZero)
231    /// );
232    /// ```
233    pub fn checked_from_ratio(
234        numerator: impl Into<Int128>,
235        denominator: impl Into<Int128>,
236    ) -> Result<Self, CheckedFromRatioError> {
237        let numerator: Int128 = numerator.into();
238        let denominator: Int128 = denominator.into();
239        match numerator.checked_multiply_ratio(Self::DECIMAL_FRACTIONAL, denominator) {
240            Ok(ratio) => {
241                // numerator * DECIMAL_FRACTIONAL / denominator
242                Ok(SignedDecimal(ratio))
243            }
244            Err(CheckedMultiplyRatioError::Overflow) => Err(CheckedFromRatioError::Overflow),
245            Err(CheckedMultiplyRatioError::DivideByZero) => {
246                Err(CheckedFromRatioError::DivideByZero)
247            }
248        }
249    }
250
251    /// Returns `true` if the number is 0
252    #[must_use]
253    pub const fn is_zero(&self) -> bool {
254        self.0.is_zero()
255    }
256
257    /// Returns `true` if the number is negative (< 0)
258    #[must_use]
259    pub const fn is_negative(&self) -> bool {
260        self.0.i128() < 0
261    }
262
263    /// A decimal is an integer of atomic units plus a number that specifies the
264    /// position of the decimal dot. So any decimal can be expressed as two numbers.
265    ///
266    /// ## Examples
267    ///
268    /// ```
269    /// # use cosmwasm_std::{SignedDecimal, Int128};
270    /// # use core::str::FromStr;
271    /// // Value with whole and fractional part
272    /// let a = SignedDecimal::from_str("1.234").unwrap();
273    /// assert_eq!(a.decimal_places(), 18);
274    /// assert_eq!(a.atomics(), Int128::new(1234000000000000000));
275    ///
276    /// // Smallest possible value
277    /// let b = SignedDecimal::from_str("0.000000000000000001").unwrap();
278    /// assert_eq!(b.decimal_places(), 18);
279    /// assert_eq!(b.atomics(), Int128::new(1));
280    /// ```
281    #[must_use]
282    #[inline]
283    pub const fn atomics(&self) -> Int128 {
284        self.0
285    }
286
287    /// The number of decimal places. This is a constant value for now
288    /// but this could potentially change as the type evolves.
289    ///
290    /// See also [`SignedDecimal::atomics()`].
291    #[must_use]
292    #[inline]
293    pub const fn decimal_places(&self) -> u32 {
294        Self::DECIMAL_PLACES
295    }
296
297    /// Rounds value by truncating the decimal places.
298    ///
299    /// # Examples
300    ///
301    /// ```
302    /// # use cosmwasm_std::SignedDecimal;
303    /// # use core::str::FromStr;
304    /// assert!(SignedDecimal::from_str("0.6").unwrap().trunc().is_zero());
305    /// assert_eq!(SignedDecimal::from_str("-5.8").unwrap().trunc().to_string(), "-5");
306    /// ```
307    #[must_use = "this returns the result of the operation, without modifying the original"]
308    pub fn trunc(&self) -> Self {
309        Self((self.0 / Self::DECIMAL_FRACTIONAL) * Self::DECIMAL_FRACTIONAL)
310    }
311
312    /// Rounds value down after decimal places. Panics on overflow.
313    ///
314    /// # Examples
315    ///
316    /// ```
317    /// # use cosmwasm_std::SignedDecimal;
318    /// # use core::str::FromStr;
319    /// assert!(SignedDecimal::from_str("0.6").unwrap().floor().is_zero());
320    /// assert_eq!(SignedDecimal::from_str("-5.2").unwrap().floor().to_string(), "-6");
321    /// ```
322    #[must_use = "this returns the result of the operation, without modifying the original"]
323    pub fn floor(&self) -> Self {
324        match self.checked_floor() {
325            Ok(value) => value,
326            Err(_) => panic!("attempt to floor with overflow"),
327        }
328    }
329
330    /// Rounds value down after decimal places.
331    pub fn checked_floor(&self) -> Result<Self, RoundDownOverflowError> {
332        if self.is_negative() {
333            let truncated = self.trunc();
334
335            if truncated != self {
336                truncated
337                    .checked_sub(SignedDecimal::one())
338                    .map_err(|_| RoundDownOverflowError)
339            } else {
340                Ok(truncated)
341            }
342        } else {
343            Ok(self.trunc())
344        }
345    }
346
347    /// Rounds value up after decimal places. Panics on overflow.
348    ///
349    /// # Examples
350    ///
351    /// ```
352    /// # use cosmwasm_std::SignedDecimal;
353    /// # use core::str::FromStr;
354    /// assert_eq!(SignedDecimal::from_str("0.2").unwrap().ceil(), SignedDecimal::one());
355    /// assert_eq!(SignedDecimal::from_str("-5.8").unwrap().ceil().to_string(), "-5");
356    /// ```
357    #[must_use = "this returns the result of the operation, without modifying the original"]
358    pub fn ceil(&self) -> Self {
359        match self.checked_ceil() {
360            Ok(value) => value,
361            Err(_) => panic!("attempt to ceil with overflow"),
362        }
363    }
364
365    /// Rounds value up after decimal places. Returns OverflowError on overflow.
366    pub fn checked_ceil(&self) -> Result<Self, RoundUpOverflowError> {
367        let floor = self.floor();
368        if floor == self {
369            Ok(floor)
370        } else {
371            floor
372                .checked_add(SignedDecimal::one())
373                .map_err(|_| RoundUpOverflowError)
374        }
375    }
376
377    /// Computes `self + other`, returning an `OverflowError` if an overflow occurred.
378    pub fn checked_add(self, other: Self) -> Result<Self, OverflowError> {
379        self.0
380            .checked_add(other.0)
381            .map(Self)
382            .map_err(|_| OverflowError::new(OverflowOperation::Add))
383    }
384
385    /// Computes `self - other`, returning an `OverflowError` if an overflow occurred.
386    pub fn checked_sub(self, other: Self) -> Result<Self, OverflowError> {
387        self.0
388            .checked_sub(other.0)
389            .map(Self)
390            .map_err(|_| OverflowError::new(OverflowOperation::Sub))
391    }
392
393    /// Multiplies one `SignedDecimal` by another, returning an `OverflowError` if an overflow occurred.
394    pub fn checked_mul(self, other: Self) -> Result<Self, OverflowError> {
395        let result_as_int256 =
396            self.numerator().full_mul(other.numerator()) / Int256::from(Self::DECIMAL_FRACTIONAL);
397        result_as_int256
398            .try_into()
399            .map(Self)
400            .map_err(|_| OverflowError::new(OverflowOperation::Mul))
401    }
402
403    /// Raises a value to the power of `exp`, panics if an overflow occurred.
404    #[must_use = "this returns the result of the operation, without modifying the original"]
405    pub fn pow(self, exp: u32) -> Self {
406        match self.checked_pow(exp) {
407            Ok(value) => value,
408            Err(_) => panic!("Multiplication overflow"),
409        }
410    }
411
412    /// Raises a value to the power of `exp`, returning an `OverflowError` if an overflow occurred.
413    pub fn checked_pow(self, exp: u32) -> Result<Self, OverflowError> {
414        // This uses the exponentiation by squaring algorithm:
415        // https://en.wikipedia.org/wiki/Exponentiation_by_squaring#Basic_method
416
417        fn inner(mut x: SignedDecimal, mut n: u32) -> Result<SignedDecimal, OverflowError> {
418            if n == 0 {
419                return Ok(SignedDecimal::one());
420            }
421
422            let mut y = SignedDecimal::one();
423
424            while n > 1 {
425                if n % 2 == 0 {
426                    x = x.checked_mul(x)?;
427                    n /= 2;
428                } else {
429                    y = x.checked_mul(y)?;
430                    x = x.checked_mul(x)?;
431                    n = (n - 1) / 2;
432                }
433            }
434
435            Ok(x * y)
436        }
437
438        inner(self, exp).map_err(|_| OverflowError::new(OverflowOperation::Pow))
439    }
440
441    pub fn checked_div(self, other: Self) -> Result<Self, CheckedFromRatioError> {
442        SignedDecimal::checked_from_ratio(self.numerator(), other.numerator())
443    }
444
445    /// Computes `self % other`, returning a `DivideByZeroError` if `other == 0`.
446    pub fn checked_rem(self, other: Self) -> Result<Self, DivideByZeroError> {
447        self.0
448            .checked_rem(other.0)
449            .map(Self)
450            .map_err(|_| DivideByZeroError)
451    }
452
453    #[must_use = "this returns the result of the operation, without modifying the original"]
454    pub const fn abs_diff(self, other: Self) -> Decimal {
455        Decimal::new(self.0.abs_diff(other.0))
456    }
457
458    #[must_use = "this returns the result of the operation, without modifying the original"]
459    pub fn saturating_add(self, other: Self) -> Self {
460        Self(self.0.saturating_add(other.0))
461    }
462
463    #[must_use = "this returns the result of the operation, without modifying the original"]
464    pub fn saturating_sub(self, other: Self) -> Self {
465        Self(self.0.saturating_sub(other.0))
466    }
467
468    #[must_use = "this returns the result of the operation, without modifying the original"]
469    pub fn saturating_mul(self, other: Self) -> Self {
470        match self.checked_mul(other) {
471            Ok(value) => value,
472            Err(_) => {
473                // both negative or both positive results in positive number, otherwise negative
474                if self.is_negative() == other.is_negative() {
475                    Self::MAX
476                } else {
477                    Self::MIN
478                }
479            }
480        }
481    }
482
483    #[must_use = "this returns the result of the operation, without modifying the original"]
484    pub fn saturating_pow(self, exp: u32) -> Self {
485        match self.checked_pow(exp) {
486            Ok(value) => value,
487            Err(_) => {
488                // odd exponent of negative number results in negative number
489                // everything else results in positive number
490                if self.is_negative() && exp % 2 == 1 {
491                    Self::MIN
492                } else {
493                    Self::MAX
494                }
495            }
496        }
497    }
498
499    /// Converts this decimal to a signed integer by rounding down
500    /// to the next integer, e.g. 22.5 becomes 22 and -1.2 becomes -2.
501    ///
502    /// ## Examples
503    ///
504    /// ```
505    /// use core::str::FromStr;
506    /// use cosmwasm_std::{SignedDecimal, Int128};
507    ///
508    /// let d = SignedDecimal::from_str("12.345").unwrap();
509    /// assert_eq!(d.to_int_floor(), Int128::new(12));
510    ///
511    /// let d = SignedDecimal::from_str("-12.999").unwrap();
512    /// assert_eq!(d.to_int_floor(), Int128::new(-13));
513    ///
514    /// let d = SignedDecimal::from_str("-0.05").unwrap();
515    /// assert_eq!(d.to_int_floor(), Int128::new(-1));
516    /// ```
517    #[must_use = "this returns the result of the operation, without modifying the original"]
518    pub fn to_int_floor(self) -> Int128 {
519        if self.is_negative() {
520            // Using `x.to_int_floor() = -(-x).to_int_ceil()` for a negative `x`,
521            // but avoiding overflow by implementing the formula from `to_int_ceil` directly.
522            let x = self.0;
523            let y = Self::DECIMAL_FRACTIONAL;
524            // making sure not to negate `x`, as this would overflow
525            -Int128::one() - ((-Int128::one() - x) / y)
526        } else {
527            self.to_int_trunc()
528        }
529    }
530
531    /// Converts this decimal to a signed integer by truncating
532    /// the fractional part, e.g. 22.5 becomes 22.
533    ///
534    /// ## Examples
535    ///
536    /// ```
537    /// use core::str::FromStr;
538    /// use cosmwasm_std::{SignedDecimal, Int128};
539    ///
540    /// let d = SignedDecimal::from_str("12.345").unwrap();
541    /// assert_eq!(d.to_int_trunc(), Int128::new(12));
542    ///
543    /// let d = SignedDecimal::from_str("-12.999").unwrap();
544    /// assert_eq!(d.to_int_trunc(), Int128::new(-12));
545    ///
546    /// let d = SignedDecimal::from_str("75.0").unwrap();
547    /// assert_eq!(d.to_int_trunc(), Int128::new(75));
548    /// ```
549    #[must_use = "this returns the result of the operation, without modifying the original"]
550    pub fn to_int_trunc(self) -> Int128 {
551        self.0 / Self::DECIMAL_FRACTIONAL
552    }
553
554    /// Converts this decimal to a signed integer by rounding up
555    /// to the next integer, e.g. 22.3 becomes 23 and -1.2 becomes -1.
556    ///
557    /// ## Examples
558    ///
559    /// ```
560    /// use core::str::FromStr;
561    /// use cosmwasm_std::{SignedDecimal, Int128};
562    ///
563    /// let d = SignedDecimal::from_str("12.345").unwrap();
564    /// assert_eq!(d.to_int_ceil(), Int128::new(13));
565    ///
566    /// let d = SignedDecimal::from_str("-12.999").unwrap();
567    /// assert_eq!(d.to_int_ceil(), Int128::new(-12));
568    ///
569    /// let d = SignedDecimal::from_str("75.0").unwrap();
570    /// assert_eq!(d.to_int_ceil(), Int128::new(75));
571    /// ```
572    #[must_use = "this returns the result of the operation, without modifying the original"]
573    pub fn to_int_ceil(self) -> Int128 {
574        if self.is_negative() {
575            self.to_int_trunc()
576        } else {
577            // Using `q = 1 + ((x - 1) / y); // if x != 0` with unsigned integers x, y, q
578            // from https://stackoverflow.com/a/2745086/2013738. We know `x + y` CAN overflow.
579            let x = self.0;
580            let y = Self::DECIMAL_FRACTIONAL;
581            if x.is_zero() {
582                Int128::zero()
583            } else {
584                Int128::one() + ((x - Int128::one()) / y)
585            }
586        }
587    }
588}
589
590impl Fraction<Int128> for SignedDecimal {
591    #[inline]
592    fn numerator(&self) -> Int128 {
593        self.0
594    }
595
596    #[inline]
597    fn denominator(&self) -> Int128 {
598        Self::DECIMAL_FRACTIONAL
599    }
600
601    /// Returns the multiplicative inverse `1/d` for decimal `d`.
602    ///
603    /// If `d` is zero, none is returned.
604    fn inv(&self) -> Option<Self> {
605        if self.is_zero() {
606            None
607        } else {
608            // Let self be p/q with p = self.0 and q = DECIMAL_FRACTIONAL.
609            // Now we calculate the inverse a/b = q/p such that b = DECIMAL_FRACTIONAL. Then
610            // `a = DECIMAL_FRACTIONAL*DECIMAL_FRACTIONAL / self.0`.
611            Some(SignedDecimal(Self::DECIMAL_FRACTIONAL_SQUARED / self.0))
612        }
613    }
614}
615
616impl Neg for SignedDecimal {
617    type Output = Self;
618
619    fn neg(self) -> Self::Output {
620        Self(-self.0)
621    }
622}
623
624impl TryFrom<SignedDecimal256> for SignedDecimal {
625    type Error = SignedDecimalRangeExceeded;
626
627    fn try_from(value: SignedDecimal256) -> Result<Self, Self::Error> {
628        value
629            .atomics()
630            .try_into()
631            .map(SignedDecimal)
632            .map_err(|_| SignedDecimalRangeExceeded)
633    }
634}
635
636impl TryFrom<Decimal> for SignedDecimal {
637    type Error = SignedDecimalRangeExceeded;
638
639    fn try_from(value: Decimal) -> Result<Self, Self::Error> {
640        value
641            .atomics()
642            .try_into()
643            .map(SignedDecimal)
644            .map_err(|_| SignedDecimalRangeExceeded)
645    }
646}
647
648impl TryFrom<Decimal256> for SignedDecimal {
649    type Error = SignedDecimalRangeExceeded;
650
651    fn try_from(value: Decimal256) -> Result<Self, Self::Error> {
652        value
653            .atomics()
654            .try_into()
655            .map(SignedDecimal)
656            .map_err(|_| SignedDecimalRangeExceeded)
657    }
658}
659
660impl TryFrom<Int128> for SignedDecimal {
661    type Error = SignedDecimalRangeExceeded;
662
663    #[inline]
664    fn try_from(value: Int128) -> Result<Self, Self::Error> {
665        Self::from_atomics(value, 0)
666    }
667}
668
669impl FromStr for SignedDecimal {
670    type Err = StdError;
671
672    /// Converts the decimal string to a SignedDecimal
673    /// Possible inputs: "1.23", "1", "000012", "1.123000000", "-1.12300"
674    /// Disallowed: "", ".23"
675    ///
676    /// This never performs any kind of rounding.
677    /// More than DECIMAL_PLACES fractional digits, even zeros, result in an error.
678    fn from_str(input: &str) -> Result<Self, Self::Err> {
679        let mut parts_iter = input.split('.');
680
681        let whole_part = parts_iter.next().unwrap(); // split always returns at least one element
682        let is_neg = whole_part.starts_with('-');
683
684        let whole = whole_part.parse::<Int128>()?;
685        let mut atomics = whole.checked_mul(Self::DECIMAL_FRACTIONAL)?;
686
687        if let Some(fractional_part) = parts_iter.next() {
688            let fractional = fractional_part.parse::<u64>()?; // u64 is enough for 18 decimal places
689            let exp = (Self::DECIMAL_PLACES.checked_sub(fractional_part.len() as u32)).ok_or_else(
690                || {
691                    StdError::msg(format_args!(
692                        "Cannot parse more than {} fractional digits",
693                        Self::DECIMAL_PLACES
694                    ))
695                },
696            )?;
697            debug_assert!(exp <= Self::DECIMAL_PLACES);
698            let fractional_factor = Int128::from(10i128.pow(exp));
699
700            // This multiplication can't overflow because
701            // fractional < 10^DECIMAL_PLACES && fractional_factor <= 10^DECIMAL_PLACES
702            let fractional_part = Int128::from(fractional)
703                .checked_mul(fractional_factor)
704                .unwrap();
705
706            // for negative numbers, we need to subtract the fractional part
707            atomics = if is_neg {
708                atomics.checked_sub(fractional_part)
709            } else {
710                atomics.checked_add(fractional_part)
711            }?;
712        }
713
714        if parts_iter.next().is_some() {
715            return Err(StdError::msg("Unexpected number of dots").with_kind(ErrorKind::Parsing));
716        }
717
718        Ok(SignedDecimal(atomics))
719    }
720}
721
722impl fmt::Display for SignedDecimal {
723    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
724        let whole = (self.0) / Self::DECIMAL_FRACTIONAL;
725        let fractional = (self.0).checked_rem(Self::DECIMAL_FRACTIONAL).unwrap();
726
727        if fractional.is_zero() {
728            write!(f, "{whole}")
729        } else {
730            let fractional_string = format!(
731                "{:0>padding$}",
732                fractional.abs(), // fractional should always be printed as positive
733                padding = Self::DECIMAL_PLACES as usize
734            );
735            if self.is_negative() {
736                f.write_char('-')?;
737            }
738            write!(
739                f,
740                "{whole}.{fractional}",
741                whole = whole.abs(),
742                fractional = fractional_string.trim_end_matches('0')
743            )
744        }
745    }
746}
747
748impl fmt::Debug for SignedDecimal {
749    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
750        write!(f, "SignedDecimal({self})")
751    }
752}
753
754impl Add for SignedDecimal {
755    type Output = Self;
756
757    fn add(self, other: Self) -> Self {
758        SignedDecimal(self.0 + other.0)
759    }
760}
761forward_ref_binop!(impl Add, add for SignedDecimal, SignedDecimal);
762
763impl AddAssign for SignedDecimal {
764    fn add_assign(&mut self, rhs: SignedDecimal) {
765        *self = *self + rhs;
766    }
767}
768forward_ref_op_assign!(impl AddAssign, add_assign for SignedDecimal, SignedDecimal);
769
770impl Sub for SignedDecimal {
771    type Output = Self;
772
773    fn sub(self, other: Self) -> Self {
774        SignedDecimal(self.0 - other.0)
775    }
776}
777forward_ref_binop!(impl Sub, sub for SignedDecimal, SignedDecimal);
778
779impl SubAssign for SignedDecimal {
780    fn sub_assign(&mut self, rhs: SignedDecimal) {
781        *self = *self - rhs;
782    }
783}
784forward_ref_op_assign!(impl SubAssign, sub_assign for SignedDecimal, SignedDecimal);
785
786impl Mul for SignedDecimal {
787    type Output = Self;
788
789    #[allow(clippy::suspicious_arithmetic_impl)]
790    fn mul(self, other: Self) -> Self {
791        // SignedDecimals are fractions. We can multiply two decimals a and b
792        // via
793        //       (a.numerator() * b.numerator()) / (a.denominator() * b.denominator())
794        //     = (a.numerator() * b.numerator()) / a.denominator() / b.denominator()
795
796        let result_as_int256 =
797            self.numerator().full_mul(other.numerator()) / Int256::from(Self::DECIMAL_FRACTIONAL);
798        match result_as_int256.try_into() {
799            Ok(result) => Self(result),
800            Err(_) => panic!("attempt to multiply with overflow"),
801        }
802    }
803}
804forward_ref_binop!(impl Mul, mul for SignedDecimal, SignedDecimal);
805
806impl MulAssign for SignedDecimal {
807    fn mul_assign(&mut self, rhs: SignedDecimal) {
808        *self = *self * rhs;
809    }
810}
811forward_ref_op_assign!(impl MulAssign, mul_assign for SignedDecimal, SignedDecimal);
812
813impl Div for SignedDecimal {
814    type Output = Self;
815
816    fn div(self, other: Self) -> Self {
817        match SignedDecimal::checked_from_ratio(self.numerator(), other.numerator()) {
818            Ok(ratio) => ratio,
819            Err(CheckedFromRatioError::DivideByZero) => {
820                panic!("Division failed - denominator must not be zero")
821            }
822            Err(CheckedFromRatioError::Overflow) => {
823                panic!("Division failed - multiplication overflow")
824            }
825        }
826    }
827}
828forward_ref_binop!(impl Div, div for SignedDecimal, SignedDecimal);
829
830impl DivAssign for SignedDecimal {
831    fn div_assign(&mut self, rhs: SignedDecimal) {
832        *self = *self / rhs;
833    }
834}
835forward_ref_op_assign!(impl DivAssign, div_assign for SignedDecimal, SignedDecimal);
836
837impl Div<Int128> for SignedDecimal {
838    type Output = Self;
839
840    fn div(self, rhs: Int128) -> Self::Output {
841        SignedDecimal(self.0 / rhs)
842    }
843}
844
845impl DivAssign<Int128> for SignedDecimal {
846    fn div_assign(&mut self, rhs: Int128) {
847        self.0 /= rhs;
848    }
849}
850
851impl Rem for SignedDecimal {
852    type Output = Self;
853
854    /// # Panics
855    ///
856    /// This operation will panic if `rhs` is zero
857    #[inline]
858    fn rem(self, rhs: Self) -> Self {
859        Self(self.0.rem(rhs.0))
860    }
861}
862forward_ref_binop!(impl Rem, rem for SignedDecimal, SignedDecimal);
863
864impl RemAssign<SignedDecimal> for SignedDecimal {
865    fn rem_assign(&mut self, rhs: SignedDecimal) {
866        *self = *self % rhs;
867    }
868}
869forward_ref_op_assign!(impl RemAssign, rem_assign for SignedDecimal, SignedDecimal);
870
871impl<A> core::iter::Sum<A> for SignedDecimal
872where
873    Self: Add<A, Output = Self>,
874{
875    fn sum<I: Iterator<Item = A>>(iter: I) -> Self {
876        iter.fold(Self::zero(), Add::add)
877    }
878}
879
880/// Serializes as a decimal string
881impl Serialize for SignedDecimal {
882    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
883    where
884        S: ser::Serializer,
885    {
886        serializer.serialize_str(&self.to_string())
887    }
888}
889
890/// Deserializes as a base64 string
891impl<'de> Deserialize<'de> for SignedDecimal {
892    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
893    where
894        D: Deserializer<'de>,
895    {
896        deserializer.deserialize_str(SignedDecimalVisitor)
897    }
898}
899
900struct SignedDecimalVisitor;
901
902impl de::Visitor<'_> for SignedDecimalVisitor {
903    type Value = SignedDecimal;
904
905    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
906        formatter.write_str("string-encoded decimal")
907    }
908
909    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
910    where
911        E: de::Error,
912    {
913        match SignedDecimal::from_str(v) {
914            Ok(d) => Ok(d),
915            Err(e) => Err(E::custom(format_args!("Error parsing decimal '{v}': {e}"))),
916        }
917    }
918}
919
920#[cfg(test)]
921mod tests {
922    use crate::Uint128;
923
924    use super::*;
925
926    use alloc::vec::Vec;
927
928    fn dec(input: &str) -> SignedDecimal {
929        SignedDecimal::from_str(input).unwrap()
930    }
931
932    #[test]
933    fn signed_decimal_new() {
934        let expected = Int128::from(300i128);
935        assert_eq!(SignedDecimal::new(expected).0, expected);
936
937        let expected = Int128::from(-300i128);
938        assert_eq!(SignedDecimal::new(expected).0, expected);
939    }
940
941    #[test]
942    #[allow(deprecated)]
943    fn signed_decimal_raw() {
944        let value = 300i128;
945        assert_eq!(SignedDecimal::raw(value).0.i128(), value);
946
947        let value = -300i128;
948        assert_eq!(SignedDecimal::raw(value).0.i128(), value);
949    }
950
951    #[test]
952    fn signed_decimal_one() {
953        let value = SignedDecimal::one();
954        assert_eq!(value.0, SignedDecimal::DECIMAL_FRACTIONAL);
955    }
956
957    #[test]
958    fn signed_decimal_zero() {
959        let value = SignedDecimal::zero();
960        assert!(value.0.is_zero());
961    }
962
963    #[test]
964    fn signed_decimal_percent() {
965        let value = SignedDecimal::percent(50);
966        assert_eq!(
967            value.0,
968            SignedDecimal::DECIMAL_FRACTIONAL / Int128::from(2u8)
969        );
970
971        let value = SignedDecimal::percent(-50);
972        assert_eq!(
973            value.0,
974            SignedDecimal::DECIMAL_FRACTIONAL / Int128::from(-2i8)
975        );
976    }
977
978    #[test]
979    fn signed_decimal_permille() {
980        let value = SignedDecimal::permille(125);
981        assert_eq!(
982            value.0,
983            SignedDecimal::DECIMAL_FRACTIONAL / Int128::from(8u8)
984        );
985
986        let value = SignedDecimal::permille(-125);
987        assert_eq!(
988            value.0,
989            SignedDecimal::DECIMAL_FRACTIONAL / Int128::from(-8i8)
990        );
991    }
992
993    #[test]
994    fn signed_decimal_bps() {
995        let value = SignedDecimal::bps(125);
996        assert_eq!(
997            value.0,
998            SignedDecimal::DECIMAL_FRACTIONAL / Int128::from(80u8)
999        );
1000
1001        let value = SignedDecimal::bps(-125);
1002        assert_eq!(
1003            value.0,
1004            SignedDecimal::DECIMAL_FRACTIONAL / Int128::from(-80i8)
1005        );
1006    }
1007
1008    #[test]
1009    fn try_from_integer() {
1010        let int = Int128::new(0xDEADBEEF);
1011        let decimal = SignedDecimal::try_from(int).unwrap();
1012        assert_eq!(int.to_string(), decimal.to_string());
1013    }
1014
1015    #[test]
1016    fn signed_decimal_from_atomics_works() {
1017        let one = SignedDecimal::one();
1018        let two = one + one;
1019        let neg_one = SignedDecimal::negative_one();
1020
1021        assert_eq!(SignedDecimal::from_atomics(1i128, 0).unwrap(), one);
1022        assert_eq!(SignedDecimal::from_atomics(10i128, 1).unwrap(), one);
1023        assert_eq!(SignedDecimal::from_atomics(100i128, 2).unwrap(), one);
1024        assert_eq!(SignedDecimal::from_atomics(1000i128, 3).unwrap(), one);
1025        assert_eq!(
1026            SignedDecimal::from_atomics(1000000000000000000i128, 18).unwrap(),
1027            one
1028        );
1029        assert_eq!(
1030            SignedDecimal::from_atomics(10000000000000000000i128, 19).unwrap(),
1031            one
1032        );
1033        assert_eq!(
1034            SignedDecimal::from_atomics(100000000000000000000i128, 20).unwrap(),
1035            one
1036        );
1037
1038        assert_eq!(SignedDecimal::from_atomics(2i128, 0).unwrap(), two);
1039        assert_eq!(SignedDecimal::from_atomics(20i128, 1).unwrap(), two);
1040        assert_eq!(SignedDecimal::from_atomics(200i128, 2).unwrap(), two);
1041        assert_eq!(SignedDecimal::from_atomics(2000i128, 3).unwrap(), two);
1042        assert_eq!(
1043            SignedDecimal::from_atomics(2000000000000000000i128, 18).unwrap(),
1044            two
1045        );
1046        assert_eq!(
1047            SignedDecimal::from_atomics(20000000000000000000i128, 19).unwrap(),
1048            two
1049        );
1050        assert_eq!(
1051            SignedDecimal::from_atomics(200000000000000000000i128, 20).unwrap(),
1052            two
1053        );
1054
1055        assert_eq!(SignedDecimal::from_atomics(-1i128, 0).unwrap(), neg_one);
1056        assert_eq!(SignedDecimal::from_atomics(-10i128, 1).unwrap(), neg_one);
1057        assert_eq!(
1058            SignedDecimal::from_atomics(-100000000000000000000i128, 20).unwrap(),
1059            neg_one
1060        );
1061
1062        // Cuts decimal digits (20 provided but only 18 can be stored)
1063        assert_eq!(
1064            SignedDecimal::from_atomics(4321i128, 20).unwrap(),
1065            SignedDecimal::from_str("0.000000000000000043").unwrap()
1066        );
1067        assert_eq!(
1068            SignedDecimal::from_atomics(-4321i128, 20).unwrap(),
1069            SignedDecimal::from_str("-0.000000000000000043").unwrap()
1070        );
1071        assert_eq!(
1072            SignedDecimal::from_atomics(6789i128, 20).unwrap(),
1073            SignedDecimal::from_str("0.000000000000000067").unwrap()
1074        );
1075        assert_eq!(
1076            SignedDecimal::from_atomics(i128::MAX, 38).unwrap(),
1077            SignedDecimal::from_str("1.701411834604692317").unwrap()
1078        );
1079        assert_eq!(
1080            SignedDecimal::from_atomics(i128::MAX, 39).unwrap(),
1081            SignedDecimal::from_str("0.170141183460469231").unwrap()
1082        );
1083        assert_eq!(
1084            SignedDecimal::from_atomics(i128::MAX, 45).unwrap(),
1085            SignedDecimal::from_str("0.000000170141183460").unwrap()
1086        );
1087        assert_eq!(
1088            SignedDecimal::from_atomics(i128::MAX, 51).unwrap(),
1089            SignedDecimal::from_str("0.000000000000170141").unwrap()
1090        );
1091        assert_eq!(
1092            SignedDecimal::from_atomics(i128::MAX, 56).unwrap(),
1093            SignedDecimal::from_str("0.000000000000000001").unwrap()
1094        );
1095        assert_eq!(
1096            SignedDecimal::from_atomics(i128::MAX, 57).unwrap(),
1097            SignedDecimal::from_str("0.000000000000000000").unwrap()
1098        );
1099        assert_eq!(
1100            SignedDecimal::from_atomics(i128::MAX, u32::MAX).unwrap(),
1101            SignedDecimal::from_str("0.000000000000000000").unwrap()
1102        );
1103        assert_eq!(
1104            SignedDecimal::from_atomics(0i128, u32::MAX).unwrap(),
1105            SignedDecimal::zero()
1106        );
1107        assert_eq!(
1108            SignedDecimal::from_atomics(i128::MIN, u32::MAX).unwrap(),
1109            SignedDecimal::zero()
1110        );
1111
1112        // Can be used with max value
1113        let max = SignedDecimal::MAX;
1114        assert_eq!(
1115            SignedDecimal::from_atomics(max.atomics(), max.decimal_places()).unwrap(),
1116            max
1117        );
1118
1119        // Can be used with min value
1120        let min = SignedDecimal::MIN;
1121        assert_eq!(
1122            SignedDecimal::from_atomics(min.atomics(), min.decimal_places()).unwrap(),
1123            min
1124        );
1125
1126        // Overflow is only possible with digits < 18
1127        let result = SignedDecimal::from_atomics(i128::MAX, 17);
1128        assert_eq!(result.unwrap_err(), SignedDecimalRangeExceeded);
1129    }
1130
1131    #[test]
1132    fn signed_decimal_from_ratio_works() {
1133        // 1.0
1134        assert_eq!(
1135            SignedDecimal::from_ratio(1i128, 1i128),
1136            SignedDecimal::one()
1137        );
1138        assert_eq!(
1139            SignedDecimal::from_ratio(53i128, 53i128),
1140            SignedDecimal::one()
1141        );
1142        assert_eq!(
1143            SignedDecimal::from_ratio(125i128, 125i128),
1144            SignedDecimal::one()
1145        );
1146
1147        // -1.0
1148        assert_eq!(
1149            SignedDecimal::from_ratio(-1i128, 1i128),
1150            SignedDecimal::negative_one()
1151        );
1152        assert_eq!(
1153            SignedDecimal::from_ratio(-53i128, 53i128),
1154            SignedDecimal::negative_one()
1155        );
1156        assert_eq!(
1157            SignedDecimal::from_ratio(125i128, -125i128),
1158            SignedDecimal::negative_one()
1159        );
1160
1161        // 1.5
1162        assert_eq!(
1163            SignedDecimal::from_ratio(3i128, 2i128),
1164            SignedDecimal::percent(150)
1165        );
1166        assert_eq!(
1167            SignedDecimal::from_ratio(150i128, 100i128),
1168            SignedDecimal::percent(150)
1169        );
1170        assert_eq!(
1171            SignedDecimal::from_ratio(333i128, 222i128),
1172            SignedDecimal::percent(150)
1173        );
1174
1175        // 0.125
1176        assert_eq!(
1177            SignedDecimal::from_ratio(1i64, 8i64),
1178            SignedDecimal::permille(125)
1179        );
1180        assert_eq!(
1181            SignedDecimal::from_ratio(125i64, 1000i64),
1182            SignedDecimal::permille(125)
1183        );
1184
1185        // -0.125
1186        assert_eq!(
1187            SignedDecimal::from_ratio(-1i64, 8i64),
1188            SignedDecimal::permille(-125)
1189        );
1190        assert_eq!(
1191            SignedDecimal::from_ratio(125i64, -1000i64),
1192            SignedDecimal::permille(-125)
1193        );
1194
1195        // 1/3 (result floored)
1196        assert_eq!(
1197            SignedDecimal::from_ratio(1i64, 3i64),
1198            SignedDecimal(Int128::from(333_333_333_333_333_333i128))
1199        );
1200
1201        // 2/3 (result floored)
1202        assert_eq!(
1203            SignedDecimal::from_ratio(2i64, 3i64),
1204            SignedDecimal(Int128::from(666_666_666_666_666_666i128))
1205        );
1206
1207        // large inputs
1208        assert_eq!(
1209            SignedDecimal::from_ratio(0i128, i128::MAX),
1210            SignedDecimal::zero()
1211        );
1212        assert_eq!(
1213            SignedDecimal::from_ratio(i128::MAX, i128::MAX),
1214            SignedDecimal::one()
1215        );
1216        // 170141183460469231731 is the largest integer <= SignedDecimal::MAX
1217        assert_eq!(
1218            SignedDecimal::from_ratio(170141183460469231731i128, 1i128),
1219            SignedDecimal::from_str("170141183460469231731").unwrap()
1220        );
1221    }
1222
1223    #[test]
1224    #[should_panic(expected = "Denominator must not be zero")]
1225    fn signed_decimal_from_ratio_panics_for_zero_denominator() {
1226        SignedDecimal::from_ratio(1i128, 0i128);
1227    }
1228
1229    #[test]
1230    #[should_panic(expected = "Multiplication overflow")]
1231    fn signed_decimal_from_ratio_panics_for_mul_overflow() {
1232        SignedDecimal::from_ratio(i128::MAX, 1i128);
1233    }
1234
1235    #[test]
1236    fn signed_decimal_checked_from_ratio_does_not_panic() {
1237        assert_eq!(
1238            SignedDecimal::checked_from_ratio(1i128, 0i128),
1239            Err(CheckedFromRatioError::DivideByZero)
1240        );
1241
1242        assert_eq!(
1243            SignedDecimal::checked_from_ratio(i128::MAX, 1i128),
1244            Err(CheckedFromRatioError::Overflow)
1245        );
1246    }
1247
1248    #[test]
1249    fn signed_decimal_implements_fraction() {
1250        let fraction = SignedDecimal::from_str("1234.567").unwrap();
1251        assert_eq!(
1252            fraction.numerator(),
1253            Int128::from(1_234_567_000_000_000_000_000i128)
1254        );
1255        assert_eq!(
1256            fraction.denominator(),
1257            Int128::from(1_000_000_000_000_000_000i128)
1258        );
1259
1260        let fraction = SignedDecimal::from_str("-1234.567").unwrap();
1261        assert_eq!(
1262            fraction.numerator(),
1263            Int128::from(-1_234_567_000_000_000_000_000i128)
1264        );
1265        assert_eq!(
1266            fraction.denominator(),
1267            Int128::from(1_000_000_000_000_000_000i128)
1268        );
1269    }
1270
1271    #[test]
1272    fn signed_decimal_from_str_works() {
1273        // Integers
1274        assert_eq!(
1275            SignedDecimal::from_str("0").unwrap(),
1276            SignedDecimal::percent(0)
1277        );
1278        assert_eq!(
1279            SignedDecimal::from_str("1").unwrap(),
1280            SignedDecimal::percent(100)
1281        );
1282        assert_eq!(
1283            SignedDecimal::from_str("5").unwrap(),
1284            SignedDecimal::percent(500)
1285        );
1286        assert_eq!(
1287            SignedDecimal::from_str("42").unwrap(),
1288            SignedDecimal::percent(4200)
1289        );
1290        assert_eq!(
1291            SignedDecimal::from_str("000").unwrap(),
1292            SignedDecimal::percent(0)
1293        );
1294        assert_eq!(
1295            SignedDecimal::from_str("001").unwrap(),
1296            SignedDecimal::percent(100)
1297        );
1298        assert_eq!(
1299            SignedDecimal::from_str("005").unwrap(),
1300            SignedDecimal::percent(500)
1301        );
1302        assert_eq!(
1303            SignedDecimal::from_str("0042").unwrap(),
1304            SignedDecimal::percent(4200)
1305        );
1306
1307        // Positive decimals
1308        assert_eq!(
1309            SignedDecimal::from_str("1.0").unwrap(),
1310            SignedDecimal::percent(100)
1311        );
1312        assert_eq!(
1313            SignedDecimal::from_str("1.5").unwrap(),
1314            SignedDecimal::percent(150)
1315        );
1316        assert_eq!(
1317            SignedDecimal::from_str("0.5").unwrap(),
1318            SignedDecimal::percent(50)
1319        );
1320        assert_eq!(
1321            SignedDecimal::from_str("0.123").unwrap(),
1322            SignedDecimal::permille(123)
1323        );
1324
1325        assert_eq!(
1326            SignedDecimal::from_str("40.00").unwrap(),
1327            SignedDecimal::percent(4000)
1328        );
1329        assert_eq!(
1330            SignedDecimal::from_str("04.00").unwrap(),
1331            SignedDecimal::percent(400)
1332        );
1333        assert_eq!(
1334            SignedDecimal::from_str("00.40").unwrap(),
1335            SignedDecimal::percent(40)
1336        );
1337        assert_eq!(
1338            SignedDecimal::from_str("00.04").unwrap(),
1339            SignedDecimal::percent(4)
1340        );
1341        // Negative decimals
1342        assert_eq!(
1343            SignedDecimal::from_str("-00.04").unwrap(),
1344            SignedDecimal::percent(-4)
1345        );
1346        assert_eq!(
1347            SignedDecimal::from_str("-00.40").unwrap(),
1348            SignedDecimal::percent(-40)
1349        );
1350        assert_eq!(
1351            SignedDecimal::from_str("-04.00").unwrap(),
1352            SignedDecimal::percent(-400)
1353        );
1354
1355        // Can handle DECIMAL_PLACES fractional digits
1356        assert_eq!(
1357            SignedDecimal::from_str("7.123456789012345678").unwrap(),
1358            SignedDecimal(Int128::from(7123456789012345678i128))
1359        );
1360        assert_eq!(
1361            SignedDecimal::from_str("7.999999999999999999").unwrap(),
1362            SignedDecimal(Int128::from(7999999999999999999i128))
1363        );
1364
1365        // Works for documented max value
1366        assert_eq!(
1367            SignedDecimal::from_str("170141183460469231731.687303715884105727").unwrap(),
1368            SignedDecimal::MAX
1369        );
1370        // Works for documented min value
1371        assert_eq!(
1372            SignedDecimal::from_str("-170141183460469231731.687303715884105728").unwrap(),
1373            SignedDecimal::MIN
1374        );
1375        assert_eq!(
1376            SignedDecimal::from_str("-1").unwrap(),
1377            SignedDecimal::negative_one()
1378        );
1379    }
1380
1381    #[test]
1382    fn signed_decimal_from_str_errors_for_broken_whole_part() {
1383        assert!(SignedDecimal::from_str("").is_err());
1384        assert!(SignedDecimal::from_str(" ").is_err());
1385        assert!(SignedDecimal::from_str("-").is_err());
1386    }
1387
1388    #[test]
1389    fn signed_decimal_from_str_errors_for_broken_fractional_part() {
1390        assert!(SignedDecimal::from_str("1.").is_err());
1391        assert!(SignedDecimal::from_str("1. ").is_err());
1392        assert!(SignedDecimal::from_str("1.e").is_err());
1393        assert!(SignedDecimal::from_str("1.2e3").is_err());
1394        assert!(SignedDecimal::from_str("1.-2").is_err());
1395    }
1396
1397    #[test]
1398    fn signed_decimal_from_str_errors_for_more_than_18_fractional_digits() {
1399        assert!(SignedDecimal::from_str("7.1234567890123456789").is_err());
1400        // No special rules for trailing zeros. This could be changed but adds gas cost for the happy path.
1401        assert!(SignedDecimal::from_str("7.1230000000000000000").is_err());
1402    }
1403
1404    #[test]
1405    fn signed_decimal_from_str_errors_for_invalid_number_of_dots() {
1406        assert!(SignedDecimal::from_str("1.2.3")
1407            .unwrap_err()
1408            .to_string()
1409            .ends_with("Unexpected number of dots"));
1410
1411        assert!(SignedDecimal::from_str("1.2.3.4")
1412            .unwrap_err()
1413            .to_string()
1414            .ends_with("Unexpected number of dots"));
1415    }
1416
1417    #[test]
1418    fn signed_decimal_from_str_errors_for_more_than_max_value() {
1419        // Integer
1420        assert!(SignedDecimal::from_str("170141183460469231732").is_err());
1421        assert!(SignedDecimal::from_str("-170141183460469231732").is_err());
1422
1423        // SignedDecimal
1424        assert!(SignedDecimal::from_str("170141183460469231732.0").is_err());
1425        assert!(SignedDecimal::from_str("170141183460469231731.687303715884105728").is_err());
1426        assert!(SignedDecimal::from_str("-170141183460469231731.687303715884105729").is_err());
1427    }
1428
1429    #[test]
1430    fn signed_decimal_conversions_work() {
1431        // signed decimal to signed decimal
1432        assert_eq!(
1433            SignedDecimal::try_from(SignedDecimal256::MAX).unwrap_err(),
1434            SignedDecimalRangeExceeded
1435        );
1436        assert_eq!(
1437            SignedDecimal::try_from(SignedDecimal256::MIN).unwrap_err(),
1438            SignedDecimalRangeExceeded
1439        );
1440        assert_eq!(
1441            SignedDecimal::try_from(SignedDecimal256::zero()).unwrap(),
1442            SignedDecimal::zero()
1443        );
1444        assert_eq!(
1445            SignedDecimal::try_from(SignedDecimal256::one()).unwrap(),
1446            SignedDecimal::one()
1447        );
1448        assert_eq!(
1449            SignedDecimal::try_from(SignedDecimal256::percent(50)).unwrap(),
1450            SignedDecimal::percent(50)
1451        );
1452        assert_eq!(
1453            SignedDecimal::try_from(SignedDecimal256::percent(-200)).unwrap(),
1454            SignedDecimal::percent(-200)
1455        );
1456
1457        // unsigned to signed decimal
1458        assert_eq!(
1459            SignedDecimal::try_from(Decimal::MAX).unwrap_err(),
1460            SignedDecimalRangeExceeded
1461        );
1462        let max = Decimal::new(Uint128::new(SignedDecimal::MAX.atomics().i128() as u128));
1463        let too_big = max + Decimal::new(Uint128::one());
1464        assert_eq!(
1465            SignedDecimal::try_from(too_big).unwrap_err(),
1466            SignedDecimalRangeExceeded
1467        );
1468        assert_eq!(
1469            SignedDecimal::try_from(Decimal::zero()).unwrap(),
1470            SignedDecimal::zero()
1471        );
1472        assert_eq!(SignedDecimal::try_from(max).unwrap(), SignedDecimal::MAX);
1473    }
1474
1475    #[test]
1476    fn signed_decimal_atomics_works() {
1477        let zero = SignedDecimal::zero();
1478        let one = SignedDecimal::one();
1479        let half = SignedDecimal::percent(50);
1480        let two = SignedDecimal::percent(200);
1481        let max = SignedDecimal::MAX;
1482        let neg_half = SignedDecimal::percent(-50);
1483        let neg_two = SignedDecimal::percent(-200);
1484        let min = SignedDecimal::MIN;
1485
1486        assert_eq!(zero.atomics(), Int128::new(0));
1487        assert_eq!(one.atomics(), Int128::new(1000000000000000000));
1488        assert_eq!(half.atomics(), Int128::new(500000000000000000));
1489        assert_eq!(two.atomics(), Int128::new(2000000000000000000));
1490        assert_eq!(max.atomics(), Int128::MAX);
1491        assert_eq!(neg_half.atomics(), Int128::new(-500000000000000000));
1492        assert_eq!(neg_two.atomics(), Int128::new(-2000000000000000000));
1493        assert_eq!(min.atomics(), Int128::MIN);
1494    }
1495
1496    #[test]
1497    fn signed_decimal_decimal_places_works() {
1498        let zero = SignedDecimal::zero();
1499        let one = SignedDecimal::one();
1500        let half = SignedDecimal::percent(50);
1501        let two = SignedDecimal::percent(200);
1502        let max = SignedDecimal::MAX;
1503        let neg_one = SignedDecimal::negative_one();
1504
1505        assert_eq!(zero.decimal_places(), 18);
1506        assert_eq!(one.decimal_places(), 18);
1507        assert_eq!(half.decimal_places(), 18);
1508        assert_eq!(two.decimal_places(), 18);
1509        assert_eq!(max.decimal_places(), 18);
1510        assert_eq!(neg_one.decimal_places(), 18);
1511    }
1512
1513    #[test]
1514    fn signed_decimal_is_zero_works() {
1515        assert!(SignedDecimal::zero().is_zero());
1516        assert!(SignedDecimal::percent(0).is_zero());
1517        assert!(SignedDecimal::permille(0).is_zero());
1518
1519        assert!(!SignedDecimal::one().is_zero());
1520        assert!(!SignedDecimal::percent(123).is_zero());
1521        assert!(!SignedDecimal::permille(-1234).is_zero());
1522    }
1523
1524    #[test]
1525    fn signed_decimal_inv_works() {
1526        // d = 0
1527        assert_eq!(SignedDecimal::zero().inv(), None);
1528
1529        // d == 1
1530        assert_eq!(SignedDecimal::one().inv(), Some(SignedDecimal::one()));
1531
1532        // d == -1
1533        assert_eq!(
1534            SignedDecimal::negative_one().inv(),
1535            Some(SignedDecimal::negative_one())
1536        );
1537
1538        // d > 1 exact
1539        assert_eq!(
1540            SignedDecimal::from_str("2").unwrap().inv(),
1541            Some(SignedDecimal::from_str("0.5").unwrap())
1542        );
1543        assert_eq!(
1544            SignedDecimal::from_str("20").unwrap().inv(),
1545            Some(SignedDecimal::from_str("0.05").unwrap())
1546        );
1547        assert_eq!(
1548            SignedDecimal::from_str("200").unwrap().inv(),
1549            Some(SignedDecimal::from_str("0.005").unwrap())
1550        );
1551        assert_eq!(
1552            SignedDecimal::from_str("2000").unwrap().inv(),
1553            Some(SignedDecimal::from_str("0.0005").unwrap())
1554        );
1555
1556        // d > 1 rounded
1557        assert_eq!(
1558            SignedDecimal::from_str("3").unwrap().inv(),
1559            Some(SignedDecimal::from_str("0.333333333333333333").unwrap())
1560        );
1561        assert_eq!(
1562            SignedDecimal::from_str("6").unwrap().inv(),
1563            Some(SignedDecimal::from_str("0.166666666666666666").unwrap())
1564        );
1565
1566        // d < 1 exact
1567        assert_eq!(
1568            SignedDecimal::from_str("0.5").unwrap().inv(),
1569            Some(SignedDecimal::from_str("2").unwrap())
1570        );
1571        assert_eq!(
1572            SignedDecimal::from_str("0.05").unwrap().inv(),
1573            Some(SignedDecimal::from_str("20").unwrap())
1574        );
1575        assert_eq!(
1576            SignedDecimal::from_str("0.005").unwrap().inv(),
1577            Some(SignedDecimal::from_str("200").unwrap())
1578        );
1579        assert_eq!(
1580            SignedDecimal::from_str("0.0005").unwrap().inv(),
1581            Some(SignedDecimal::from_str("2000").unwrap())
1582        );
1583
1584        // d < 0
1585        assert_eq!(
1586            SignedDecimal::from_str("-0.5").unwrap().inv(),
1587            Some(SignedDecimal::from_str("-2").unwrap())
1588        );
1589        // d < 0 rounded
1590        assert_eq!(
1591            SignedDecimal::from_str("-3").unwrap().inv(),
1592            Some(SignedDecimal::from_str("-0.333333333333333333").unwrap())
1593        );
1594    }
1595
1596    #[test]
1597    #[allow(clippy::op_ref)]
1598    fn signed_decimal_add_works() {
1599        let value = SignedDecimal::one() + SignedDecimal::percent(50); // 1.5
1600        assert_eq!(
1601            value.0,
1602            SignedDecimal::DECIMAL_FRACTIONAL * Int128::from(3u8) / Int128::from(2u8)
1603        );
1604
1605        assert_eq!(
1606            SignedDecimal::percent(5) + SignedDecimal::percent(4),
1607            SignedDecimal::percent(9)
1608        );
1609        assert_eq!(
1610            SignedDecimal::percent(5) + SignedDecimal::zero(),
1611            SignedDecimal::percent(5)
1612        );
1613        assert_eq!(
1614            SignedDecimal::zero() + SignedDecimal::zero(),
1615            SignedDecimal::zero()
1616        );
1617        // negative numbers
1618        assert_eq!(
1619            SignedDecimal::percent(-5) + SignedDecimal::percent(-4),
1620            SignedDecimal::percent(-9)
1621        );
1622        assert_eq!(
1623            SignedDecimal::percent(-5) + SignedDecimal::percent(4),
1624            SignedDecimal::percent(-1)
1625        );
1626        assert_eq!(
1627            SignedDecimal::percent(5) + SignedDecimal::percent(-4),
1628            SignedDecimal::percent(1)
1629        );
1630
1631        // works for refs
1632        let a = SignedDecimal::percent(15);
1633        let b = SignedDecimal::percent(25);
1634        let expected = SignedDecimal::percent(40);
1635        assert_eq!(a + b, expected);
1636        assert_eq!(&a + b, expected);
1637        assert_eq!(a + &b, expected);
1638        assert_eq!(&a + &b, expected);
1639    }
1640
1641    #[test]
1642    #[should_panic]
1643    fn signed_decimal_add_overflow_panics() {
1644        let _value = SignedDecimal::MAX + SignedDecimal::percent(50);
1645    }
1646
1647    #[test]
1648    fn signed_decimal_add_assign_works() {
1649        let mut a = SignedDecimal::percent(30);
1650        a += SignedDecimal::percent(20);
1651        assert_eq!(a, SignedDecimal::percent(50));
1652
1653        // works for refs
1654        let mut a = SignedDecimal::percent(15);
1655        let b = SignedDecimal::percent(3);
1656        let expected = SignedDecimal::percent(18);
1657        a += &b;
1658        assert_eq!(a, expected);
1659    }
1660
1661    #[test]
1662    #[allow(clippy::op_ref)]
1663    fn signed_decimal_sub_works() {
1664        let value = SignedDecimal::one() - SignedDecimal::percent(50); // 0.5
1665        assert_eq!(
1666            value.0,
1667            SignedDecimal::DECIMAL_FRACTIONAL / Int128::from(2u8)
1668        );
1669
1670        assert_eq!(
1671            SignedDecimal::percent(9) - SignedDecimal::percent(4),
1672            SignedDecimal::percent(5)
1673        );
1674        assert_eq!(
1675            SignedDecimal::percent(16) - SignedDecimal::zero(),
1676            SignedDecimal::percent(16)
1677        );
1678        assert_eq!(
1679            SignedDecimal::percent(16) - SignedDecimal::percent(16),
1680            SignedDecimal::zero()
1681        );
1682        assert_eq!(
1683            SignedDecimal::zero() - SignedDecimal::zero(),
1684            SignedDecimal::zero()
1685        );
1686
1687        // negative numbers
1688        assert_eq!(
1689            SignedDecimal::percent(-5) - SignedDecimal::percent(-4),
1690            SignedDecimal::percent(-1)
1691        );
1692        assert_eq!(
1693            SignedDecimal::percent(-5) - SignedDecimal::percent(4),
1694            SignedDecimal::percent(-9)
1695        );
1696        assert_eq!(
1697            SignedDecimal::percent(500) - SignedDecimal::percent(-4),
1698            SignedDecimal::percent(504)
1699        );
1700
1701        // works for refs
1702        let a = SignedDecimal::percent(13);
1703        let b = SignedDecimal::percent(6);
1704        let expected = SignedDecimal::percent(7);
1705        assert_eq!(a - b, expected);
1706        assert_eq!(&a - b, expected);
1707        assert_eq!(a - &b, expected);
1708        assert_eq!(&a - &b, expected);
1709    }
1710
1711    #[test]
1712    #[should_panic]
1713    fn signed_decimal_sub_overflow_panics() {
1714        let _value = SignedDecimal::MIN - SignedDecimal::percent(50);
1715    }
1716
1717    #[test]
1718    fn signed_decimal_sub_assign_works() {
1719        let mut a = SignedDecimal::percent(20);
1720        a -= SignedDecimal::percent(2);
1721        assert_eq!(a, SignedDecimal::percent(18));
1722
1723        // works for refs
1724        let mut a = SignedDecimal::percent(33);
1725        let b = SignedDecimal::percent(13);
1726        let expected = SignedDecimal::percent(20);
1727        a -= &b;
1728        assert_eq!(a, expected);
1729    }
1730
1731    #[test]
1732    #[allow(clippy::op_ref)]
1733    fn signed_decimal_implements_mul() {
1734        let one = SignedDecimal::one();
1735        let two = one + one;
1736        let half = SignedDecimal::percent(50);
1737
1738        // 1*x and x*1
1739        assert_eq!(one * SignedDecimal::percent(0), SignedDecimal::percent(0));
1740        assert_eq!(one * SignedDecimal::percent(1), SignedDecimal::percent(1));
1741        assert_eq!(one * SignedDecimal::percent(10), SignedDecimal::percent(10));
1742        assert_eq!(
1743            one * SignedDecimal::percent(100),
1744            SignedDecimal::percent(100)
1745        );
1746        assert_eq!(
1747            one * SignedDecimal::percent(1000),
1748            SignedDecimal::percent(1000)
1749        );
1750        assert_eq!(one * SignedDecimal::MAX, SignedDecimal::MAX);
1751        assert_eq!(SignedDecimal::percent(0) * one, SignedDecimal::percent(0));
1752        assert_eq!(SignedDecimal::percent(1) * one, SignedDecimal::percent(1));
1753        assert_eq!(SignedDecimal::percent(10) * one, SignedDecimal::percent(10));
1754        assert_eq!(
1755            SignedDecimal::percent(100) * one,
1756            SignedDecimal::percent(100)
1757        );
1758        assert_eq!(
1759            SignedDecimal::percent(1000) * one,
1760            SignedDecimal::percent(1000)
1761        );
1762        assert_eq!(SignedDecimal::MAX * one, SignedDecimal::MAX);
1763        assert_eq!(SignedDecimal::percent(-1) * one, SignedDecimal::percent(-1));
1764        assert_eq!(
1765            one * SignedDecimal::percent(-10),
1766            SignedDecimal::percent(-10)
1767        );
1768
1769        // double
1770        assert_eq!(two * SignedDecimal::percent(0), SignedDecimal::percent(0));
1771        assert_eq!(two * SignedDecimal::percent(1), SignedDecimal::percent(2));
1772        assert_eq!(two * SignedDecimal::percent(10), SignedDecimal::percent(20));
1773        assert_eq!(
1774            two * SignedDecimal::percent(100),
1775            SignedDecimal::percent(200)
1776        );
1777        assert_eq!(
1778            two * SignedDecimal::percent(1000),
1779            SignedDecimal::percent(2000)
1780        );
1781        assert_eq!(SignedDecimal::percent(0) * two, SignedDecimal::percent(0));
1782        assert_eq!(SignedDecimal::percent(1) * two, SignedDecimal::percent(2));
1783        assert_eq!(SignedDecimal::percent(10) * two, SignedDecimal::percent(20));
1784        assert_eq!(
1785            SignedDecimal::percent(100) * two,
1786            SignedDecimal::percent(200)
1787        );
1788        assert_eq!(
1789            SignedDecimal::percent(1000) * two,
1790            SignedDecimal::percent(2000)
1791        );
1792        assert_eq!(SignedDecimal::percent(-1) * two, SignedDecimal::percent(-2));
1793        assert_eq!(
1794            two * SignedDecimal::new(Int128::MIN / Int128::new(2)),
1795            SignedDecimal::MIN
1796        );
1797
1798        // half
1799        assert_eq!(half * SignedDecimal::percent(0), SignedDecimal::percent(0));
1800        assert_eq!(half * SignedDecimal::percent(1), SignedDecimal::permille(5));
1801        assert_eq!(half * SignedDecimal::percent(10), SignedDecimal::percent(5));
1802        assert_eq!(
1803            half * SignedDecimal::percent(100),
1804            SignedDecimal::percent(50)
1805        );
1806        assert_eq!(
1807            half * SignedDecimal::percent(1000),
1808            SignedDecimal::percent(500)
1809        );
1810        assert_eq!(SignedDecimal::percent(0) * half, SignedDecimal::percent(0));
1811        assert_eq!(SignedDecimal::percent(1) * half, SignedDecimal::permille(5));
1812        assert_eq!(SignedDecimal::percent(10) * half, SignedDecimal::percent(5));
1813        assert_eq!(
1814            SignedDecimal::percent(100) * half,
1815            SignedDecimal::percent(50)
1816        );
1817        assert_eq!(
1818            SignedDecimal::percent(1000) * half,
1819            SignedDecimal::percent(500)
1820        );
1821
1822        // Move left
1823        let a = dec("123.127726548762582");
1824        assert_eq!(a * dec("1"), dec("123.127726548762582"));
1825        assert_eq!(a * dec("10"), dec("1231.27726548762582"));
1826        assert_eq!(a * dec("100"), dec("12312.7726548762582"));
1827        assert_eq!(a * dec("1000"), dec("123127.726548762582"));
1828        assert_eq!(a * dec("1000000"), dec("123127726.548762582"));
1829        assert_eq!(a * dec("1000000000"), dec("123127726548.762582"));
1830        assert_eq!(a * dec("1000000000000"), dec("123127726548762.582"));
1831        assert_eq!(a * dec("1000000000000000"), dec("123127726548762582"));
1832        assert_eq!(a * dec("1000000000000000000"), dec("123127726548762582000"));
1833        assert_eq!(dec("1") * a, dec("123.127726548762582"));
1834        assert_eq!(dec("10") * a, dec("1231.27726548762582"));
1835        assert_eq!(dec("100") * a, dec("12312.7726548762582"));
1836        assert_eq!(dec("1000") * a, dec("123127.726548762582"));
1837        assert_eq!(dec("1000000") * a, dec("123127726.548762582"));
1838        assert_eq!(dec("1000000000") * a, dec("123127726548.762582"));
1839        assert_eq!(dec("1000000000000") * a, dec("123127726548762.582"));
1840        assert_eq!(dec("1000000000000000") * a, dec("123127726548762582"));
1841        assert_eq!(dec("1000000000000000000") * a, dec("123127726548762582000"));
1842        assert_eq!(
1843            dec("-1000000000000000000") * a,
1844            dec("-123127726548762582000")
1845        );
1846
1847        // Move right
1848        let max = SignedDecimal::MAX;
1849        assert_eq!(
1850            max * dec("1.0"),
1851            dec("170141183460469231731.687303715884105727")
1852        );
1853        assert_eq!(
1854            max * dec("0.1"),
1855            dec("17014118346046923173.168730371588410572")
1856        );
1857        assert_eq!(
1858            max * dec("0.01"),
1859            dec("1701411834604692317.316873037158841057")
1860        );
1861        assert_eq!(
1862            max * dec("0.001"),
1863            dec("170141183460469231.731687303715884105")
1864        );
1865        assert_eq!(
1866            max * dec("0.000001"),
1867            dec("170141183460469.231731687303715884")
1868        );
1869        assert_eq!(
1870            max * dec("0.000000001"),
1871            dec("170141183460.469231731687303715")
1872        );
1873        assert_eq!(
1874            max * dec("0.000000000001"),
1875            dec("170141183.460469231731687303")
1876        );
1877        assert_eq!(
1878            max * dec("0.000000000000001"),
1879            dec("170141.183460469231731687")
1880        );
1881        assert_eq!(
1882            max * dec("0.000000000000000001"),
1883            dec("170.141183460469231731")
1884        );
1885
1886        // works for refs
1887        let a = SignedDecimal::percent(20);
1888        let b = SignedDecimal::percent(30);
1889        let expected = SignedDecimal::percent(6);
1890        assert_eq!(a * b, expected);
1891        assert_eq!(&a * b, expected);
1892        assert_eq!(a * &b, expected);
1893        assert_eq!(&a * &b, expected);
1894    }
1895
1896    #[test]
1897    fn signed_decimal_mul_assign_works() {
1898        let mut a = SignedDecimal::percent(15);
1899        a *= SignedDecimal::percent(60);
1900        assert_eq!(a, SignedDecimal::percent(9));
1901
1902        // works for refs
1903        let mut a = SignedDecimal::percent(50);
1904        let b = SignedDecimal::percent(20);
1905        a *= &b;
1906        assert_eq!(a, SignedDecimal::percent(10));
1907    }
1908
1909    #[test]
1910    #[should_panic(expected = "attempt to multiply with overflow")]
1911    fn signed_decimal_mul_overflow_panics() {
1912        let _value = SignedDecimal::MAX * SignedDecimal::percent(101);
1913    }
1914
1915    #[test]
1916    fn signed_decimal_checked_mul() {
1917        let test_data = [
1918            (SignedDecimal::zero(), SignedDecimal::zero()),
1919            (SignedDecimal::zero(), SignedDecimal::one()),
1920            (SignedDecimal::one(), SignedDecimal::zero()),
1921            (SignedDecimal::percent(10), SignedDecimal::zero()),
1922            (SignedDecimal::percent(10), SignedDecimal::percent(5)),
1923            (SignedDecimal::MAX, SignedDecimal::one()),
1924            (
1925                SignedDecimal::MAX / Int128::new(2),
1926                SignedDecimal::percent(200),
1927            ),
1928            (SignedDecimal::permille(6), SignedDecimal::permille(13)),
1929            (SignedDecimal::permille(-6), SignedDecimal::permille(0)),
1930            (SignedDecimal::MAX, SignedDecimal::negative_one()),
1931        ];
1932
1933        // The regular core::ops::Mul is our source of truth for these tests.
1934        for (x, y) in test_data.into_iter() {
1935            assert_eq!(x * y, x.checked_mul(y).unwrap());
1936        }
1937    }
1938
1939    #[test]
1940    fn signed_decimal_checked_mul_overflow() {
1941        assert_eq!(
1942            SignedDecimal::MAX.checked_mul(SignedDecimal::percent(200)),
1943            Err(OverflowError::new(OverflowOperation::Mul))
1944        );
1945    }
1946
1947    #[test]
1948    #[allow(clippy::op_ref)]
1949    fn signed_decimal_implements_div() {
1950        let one = SignedDecimal::one();
1951        let two = one + one;
1952        let half = SignedDecimal::percent(50);
1953
1954        // 1/x and x/1
1955        assert_eq!(
1956            one / SignedDecimal::percent(1),
1957            SignedDecimal::percent(10_000)
1958        );
1959        assert_eq!(
1960            one / SignedDecimal::percent(10),
1961            SignedDecimal::percent(1_000)
1962        );
1963        assert_eq!(
1964            one / SignedDecimal::percent(100),
1965            SignedDecimal::percent(100)
1966        );
1967        assert_eq!(
1968            one / SignedDecimal::percent(1000),
1969            SignedDecimal::percent(10)
1970        );
1971        assert_eq!(SignedDecimal::percent(0) / one, SignedDecimal::percent(0));
1972        assert_eq!(SignedDecimal::percent(1) / one, SignedDecimal::percent(1));
1973        assert_eq!(SignedDecimal::percent(10) / one, SignedDecimal::percent(10));
1974        assert_eq!(
1975            SignedDecimal::percent(100) / one,
1976            SignedDecimal::percent(100)
1977        );
1978        assert_eq!(
1979            SignedDecimal::percent(1000) / one,
1980            SignedDecimal::percent(1000)
1981        );
1982        assert_eq!(
1983            one / SignedDecimal::percent(-1),
1984            SignedDecimal::percent(-10_000)
1985        );
1986        assert_eq!(
1987            one / SignedDecimal::percent(-10),
1988            SignedDecimal::percent(-1_000)
1989        );
1990
1991        // double
1992        assert_eq!(
1993            two / SignedDecimal::percent(1),
1994            SignedDecimal::percent(20_000)
1995        );
1996        assert_eq!(
1997            two / SignedDecimal::percent(10),
1998            SignedDecimal::percent(2_000)
1999        );
2000        assert_eq!(
2001            two / SignedDecimal::percent(100),
2002            SignedDecimal::percent(200)
2003        );
2004        assert_eq!(
2005            two / SignedDecimal::percent(1000),
2006            SignedDecimal::percent(20)
2007        );
2008        assert_eq!(SignedDecimal::percent(0) / two, SignedDecimal::percent(0));
2009        assert_eq!(SignedDecimal::percent(1) / two, dec("0.005"));
2010        assert_eq!(SignedDecimal::percent(10) / two, SignedDecimal::percent(5));
2011        assert_eq!(
2012            SignedDecimal::percent(100) / two,
2013            SignedDecimal::percent(50)
2014        );
2015        assert_eq!(
2016            SignedDecimal::percent(1000) / two,
2017            SignedDecimal::percent(500)
2018        );
2019        assert_eq!(
2020            two / SignedDecimal::percent(-1),
2021            SignedDecimal::percent(-20_000)
2022        );
2023        assert_eq!(
2024            SignedDecimal::percent(-10000) / two,
2025            SignedDecimal::percent(-5000)
2026        );
2027
2028        // half
2029        assert_eq!(
2030            half / SignedDecimal::percent(1),
2031            SignedDecimal::percent(5_000)
2032        );
2033        assert_eq!(
2034            half / SignedDecimal::percent(10),
2035            SignedDecimal::percent(500)
2036        );
2037        assert_eq!(
2038            half / SignedDecimal::percent(100),
2039            SignedDecimal::percent(50)
2040        );
2041        assert_eq!(
2042            half / SignedDecimal::percent(1000),
2043            SignedDecimal::percent(5)
2044        );
2045        assert_eq!(SignedDecimal::percent(0) / half, SignedDecimal::percent(0));
2046        assert_eq!(SignedDecimal::percent(1) / half, SignedDecimal::percent(2));
2047        assert_eq!(
2048            SignedDecimal::percent(10) / half,
2049            SignedDecimal::percent(20)
2050        );
2051        assert_eq!(
2052            SignedDecimal::percent(100) / half,
2053            SignedDecimal::percent(200)
2054        );
2055        assert_eq!(
2056            SignedDecimal::percent(1000) / half,
2057            SignedDecimal::percent(2000)
2058        );
2059
2060        // Move right
2061        let a = dec("123127726548762582");
2062        assert_eq!(a / dec("1"), dec("123127726548762582"));
2063        assert_eq!(a / dec("10"), dec("12312772654876258.2"));
2064        assert_eq!(a / dec("100"), dec("1231277265487625.82"));
2065        assert_eq!(a / dec("1000"), dec("123127726548762.582"));
2066        assert_eq!(a / dec("1000000"), dec("123127726548.762582"));
2067        assert_eq!(a / dec("1000000000"), dec("123127726.548762582"));
2068        assert_eq!(a / dec("1000000000000"), dec("123127.726548762582"));
2069        assert_eq!(a / dec("1000000000000000"), dec("123.127726548762582"));
2070        assert_eq!(a / dec("1000000000000000000"), dec("0.123127726548762582"));
2071        assert_eq!(dec("1") / a, dec("0.000000000000000008"));
2072        assert_eq!(dec("10") / a, dec("0.000000000000000081"));
2073        assert_eq!(dec("100") / a, dec("0.000000000000000812"));
2074        assert_eq!(dec("1000") / a, dec("0.000000000000008121"));
2075        assert_eq!(dec("1000000") / a, dec("0.000000000008121647"));
2076        assert_eq!(dec("1000000000") / a, dec("0.000000008121647560"));
2077        assert_eq!(dec("1000000000000") / a, dec("0.000008121647560868"));
2078        assert_eq!(dec("1000000000000000") / a, dec("0.008121647560868164"));
2079        assert_eq!(dec("1000000000000000000") / a, dec("8.121647560868164773"));
2080        // negative
2081        let a = dec("-123127726548762582");
2082        assert_eq!(a / dec("1"), dec("-123127726548762582"));
2083        assert_eq!(a / dec("10"), dec("-12312772654876258.2"));
2084        assert_eq!(a / dec("100"), dec("-1231277265487625.82"));
2085        assert_eq!(a / dec("1000"), dec("-123127726548762.582"));
2086        assert_eq!(a / dec("1000000"), dec("-123127726548.762582"));
2087        assert_eq!(a / dec("1000000000"), dec("-123127726.548762582"));
2088        assert_eq!(a / dec("1000000000000"), dec("-123127.726548762582"));
2089        assert_eq!(a / dec("1000000000000000"), dec("-123.127726548762582"));
2090        assert_eq!(a / dec("1000000000000000000"), dec("-0.123127726548762582"));
2091        assert_eq!(dec("1") / a, dec("-0.000000000000000008"));
2092
2093        // Move left
2094        let a = dec("0.123127726548762582");
2095        assert_eq!(a / dec("1.0"), dec("0.123127726548762582"));
2096        assert_eq!(a / dec("0.1"), dec("1.23127726548762582"));
2097        assert_eq!(a / dec("0.01"), dec("12.3127726548762582"));
2098        assert_eq!(a / dec("0.001"), dec("123.127726548762582"));
2099        assert_eq!(a / dec("0.000001"), dec("123127.726548762582"));
2100        assert_eq!(a / dec("0.000000001"), dec("123127726.548762582"));
2101        assert_eq!(a / dec("0.000000000001"), dec("123127726548.762582"));
2102        assert_eq!(a / dec("0.000000000000001"), dec("123127726548762.582"));
2103        assert_eq!(a / dec("0.000000000000000001"), dec("123127726548762582"));
2104        // negative
2105        let a = dec("-0.123127726548762582");
2106        assert_eq!(a / dec("1.0"), dec("-0.123127726548762582"));
2107        assert_eq!(a / dec("0.1"), dec("-1.23127726548762582"));
2108        assert_eq!(a / dec("0.01"), dec("-12.3127726548762582"));
2109        assert_eq!(a / dec("0.001"), dec("-123.127726548762582"));
2110        assert_eq!(a / dec("0.000001"), dec("-123127.726548762582"));
2111        assert_eq!(a / dec("0.000000001"), dec("-123127726.548762582"));
2112
2113        assert_eq!(
2114            SignedDecimal::percent(15) / SignedDecimal::percent(60),
2115            SignedDecimal::percent(25)
2116        );
2117
2118        // works for refs
2119        let a = SignedDecimal::percent(100);
2120        let b = SignedDecimal::percent(20);
2121        let expected = SignedDecimal::percent(500);
2122        assert_eq!(a / b, expected);
2123        assert_eq!(&a / b, expected);
2124        assert_eq!(a / &b, expected);
2125        assert_eq!(&a / &b, expected);
2126    }
2127
2128    #[test]
2129    fn signed_decimal_div_assign_works() {
2130        let mut a = SignedDecimal::percent(15);
2131        a /= SignedDecimal::percent(20);
2132        assert_eq!(a, SignedDecimal::percent(75));
2133
2134        // works for refs
2135        let mut a = SignedDecimal::percent(50);
2136        let b = SignedDecimal::percent(20);
2137        a /= &b;
2138        assert_eq!(a, SignedDecimal::percent(250));
2139    }
2140
2141    #[test]
2142    #[should_panic(expected = "Division failed - multiplication overflow")]
2143    fn signed_decimal_div_overflow_panics() {
2144        let _value = SignedDecimal::MAX / SignedDecimal::percent(10);
2145    }
2146
2147    #[test]
2148    #[should_panic(expected = "Division failed - denominator must not be zero")]
2149    fn signed_decimal_div_by_zero_panics() {
2150        let _value = SignedDecimal::one() / SignedDecimal::zero();
2151    }
2152
2153    #[test]
2154    fn signed_decimal_int128_division() {
2155        // a/b
2156        let left = SignedDecimal::percent(150); // 1.5
2157        let right = Int128::new(3);
2158        assert_eq!(left / right, SignedDecimal::percent(50));
2159
2160        // negative
2161        let left = SignedDecimal::percent(-150); // -1.5
2162        let right = Int128::new(3);
2163        assert_eq!(left / right, SignedDecimal::percent(-50));
2164
2165        // 0/a
2166        let left = SignedDecimal::zero();
2167        let right = Int128::new(300);
2168        assert_eq!(left / right, SignedDecimal::zero());
2169    }
2170
2171    #[test]
2172    #[should_panic]
2173    fn signed_decimal_int128_divide_by_zero() {
2174        let left = SignedDecimal::percent(150); // 1.5
2175        let right = Int128::new(0);
2176        let _result = left / right;
2177    }
2178
2179    #[test]
2180    fn signed_decimal_int128_div_assign() {
2181        // a/b
2182        let mut dec = SignedDecimal::percent(150); // 1.5
2183        dec /= Int128::new(3);
2184        assert_eq!(dec, SignedDecimal::percent(50));
2185
2186        // 0/a
2187        let mut dec = SignedDecimal::zero();
2188        dec /= Int128::new(300);
2189        assert_eq!(dec, SignedDecimal::zero());
2190    }
2191
2192    #[test]
2193    #[should_panic]
2194    fn signed_decimal_int128_div_assign_by_zero() {
2195        // a/0
2196        let mut dec = SignedDecimal::percent(50);
2197        dec /= Int128::new(0);
2198    }
2199
2200    #[test]
2201    fn signed_decimal_checked_pow() {
2202        for exp in 0..10 {
2203            assert_eq!(
2204                SignedDecimal::one().checked_pow(exp).unwrap(),
2205                SignedDecimal::one()
2206            );
2207        }
2208
2209        // This case is mathematically undefined but we ensure consistency with Rust standard types
2210        // https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=20df6716048e77087acd40194b233494
2211        assert_eq!(
2212            SignedDecimal::zero().checked_pow(0).unwrap(),
2213            SignedDecimal::one()
2214        );
2215
2216        for exp in 1..10 {
2217            assert_eq!(
2218                SignedDecimal::zero().checked_pow(exp).unwrap(),
2219                SignedDecimal::zero()
2220            );
2221        }
2222
2223        for exp in 1..10 {
2224            assert_eq!(
2225                SignedDecimal::negative_one().checked_pow(exp).unwrap(),
2226                // alternates between 1 and -1
2227                if exp % 2 == 0 {
2228                    SignedDecimal::one()
2229                } else {
2230                    SignedDecimal::negative_one()
2231                }
2232            )
2233        }
2234
2235        for num in &[
2236            SignedDecimal::percent(50),
2237            SignedDecimal::percent(99),
2238            SignedDecimal::percent(200),
2239        ] {
2240            assert_eq!(num.checked_pow(0).unwrap(), SignedDecimal::one())
2241        }
2242
2243        assert_eq!(
2244            SignedDecimal::percent(20).checked_pow(2).unwrap(),
2245            SignedDecimal::percent(4)
2246        );
2247
2248        assert_eq!(
2249            SignedDecimal::percent(20).checked_pow(3).unwrap(),
2250            SignedDecimal::permille(8)
2251        );
2252
2253        assert_eq!(
2254            SignedDecimal::percent(200).checked_pow(4).unwrap(),
2255            SignedDecimal::percent(1600)
2256        );
2257
2258        assert_eq!(
2259            SignedDecimal::percent(200).checked_pow(4).unwrap(),
2260            SignedDecimal::percent(1600)
2261        );
2262
2263        assert_eq!(
2264            SignedDecimal::percent(700).checked_pow(5).unwrap(),
2265            SignedDecimal::percent(1680700)
2266        );
2267
2268        assert_eq!(
2269            SignedDecimal::percent(700).checked_pow(8).unwrap(),
2270            SignedDecimal::percent(576480100)
2271        );
2272
2273        assert_eq!(
2274            SignedDecimal::percent(700).checked_pow(10).unwrap(),
2275            SignedDecimal::percent(28247524900)
2276        );
2277
2278        assert_eq!(
2279            SignedDecimal::percent(120).checked_pow(123).unwrap(),
2280            SignedDecimal(5486473221892422150877397607i128.into())
2281        );
2282
2283        assert_eq!(
2284            SignedDecimal::percent(10).checked_pow(2).unwrap(),
2285            SignedDecimal(10000000000000000i128.into())
2286        );
2287
2288        assert_eq!(
2289            SignedDecimal::percent(10).checked_pow(18).unwrap(),
2290            SignedDecimal(1i128.into())
2291        );
2292
2293        let decimals = [
2294            SignedDecimal::percent(-50),
2295            SignedDecimal::percent(-99),
2296            SignedDecimal::percent(-200),
2297        ];
2298        let exponents = [1, 2, 3, 4, 5, 8, 10];
2299
2300        for d in decimals {
2301            for e in exponents {
2302                // use multiplication as source of truth
2303                let mut mul = Ok(d);
2304                for _ in 1..e {
2305                    mul = mul.and_then(|mul| mul.checked_mul(d));
2306                }
2307                assert_eq!(mul, d.checked_pow(e));
2308            }
2309        }
2310    }
2311
2312    #[test]
2313    fn signed_decimal_checked_pow_overflow() {
2314        assert_eq!(
2315            SignedDecimal::MAX.checked_pow(2),
2316            Err(OverflowError::new(OverflowOperation::Pow))
2317        );
2318    }
2319
2320    #[test]
2321    fn signed_decimal_to_string() {
2322        // Integers
2323        assert_eq!(SignedDecimal::zero().to_string(), "0");
2324        assert_eq!(SignedDecimal::one().to_string(), "1");
2325        assert_eq!(SignedDecimal::percent(500).to_string(), "5");
2326        assert_eq!(SignedDecimal::percent(-500).to_string(), "-5");
2327
2328        // SignedDecimals
2329        assert_eq!(SignedDecimal::percent(125).to_string(), "1.25");
2330        assert_eq!(SignedDecimal::percent(42638).to_string(), "426.38");
2331        assert_eq!(SignedDecimal::percent(3).to_string(), "0.03");
2332        assert_eq!(SignedDecimal::permille(987).to_string(), "0.987");
2333        assert_eq!(SignedDecimal::percent(-125).to_string(), "-1.25");
2334        assert_eq!(SignedDecimal::percent(-42638).to_string(), "-426.38");
2335        assert_eq!(SignedDecimal::percent(-3).to_string(), "-0.03");
2336        assert_eq!(SignedDecimal::permille(-987).to_string(), "-0.987");
2337
2338        assert_eq!(
2339            SignedDecimal(Int128::from(1i128)).to_string(),
2340            "0.000000000000000001"
2341        );
2342        assert_eq!(
2343            SignedDecimal(Int128::from(10i128)).to_string(),
2344            "0.00000000000000001"
2345        );
2346        assert_eq!(
2347            SignedDecimal(Int128::from(100i128)).to_string(),
2348            "0.0000000000000001"
2349        );
2350        assert_eq!(
2351            SignedDecimal(Int128::from(1000i128)).to_string(),
2352            "0.000000000000001"
2353        );
2354        assert_eq!(
2355            SignedDecimal(Int128::from(10000i128)).to_string(),
2356            "0.00000000000001"
2357        );
2358        assert_eq!(
2359            SignedDecimal(Int128::from(100000i128)).to_string(),
2360            "0.0000000000001"
2361        );
2362        assert_eq!(
2363            SignedDecimal(Int128::from(1000000i128)).to_string(),
2364            "0.000000000001"
2365        );
2366        assert_eq!(
2367            SignedDecimal(Int128::from(10000000i128)).to_string(),
2368            "0.00000000001"
2369        );
2370        assert_eq!(
2371            SignedDecimal(Int128::from(100000000i128)).to_string(),
2372            "0.0000000001"
2373        );
2374        assert_eq!(
2375            SignedDecimal(Int128::from(1000000000i128)).to_string(),
2376            "0.000000001"
2377        );
2378        assert_eq!(
2379            SignedDecimal(Int128::from(10000000000i128)).to_string(),
2380            "0.00000001"
2381        );
2382        assert_eq!(
2383            SignedDecimal(Int128::from(100000000000i128)).to_string(),
2384            "0.0000001"
2385        );
2386        assert_eq!(
2387            SignedDecimal(Int128::from(10000000000000i128)).to_string(),
2388            "0.00001"
2389        );
2390        assert_eq!(
2391            SignedDecimal(Int128::from(100000000000000i128)).to_string(),
2392            "0.0001"
2393        );
2394        assert_eq!(
2395            SignedDecimal(Int128::from(1000000000000000i128)).to_string(),
2396            "0.001"
2397        );
2398        assert_eq!(
2399            SignedDecimal(Int128::from(10000000000000000i128)).to_string(),
2400            "0.01"
2401        );
2402        assert_eq!(
2403            SignedDecimal(Int128::from(100000000000000000i128)).to_string(),
2404            "0.1"
2405        );
2406        assert_eq!(
2407            SignedDecimal(Int128::from(-1i128)).to_string(),
2408            "-0.000000000000000001"
2409        );
2410        assert_eq!(
2411            SignedDecimal(Int128::from(-100000000000000i128)).to_string(),
2412            "-0.0001"
2413        );
2414        assert_eq!(
2415            SignedDecimal(Int128::from(-100000000000000000i128)).to_string(),
2416            "-0.1"
2417        );
2418    }
2419
2420    #[test]
2421    fn signed_decimal_iter_sum() {
2422        let items = vec![
2423            SignedDecimal::zero(),
2424            SignedDecimal(Int128::from(2i128)),
2425            SignedDecimal(Int128::from(2i128)),
2426            SignedDecimal(Int128::from(-2i128)),
2427        ];
2428        assert_eq!(
2429            items.iter().sum::<SignedDecimal>(),
2430            SignedDecimal(Int128::from(2i128))
2431        );
2432        assert_eq!(
2433            items.into_iter().sum::<SignedDecimal>(),
2434            SignedDecimal(Int128::from(2i128))
2435        );
2436
2437        let empty: Vec<SignedDecimal> = vec![];
2438        assert_eq!(SignedDecimal::zero(), empty.iter().sum::<SignedDecimal>());
2439    }
2440
2441    #[test]
2442    fn signed_decimal_serialize() {
2443        assert_eq!(
2444            serde_json::to_vec(&SignedDecimal::zero()).unwrap(),
2445            br#""0""#
2446        );
2447        assert_eq!(
2448            serde_json::to_vec(&SignedDecimal::one()).unwrap(),
2449            br#""1""#
2450        );
2451        assert_eq!(
2452            serde_json::to_vec(&SignedDecimal::percent(8)).unwrap(),
2453            br#""0.08""#
2454        );
2455        assert_eq!(
2456            serde_json::to_vec(&SignedDecimal::percent(87)).unwrap(),
2457            br#""0.87""#
2458        );
2459        assert_eq!(
2460            serde_json::to_vec(&SignedDecimal::percent(876)).unwrap(),
2461            br#""8.76""#
2462        );
2463        assert_eq!(
2464            serde_json::to_vec(&SignedDecimal::percent(8765)).unwrap(),
2465            br#""87.65""#
2466        );
2467        assert_eq!(
2468            serde_json::to_vec(&SignedDecimal::percent(-87654)).unwrap(),
2469            br#""-876.54""#
2470        );
2471        assert_eq!(
2472            serde_json::to_vec(&SignedDecimal::negative_one()).unwrap(),
2473            br#""-1""#
2474        );
2475        assert_eq!(
2476            serde_json::to_vec(&-SignedDecimal::percent(8)).unwrap(),
2477            br#""-0.08""#
2478        );
2479    }
2480
2481    #[test]
2482    fn signed_decimal_deserialize() {
2483        assert_eq!(
2484            serde_json::from_slice::<SignedDecimal>(br#""0""#).unwrap(),
2485            SignedDecimal::zero()
2486        );
2487        assert_eq!(
2488            serde_json::from_slice::<SignedDecimal>(br#""1""#).unwrap(),
2489            SignedDecimal::one()
2490        );
2491        assert_eq!(
2492            serde_json::from_slice::<SignedDecimal>(br#""000""#).unwrap(),
2493            SignedDecimal::zero()
2494        );
2495        assert_eq!(
2496            serde_json::from_slice::<SignedDecimal>(br#""001""#).unwrap(),
2497            SignedDecimal::one()
2498        );
2499
2500        assert_eq!(
2501            serde_json::from_slice::<SignedDecimal>(br#""0.08""#).unwrap(),
2502            SignedDecimal::percent(8)
2503        );
2504        assert_eq!(
2505            serde_json::from_slice::<SignedDecimal>(br#""0.87""#).unwrap(),
2506            SignedDecimal::percent(87)
2507        );
2508        assert_eq!(
2509            serde_json::from_slice::<SignedDecimal>(br#""8.76""#).unwrap(),
2510            SignedDecimal::percent(876)
2511        );
2512        assert_eq!(
2513            serde_json::from_slice::<SignedDecimal>(br#""87.65""#).unwrap(),
2514            SignedDecimal::percent(8765)
2515        );
2516
2517        // negative numbers
2518        assert_eq!(
2519            serde_json::from_slice::<SignedDecimal>(br#""-0""#).unwrap(),
2520            SignedDecimal::zero()
2521        );
2522        assert_eq!(
2523            serde_json::from_slice::<SignedDecimal>(br#""-1""#).unwrap(),
2524            SignedDecimal::negative_one()
2525        );
2526        assert_eq!(
2527            serde_json::from_slice::<SignedDecimal>(br#""-001""#).unwrap(),
2528            SignedDecimal::negative_one()
2529        );
2530        assert_eq!(
2531            serde_json::from_slice::<SignedDecimal>(br#""-0.08""#).unwrap(),
2532            SignedDecimal::percent(-8)
2533        );
2534    }
2535
2536    #[test]
2537    fn signed_decimal_abs_diff_works() {
2538        let a = SignedDecimal::percent(285);
2539        let b = SignedDecimal::percent(200);
2540        let expected = Decimal::percent(85);
2541        assert_eq!(a.abs_diff(b), expected);
2542        assert_eq!(b.abs_diff(a), expected);
2543
2544        let a = SignedDecimal::percent(-200);
2545        let b = SignedDecimal::percent(200);
2546        let expected = Decimal::percent(400);
2547        assert_eq!(a.abs_diff(b), expected);
2548        assert_eq!(b.abs_diff(a), expected);
2549
2550        let a = SignedDecimal::percent(-200);
2551        let b = SignedDecimal::percent(-240);
2552        let expected = Decimal::percent(40);
2553        assert_eq!(a.abs_diff(b), expected);
2554        assert_eq!(b.abs_diff(a), expected);
2555    }
2556
2557    #[test]
2558    #[allow(clippy::op_ref)]
2559    fn signed_decimal_rem_works() {
2560        // 4.02 % 1.11 = 0.69
2561        assert_eq!(
2562            SignedDecimal::percent(402) % SignedDecimal::percent(111),
2563            SignedDecimal::percent(69)
2564        );
2565
2566        // 15.25 % 4 = 3.25
2567        assert_eq!(
2568            SignedDecimal::percent(1525) % SignedDecimal::percent(400),
2569            SignedDecimal::percent(325)
2570        );
2571
2572        // -20.25 % 5 = -25
2573        assert_eq!(
2574            SignedDecimal::percent(-2025) % SignedDecimal::percent(500),
2575            SignedDecimal::percent(-25)
2576        );
2577
2578        let a = SignedDecimal::percent(318);
2579        let b = SignedDecimal::percent(317);
2580        let expected = SignedDecimal::percent(1);
2581        assert_eq!(a % b, expected);
2582        assert_eq!(a % &b, expected);
2583        assert_eq!(&a % b, expected);
2584        assert_eq!(&a % &b, expected);
2585    }
2586
2587    #[test]
2588    fn signed_decimal_rem_assign_works() {
2589        let mut a = SignedDecimal::percent(17673);
2590        a %= SignedDecimal::percent(2362);
2591        assert_eq!(a, SignedDecimal::percent(1139)); // 176.73 % 23.62 = 11.39
2592
2593        let mut a = SignedDecimal::percent(4262);
2594        let b = SignedDecimal::percent(1270);
2595        a %= &b;
2596        assert_eq!(a, SignedDecimal::percent(452)); // 42.62 % 12.7 = 4.52
2597
2598        let mut a = SignedDecimal::percent(-4262);
2599        let b = SignedDecimal::percent(1270);
2600        a %= &b;
2601        assert_eq!(a, SignedDecimal::percent(-452)); // -42.62 % 12.7 = -4.52
2602    }
2603
2604    #[test]
2605    #[should_panic(expected = "divisor of zero")]
2606    fn signed_decimal_rem_panics_for_zero() {
2607        let _ = SignedDecimal::percent(777) % SignedDecimal::zero();
2608    }
2609
2610    #[test]
2611    fn signed_decimal_checked_methods() {
2612        // checked add
2613        assert_eq!(
2614            SignedDecimal::percent(402)
2615                .checked_add(SignedDecimal::percent(111))
2616                .unwrap(),
2617            SignedDecimal::percent(513)
2618        );
2619        assert!(matches!(
2620            SignedDecimal::MAX.checked_add(SignedDecimal::percent(1)),
2621            Err(OverflowError { .. })
2622        ));
2623        assert!(matches!(
2624            SignedDecimal::MIN.checked_add(SignedDecimal::percent(-1)),
2625            Err(OverflowError { .. })
2626        ));
2627
2628        // checked sub
2629        assert_eq!(
2630            SignedDecimal::percent(1111)
2631                .checked_sub(SignedDecimal::percent(111))
2632                .unwrap(),
2633            SignedDecimal::percent(1000)
2634        );
2635        assert_eq!(
2636            SignedDecimal::zero()
2637                .checked_sub(SignedDecimal::percent(1))
2638                .unwrap(),
2639            SignedDecimal::percent(-1)
2640        );
2641        assert!(matches!(
2642            SignedDecimal::MIN.checked_sub(SignedDecimal::percent(1)),
2643            Err(OverflowError { .. })
2644        ));
2645        assert!(matches!(
2646            SignedDecimal::MAX.checked_sub(SignedDecimal::percent(-1)),
2647            Err(OverflowError { .. })
2648        ));
2649
2650        // checked div
2651        assert_eq!(
2652            SignedDecimal::percent(30)
2653                .checked_div(SignedDecimal::percent(200))
2654                .unwrap(),
2655            SignedDecimal::percent(15)
2656        );
2657        assert_eq!(
2658            SignedDecimal::percent(88)
2659                .checked_div(SignedDecimal::percent(20))
2660                .unwrap(),
2661            SignedDecimal::percent(440)
2662        );
2663        assert!(matches!(
2664            SignedDecimal::MAX.checked_div(SignedDecimal::zero()),
2665            Err(CheckedFromRatioError::DivideByZero)
2666        ));
2667        assert!(matches!(
2668            SignedDecimal::MAX.checked_div(SignedDecimal::percent(1)),
2669            Err(CheckedFromRatioError::Overflow)
2670        ));
2671        assert_eq!(
2672            SignedDecimal::percent(-88)
2673                .checked_div(SignedDecimal::percent(20))
2674                .unwrap(),
2675            SignedDecimal::percent(-440)
2676        );
2677        assert_eq!(
2678            SignedDecimal::percent(-88)
2679                .checked_div(SignedDecimal::percent(-20))
2680                .unwrap(),
2681            SignedDecimal::percent(440)
2682        );
2683
2684        // checked rem
2685        assert_eq!(
2686            SignedDecimal::percent(402)
2687                .checked_rem(SignedDecimal::percent(111))
2688                .unwrap(),
2689            SignedDecimal::percent(69)
2690        );
2691        assert_eq!(
2692            SignedDecimal::percent(1525)
2693                .checked_rem(SignedDecimal::percent(400))
2694                .unwrap(),
2695            SignedDecimal::percent(325)
2696        );
2697        assert_eq!(
2698            SignedDecimal::percent(-1525)
2699                .checked_rem(SignedDecimal::percent(400))
2700                .unwrap(),
2701            SignedDecimal::percent(-325)
2702        );
2703        assert_eq!(
2704            SignedDecimal::percent(-1525)
2705                .checked_rem(SignedDecimal::percent(-400))
2706                .unwrap(),
2707            SignedDecimal::percent(-325)
2708        );
2709        assert!(matches!(
2710            SignedDecimal::MAX.checked_rem(SignedDecimal::zero()),
2711            Err(DivideByZeroError { .. })
2712        ));
2713    }
2714
2715    #[test]
2716    fn signed_decimal_pow_works() {
2717        assert_eq!(
2718            SignedDecimal::percent(200).pow(2),
2719            SignedDecimal::percent(400)
2720        );
2721        assert_eq!(
2722            SignedDecimal::percent(-200).pow(2),
2723            SignedDecimal::percent(400)
2724        );
2725        assert_eq!(
2726            SignedDecimal::percent(-200).pow(3),
2727            SignedDecimal::percent(-800)
2728        );
2729        assert_eq!(
2730            SignedDecimal::percent(200).pow(10),
2731            SignedDecimal::percent(102400)
2732        );
2733    }
2734
2735    #[test]
2736    #[should_panic]
2737    fn signed_decimal_pow_overflow_panics() {
2738        _ = SignedDecimal::MAX.pow(2u32);
2739    }
2740
2741    #[test]
2742    fn signed_decimal_saturating_works() {
2743        assert_eq!(
2744            SignedDecimal::percent(200).saturating_add(SignedDecimal::percent(200)),
2745            SignedDecimal::percent(400)
2746        );
2747        assert_eq!(
2748            SignedDecimal::percent(-200).saturating_add(SignedDecimal::percent(200)),
2749            SignedDecimal::zero()
2750        );
2751        assert_eq!(
2752            SignedDecimal::percent(-200).saturating_add(SignedDecimal::percent(-200)),
2753            SignedDecimal::percent(-400)
2754        );
2755        assert_eq!(
2756            SignedDecimal::MAX.saturating_add(SignedDecimal::percent(200)),
2757            SignedDecimal::MAX
2758        );
2759        assert_eq!(
2760            SignedDecimal::MIN.saturating_add(SignedDecimal::percent(-1)),
2761            SignedDecimal::MIN
2762        );
2763        assert_eq!(
2764            SignedDecimal::percent(200).saturating_sub(SignedDecimal::percent(100)),
2765            SignedDecimal::percent(100)
2766        );
2767        assert_eq!(
2768            SignedDecimal::percent(-200).saturating_sub(SignedDecimal::percent(100)),
2769            SignedDecimal::percent(-300)
2770        );
2771        assert_eq!(
2772            SignedDecimal::percent(-200).saturating_sub(SignedDecimal::percent(-100)),
2773            SignedDecimal::percent(-100)
2774        );
2775        assert_eq!(
2776            SignedDecimal::zero().saturating_sub(SignedDecimal::percent(200)),
2777            SignedDecimal::from_str("-2").unwrap()
2778        );
2779        assert_eq!(
2780            SignedDecimal::MIN.saturating_sub(SignedDecimal::percent(200)),
2781            SignedDecimal::MIN
2782        );
2783        assert_eq!(
2784            SignedDecimal::MAX.saturating_sub(SignedDecimal::percent(-200)),
2785            SignedDecimal::MAX
2786        );
2787        assert_eq!(
2788            SignedDecimal::percent(200).saturating_mul(SignedDecimal::percent(50)),
2789            SignedDecimal::percent(100)
2790        );
2791        assert_eq!(
2792            SignedDecimal::percent(-200).saturating_mul(SignedDecimal::percent(50)),
2793            SignedDecimal::percent(-100)
2794        );
2795        assert_eq!(
2796            SignedDecimal::percent(-200).saturating_mul(SignedDecimal::percent(-50)),
2797            SignedDecimal::percent(100)
2798        );
2799        assert_eq!(
2800            SignedDecimal::MAX.saturating_mul(SignedDecimal::percent(200)),
2801            SignedDecimal::MAX
2802        );
2803        assert_eq!(
2804            SignedDecimal::MIN.saturating_mul(SignedDecimal::percent(200)),
2805            SignedDecimal::MIN
2806        );
2807        assert_eq!(
2808            SignedDecimal::MIN.saturating_mul(SignedDecimal::percent(-200)),
2809            SignedDecimal::MAX
2810        );
2811        assert_eq!(
2812            SignedDecimal::percent(400).saturating_pow(2u32),
2813            SignedDecimal::percent(1600)
2814        );
2815        assert_eq!(SignedDecimal::MAX.saturating_pow(2u32), SignedDecimal::MAX);
2816        assert_eq!(SignedDecimal::MAX.saturating_pow(3u32), SignedDecimal::MAX);
2817        assert_eq!(SignedDecimal::MIN.saturating_pow(2u32), SignedDecimal::MAX);
2818        assert_eq!(SignedDecimal::MIN.saturating_pow(3u32), SignedDecimal::MIN);
2819    }
2820
2821    #[test]
2822    fn signed_decimal_rounding() {
2823        assert_eq!(SignedDecimal::one().floor(), SignedDecimal::one());
2824        assert_eq!(SignedDecimal::percent(150).floor(), SignedDecimal::one());
2825        assert_eq!(SignedDecimal::percent(199).floor(), SignedDecimal::one());
2826        assert_eq!(
2827            SignedDecimal::percent(200).floor(),
2828            SignedDecimal::percent(200)
2829        );
2830        assert_eq!(SignedDecimal::percent(99).floor(), SignedDecimal::zero());
2831        assert_eq!(
2832            SignedDecimal(Int128::from(1i128)).floor(),
2833            SignedDecimal::zero()
2834        );
2835        assert_eq!(
2836            SignedDecimal(Int128::from(-1i128)).floor(),
2837            SignedDecimal::negative_one()
2838        );
2839        assert_eq!(
2840            SignedDecimal::permille(-1234).floor(),
2841            SignedDecimal::percent(-200)
2842        );
2843
2844        assert_eq!(SignedDecimal::one().ceil(), SignedDecimal::one());
2845        assert_eq!(
2846            SignedDecimal::percent(150).ceil(),
2847            SignedDecimal::percent(200)
2848        );
2849        assert_eq!(
2850            SignedDecimal::percent(199).ceil(),
2851            SignedDecimal::percent(200)
2852        );
2853        assert_eq!(SignedDecimal::percent(99).ceil(), SignedDecimal::one());
2854        assert_eq!(
2855            SignedDecimal(Int128::from(1i128)).ceil(),
2856            SignedDecimal::one()
2857        );
2858        assert_eq!(
2859            SignedDecimal(Int128::from(-1i128)).ceil(),
2860            SignedDecimal::zero()
2861        );
2862        assert_eq!(
2863            SignedDecimal::permille(-1234).ceil(),
2864            SignedDecimal::negative_one()
2865        );
2866
2867        assert_eq!(SignedDecimal::one().trunc(), SignedDecimal::one());
2868        assert_eq!(SignedDecimal::percent(150).trunc(), SignedDecimal::one());
2869        assert_eq!(SignedDecimal::percent(199).trunc(), SignedDecimal::one());
2870        assert_eq!(
2871            SignedDecimal::percent(200).trunc(),
2872            SignedDecimal::percent(200)
2873        );
2874        assert_eq!(SignedDecimal::percent(99).trunc(), SignedDecimal::zero());
2875        assert_eq!(
2876            SignedDecimal(Int128::from(1i128)).trunc(),
2877            SignedDecimal::zero()
2878        );
2879        assert_eq!(
2880            SignedDecimal(Int128::from(-1i128)).trunc(),
2881            SignedDecimal::zero()
2882        );
2883        assert_eq!(
2884            SignedDecimal::permille(-1234).trunc(),
2885            SignedDecimal::negative_one()
2886        );
2887    }
2888
2889    #[test]
2890    #[should_panic(expected = "attempt to ceil with overflow")]
2891    fn signed_decimal_ceil_panics() {
2892        let _ = SignedDecimal::MAX.ceil();
2893    }
2894
2895    #[test]
2896    #[should_panic(expected = "attempt to floor with overflow")]
2897    fn signed_decimal_floor_panics() {
2898        let _ = SignedDecimal::MIN.floor();
2899    }
2900
2901    #[test]
2902    fn signed_decimal_checked_ceil() {
2903        assert_eq!(
2904            SignedDecimal::percent(199).checked_ceil(),
2905            Ok(SignedDecimal::percent(200))
2906        );
2907        assert_eq!(SignedDecimal::MAX.checked_ceil(), Err(RoundUpOverflowError));
2908    }
2909
2910    #[test]
2911    fn signed_decimal_checked_floor() {
2912        assert_eq!(
2913            SignedDecimal::percent(199).checked_floor(),
2914            Ok(SignedDecimal::one())
2915        );
2916        assert_eq!(
2917            SignedDecimal::percent(-199).checked_floor(),
2918            Ok(SignedDecimal::percent(-200))
2919        );
2920        assert_eq!(
2921            SignedDecimal::MIN.checked_floor(),
2922            Err(RoundDownOverflowError)
2923        );
2924        assert_eq!(
2925            SignedDecimal::negative_one().checked_floor(),
2926            Ok(SignedDecimal::negative_one())
2927        );
2928    }
2929
2930    #[test]
2931    fn signed_decimal_to_int_floor_works() {
2932        let d = SignedDecimal::from_str("12.000000000000000001").unwrap();
2933        assert_eq!(d.to_int_floor(), Int128::new(12));
2934        let d = SignedDecimal::from_str("12.345").unwrap();
2935        assert_eq!(d.to_int_floor(), Int128::new(12));
2936        let d = SignedDecimal::from_str("12.999").unwrap();
2937        assert_eq!(d.to_int_floor(), Int128::new(12));
2938        let d = SignedDecimal::from_str("0.98451384").unwrap();
2939        assert_eq!(d.to_int_floor(), Int128::new(0));
2940        let d = SignedDecimal::from_str("-12.000000000000000001").unwrap();
2941        assert_eq!(d.to_int_floor(), Int128::new(-13));
2942        let d = SignedDecimal::from_str("-12.345").unwrap();
2943        assert_eq!(d.to_int_floor(), Int128::new(-13));
2944        let d = SignedDecimal::from_str("75.0").unwrap();
2945        assert_eq!(d.to_int_floor(), Int128::new(75));
2946        let d = SignedDecimal::from_str("0.0001").unwrap();
2947        assert_eq!(d.to_int_floor(), Int128::new(0));
2948        let d = SignedDecimal::from_str("0.0").unwrap();
2949        assert_eq!(d.to_int_floor(), Int128::new(0));
2950        let d = SignedDecimal::from_str("-0.0").unwrap();
2951        assert_eq!(d.to_int_floor(), Int128::new(0));
2952        let d = SignedDecimal::from_str("-0.0001").unwrap();
2953        assert_eq!(d.to_int_floor(), Int128::new(-1));
2954        let d = SignedDecimal::from_str("-75.0").unwrap();
2955        assert_eq!(d.to_int_floor(), Int128::new(-75));
2956        let d = SignedDecimal::MAX;
2957        assert_eq!(d.to_int_floor(), Int128::new(170141183460469231731));
2958        let d = SignedDecimal::MIN;
2959        assert_eq!(d.to_int_floor(), Int128::new(-170141183460469231732));
2960    }
2961
2962    #[test]
2963    fn signed_decimal_to_int_ceil_works() {
2964        let d = SignedDecimal::from_str("12.000000000000000001").unwrap();
2965        assert_eq!(d.to_int_ceil(), Int128::new(13));
2966        let d = SignedDecimal::from_str("12.345").unwrap();
2967        assert_eq!(d.to_int_ceil(), Int128::new(13));
2968        let d = SignedDecimal::from_str("12.999").unwrap();
2969        assert_eq!(d.to_int_ceil(), Int128::new(13));
2970        let d = SignedDecimal::from_str("-12.000000000000000001").unwrap();
2971        assert_eq!(d.to_int_ceil(), Int128::new(-12));
2972        let d = SignedDecimal::from_str("-12.345").unwrap();
2973        assert_eq!(d.to_int_ceil(), Int128::new(-12));
2974
2975        let d = SignedDecimal::from_str("75.0").unwrap();
2976        assert_eq!(d.to_int_ceil(), Int128::new(75));
2977        let d = SignedDecimal::from_str("0.0").unwrap();
2978        assert_eq!(d.to_int_ceil(), Int128::new(0));
2979        let d = SignedDecimal::from_str("-75.0").unwrap();
2980        assert_eq!(d.to_int_ceil(), Int128::new(-75));
2981
2982        let d = SignedDecimal::MAX;
2983        assert_eq!(d.to_int_ceil(), Int128::new(170141183460469231732));
2984        let d = SignedDecimal::MIN;
2985        assert_eq!(d.to_int_ceil(), Int128::new(-170141183460469231731));
2986    }
2987
2988    #[test]
2989    fn signed_decimal_to_int_trunc_works() {
2990        let d = SignedDecimal::from_str("12.000000000000000001").unwrap();
2991        assert_eq!(d.to_int_trunc(), Int128::new(12));
2992        let d = SignedDecimal::from_str("12.345").unwrap();
2993        assert_eq!(d.to_int_trunc(), Int128::new(12));
2994        let d = SignedDecimal::from_str("12.999").unwrap();
2995        assert_eq!(d.to_int_trunc(), Int128::new(12));
2996        let d = SignedDecimal::from_str("-12.000000000000000001").unwrap();
2997        assert_eq!(d.to_int_trunc(), Int128::new(-12));
2998        let d = SignedDecimal::from_str("-12.345").unwrap();
2999        assert_eq!(d.to_int_trunc(), Int128::new(-12));
3000
3001        let d = SignedDecimal::from_str("75.0").unwrap();
3002        assert_eq!(d.to_int_trunc(), Int128::new(75));
3003        let d = SignedDecimal::from_str("0.0").unwrap();
3004        assert_eq!(d.to_int_trunc(), Int128::new(0));
3005        let d = SignedDecimal::from_str("-75.0").unwrap();
3006        assert_eq!(d.to_int_trunc(), Int128::new(-75));
3007
3008        let d = SignedDecimal::MAX;
3009        assert_eq!(d.to_int_trunc(), Int128::new(170141183460469231731));
3010        let d = SignedDecimal::MIN;
3011        assert_eq!(d.to_int_trunc(), Int128::new(-170141183460469231731));
3012    }
3013
3014    #[test]
3015    fn signed_decimal_neg_works() {
3016        assert_eq!(-SignedDecimal::percent(50), SignedDecimal::percent(-50));
3017        assert_eq!(-SignedDecimal::one(), SignedDecimal::negative_one());
3018    }
3019
3020    #[test]
3021    fn signed_decimal_partial_eq() {
3022        let test_cases = [
3023            ("1", "1", true),
3024            ("0.5", "0.5", true),
3025            ("0.5", "0.51", false),
3026            ("0", "0.00000", true),
3027            ("-1", "-1", true),
3028            ("-0.5", "-0.5", true),
3029            ("-0.5", "0.5", false),
3030            ("-0.5", "-0.51", false),
3031            ("-0", "-0.00000", true),
3032        ]
3033        .into_iter()
3034        .map(|(lhs, rhs, expected)| (dec(lhs), dec(rhs), expected));
3035
3036        #[allow(clippy::op_ref)]
3037        for (lhs, rhs, expected) in test_cases {
3038            assert_eq!(lhs == rhs, expected);
3039            assert_eq!(&lhs == rhs, expected);
3040            assert_eq!(lhs == &rhs, expected);
3041            assert_eq!(&lhs == &rhs, expected);
3042        }
3043    }
3044
3045    #[test]
3046    fn signed_decimal_implements_debug() {
3047        let decimal = SignedDecimal::from_str("123.45").unwrap();
3048        assert_eq!(format!("{decimal:?}"), "SignedDecimal(123.45)");
3049
3050        let test_cases = ["5", "5.01", "42", "0", "2", "-0.000001"];
3051        for s in test_cases {
3052            let decimal = SignedDecimal::from_str(s).unwrap();
3053            let expected = format!("SignedDecimal({s})");
3054            assert_eq!(format!("{decimal:?}"), expected);
3055        }
3056    }
3057
3058    #[test]
3059    fn signed_decimal_can_be_instantiated_from_decimal256() {
3060        let d: SignedDecimal = Decimal256::zero().try_into().unwrap();
3061        assert_eq!(d, SignedDecimal::zero());
3062    }
3063
3064    #[test]
3065    fn signed_decimal_may_fail_when_instantiated_from_decimal256() {
3066        let err = <Decimal256 as TryInto<SignedDecimal>>::try_into(Decimal256::MAX).unwrap_err();
3067        assert_eq!("SignedDecimalRangeExceeded", format!("{err:?}"));
3068        assert_eq!("SignedDecimal range exceeded", format!("{err}"));
3069    }
3070
3071    #[test]
3072    fn signed_decimal_can_be_serialized_and_deserialized() {
3073        // properly deserialized
3074        let value: SignedDecimal = serde_json::from_str(r#""123""#).unwrap();
3075        assert_eq!(SignedDecimal::from_str("123").unwrap(), value);
3076
3077        // properly serialized
3078        let value = SignedDecimal::from_str("456").unwrap();
3079        assert_eq!(r#""456""#, serde_json::to_string(&value).unwrap());
3080
3081        // invalid: not a string encoded decimal
3082        assert_eq!(
3083            "invalid type: integer `123`, expected string-encoded decimal at line 1 column 3",
3084            serde_json::from_str::<SignedDecimal>("123")
3085                .err()
3086                .unwrap()
3087                .to_string()
3088        );
3089
3090        // invalid: not properly defined signed decimal value
3091        assert_eq!(
3092            "Error parsing decimal '1.e': kind: Parsing, error: invalid digit found in string at line 1 column 5",
3093            serde_json::from_str::<SignedDecimal>(r#""1.e""#)
3094                .err()
3095                .unwrap()
3096                .to_string()
3097        );
3098    }
3099
3100    #[test]
3101    fn signed_decimal_has_defined_json_schema() {
3102        let schema = schemars::schema_for!(SignedDecimal);
3103        assert_eq!(
3104            "SignedDecimal",
3105            schema.schema.metadata.unwrap().title.unwrap()
3106        );
3107    }
3108}