Skip to main content

lean_decimal/
ops.rs

1use core::cmp::Ordering;
2use core::fmt;
3use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
4
5use crate::{Decimal, UnderlyingInt, bits_to_digits};
6
7impl<I: UnderlyingInt> Decimal<I> {
8    /// Computes the absolute value of self.
9    #[must_use]
10    pub fn abs(self) -> Self {
11        Self(self.0 << 1 >> 1)
12    }
13
14    /// Computes the addition.
15    ///
16    /// Return `None` if overflow.
17    ///
18    /// There may loss precision if the scales of the 2 operands differ too greatly.
19    /// It's a classic [round-off errors](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Addition_and_subtraction).
20    /// of floating-point calculation.
21    ///
22    /// # Examples:
23    ///
24    /// ```
25    /// use lean_decimal::Dec128;
26    /// let a = Dec128::from_parts(123, 2); // 1.23
27    /// let b = Dec128::from_parts(1, 4);   // 0.0001
28    /// let sum = Dec128::from_parts(12301, 4); // 1.2301
29    /// assert_eq!(a.checked_add(b).unwrap(), sum);
30    /// ```
31    #[must_use]
32    pub fn checked_add(self, right: Self) -> Option<Self> {
33        let (b_sign, b_scale, b_man) = right.unpack();
34        self.do_add(b_sign, b_scale, b_man)
35    }
36
37    /// Computes the addition.
38    ///
39    /// Return `None` if overflow.
40    ///
41    /// There may loss precision if the scales of the 2 operands differ too greatly.
42    /// It's a classic [round-off errors](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Addition_and_subtraction).
43    /// of floating-point calculation.
44    ///
45    /// # Examples:
46    ///
47    /// ```
48    /// use lean_decimal::Dec128;
49    /// let a = Dec128::from_parts(123, 2); // 1.23
50    /// let b = Dec128::from_parts(1, 4);   // 0.0001
51    /// let diff = Dec128::from_parts(12299, 4); // 1.2299
52    /// assert_eq!(a.checked_sub(b).unwrap(), diff);
53    /// ```
54    #[must_use]
55    pub fn checked_sub(self, right: Self) -> Option<Self> {
56        let (b_sign, b_scale, b_man) = right.unpack();
57        self.do_add(b_sign ^ 1, b_scale, b_man)
58    }
59
60    #[inline]
61    fn do_add(self, b_sign: u8, b_scale: u32, b_man: I) -> Option<Self> {
62        let (a_sign, a_scale, a_man) = self.unpack();
63
64        let (a_man, b_man, scale) = if a_scale == b_scale {
65            (a_man, b_man, a_scale)
66        } else {
67            align_scale(a_man, a_scale, b_man, b_scale)
68        };
69
70        // do the addition
71        let (sign, sum) = if a_sign == b_sign {
72            (a_sign, a_man + b_man)
73        } else if a_man > b_man {
74            (a_sign, a_man - b_man)
75        } else {
76            (b_sign, b_man - a_man)
77        };
78
79        // pack
80        if sum <= I::MAX_MATISSA {
81            Some(Self::pack(sign, scale, sum))
82        } else if scale > 0 {
83            let man = (sum + (I::TEN >> 1)) / I::TEN; // rounding-divide
84            Some(Self::pack(sign, scale - 1, man))
85        } else {
86            None
87        }
88    }
89
90    /// Computes the multiplication.
91    ///
92    /// Return `None` if overflow.
93    ///
94    /// The right oprand could be short integers or decimals.
95    ///
96    /// # Examples:
97    ///
98    /// ```
99    /// use lean_decimal::Dec128;
100    /// let a = Dec128::from_parts(123, 2); // 1.23
101    /// let b = Dec128::from_parts(1, 4);   // 0.0001
102    /// let prod = Dec128::from_parts(123, 6); // 0.000123
103    /// assert_eq!(a.checked_mul(b).unwrap(), prod);
104    ///
105    /// // by integer
106    /// let prod = Dec128::from_parts(246, 2); // 2.46
107    /// assert_eq!(a.checked_mul(2).unwrap(), prod);
108    /// ```
109    #[must_use]
110    pub fn checked_mul(self, right: impl Into<Self>) -> Option<Self> {
111        let (a_sign, a_scale, a_man) = self.unpack();
112        let (b_sign, b_scale, b_man) = right.into().unpack();
113
114        let (p_man, p_scale) = a_man.mul_with_sum_scale(b_man, a_scale + b_scale)?;
115
116        Some(Self::pack(a_sign ^ b_sign, p_scale, p_man))
117    }
118
119    /// Computes the division.
120    ///
121    /// Return `None` if overflow or divied by zero.
122    ///
123    /// The right oprand could be short integers or decimals.
124    ///
125    /// # Examples:
126    ///
127    /// ```
128    /// use lean_decimal::Dec128;
129    /// let a = Dec128::from_parts(123, 2); // 1.23
130    /// let b = Dec128::from_parts(1, 4);   // 0.0001
131    /// let q = Dec128::from_parts(12300, 0); // 12300
132    /// assert_eq!(a.checked_div(b).unwrap(), q);
133    ///
134    /// // by integer
135    /// let q = Dec128::from_parts(615, 3); // 0.615
136    /// assert_eq!(a.checked_div(2).unwrap(), q);
137    /// ```
138    #[must_use]
139    pub fn checked_div(self, right: impl Into<Self>) -> Option<Self> {
140        let (a_sign, a_scale, a_man) = self.unpack();
141        let (b_sign, b_scale, b_man) = right.into().unpack();
142        if b_man == I::ZERO {
143            return None;
144        }
145
146        let (q_man, q_scale) = a_man.div_with_scales(b_man, a_scale, b_scale)?;
147
148        Some(Self::pack(a_sign ^ b_sign, q_scale, q_man))
149    }
150
151    /// Round to the @dst_scale. Keep @dst_scale fraction decimal fractions.
152    ///
153    /// Do nothing if the original scale is not bigger than @dst_scale
154    ///
155    /// # Examples:
156    ///
157    /// ```
158    /// use lean_decimal::Dec128;
159    /// let a = Dec128::from_parts(12345678, 6); // 12.345678
160    /// let b = Dec128::from_parts(1235, 2);   // 12.35
161    /// assert_eq!(a.round_to(2), b);
162    /// ```
163    #[must_use]
164    pub fn round_to(self, dst_scale: u32) -> Self {
165        let (a_sign, a_scale, a_man) = self.unpack();
166        if dst_scale >= a_scale {
167            return self;
168        }
169        let new_man = a_man.div_exp(a_scale - dst_scale);
170        Self::pack(a_sign, dst_scale, new_man)
171    }
172}
173
174impl<I: UnderlyingInt> Decimal<I> {
175    /// Return if the number is zero.
176    #[must_use]
177    pub fn is_zero(self) -> bool {
178        let (_, _, man) = self.unpack();
179        man == I::ZERO
180    }
181
182    /// Return if the number is positive.
183    #[must_use]
184    pub fn is_positive(self) -> bool {
185        let (sign, _, man) = self.unpack();
186        sign == 0 && man != I::ZERO
187    }
188
189    /// Return if the number is negative.
190    #[must_use]
191    pub fn is_negative(self) -> bool {
192        let (sign, _, man) = self.unpack();
193        sign != 0 && man != I::ZERO
194    }
195}
196
197impl<I: UnderlyingInt> Eq for Decimal<I> {}
198
199impl<I: UnderlyingInt> PartialEq for Decimal<I> {
200    fn eq(&self, other: &Self) -> bool {
201        let (a_sign, a_scale, a_man) = self.unpack();
202        let (b_sign, b_scale, b_man) = other.unpack();
203
204        if a_man == I::ZERO {
205            return b_man == I::ZERO;
206        }
207        if b_man == I::ZERO {
208            return a_man == I::ZERO;
209        }
210        if a_sign != b_sign {
211            return false;
212        }
213        if a_scale == b_scale {
214            return a_man == b_man;
215        }
216        if a_scale < b_scale {
217            match a_man.checked_mul_exp(b_scale - a_scale) {
218                Some(a_man) => a_man == b_man,
219                None => false,
220            }
221        } else {
222            match b_man.checked_mul_exp(a_scale - b_scale) {
223                Some(b_man) => b_man == a_man,
224                None => false,
225            }
226        }
227    }
228}
229
230impl<I: UnderlyingInt> Ord for Decimal<I> {
231    fn cmp(&self, other: &Self) -> Ordering {
232        let (a_sign, a_scale, a_man) = self.unpack();
233        let (b_sign, b_scale, b_man) = other.unpack();
234
235        if a_sign != b_sign {
236            if a_man == I::ZERO && b_man == I::ZERO {
237                Ordering::Equal
238            } else if a_sign == 0 {
239                Ordering::Greater
240            } else {
241                Ordering::Less
242            }
243        } else {
244            let ret = if a_scale == b_scale {
245                a_man.cmp(&b_man)
246            } else if a_scale < b_scale {
247                match a_man.checked_mul_exp(b_scale - a_scale) {
248                    Some(a_man) => a_man.cmp(&b_man),
249                    None => Ordering::Greater,
250                }
251            } else {
252                match b_man.checked_mul_exp(a_scale - b_scale) {
253                    Some(b_man) => a_man.cmp(&b_man),
254                    None => Ordering::Less,
255                }
256            };
257
258            if a_sign == 0 {
259                ret
260            } else {
261                match ret {
262                    Ordering::Less => Ordering::Greater,
263                    Ordering::Greater => Ordering::Less,
264                    Ordering::Equal => Ordering::Equal,
265                }
266            }
267        }
268    }
269}
270
271impl<I: UnderlyingInt> PartialOrd for Decimal<I> {
272    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
273        Some(self.cmp(other))
274    }
275}
276
277impl<I: UnderlyingInt> Neg for Decimal<I> {
278    type Output = Self;
279    fn neg(self) -> Self::Output {
280        let sign = I::ONE << (I::BITS - 1);
281        Self(self.0 ^ sign)
282    }
283}
284
285impl<I: UnderlyingInt> Add for Decimal<I> {
286    type Output = Self;
287    fn add(self, rhs: Self) -> Self::Output {
288        self.checked_add(rhs).expect("addition overflow")
289    }
290}
291
292impl<I: UnderlyingInt> AddAssign for Decimal<I> {
293    fn add_assign(&mut self, rhs: Self) {
294        *self = *self + rhs;
295    }
296}
297
298impl<I: UnderlyingInt> Sub for Decimal<I> {
299    type Output = Self;
300    fn sub(self, rhs: Self) -> Self::Output {
301        self.checked_sub(rhs).expect("substraction overflow")
302    }
303}
304
305impl<I: UnderlyingInt> SubAssign for Decimal<I> {
306    fn sub_assign(&mut self, rhs: Self) {
307        *self = *self - rhs;
308    }
309}
310
311impl<I: UnderlyingInt, R: Into<Self>> Mul<R> for Decimal<I> {
312    type Output = Self;
313    fn mul(self, rhs: R) -> Self::Output {
314        self.checked_mul(rhs).expect("multiplication overflow")
315    }
316}
317
318impl<I: UnderlyingInt, R: Into<Self>> MulAssign<R> for Decimal<I> {
319    fn mul_assign(&mut self, rhs: R) {
320        *self = *self * rhs;
321    }
322}
323
324impl<I: UnderlyingInt, R: Into<Self>> Div<R> for Decimal<I> {
325    type Output = Self;
326    fn div(self, rhs: R) -> Self::Output {
327        self.checked_div(rhs).expect("division overflow or by zero")
328    }
329}
330
331impl<I: UnderlyingInt, R: Into<Self>> DivAssign<R> for Decimal<I> {
332    fn div_assign(&mut self, rhs: R) {
333        *self = *self / rhs;
334    }
335}
336
337impl<I: UnderlyingInt> core::iter::Sum for Decimal<I> {
338    fn sum<Iter: Iterator<Item = Self>>(iter: Iter) -> Self {
339        iter.fold(Self::ZERO, |acc, d| acc + d)
340    }
341}
342
343impl<'a, I: UnderlyingInt> core::iter::Sum<&'a Self> for Decimal<I> {
344    fn sum<Iter: Iterator<Item = &'a Self>>(iter: Iter) -> Self {
345        iter.fold(Self::ZERO, |acc, d| acc + *d)
346    }
347}
348
349impl<I: UnderlyingInt> fmt::Debug for Decimal<I> {
350    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
351        let (iman, scale) = self.parts();
352        write!(f, "Decimal[{iman} {scale}]")
353    }
354}
355
356// Mark this function as #[inline(never)] to avoid interfering with the
357// main flow of the caller add_or_sub(), thereby enabling better compiler
358// optimizations.
359#[inline(never)]
360fn align_scale<I>(mut a_man: I, a_scale: u32, mut b_man: I, b_scale: u32) -> (I, I, u32)
361where
362    I: UnderlyingInt,
363{
364    // big_man/big_scale: the number with bigger scale
365    // small_man/small_scale: the number with smaller scale
366    let (big_man, mut big_scale, small_man, small_scale) = if a_scale > b_scale {
367        (&mut a_man, a_scale, &mut b_man, b_scale)
368    } else {
369        (&mut b_man, b_scale, &mut a_man, a_scale)
370    };
371
372    let small_avail = bits_to_digits(small_man.leading_zeros() - I::META_BITS);
373    let diff = big_scale - small_scale;
374
375    if diff <= small_avail {
376        // rescale small_man to big_scale
377        *small_man = small_man.mul_exp(diff);
378    } else {
379        // rescale both small_man and big_man
380        *small_man = small_man.mul_exp(small_avail);
381        *big_man = big_man.div_exp(diff - small_avail);
382        big_scale = small_scale + small_avail;
383    }
384
385    (a_man, b_man, big_scale)
386}