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