injective_math/fp_decimal/
arithmetic.rs1use 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(), 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 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 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 assert_eq!(FPDecimal::E * FPDecimal::E, FPDecimal::must_from_str("7.389056098930650225"));
345
346 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 assert_eq!(FPDecimal::FIVE * FPDecimal::must_from_str("0.5"), FPDecimal::must_from_str("2.5"));
354
355 assert_eq!(FPDecimal::must_from_str("0.5") * FPDecimal::FIVE, FPDecimal::must_from_str("2.5"));
357
358 assert_eq!(FPDecimal::FOUR * FPDecimal::must_from_str("2.5"), FPDecimal::must_from_str("10"));
360
361 assert_eq!(FPDecimal::must_from_str("2.5") * FPDecimal::FOUR, FPDecimal::must_from_str("10"));
363
364 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 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 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 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 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 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}