jk_cosmwasm_std/math/
decimal.rs

1use schemars::JsonSchema;
2use serde::{de, ser, Deserialize, Deserializer, Serialize};
3use std::fmt::{self, Write};
4use std::ops;
5use std::str::FromStr;
6
7use crate::errors::StdError;
8
9use super::Fraction;
10use super::Isqrt;
11use super::Uint128;
12
13/// A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0
14///
15/// The greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18)
16#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, JsonSchema)]
17pub struct Decimal(#[schemars(with = "String")] Uint128);
18
19impl Decimal {
20    const DECIMAL_FRACTIONAL: Uint128 = Uint128::new(1_000_000_000_000_000_000u128); // 1*10**18
21    const DECIMAL_FRACTIONAL_SQUARED: Uint128 =
22        Uint128::new(1_000_000_000_000_000_000_000_000_000_000_000_000u128); // (1*10**18)**2 = 1*10**36
23    const DECIMAL_PLACES: usize = 18; // This needs to be an even number.
24
25    pub const MAX: Self = Self(Uint128::MAX);
26
27    /// Create a 1.0 Decimal
28    pub const fn one() -> Self {
29        Decimal(Self::DECIMAL_FRACTIONAL)
30    }
31
32    /// Create a 0.0 Decimal
33    pub const fn zero() -> Self {
34        Decimal(Uint128::zero())
35    }
36
37    /// Convert x% into Decimal
38    pub fn percent(x: u64) -> Self {
39        Decimal(((x as u128) * 10_000_000_000_000_000).into())
40    }
41
42    /// Convert permille (x/1000) into Decimal
43    pub fn permille(x: u64) -> Self {
44        Decimal(((x as u128) * 1_000_000_000_000_000).into())
45    }
46
47    /// Returns the ratio (numerator / denominator) as a Decimal
48    pub fn from_ratio(numerator: impl Into<Uint128>, denominator: impl Into<Uint128>) -> Self {
49        let numerator: Uint128 = numerator.into();
50        let denominator: Uint128 = denominator.into();
51        if denominator.is_zero() {
52            panic!("Denominator must not be zero");
53        }
54
55        Decimal(
56            // numerator * DECIMAL_FRACTIONAL / denominator
57            numerator.multiply_ratio(Self::DECIMAL_FRACTIONAL, denominator),
58        )
59    }
60
61    pub fn is_zero(&self) -> bool {
62        self.0.is_zero()
63    }
64
65    /// Returns the approximate square root as a Decimal.
66    ///
67    /// This should not overflow or panic.
68    pub fn sqrt(&self) -> Self {
69        // Algorithm described in https://hackmd.io/@webmaster128/SJThlukj_
70        // We start with the highest precision possible and lower it until
71        // there's no overflow.
72        //
73        // TODO: This could be made more efficient once log10 is in:
74        // https://github.com/rust-lang/rust/issues/70887
75        // The max precision is something like `9 - log10(self.0) / 2`.
76        (0..=Self::DECIMAL_PLACES / 2)
77            .rev()
78            .find_map(|i| self.sqrt_with_precision(i))
79            // The last step (i = 0) is guaranteed to succeed because `isqrt(u128::MAX) * 10^9` does not overflow
80            .unwrap()
81    }
82
83    /// Lower precision means more aggressive rounding, but less risk of overflow.
84    /// Precision *must* be a number between 0 and 9 (inclusive).
85    ///
86    /// Returns `None` if the internal multiplication overflows.
87    fn sqrt_with_precision(&self, precision: usize) -> Option<Self> {
88        let precision = precision as u32;
89
90        let inner_mul = 100u128.pow(precision);
91        self.0.checked_mul(inner_mul.into()).ok().map(|inner| {
92            let outer_mul = 10u128.pow(Self::DECIMAL_PLACES as u32 / 2 - precision);
93            Decimal(inner.isqrt().checked_mul(Uint128::from(outer_mul)).unwrap())
94        })
95    }
96}
97
98impl Fraction<u128> for Decimal {
99    #[inline]
100    fn numerator(&self) -> u128 {
101        self.0.u128()
102    }
103
104    #[inline]
105    fn denominator(&self) -> u128 {
106        Self::DECIMAL_FRACTIONAL.u128()
107    }
108
109    /// Returns the multiplicative inverse `1/d` for decimal `d`.
110    ///
111    /// If `d` is zero, none is returned.
112    fn inv(&self) -> Option<Self> {
113        if self.is_zero() {
114            None
115        } else {
116            // Let self be p/q with p = self.0 and q = DECIMAL_FRACTIONAL.
117            // Now we calculate the inverse a/b = q/p such that b = DECIMAL_FRACTIONAL. Then
118            // `a = DECIMAL_FRACTIONAL*DECIMAL_FRACTIONAL / self.0`.
119            Some(Decimal(Self::DECIMAL_FRACTIONAL_SQUARED / self.0))
120        }
121    }
122}
123
124impl FromStr for Decimal {
125    type Err = StdError;
126
127    /// Converts the decimal string to a Decimal
128    /// Possible inputs: "1.23", "1", "000012", "1.123000000"
129    /// Disallowed: "", ".23"
130    ///
131    /// This never performs any kind of rounding.
132    /// More than DECIMAL_PLACES fractional digits, even zeros, result in an error.
133    fn from_str(input: &str) -> Result<Self, Self::Err> {
134        let mut parts_iter = input.split('.');
135
136        let whole_part = parts_iter.next().unwrap(); // split always returns at least one element
137        let whole = whole_part
138            .parse::<Uint128>()
139            .map_err(|_| StdError::generic_err("Error parsing whole"))?;
140        let mut atomics = whole
141            .checked_mul(Self::DECIMAL_FRACTIONAL)
142            .map_err(|_| StdError::generic_err("Value too big"))?;
143
144        if let Some(fractional_part) = parts_iter.next() {
145            let fractional = fractional_part
146                .parse::<Uint128>()
147                .map_err(|_| StdError::generic_err("Error parsing fractional"))?;
148            let exp =
149                (Self::DECIMAL_PLACES.checked_sub(fractional_part.len())).ok_or_else(|| {
150                    StdError::generic_err(format!(
151                        "Cannot parse more than {} fractional digits",
152                        Self::DECIMAL_PLACES
153                    ))
154                })?;
155            debug_assert!(exp <= Self::DECIMAL_PLACES);
156            let fractional_factor = Uint128::from(10u128.pow(exp as u32));
157            atomics = atomics
158                .checked_add(
159                    // The inner multiplication can't overflow because
160                    // fractional < 10^DECIMAL_PLACES && fractional_factor <= 10^DECIMAL_PLACES
161                    fractional.checked_mul(fractional_factor).unwrap(),
162                )
163                .map_err(|_| StdError::generic_err("Value too big"))?;
164        }
165
166        if parts_iter.next().is_some() {
167            return Err(StdError::generic_err("Unexpected number of dots"));
168        }
169
170        Ok(Decimal(atomics))
171    }
172}
173
174impl fmt::Display for Decimal {
175    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
176        let whole = (self.0) / Self::DECIMAL_FRACTIONAL;
177        let fractional = (self.0).checked_rem(Self::DECIMAL_FRACTIONAL).unwrap();
178
179        if fractional.is_zero() {
180            write!(f, "{}", whole)
181        } else {
182            let fractional_string =
183                format!("{:0>padding$}", fractional, padding = Self::DECIMAL_PLACES);
184            f.write_str(&whole.to_string())?;
185            f.write_char('.')?;
186            f.write_str(fractional_string.trim_end_matches('0'))?;
187            Ok(())
188        }
189    }
190}
191
192impl ops::Add for Decimal {
193    type Output = Self;
194
195    fn add(self, other: Self) -> Self {
196        Decimal(self.0 + other.0)
197    }
198}
199
200impl ops::Sub for Decimal {
201    type Output = Self;
202
203    fn sub(self, other: Self) -> Self {
204        Decimal(self.0 - other.0)
205    }
206}
207
208/// Both d*u and u*d with d: Decimal and u: Uint128 returns an Uint128. There is no
209/// specific reason for this decision other than the initial use cases we have. If you
210/// need a Decimal result for the same calculation, use Decimal(d*u) or Decimal(u*d).
211impl ops::Mul<Decimal> for Uint128 {
212    type Output = Self;
213
214    #[allow(clippy::suspicious_arithmetic_impl)]
215    fn mul(self, rhs: Decimal) -> Self::Output {
216        // 0*a and b*0 is always 0
217        if self.is_zero() || rhs.is_zero() {
218            return Uint128::zero();
219        }
220        self.multiply_ratio(rhs.0, Decimal::DECIMAL_FRACTIONAL)
221    }
222}
223
224impl ops::Mul<Uint128> for Decimal {
225    type Output = Uint128;
226
227    fn mul(self, rhs: Uint128) -> Self::Output {
228        rhs * self
229    }
230}
231
232impl ops::Div<Uint128> for Decimal {
233    type Output = Self;
234
235    fn div(self, rhs: Uint128) -> Self::Output {
236        Decimal(self.0 / rhs)
237    }
238}
239
240impl ops::DivAssign<Uint128> for Decimal {
241    fn div_assign(&mut self, rhs: Uint128) {
242        self.0 /= rhs;
243    }
244}
245
246/// Serializes as a decimal string
247impl Serialize for Decimal {
248    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
249    where
250        S: ser::Serializer,
251    {
252        serializer.serialize_str(&self.to_string())
253    }
254}
255
256/// Deserializes as a base64 string
257impl<'de> Deserialize<'de> for Decimal {
258    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
259    where
260        D: Deserializer<'de>,
261    {
262        deserializer.deserialize_str(DecimalVisitor)
263    }
264}
265
266struct DecimalVisitor;
267
268impl<'de> de::Visitor<'de> for DecimalVisitor {
269    type Value = Decimal;
270
271    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
272        formatter.write_str("string-encoded decimal")
273    }
274
275    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
276    where
277        E: de::Error,
278    {
279        match Decimal::from_str(v) {
280            Ok(d) => Ok(d),
281            Err(e) => Err(E::custom(format!("Error parsing decimal '{}': {}", v, e))),
282        }
283    }
284}
285
286#[cfg(test)]
287mod tests {
288    use super::*;
289    use crate::errors::StdError;
290    use crate::{from_slice, to_vec};
291
292    #[test]
293    fn decimal_one() {
294        let value = Decimal::one();
295        assert_eq!(value.0, Decimal::DECIMAL_FRACTIONAL);
296    }
297
298    #[test]
299    fn decimal_zero() {
300        let value = Decimal::zero();
301        assert!(value.0.is_zero());
302    }
303
304    #[test]
305    fn decimal_percent() {
306        let value = Decimal::percent(50);
307        assert_eq!(value.0, Decimal::DECIMAL_FRACTIONAL / Uint128::from(2u8));
308    }
309
310    #[test]
311    fn decimal_permille() {
312        let value = Decimal::permille(125);
313        assert_eq!(value.0, Decimal::DECIMAL_FRACTIONAL / Uint128::from(8u8));
314    }
315
316    #[test]
317    fn decimal_from_ratio_works() {
318        // 1.0
319        assert_eq!(Decimal::from_ratio(1u128, 1u128), Decimal::one());
320        assert_eq!(Decimal::from_ratio(53u128, 53u128), Decimal::one());
321        assert_eq!(Decimal::from_ratio(125u128, 125u128), Decimal::one());
322
323        // 1.5
324        assert_eq!(Decimal::from_ratio(3u128, 2u128), Decimal::percent(150));
325        assert_eq!(Decimal::from_ratio(150u128, 100u128), Decimal::percent(150));
326        assert_eq!(Decimal::from_ratio(333u128, 222u128), Decimal::percent(150));
327
328        // 0.125
329        assert_eq!(Decimal::from_ratio(1u64, 8u64), Decimal::permille(125));
330        assert_eq!(Decimal::from_ratio(125u64, 1000u64), Decimal::permille(125));
331
332        // 1/3 (result floored)
333        assert_eq!(
334            Decimal::from_ratio(1u64, 3u64),
335            Decimal(Uint128::from(333_333_333_333_333_333u128))
336        );
337
338        // 2/3 (result floored)
339        assert_eq!(
340            Decimal::from_ratio(2u64, 3u64),
341            Decimal(Uint128::from(666_666_666_666_666_666u128))
342        );
343
344        // large inputs
345        assert_eq!(Decimal::from_ratio(0u128, u128::MAX), Decimal::zero());
346        assert_eq!(Decimal::from_ratio(u128::MAX, u128::MAX), Decimal::one());
347        // 340282366920938463463 is the largest integer <= Decimal::MAX
348        assert_eq!(
349            Decimal::from_ratio(340282366920938463463u128, 1u128),
350            Decimal::from_str("340282366920938463463").unwrap()
351        );
352    }
353
354    #[test]
355    #[should_panic(expected = "Denominator must not be zero")]
356    fn decimal_from_ratio_panics_for_zero_denominator() {
357        Decimal::from_ratio(1u128, 0u128);
358    }
359
360    #[test]
361    fn decimal_implements_fraction() {
362        let fraction = Decimal::from_str("1234.567").unwrap();
363        assert_eq!(fraction.numerator(), 1_234_567_000_000_000_000_000u128);
364        assert_eq!(fraction.denominator(), 1_000_000_000_000_000_000u128);
365    }
366
367    #[test]
368    fn decimal_from_str_works() {
369        // Integers
370        assert_eq!(Decimal::from_str("0").unwrap(), Decimal::percent(0));
371        assert_eq!(Decimal::from_str("1").unwrap(), Decimal::percent(100));
372        assert_eq!(Decimal::from_str("5").unwrap(), Decimal::percent(500));
373        assert_eq!(Decimal::from_str("42").unwrap(), Decimal::percent(4200));
374        assert_eq!(Decimal::from_str("000").unwrap(), Decimal::percent(0));
375        assert_eq!(Decimal::from_str("001").unwrap(), Decimal::percent(100));
376        assert_eq!(Decimal::from_str("005").unwrap(), Decimal::percent(500));
377        assert_eq!(Decimal::from_str("0042").unwrap(), Decimal::percent(4200));
378
379        // Decimals
380        assert_eq!(Decimal::from_str("1.0").unwrap(), Decimal::percent(100));
381        assert_eq!(Decimal::from_str("1.5").unwrap(), Decimal::percent(150));
382        assert_eq!(Decimal::from_str("0.5").unwrap(), Decimal::percent(50));
383        assert_eq!(Decimal::from_str("0.123").unwrap(), Decimal::permille(123));
384
385        assert_eq!(Decimal::from_str("40.00").unwrap(), Decimal::percent(4000));
386        assert_eq!(Decimal::from_str("04.00").unwrap(), Decimal::percent(400));
387        assert_eq!(Decimal::from_str("00.40").unwrap(), Decimal::percent(40));
388        assert_eq!(Decimal::from_str("00.04").unwrap(), Decimal::percent(4));
389
390        // Can handle DECIMAL_PLACES fractional digits
391        assert_eq!(
392            Decimal::from_str("7.123456789012345678").unwrap(),
393            Decimal(Uint128::from(7123456789012345678u128))
394        );
395        assert_eq!(
396            Decimal::from_str("7.999999999999999999").unwrap(),
397            Decimal(Uint128::from(7999999999999999999u128))
398        );
399
400        // Works for documented max value
401        assert_eq!(
402            Decimal::from_str("340282366920938463463.374607431768211455").unwrap(),
403            Decimal::MAX
404        );
405    }
406
407    #[test]
408    fn decimal_from_str_errors_for_broken_whole_part() {
409        match Decimal::from_str("").unwrap_err() {
410            StdError::GenericErr { msg, .. } => assert_eq!(msg, "Error parsing whole"),
411            e => panic!("Unexpected error: {:?}", e),
412        }
413
414        match Decimal::from_str(" ").unwrap_err() {
415            StdError::GenericErr { msg, .. } => assert_eq!(msg, "Error parsing whole"),
416            e => panic!("Unexpected error: {:?}", e),
417        }
418
419        match Decimal::from_str("-1").unwrap_err() {
420            StdError::GenericErr { msg, .. } => assert_eq!(msg, "Error parsing whole"),
421            e => panic!("Unexpected error: {:?}", e),
422        }
423    }
424
425    #[test]
426    fn decimal_from_str_errors_for_broken_fractinal_part() {
427        match Decimal::from_str("1.").unwrap_err() {
428            StdError::GenericErr { msg, .. } => assert_eq!(msg, "Error parsing fractional"),
429            e => panic!("Unexpected error: {:?}", e),
430        }
431
432        match Decimal::from_str("1. ").unwrap_err() {
433            StdError::GenericErr { msg, .. } => assert_eq!(msg, "Error parsing fractional"),
434            e => panic!("Unexpected error: {:?}", e),
435        }
436
437        match Decimal::from_str("1.e").unwrap_err() {
438            StdError::GenericErr { msg, .. } => assert_eq!(msg, "Error parsing fractional"),
439            e => panic!("Unexpected error: {:?}", e),
440        }
441
442        match Decimal::from_str("1.2e3").unwrap_err() {
443            StdError::GenericErr { msg, .. } => assert_eq!(msg, "Error parsing fractional"),
444            e => panic!("Unexpected error: {:?}", e),
445        }
446    }
447
448    #[test]
449    fn decimal_from_str_errors_for_more_than_18_fractional_digits() {
450        match Decimal::from_str("7.1234567890123456789").unwrap_err() {
451            StdError::GenericErr { msg, .. } => {
452                assert_eq!(msg, "Cannot parse more than 18 fractional digits",)
453            }
454            e => panic!("Unexpected error: {:?}", e),
455        }
456
457        // No special rules for trailing zeros. This could be changed but adds gas cost for the happy path.
458        match Decimal::from_str("7.1230000000000000000").unwrap_err() {
459            StdError::GenericErr { msg, .. } => {
460                assert_eq!(msg, "Cannot parse more than 18 fractional digits")
461            }
462            e => panic!("Unexpected error: {:?}", e),
463        }
464    }
465
466    #[test]
467    fn decimal_from_str_errors_for_invalid_number_of_dots() {
468        match Decimal::from_str("1.2.3").unwrap_err() {
469            StdError::GenericErr { msg, .. } => assert_eq!(msg, "Unexpected number of dots"),
470            e => panic!("Unexpected error: {:?}", e),
471        }
472
473        match Decimal::from_str("1.2.3.4").unwrap_err() {
474            StdError::GenericErr { msg, .. } => assert_eq!(msg, "Unexpected number of dots"),
475            e => panic!("Unexpected error: {:?}", e),
476        }
477    }
478
479    #[test]
480    fn decimal_from_str_errors_for_more_than_max_value() {
481        // Integer
482        match Decimal::from_str("340282366920938463464").unwrap_err() {
483            StdError::GenericErr { msg, .. } => assert_eq!(msg, "Value too big"),
484            e => panic!("Unexpected error: {:?}", e),
485        }
486
487        // Decimal
488        match Decimal::from_str("340282366920938463464.0").unwrap_err() {
489            StdError::GenericErr { msg, .. } => assert_eq!(msg, "Value too big"),
490            e => panic!("Unexpected error: {:?}", e),
491        }
492        match Decimal::from_str("340282366920938463463.374607431768211456").unwrap_err() {
493            StdError::GenericErr { msg, .. } => assert_eq!(msg, "Value too big"),
494            e => panic!("Unexpected error: {:?}", e),
495        }
496    }
497
498    #[test]
499    fn decimal_is_zero_works() {
500        assert!(Decimal::zero().is_zero());
501        assert!(Decimal::percent(0).is_zero());
502        assert!(Decimal::permille(0).is_zero());
503
504        assert!(!Decimal::one().is_zero());
505        assert!(!Decimal::percent(123).is_zero());
506        assert!(!Decimal::permille(1234).is_zero());
507    }
508
509    #[test]
510    fn decimal_inv_works() {
511        // d = 0
512        assert_eq!(Decimal::zero().inv(), None);
513
514        // d == 1
515        assert_eq!(Decimal::one().inv(), Some(Decimal::one()));
516
517        // d > 1 exact
518        assert_eq!(
519            Decimal::from_str("2").unwrap().inv(),
520            Some(Decimal::from_str("0.5").unwrap())
521        );
522        assert_eq!(
523            Decimal::from_str("20").unwrap().inv(),
524            Some(Decimal::from_str("0.05").unwrap())
525        );
526        assert_eq!(
527            Decimal::from_str("200").unwrap().inv(),
528            Some(Decimal::from_str("0.005").unwrap())
529        );
530        assert_eq!(
531            Decimal::from_str("2000").unwrap().inv(),
532            Some(Decimal::from_str("0.0005").unwrap())
533        );
534
535        // d > 1 rounded
536        assert_eq!(
537            Decimal::from_str("3").unwrap().inv(),
538            Some(Decimal::from_str("0.333333333333333333").unwrap())
539        );
540        assert_eq!(
541            Decimal::from_str("6").unwrap().inv(),
542            Some(Decimal::from_str("0.166666666666666666").unwrap())
543        );
544
545        // d < 1 exact
546        assert_eq!(
547            Decimal::from_str("0.5").unwrap().inv(),
548            Some(Decimal::from_str("2").unwrap())
549        );
550        assert_eq!(
551            Decimal::from_str("0.05").unwrap().inv(),
552            Some(Decimal::from_str("20").unwrap())
553        );
554        assert_eq!(
555            Decimal::from_str("0.005").unwrap().inv(),
556            Some(Decimal::from_str("200").unwrap())
557        );
558        assert_eq!(
559            Decimal::from_str("0.0005").unwrap().inv(),
560            Some(Decimal::from_str("2000").unwrap())
561        );
562    }
563
564    #[test]
565    fn decimal_add() {
566        let value = Decimal::one() + Decimal::percent(50); // 1.5
567        assert_eq!(
568            value.0,
569            Decimal::DECIMAL_FRACTIONAL * Uint128::from(3u8) / Uint128::from(2u8)
570        );
571    }
572
573    #[test]
574    #[should_panic(expected = "attempt to add with overflow")]
575    fn decimal_add_overflow_panics() {
576        let _value = Decimal::MAX + Decimal::percent(50);
577    }
578
579    #[test]
580    fn decimal_sub() {
581        let value = Decimal::one() - Decimal::percent(50); // 0.5
582        assert_eq!(value.0, Decimal::DECIMAL_FRACTIONAL / Uint128::from(2u8));
583    }
584
585    #[test]
586    #[should_panic(expected = "attempt to subtract with overflow")]
587    fn decimal_sub_overflow_panics() {
588        let _value = Decimal::zero() - Decimal::percent(50);
589    }
590
591    #[test]
592    // in this test the Decimal is on the right
593    fn uint128_decimal_multiply() {
594        // a*b
595        let left = Uint128::new(300);
596        let right = Decimal::one() + Decimal::percent(50); // 1.5
597        assert_eq!(left * right, Uint128::new(450));
598
599        // a*0
600        let left = Uint128::new(300);
601        let right = Decimal::zero();
602        assert_eq!(left * right, Uint128::new(0));
603
604        // 0*a
605        let left = Uint128::new(0);
606        let right = Decimal::one() + Decimal::percent(50); // 1.5
607        assert_eq!(left * right, Uint128::new(0));
608    }
609
610    #[test]
611    // in this test the Decimal is on the left
612    fn decimal_uint128_multiply() {
613        // a*b
614        let left = Decimal::one() + Decimal::percent(50); // 1.5
615        let right = Uint128::new(300);
616        assert_eq!(left * right, Uint128::new(450));
617
618        // 0*a
619        let left = Decimal::zero();
620        let right = Uint128::new(300);
621        assert_eq!(left * right, Uint128::new(0));
622
623        // a*0
624        let left = Decimal::one() + Decimal::percent(50); // 1.5
625        let right = Uint128::new(0);
626        assert_eq!(left * right, Uint128::new(0));
627    }
628
629    #[test]
630    fn decimal_uint128_division() {
631        // a/b
632        let left = Decimal::percent(150); // 1.5
633        let right = Uint128::new(3);
634        assert_eq!(left / right, Decimal::percent(50));
635
636        // 0/a
637        let left = Decimal::zero();
638        let right = Uint128::new(300);
639        assert_eq!(left / right, Decimal::zero());
640    }
641
642    #[test]
643    #[should_panic(expected = "attempt to divide by zero")]
644    fn decimal_uint128_divide_by_zero() {
645        let left = Decimal::percent(150); // 1.5
646        let right = Uint128::new(0);
647        let _result = left / right;
648    }
649
650    #[test]
651    fn decimal_uint128_div_assign() {
652        // a/b
653        let mut dec = Decimal::percent(150); // 1.5
654        dec /= Uint128::new(3);
655        assert_eq!(dec, Decimal::percent(50));
656
657        // 0/a
658        let mut dec = Decimal::zero();
659        dec /= Uint128::new(300);
660        assert_eq!(dec, Decimal::zero());
661    }
662
663    #[test]
664    #[should_panic(expected = "attempt to divide by zero")]
665    fn decimal_uint128_div_assign_by_zero() {
666        // a/0
667        let mut dec = Decimal::percent(50);
668        dec /= Uint128::new(0);
669    }
670
671    #[test]
672    fn decimal_uint128_sqrt() {
673        assert_eq!(Decimal::percent(900).sqrt(), Decimal::percent(300));
674
675        assert!(Decimal::percent(316) < Decimal::percent(1000).sqrt());
676        assert!(Decimal::percent(1000).sqrt() < Decimal::percent(317));
677    }
678
679    /// sqrt(2) is an irrational number, i.e. all 18 decimal places should be used.
680    #[test]
681    fn decimal_uint128_sqrt_is_precise() {
682        assert_eq!(
683            Decimal::from_str("2").unwrap().sqrt(),
684            Decimal::from_str("1.414213562373095048").unwrap() // https://www.wolframalpha.com/input/?i=sqrt%282%29
685        );
686    }
687
688    #[test]
689    fn decimal_uint128_sqrt_does_not_overflow() {
690        assert_eq!(
691            Decimal::from_str("400").unwrap().sqrt(),
692            Decimal::from_str("20").unwrap()
693        );
694    }
695
696    #[test]
697    fn decimal_uint128_sqrt_intermediate_precision_used() {
698        assert_eq!(
699            Decimal::from_str("400001").unwrap().sqrt(),
700            // The last two digits (27) are truncated below due to the algorithm
701            // we use. Larger numbers will cause less precision.
702            // https://www.wolframalpha.com/input/?i=sqrt%28400001%29
703            Decimal::from_str("632.456322602596803200").unwrap()
704        );
705    }
706
707    #[test]
708    fn decimal_to_string() {
709        // Integers
710        assert_eq!(Decimal::zero().to_string(), "0");
711        assert_eq!(Decimal::one().to_string(), "1");
712        assert_eq!(Decimal::percent(500).to_string(), "5");
713
714        // Decimals
715        assert_eq!(Decimal::percent(125).to_string(), "1.25");
716        assert_eq!(Decimal::percent(42638).to_string(), "426.38");
717        assert_eq!(Decimal::percent(3).to_string(), "0.03");
718        assert_eq!(Decimal::permille(987).to_string(), "0.987");
719
720        assert_eq!(
721            Decimal(Uint128::from(1u128)).to_string(),
722            "0.000000000000000001"
723        );
724        assert_eq!(
725            Decimal(Uint128::from(10u128)).to_string(),
726            "0.00000000000000001"
727        );
728        assert_eq!(
729            Decimal(Uint128::from(100u128)).to_string(),
730            "0.0000000000000001"
731        );
732        assert_eq!(
733            Decimal(Uint128::from(1000u128)).to_string(),
734            "0.000000000000001"
735        );
736        assert_eq!(
737            Decimal(Uint128::from(10000u128)).to_string(),
738            "0.00000000000001"
739        );
740        assert_eq!(
741            Decimal(Uint128::from(100000u128)).to_string(),
742            "0.0000000000001"
743        );
744        assert_eq!(
745            Decimal(Uint128::from(1000000u128)).to_string(),
746            "0.000000000001"
747        );
748        assert_eq!(
749            Decimal(Uint128::from(10000000u128)).to_string(),
750            "0.00000000001"
751        );
752        assert_eq!(
753            Decimal(Uint128::from(100000000u128)).to_string(),
754            "0.0000000001"
755        );
756        assert_eq!(
757            Decimal(Uint128::from(1000000000u128)).to_string(),
758            "0.000000001"
759        );
760        assert_eq!(
761            Decimal(Uint128::from(10000000000u128)).to_string(),
762            "0.00000001"
763        );
764        assert_eq!(
765            Decimal(Uint128::from(100000000000u128)).to_string(),
766            "0.0000001"
767        );
768        assert_eq!(
769            Decimal(Uint128::from(10000000000000u128)).to_string(),
770            "0.00001"
771        );
772        assert_eq!(
773            Decimal(Uint128::from(100000000000000u128)).to_string(),
774            "0.0001"
775        );
776        assert_eq!(
777            Decimal(Uint128::from(1000000000000000u128)).to_string(),
778            "0.001"
779        );
780        assert_eq!(
781            Decimal(Uint128::from(10000000000000000u128)).to_string(),
782            "0.01"
783        );
784        assert_eq!(
785            Decimal(Uint128::from(100000000000000000u128)).to_string(),
786            "0.1"
787        );
788    }
789
790    #[test]
791    fn decimal_serialize() {
792        assert_eq!(to_vec(&Decimal::zero()).unwrap(), br#""0""#);
793        assert_eq!(to_vec(&Decimal::one()).unwrap(), br#""1""#);
794        assert_eq!(to_vec(&Decimal::percent(8)).unwrap(), br#""0.08""#);
795        assert_eq!(to_vec(&Decimal::percent(87)).unwrap(), br#""0.87""#);
796        assert_eq!(to_vec(&Decimal::percent(876)).unwrap(), br#""8.76""#);
797        assert_eq!(to_vec(&Decimal::percent(8765)).unwrap(), br#""87.65""#);
798    }
799
800    #[test]
801    fn decimal_deserialize() {
802        assert_eq!(from_slice::<Decimal>(br#""0""#).unwrap(), Decimal::zero());
803        assert_eq!(from_slice::<Decimal>(br#""1""#).unwrap(), Decimal::one());
804        assert_eq!(from_slice::<Decimal>(br#""000""#).unwrap(), Decimal::zero());
805        assert_eq!(from_slice::<Decimal>(br#""001""#).unwrap(), Decimal::one());
806
807        assert_eq!(
808            from_slice::<Decimal>(br#""0.08""#).unwrap(),
809            Decimal::percent(8)
810        );
811        assert_eq!(
812            from_slice::<Decimal>(br#""0.87""#).unwrap(),
813            Decimal::percent(87)
814        );
815        assert_eq!(
816            from_slice::<Decimal>(br#""8.76""#).unwrap(),
817            Decimal::percent(876)
818        );
819        assert_eq!(
820            from_slice::<Decimal>(br#""87.65""#).unwrap(),
821            Decimal::percent(8765)
822        );
823    }
824}