Skip to main content

nanvm_lib/vm/bigint/
add.rs

1use core::ops::Add;
2
3use crate::vm::{Any, BigInt, IVm};
4
5/// `+`, or the `RangeError` of a sum longer than `MAX_WORDS` words, as `*`
6/// and `<<` throw for a result that long.
7impl<A: IVm> Add for BigInt<A> {
8    type Output = Result<Self, Any<A>>;
9    fn add(self, rhs: Self) -> Self::Output {
10        let rhs_sign = rhs.sign();
11        self.add_signed(rhs, rhs_sign).within_limit()
12    }
13}
14
15#[cfg(test)]
16mod tests {
17    use crate::vm::{
18        bigint::test_util::{T, int, pos, pow2},
19        error,
20    };
21
22    #[test]
23    fn same_signs() {
24        assert_eq!(int(3) + int(5), Ok(int(8)));
25        assert_eq!(int(-3) + int(-5), Ok(int(-8)));
26    }
27
28    #[test]
29    fn different_signs_rhs_magnitude_greater() {
30        assert_eq!(int(3) + int(-5), Ok(int(-2)));
31        assert_eq!(int(-3) + int(5), Ok(int(2)));
32    }
33
34    #[test]
35    fn different_signs_lhs_magnitude_greater() {
36        assert_eq!(int(5) + int(-3), Ok(int(2)));
37        assert_eq!(int(-5) + int(3), Ok(int(-2)));
38    }
39
40    #[test]
41    fn cancellation_to_zero() {
42        assert_eq!(int(7) + int(-7), Ok(T::default()));
43        assert_eq!(int(-7) + int(7), Ok(T::default()));
44    }
45
46    #[test]
47    fn multi_word_carry() {
48        let a: T = u64::MAX.into();
49        let b: T = 1u64.into();
50        assert_eq!(a + b, Ok(pos([0, 1])));
51    }
52
53    /// `2^1048575` is `MAX_WORDS` words; twice it is one word more.
54    #[test]
55    fn sum_at_and_past_the_limit() {
56        assert_eq!(pow2(1_048_575) + int(0), Ok(pow2(1_048_575)));
57        assert_eq!(
58            pow2(1_048_575) + pow2(1_048_575),
59            Err(error::bigint_too_large())
60        );
61        assert_eq!(
62            -pow2(1_048_575) + -pow2(1_048_575),
63            Err(error::bigint_too_large())
64        );
65    }
66}