bitcoin/util/
decimal.rs

1// Rust Bitcoin Library
2// Written in 2014 by
3//     Andrew Poelstra <apoelstra@wpsoftware.net>
4//
5// To the extent possible under law, the author(s) have dedicated all
6// copyright and related and neighboring rights to this software to
7// the public domain worldwide. This software is distributed without
8// any warranty.
9//
10// You should have received a copy of the CC0 Public Domain Dedication
11// along with this software.
12// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
13//
14
15//! Floating-point decimal type
16//!
17//! `i64`-based floating-point decimal type designed to hold Bitcoin
18//! amounts. For satoshi amounts (8 decimal places) the maximum
19//! amounts that can be represented is ~92.25bn, well over the 21m
20//! maximum number of bitcoin in existence. Be aware that some
21//! altcoins with different granularity may require a wider type.
22//!
23
24use std::{fmt, ops};
25#[cfg(feature = "serde-decimal")] use std::error;
26#[cfg(feature = "serde-decimal")] use std::str::FromStr;
27
28#[cfg(feature = "serde-decimal")] use serde;
29#[cfg(feature = "serde-decimal")] use strason::{self, Json};
30
31/// A fixed-point decimal type
32#[derive(Copy, Clone, Debug, Eq, Ord)]
33pub struct Decimal {
34    mantissa: i64,
35    exponent: usize,
36}
37
38/// Unsigned fixed-point decimal type
39#[derive(Copy, Clone, Debug, Eq, Ord)]
40pub struct UDecimal {
41    mantissa: u64,
42    exponent: usize,
43}
44
45impl PartialEq<Decimal> for Decimal {
46    fn eq(&self, other: &Decimal) -> bool {
47        use std::cmp::max;
48        let exp = max(self.exponent(), other.exponent());
49        self.integer_value(exp) == other.integer_value(exp)
50    }
51}
52
53impl PartialOrd<Decimal> for Decimal {
54    fn partial_cmp(&self, other: &Decimal) -> Option<::std::cmp::Ordering> {
55        use std::cmp::max;
56        let exp = max(self.exponent(), other.exponent());
57        self.integer_value(exp).partial_cmp(&other.integer_value(exp))
58    }
59}
60
61impl fmt::Display for Decimal {
62    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
63        let ten = 10i64.pow(self.exponent as u32);
64        let int_part = self.mantissa / ten;
65        let dec_part = (self.mantissa % ten).abs();
66        if int_part == 0 && self.mantissa < 0 {
67            write!(f, "-{}.{:02$}", int_part, dec_part, self.exponent)
68        } else {
69            write!(f, "{}.{:02$}", int_part, dec_part, self.exponent)
70        }
71    }
72}
73
74impl ops::Add for Decimal {
75    type Output = Decimal;
76
77    #[inline]
78    fn add(self, other: Decimal) -> Decimal {
79        if self.exponent > other.exponent {
80            Decimal {
81                mantissa: other.mantissa * 10i64.pow((self.exponent - other.exponent) as u32) + self.mantissa,
82                exponent: self.exponent
83            }
84        } else {
85            Decimal {
86                mantissa: self.mantissa * 10i64.pow((other.exponent - self.exponent) as u32) + other.mantissa,
87                exponent: other.exponent
88            }
89        }
90    }
91}
92
93impl ops::Neg for Decimal {
94    type Output = Decimal;
95    #[inline]
96    fn neg(self) -> Decimal { Decimal { mantissa: -self.mantissa, exponent: self.exponent } }
97}
98
99impl ops::Sub for Decimal {
100    type Output = Decimal;
101    #[inline]
102    fn sub(self, other: Decimal) -> Decimal { self + (-other) }
103}
104
105impl Decimal {
106    /// Creates a new Decimal
107    pub fn new(mantissa: i64, exponent: usize) -> Decimal {
108        Decimal {
109            mantissa: mantissa,
110            exponent: exponent
111        }
112    }
113
114    /// Returns the mantissa
115    #[inline]
116    pub fn mantissa(&self) -> i64 { self.mantissa }
117    /// Returns the exponent
118    #[inline]
119    pub fn exponent(&self) -> usize { self.exponent }
120
121    /// Get the decimal's value in an integer type, by multiplying
122    /// by some power of ten to ensure the returned value is 10 **
123    /// `exponent` types the actual value.
124    pub fn integer_value(&self, exponent: usize) -> i64 {
125        if exponent < self.exponent {
126            self.mantissa / 10i64.pow((self.exponent - exponent) as u32)
127        } else {
128            self.mantissa * 10i64.pow((exponent - self.exponent) as u32)
129        }
130    }
131
132    /// Returns whether or not the number is nonnegative
133    #[inline]
134    pub fn nonnegative(&self) -> bool { self.mantissa >= 0 }
135
136    // Converts a JSON number to a Decimal previously parsed by strason
137    #[cfg(feature = "serde-decimal")]
138    fn parse_decimal(s: &str) -> Result<Decimal, ParseDecimalError> {
139        // We know this will be a well-formed Json number, so we can
140        // be pretty lax about parsing
141        let mut negative = false;
142        let mut past_dec = false;
143        let mut exponent = 0;
144        let mut mantissa = 0i64;
145
146        for b in s.as_bytes() {
147            match *b {
148                b'-' => { negative = true; }
149                b'0'...b'9' => {
150                    match 10i64.checked_mul(mantissa) {
151                        None => return Err(ParseDecimalError::TooBig),
152                        Some(n) => {
153                            match n.checked_add((b - b'0') as i64) {
154                                None => return Err(ParseDecimalError::TooBig),
155                                Some(n) => mantissa = n,
156                            }
157                        }
158                    }
159                    if past_dec {
160                        exponent += 1;
161                        if exponent > 18 {
162                            return Err(ParseDecimalError::TooBig);
163                        }
164                    }
165                }
166                b'.' => { past_dec = true; }
167                _ => { /* whitespace or something, just ignore it */ }
168            }
169        }
170        if negative { mantissa *= -1; }
171        Ok(Decimal {
172            mantissa: mantissa,
173            exponent: exponent,
174        })
175    }
176}
177
178#[cfg(feature = "serde-decimal")]
179impl FromStr for Decimal {
180    type Err = ParseDecimalError;
181
182    /// Parses a `Decimal` from the given amount string.
183    fn from_str(s: &str) -> Result<Self, Self::Err> {
184        Json::from_str(s)?
185            .num()
186            .ok_or(ParseDecimalError::NotANumber)
187            .and_then(Decimal::parse_decimal)
188    }
189}
190
191#[cfg(feature = "serde-decimal")]
192impl<'de> serde::Deserialize<'de> for Decimal {
193    /// Deserialize a `Decimal`.
194    ///
195    /// This type is deserialized through [`strason`][1] for the same reason as
196    /// it's explained in the `Serialize` implementation.
197    ///
198    /// [1]: https://github.com/apoelstra/strason
199    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
200    where
201        D: serde::Deserializer<'de>,
202    {
203        use serde::de;
204
205        Json::deserialize(deserializer)?
206            .num()
207            .ok_or(de::Error::custom("expected decimal, got non-numeric"))
208            .and_then(|s| Decimal::parse_decimal(s).map_err(de::Error::custom))
209    }
210}
211
212#[cfg(feature = "serde-decimal")]
213impl serde::Serialize for Decimal {
214    /// Serialize a `Decimal`.
215    ///
216    /// This type is serialized through [`strason`][1] since it will not lose
217    /// precision (when serializing to [`strason`][1] itself, the value will be
218    /// passed through; otherwise it will be encoded as a string).
219    ///
220    /// [1]: https://github.com/apoelstra/strason
221    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
222    where
223        S: serde::Serializer,
224    {
225        let json = Json::from_str(&self.to_string()).unwrap();
226        json.serialize(serializer)
227    }
228}
229
230impl PartialEq<UDecimal> for UDecimal {
231    fn eq(&self, other: &UDecimal) -> bool {
232        use std::cmp::max;
233        let exp = max(self.exponent(), other.exponent());
234        self.integer_value(exp) == other.integer_value(exp)
235    }
236}
237
238impl PartialOrd<UDecimal> for UDecimal {
239    fn partial_cmp(&self, other: &UDecimal) -> Option<::std::cmp::Ordering> {
240        use std::cmp::max;
241        let exp = max(self.exponent(), other.exponent());
242        self.integer_value(exp).partial_cmp(&other.integer_value(exp))
243    }
244}
245
246impl fmt::Display for UDecimal {
247    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
248        let ten = 10u64.pow(self.exponent as u32);
249        let int_part = self.mantissa / ten;
250        let dec_part = self.mantissa % ten;
251        write!(f, "{}.{:02$}", int_part, dec_part, self.exponent)
252    }
253}
254
255impl ops::Add for UDecimal {
256    type Output = UDecimal;
257
258    #[inline]
259    fn add(self, other: UDecimal) -> UDecimal {
260        if self.exponent > other.exponent {
261            UDecimal {
262                mantissa: other.mantissa * 10u64.pow((self.exponent - other.exponent) as u32) + self.mantissa,
263                exponent: self.exponent
264            }
265        } else {
266            UDecimal {
267                mantissa: self.mantissa * 10u64.pow((other.exponent - self.exponent) as u32) + other.mantissa,
268                exponent: other.exponent
269            }
270        }
271    }
272}
273
274impl UDecimal {
275    /// Creates a new Decimal
276    pub fn new(mantissa: u64, exponent: usize) -> UDecimal {
277        UDecimal {
278            mantissa: mantissa,
279            exponent: exponent
280        }
281    }
282
283    /// Returns the mantissa
284    #[inline]
285    pub fn mantissa(&self) -> u64 { self.mantissa }
286    /// Returns the exponent
287    #[inline]
288    pub fn exponent(&self) -> usize { self.exponent }
289
290    /// Get the decimal's value in an integer type, by multiplying
291    /// by some power of ten to ensure the returned value is 10 **
292    /// `exponent` types the actual value.
293    pub fn integer_value(&self, exponent: usize) -> u64 {
294        if exponent < self.exponent {
295            self.mantissa / 10u64.pow((self.exponent - exponent) as u32)
296        } else {
297            self.mantissa * 10u64.pow((exponent - self.exponent) as u32)
298        }
299    }
300
301    // Converts a JSON number to a Decimal previously parsed by strason
302    #[cfg(feature = "serde-decimal")]
303    fn parse_udecimal(s: &str) -> Result<UDecimal, ParseDecimalError> {
304        // We know this will be a well-formed Json number, so we can
305        // be pretty lax about parsing
306        let mut past_dec = false;
307        let mut exponent = 0;
308        let mut mantissa = 0u64;
309
310        for b in s.as_bytes() {
311            match *b {
312                b'0'...b'9' => {
313                    match 10u64.checked_mul(mantissa) {
314                        None => return Err(ParseDecimalError::TooBig),
315                        Some(n) => {
316                            match n.checked_add((b - b'0') as u64) {
317                                None => return Err(ParseDecimalError::TooBig),
318                                Some(n) => mantissa = n,
319                            }
320                        }
321                    }
322                    if past_dec {
323                        exponent += 1;
324                        if exponent > 18 {
325                            return Err(ParseDecimalError::TooBig);
326                        }
327                    }
328                }
329                b'.' => { past_dec = true; }
330                _ => { /* whitespace or something, just ignore it */ }
331            }
332        }
333        Ok(UDecimal {
334            mantissa: mantissa,
335            exponent: exponent,
336        })
337    }
338}
339
340#[cfg(feature = "serde-decimal")]
341impl FromStr for UDecimal {
342    type Err = ParseDecimalError;
343
344    /// Parses a `UDecimal` from the given amount string.
345    fn from_str(s: &str) -> Result<Self, Self::Err> {
346        Json::from_str(s)?
347            .num()
348            .ok_or(ParseDecimalError::NotANumber)
349            .and_then(UDecimal::parse_udecimal)
350    }
351}
352
353#[cfg(feature = "serde-decimal")]
354impl<'de> serde::Deserialize<'de> for UDecimal {
355    /// Deserialize an `UDecimal`.
356    ///
357    /// This type is deserialized through [`strason`][1] for the same reason as
358    /// it's explained in the `Serialize` implementation.
359    ///
360    /// [1]: https://github.com/apoelstra/strason
361    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
362    where
363        D: serde::Deserializer<'de>,
364    {
365        use serde::de;
366
367        Json::deserialize(deserializer)?
368            .num()
369            .ok_or(de::Error::custom("expected decimal, got non-numeric"))
370            .and_then(|s| UDecimal::parse_udecimal(s).map_err(de::Error::custom))
371    }
372}
373
374#[cfg(feature = "serde-decimal")]
375impl serde::Serialize for UDecimal {
376    /// Serialize an `UDecimal`.
377    ///
378    /// This type is serialized through [`strason`][1] since it will not lose
379    /// precision (when serializing to [`strason`][1] itself, the value will be
380    /// passed through; otherwise it will be encoded as a string).
381    ///
382    /// [1]: https://github.com/apoelstra/strason
383    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
384    where
385        S: serde::Serializer,
386    {
387        let json = Json::from_str(&self.to_string()).unwrap();
388        json.serialize(serializer)
389    }
390}
391
392/// Errors that occur during `Decimal`/`UDecimal` parsing.
393#[cfg(feature = "serde-decimal")]
394#[derive(Debug)]
395pub enum ParseDecimalError {
396    /// An error ocurred while parsing the JSON number.
397    Json(strason::Error),
398    /// Not a number.
399    NotANumber,
400    /// The number is too big to fit in a `Decimal` or `UDecimal`.
401    TooBig,
402}
403
404#[cfg(feature = "serde-decimal")]
405#[doc(hidden)]
406impl From<strason::Error> for ParseDecimalError {
407    fn from(e: strason::Error) -> ParseDecimalError {
408        ParseDecimalError::Json(e)
409    }
410}
411
412#[cfg(feature = "serde-decimal")]
413impl fmt::Display for ParseDecimalError {
414    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
415        match *self {
416            ParseDecimalError::Json(ref e) => fmt::Display::fmt(e, fmt),
417            ParseDecimalError::NotANumber => fmt.write_str("not a valid JSON number"),
418            ParseDecimalError::TooBig => fmt.write_str("number is too big"),
419        }
420    }
421}
422
423#[cfg(feature = "serde-decimal")]
424impl error::Error for ParseDecimalError {
425    fn description(&self) -> &str {
426        match *self {
427            ParseDecimalError::Json(ref e) => e.description(),
428            ParseDecimalError::NotANumber => "not a valid JSON number",
429            ParseDecimalError::TooBig => "number is too big",
430        }
431    }
432
433    fn cause(&self) -> Option<&error::Error> {
434        match *self {
435            ParseDecimalError::Json(ref e) => Some(e),
436            _ => None,
437        }
438    }
439}
440
441#[cfg(test)]
442mod tests {
443    use super::*;
444    #[cfg(feature = "serde-decimal")]
445    use strason::Json;
446
447    #[test]
448    fn integer_value() {
449        let d = Decimal::new(12345678, 4);
450        assert_eq!(d.mantissa(), 12345678);
451        assert_eq!(d.exponent(), 4);
452
453        assert_eq!(d.integer_value(0), 1234);
454        assert_eq!(d.integer_value(1), 12345);
455        assert_eq!(d.integer_value(2), 123456);
456        assert_eq!(d.integer_value(3), 1234567);
457        assert_eq!(d.integer_value(4), 12345678);
458        assert_eq!(d.integer_value(5), 123456780);
459        assert_eq!(d.integer_value(6), 1234567800);
460        assert_eq!(d.integer_value(7), 12345678000);
461        assert_eq!(d.integer_value(8), 123456780000);
462
463        let u = UDecimal::new(12345678, 4);
464        assert_eq!(u.mantissa(), 12345678);
465        assert_eq!(u.exponent(), 4);
466
467        assert_eq!(u.integer_value(0), 1234);
468        assert_eq!(u.integer_value(1), 12345);
469        assert_eq!(u.integer_value(2), 123456);
470        assert_eq!(u.integer_value(3), 1234567);
471        assert_eq!(u.integer_value(4), 12345678);
472        assert_eq!(u.integer_value(5), 123456780);
473        assert_eq!(u.integer_value(6), 1234567800);
474        assert_eq!(u.integer_value(7), 12345678000);
475        assert_eq!(u.integer_value(8), 123456780000);
476    }
477
478    #[cfg(feature = "serde-decimal")]
479    macro_rules! deserialize_round_trip(
480        ($dec:expr, $s:expr) => ({
481            let d = $dec;
482            let encoded = Json::from_serialize(&d).unwrap();
483            assert_eq!(encoded, Json::from_reader(&$s[..]).unwrap());
484            assert_eq!(encoded.to_bytes(), &$s[..]);
485
486            // hack to force type inference
487            let mut decoded_res = encoded.into_deserialize();
488            if false { decoded_res = Ok($dec); }
489            let decoded = decoded_res.unwrap();
490            assert_eq!(decoded, d);
491        })
492    );
493
494    #[test]
495    #[cfg(feature = "serde-decimal")]
496    fn deserialize() {
497        deserialize_round_trip!(Decimal::new(0, 0), b"0.0");
498        deserialize_round_trip!(UDecimal::new(0, 0), b"0.0");
499
500        deserialize_round_trip!(Decimal::new(123456789001, 8), b"1234.56789001");
501        deserialize_round_trip!(UDecimal::new(123456789001, 8), b"1234.56789001");
502        deserialize_round_trip!(Decimal::new(-123456789001, 8), b"-1234.56789001");
503        deserialize_round_trip!(Decimal::new(123456789001, 1), b"12345678900.1");
504        deserialize_round_trip!(UDecimal::new(123456789001, 1), b"12345678900.1");
505        deserialize_round_trip!(Decimal::new(-123456789001, 1), b"-12345678900.1");
506        deserialize_round_trip!(Decimal::new(123456789001, 0), b"123456789001.0");
507        deserialize_round_trip!(UDecimal::new(123456789001, 0), b"123456789001.0");
508        deserialize_round_trip!(Decimal::new(-123456789001, 0), b"-123456789001.0");
509
510        deserialize_round_trip!(Decimal::new(123400000001, 8), b"1234.00000001");
511        deserialize_round_trip!(UDecimal::new(123400000001, 8), b"1234.00000001");
512        deserialize_round_trip!(Decimal::new(-123400000001, 8), b"-1234.00000001");
513    }
514
515    #[test]
516    fn equality() {
517        let d1 = Decimal::new(1234, 8);
518        let d2 = Decimal::new(12340, 9);
519        let d3 = Decimal::new(12340, 8);
520        assert_eq!(d1, d1);
521        assert_eq!(d1, d2);
522        assert!(d1 != d3);
523        assert!(d2 != d3);
524
525        assert!(d1 <= d1);
526        assert!(d2 <= d2);
527        assert!(d3 <= d3);
528        assert!(d1 <= d2);
529        assert!(d1 <= d3);
530        assert!(d3 > d1);
531        assert!(d3 > d2);
532    }
533
534    #[test]
535    fn arithmetic() {
536        let d1 = Decimal::new(5, 1);   //  0.5
537        let d2 = Decimal::new(-2, 2);  // -0.02
538        let d3 = Decimal::new(3, 0);   //  3.0
539        let d4 = Decimal::new(0, 5);  //   0.00000
540        let u1 = UDecimal::new(5, 1);   //  0.5
541        let u3 = UDecimal::new(3, 0);   //  3.0
542        let u4 = UDecimal::new(0, 5);  //   0.00000
543
544        assert!(d1.nonnegative());
545        assert!(!d2.nonnegative());
546        assert!(d3.nonnegative());
547        assert!(d4.nonnegative());
548
549        assert_eq!(d1 + d2, Decimal::new(48, 2));
550        assert_eq!(d1 - d2, Decimal::new(52, 2));
551        assert_eq!(d1 + d3, Decimal::new(35, 1));
552        assert_eq!(u1 + u3, UDecimal::new(35, 1));
553        assert_eq!(d1 - d3, Decimal::new(-25, 1));
554        assert_eq!(d2 + d3, Decimal::new(298, 2));
555        assert_eq!(d2 - d3, Decimal::new(-302, 2));
556
557        assert_eq!(d1 + d4, d1);
558        assert_eq!(u1 + u4, u1);
559        assert_eq!(d1 - d4, d1);
560        assert_eq!(d1 + d4, d1 - d4);
561        assert_eq!(d4 + d4, d4);
562        assert_eq!(u4 + u4, u4);
563    }
564
565    #[test]
566    #[cfg(feature = "serde-decimal")]
567    fn json_parse() {
568        let json = Json::from_str("0.00980000").unwrap();
569        assert_eq!(json.to_bytes(), b"0.00980000");
570        let dec: Decimal = json.into_deserialize().unwrap();
571        assert_eq!(dec, Decimal::new(980000, 8));
572
573        let json = Json::from_str("0.00980000").unwrap();
574        assert_eq!(json.to_bytes(), b"0.00980000");
575        let dec: UDecimal = json.into_deserialize().unwrap();
576        assert_eq!(dec, UDecimal::new(980000, 8));
577
578        let json = Json::from_str("0.00980").unwrap();
579        assert_eq!(json.to_bytes(), b"0.00980");
580        let dec: Decimal = json.into_deserialize().unwrap();
581        assert_eq!(dec, Decimal::new(98000, 7));
582
583        let json = Json::from_str("0.00980").unwrap();
584        assert_eq!(json.to_bytes(), b"0.00980");
585        let dec: UDecimal = json.into_deserialize().unwrap();
586        assert_eq!(dec, UDecimal::new(98000, 7));
587    }
588
589    #[test]
590    #[cfg(feature = "serde-decimal")]
591    fn parse_decimal_udecimal() {
592        let dec = "0.00980000".parse::<Decimal>().unwrap();
593        assert_eq!(dec, Decimal::new(980000, 8));
594
595        let dec = "0.00980000".parse::<UDecimal>().unwrap();
596        assert_eq!(dec, UDecimal::new(980000, 8));
597
598        let dec = "0.00980".parse::<Decimal>().unwrap();
599        assert_eq!(dec, Decimal::new(98000, 7));
600
601        let dec = "0.00980".parse::<UDecimal>().unwrap();
602        assert_eq!(dec, UDecimal::new(98000, 7));
603    }
604}