injective_math/fp_decimal/
arithmetic.rs

1/// Arithmetic operators for FPDecimal
2use crate::fp_decimal::{FPDecimal, U256};
3use core::convert::TryFrom;
4use primitive_types::U512;
5use std::iter;
6use std::ops;
7
8impl FPDecimal {
9    pub(crate) fn _add(x: FPDecimal, y: FPDecimal) -> FPDecimal {
10        if x.sign == y.sign {
11            return FPDecimal {
12                num: x.num + y.num,
13                sign: x.sign,
14            };
15        }
16
17        if x.num > y.num {
18            return FPDecimal {
19                num: x.num - y.num,
20                sign: x.sign,
21            };
22        }
23        if y.num == x.num {
24            return FPDecimal::ZERO;
25        }
26
27        FPDecimal {
28            num: y.num - x.num,
29            sign: y.sign,
30        }
31    }
32
33    pub fn add(&self, other: i128) -> FPDecimal {
34        FPDecimal::_add(*self, FPDecimal::from(other))
35    }
36
37    pub(crate) fn _sub(x: FPDecimal, y: FPDecimal) -> FPDecimal {
38        let neg_y = FPDecimal {
39            num: y.num,
40            sign: 1 - y.sign,
41        };
42        FPDecimal::_add(x, neg_y)
43    }
44
45    pub fn sub(&self, other: i128) -> FPDecimal {
46        FPDecimal::_sub(*self, FPDecimal::from(other))
47    }
48
49    pub(crate) fn _mul(x: FPDecimal, y: FPDecimal) -> FPDecimal {
50        let mut sign = 1;
51        if x.sign != y.sign {
52            sign = 0;
53        }
54        let x1 = FPDecimal::_int(x).num / FPDecimal::ONE.num;
55        let x2 = FPDecimal::_fraction(x).num;
56        let y1 = FPDecimal::_int(y).num / FPDecimal::ONE.num;
57        let y2 = FPDecimal::_fraction(y).num;
58        let mut x1y1 = x1 * y1;
59        let dec_x1y1 = x1y1 * FPDecimal::ONE.num;
60        x1y1 = dec_x1y1;
61        let x2y1 = x2 * y1;
62        let x1y2 = x1 * y2;
63
64        let x2y2 = x2 * y2;
65        let mut result = x1y1;
66        result += x2y1;
67        result += x1y2;
68        result += x2y2 / FPDecimal::MUL_PRECISION.num / FPDecimal::MUL_PRECISION.num;
69
70        FPDecimal { num: result, sign }
71    }
72
73    pub fn mul(&self, other: i128) -> FPDecimal {
74        FPDecimal::_mul(*self, FPDecimal::from(other))
75    }
76
77    pub(crate) fn _div(x: FPDecimal, y: FPDecimal) -> FPDecimal {
78        if y == FPDecimal::ONE {
79            return x;
80        }
81
82        assert_ne!(y.num, U256::zero());
83
84        let num = FPDecimal::ONE.num.full_mul(x.num) / U512::from(y.num);
85        if num.is_zero() {
86            return FPDecimal::ZERO;
87        }
88
89        FPDecimal {
90            num: U256::try_from(num).unwrap(), // panic only in MIN_FPDeciaml/-1
91            sign: 1 ^ x.sign ^ y.sign,
92        }
93    }
94
95    pub fn div(&self, other: i128) -> Self {
96        FPDecimal::_div(*self, FPDecimal::from(other))
97    }
98
99    pub fn reciprocal(x: FPDecimal) -> Self {
100        assert!(x.num != U256::zero());
101        FPDecimal {
102            num: FPDecimal::ONE.num * FPDecimal::ONE.num / x.num,
103            sign: x.sign,
104        }
105    }
106
107    pub fn abs(&self) -> Self {
108        FPDecimal { num: self.num, sign: 1i8 }
109    }
110
111    pub fn abs_diff(&self, other: &Self) -> Self {
112        if self > other {
113            *self - *other
114        } else {
115            *other - *self
116        }
117    }
118}
119
120impl ops::Add for FPDecimal {
121    type Output = Self;
122
123    fn add(self, rhs: Self) -> Self {
124        FPDecimal::_add(self, rhs)
125    }
126}
127
128impl ops::AddAssign for FPDecimal {
129    fn add_assign(&mut self, rhs: Self) {
130        *self = FPDecimal::_add(*self, rhs);
131    }
132}
133
134impl ops::Sub for FPDecimal {
135    type Output = Self;
136
137    fn sub(self, rhs: Self) -> Self {
138        FPDecimal::_sub(self, rhs)
139    }
140}
141
142impl ops::SubAssign for FPDecimal {
143    fn sub_assign(&mut self, rhs: Self) {
144        *self = FPDecimal::_sub(*self, rhs);
145    }
146}
147
148impl ops::Mul for FPDecimal {
149    type Output = Self;
150
151    fn mul(self, rhs: Self) -> Self {
152        FPDecimal::_mul(self, rhs)
153    }
154}
155
156impl ops::MulAssign for FPDecimal {
157    fn mul_assign(&mut self, rhs: Self) {
158        *self = FPDecimal::_mul(*self, rhs);
159    }
160}
161
162impl ops::Div for FPDecimal {
163    type Output = Self;
164
165    fn div(self, rhs: Self) -> Self {
166        FPDecimal::_div(self, rhs)
167    }
168}
169
170impl ops::DivAssign for FPDecimal {
171    fn div_assign(&mut self, rhs: FPDecimal) {
172        *self = *self / rhs;
173    }
174}
175
176impl ops::Rem for FPDecimal {
177    type Output = Self;
178
179    fn rem(self, divisor: FPDecimal) -> Self::Output {
180        assert_ne!(divisor, FPDecimal::ZERO);
181
182        if divisor.is_negative() {
183            return self.calculate_negative_remainder(divisor);
184        }
185
186        self.calculate_positive_remainder(divisor)
187    }
188}
189
190impl FPDecimal {
191    fn calculate_positive_remainder(&self, divisor: FPDecimal) -> FPDecimal {
192        let mut remainder = *self;
193
194        if self.is_negative() {
195            while remainder < FPDecimal::ZERO {
196                remainder += divisor;
197            }
198
199            return remainder;
200        }
201
202        while remainder >= divisor {
203            remainder -= divisor;
204        }
205
206        remainder
207    }
208
209    fn calculate_negative_remainder(&self, divisor: FPDecimal) -> FPDecimal {
210        let mut remainder = *self;
211
212        if self.is_negative() {
213            while remainder < divisor {
214                remainder -= divisor;
215            }
216
217            return remainder;
218        }
219
220        while remainder >= -divisor {
221            remainder += divisor;
222        }
223
224        remainder
225    }
226}
227
228#[allow(clippy::suspicious_arithmetic_impl)]
229impl ops::RemAssign for FPDecimal {
230    fn rem_assign(&mut self, b: FPDecimal) {
231        *self = *self % b;
232    }
233}
234
235impl<'a> iter::Sum<&'a Self> for FPDecimal {
236    fn sum<I>(iter: I) -> Self
237    where
238        I: Iterator<Item = &'a Self>,
239    {
240        iter.fold(FPDecimal::ZERO, |a, b| a + *b)
241    }
242}
243
244#[cfg(test)]
245mod tests {
246
247    use crate::fp_decimal::U256;
248    use crate::FPDecimal;
249
250    #[test]
251    fn compare() {
252        let neg_ten = -FPDecimal::TEN;
253        let neg_point_one = -FPDecimal::must_from_str("0.1");
254        let neg_point_two = -FPDecimal::must_from_str("0.2");
255        let neg_one = -FPDecimal::ONE;
256        let point_one = FPDecimal::must_from_str("0.1");
257        let one = FPDecimal::ONE;
258        let ten = FPDecimal::TEN;
259        assert!(neg_ten < neg_one);
260        assert!(neg_one < neg_point_two);
261        assert!(neg_point_two < neg_point_one);
262        assert!(neg_point_one < point_one);
263        assert!(point_one < one);
264        assert!(one < ten);
265    }
266
267    #[test]
268    fn test_into_u128() {
269        let first_num: u128 = FPDecimal::from(1234567890123456789u128).into();
270        assert_eq!(first_num, 1234567890123456789u128);
271
272        let num: u128 = FPDecimal::from(u128::MAX).into();
273        assert_eq!(num, u128::MAX);
274    }
275
276    #[test]
277    #[should_panic(expected = "overflow")]
278    fn panic_into_u128() {
279        let _: u128 = (FPDecimal::from(u128::MAX) + FPDecimal::ONE).into();
280    }
281
282    #[test]
283    #[should_panic(expected = "overflow")]
284    fn test_overflow() {
285        let num1 = FPDecimal::MAX + FPDecimal::ONE;
286        assert_eq!(num1, FPDecimal::ONE);
287    }
288
289    #[test]
290    fn test_add() {
291        let five = FPDecimal::FIVE;
292        let three = FPDecimal::THREE;
293        let eight = FPDecimal::EIGHT;
294        assert_eq!(five + three, eight);
295    }
296
297    #[test]
298    fn test_add_neg() {
299        let neg_five = -FPDecimal::FIVE;
300        let neg_three = -FPDecimal::THREE;
301        let neg_eight = -FPDecimal::EIGHT;
302        assert_eq!(neg_five + neg_three, neg_eight);
303    }
304
305    #[test]
306    fn test_sub() {
307        let five = FPDecimal::FIVE;
308        let three = FPDecimal::THREE;
309        let two = FPDecimal::TWO;
310        assert_eq!(five - three, two);
311    }
312
313    #[test]
314    fn test_sub_neg() {
315        let five = FPDecimal::FIVE;
316        let neg_three = -FPDecimal::THREE;
317        let eight = FPDecimal::EIGHT;
318        assert_eq!(FPDecimal::_sub(five, neg_three), eight);
319    }
320
321    #[test]
322    fn test_mul() {
323        let five = FPDecimal::FIVE;
324        let three = FPDecimal::THREE;
325        let fifteen = FPDecimal::must_from_str("15");
326        assert_eq!(five * three, fifteen);
327    }
328
329    #[test]
330    fn test_mul_precisions() {
331        // 8.33157469 * 0.000000000001 = 0.00000000000833157469
332        assert_eq!(
333            FPDecimal::must_from_str("8.33157469") * FPDecimal::must_from_str("0.000000000001"),
334            FPDecimal::must_from_str("0.000000000008331574")
335        );
336
337        // 1.5 * 1.5 = 2.25
338        assert_eq!(
339            FPDecimal::must_from_str("1.5") * FPDecimal::must_from_str("1.5"),
340            FPDecimal::must_from_str("2.25")
341        );
342
343        // 2.718281828459045235 * 2.718281828459045235 = 7.389056098930650225
344        assert_eq!(FPDecimal::E * FPDecimal::E, FPDecimal::must_from_str("7.389056098930650225"));
345
346        // 0.5 * 0.5 = 0.25
347        assert_eq!(
348            FPDecimal::must_from_str("0.5") * FPDecimal::must_from_str("0.5"),
349            FPDecimal::must_from_str("0.25")
350        );
351
352        // 5 * 0.5 = 2.5
353        assert_eq!(FPDecimal::FIVE * FPDecimal::must_from_str("0.5"), FPDecimal::must_from_str("2.5"));
354
355        // 0.5 * 5 = 2.5
356        assert_eq!(FPDecimal::must_from_str("0.5") * FPDecimal::FIVE, FPDecimal::must_from_str("2.5"));
357
358        // 4 * 2.5 = 10
359        assert_eq!(FPDecimal::FOUR * FPDecimal::must_from_str("2.5"), FPDecimal::must_from_str("10"));
360
361        // 2.5 * 4 = 10
362        assert_eq!(FPDecimal::must_from_str("2.5") * FPDecimal::FOUR, FPDecimal::must_from_str("10"));
363
364        // 0.000000008 * 0.9 = 0.0000000072
365        assert_eq!(
366            FPDecimal::must_from_str("0.000000008") * FPDecimal::must_from_str("0.9"),
367            FPDecimal::must_from_str("0.0000000072")
368        );
369
370        // 0.0000000008 * 0.9 = 0.00000000072
371        assert_eq!(
372            FPDecimal::must_from_str("0.0000000008") * FPDecimal::must_from_str("0.9"),
373            FPDecimal::must_from_str("0.00000000072")
374        );
375
376        // -0.5 * 0.5 = -0.25
377        assert_eq!(
378            FPDecimal::must_from_str("-0.5") * FPDecimal::must_from_str("0.5"),
379            FPDecimal::must_from_str("-0.25")
380        );
381
382        // -0.5 * -0.5 = 0.25
383        assert_eq!(
384            FPDecimal::must_from_str("-0.5") * FPDecimal::must_from_str("-0.5"),
385            FPDecimal::must_from_str("0.25")
386        );
387
388        // -5 * -3 = 15
389        assert_eq!(
390            FPDecimal::must_from_str("-5") * FPDecimal::must_from_str("-3"),
391            FPDecimal::must_from_str("15")
392        );
393    }
394
395    #[test]
396    fn test_mul_pos_neg() {
397        let five = FPDecimal::FIVE;
398        let neg_three = -FPDecimal::THREE;
399        let neg_fifteen = FPDecimal::must_from_str("-15");
400        assert_eq!(five * neg_three, neg_fifteen);
401    }
402
403    #[test]
404    fn test_mul_neg_pos() {
405        let neg_five = -FPDecimal::FIVE;
406        let three = FPDecimal::THREE;
407        let neg_fifteen = FPDecimal::must_from_str("-15");
408        assert_eq!(neg_five * three, neg_fifteen);
409    }
410
411    #[test]
412    fn test_mul_neg_neg() {
413        let neg_five = -FPDecimal::FIVE;
414        let neg_three = -FPDecimal::THREE;
415        let fifteen = FPDecimal::must_from_str("15");
416        assert_eq!(neg_five * neg_three, fifteen);
417    }
418
419    #[test]
420    fn test_div() {
421        let hundred = FPDecimal::must_from_str("100");
422        let five = FPDecimal::FIVE;
423        let twenty = FPDecimal::must_from_str("20");
424        assert_eq!(hundred / five, twenty);
425    }
426
427    #[test]
428    fn test_reciprocal() {
429        let five = FPDecimal::FIVE;
430        let point_2 = FPDecimal::TWO / FPDecimal::TEN;
431        assert_eq!(FPDecimal::reciprocal(five), point_2);
432        assert_eq!(FPDecimal::reciprocal(point_2), five);
433        assert_eq!(FPDecimal::reciprocal(FPDecimal::must_from_str("0.5")), FPDecimal::TWO);
434    }
435
436    #[test]
437    fn test_abs() {
438        let neg_five = -FPDecimal::FIVE;
439        let five = FPDecimal::FIVE;
440        assert_eq!(neg_five.abs(), five);
441    }
442
443    #[test]
444    fn test_div_identity() {
445        for i in 1..10000 {
446            let a = FPDecimal::must_from_str(&format!("{}", i));
447            assert_eq!(a / a, FPDecimal::ONE);
448        }
449    }
450
451    #[test]
452    fn test_add_assign() {
453        let mut ans = FPDecimal::FIVE;
454        let four = FPDecimal::FOUR;
455        let nine = FPDecimal::NINE;
456        ans += four;
457        assert_eq!(ans, nine);
458
459        let mut ans2 = FPDecimal::NINE;
460        let five = FPDecimal::FIVE;
461        let neg_four = -FPDecimal::FOUR;
462        ans2 += neg_four;
463        assert_eq!(five, ans2);
464    }
465
466    #[test]
467    fn test_sub_assign() {
468        let mut ans = FPDecimal::FIVE;
469        let four = FPDecimal::FOUR;
470        ans -= four;
471        assert_eq!(ans, FPDecimal::ONE);
472
473        let mut ans = FPDecimal::ONE;
474        let five = FPDecimal::FIVE;
475        let neg_four = -FPDecimal::FOUR;
476        ans -= neg_four;
477        assert_eq!(five, ans);
478    }
479
480    #[test]
481    fn test_mul_assign() {
482        let mut ans = FPDecimal::FIVE;
483        let two = FPDecimal::TWO;
484        let ten = FPDecimal::TEN;
485        ans *= two;
486        assert_eq!(ten, ans);
487
488        let mut ans = -FPDecimal::FIVE;
489        let two = FPDecimal::TWO;
490        let neg_ten = -FPDecimal::TEN;
491        ans *= two;
492        assert_eq!(neg_ten, ans);
493    }
494
495    #[test]
496    fn test_div_assign() {
497        let mut ans = FPDecimal::EIGHT;
498        ans /= FPDecimal::TWO;
499        assert_eq!(FPDecimal::FOUR, ans);
500
501        let mut y = FPDecimal::FIVE;
502        y /= FPDecimal::TWO;
503        assert_eq!(FPDecimal::must_from_str("2.5"), y);
504
505        let mut z = FPDecimal::ONE;
506        z /= FPDecimal::THREE;
507        assert_eq!(z, FPDecimal::THREE / FPDecimal::NINE);
508    }
509
510    #[test]
511    fn test_is_negative() {
512        let val = FPDecimal::TWO;
513        assert!(!val.is_negative());
514
515        let val = FPDecimal::ZERO;
516        assert!(!val.is_negative());
517
518        // even a manually assigned negative zero value returns positive
519        let val = FPDecimal {
520            num: U256([0, 0, 0, 0]),
521            sign: 1,
522        };
523        assert!(!val.is_negative());
524
525        let val = FPDecimal::NEGATIVE_ONE;
526        assert!(val.is_negative());
527    }
528
529    #[test]
530    fn test_abs_diff() {
531        let lhs = FPDecimal::TWO;
532        let rhs = FPDecimal::THREE;
533        let ans = lhs.abs_diff(&rhs);
534        assert_eq!(FPDecimal::ONE, ans);
535
536        let lhs = FPDecimal::THREE;
537        let rhs = FPDecimal::ONE;
538        let ans = lhs.abs_diff(&rhs);
539        assert_eq!(FPDecimal::TWO, ans);
540
541        let lhs = FPDecimal::NEGATIVE_ONE;
542        let rhs = FPDecimal::TWO;
543        let ans = lhs.abs_diff(&rhs);
544        assert_eq!(FPDecimal::THREE, ans);
545    }
546
547    #[test]
548    fn test_remainder() {
549        let x = FPDecimal::FIVE;
550        let y = x % FPDecimal::TWO;
551        assert_eq!(FPDecimal::ONE, y);
552
553        let x = -FPDecimal::SEVEN;
554        let y = x % FPDecimal::THREE;
555        assert_eq!(FPDecimal::TWO, y);
556
557        let x = -FPDecimal::SEVEN;
558        let y = x % FPDecimal::SEVEN;
559        assert_eq!(FPDecimal::ZERO, y);
560
561        let x = FPDecimal::must_from_str("3.5");
562        let y = x % FPDecimal::must_from_str("0.8");
563        assert_eq!(FPDecimal::must_from_str("0.3"), y);
564
565        let x = FPDecimal::must_from_str("-3.5");
566        let y = x % FPDecimal::must_from_str("0.8");
567        assert_eq!(FPDecimal::must_from_str("0.5"), y);
568
569        let x = FPDecimal::must_from_str("-3.5");
570        let y = x % FPDecimal::must_from_str("-0.8");
571        assert_eq!(FPDecimal::must_from_str("-0.3"), y);
572    }
573
574    #[test]
575    fn test_remainder_assign() {
576        let mut x = FPDecimal::NINE;
577        x %= FPDecimal::FIVE;
578        assert_eq!(FPDecimal::FOUR, x);
579    }
580
581    #[test]
582    fn test_chain_sum() {
583        let vector = [FPDecimal::ZERO, FPDecimal::ONE, FPDecimal::TWO, FPDecimal::THREE];
584        assert_eq!(FPDecimal::SIX, vector.iter().sum());
585    }
586    #[test]
587    fn test_chain_sum_equal_zero() {
588        let vector = [FPDecimal::ZERO, FPDecimal::ONE, FPDecimal::TWO, -FPDecimal::THREE];
589        assert_eq!(FPDecimal::ZERO, vector.iter().sum());
590    }
591}