Skip to main content

nanvm_lib/vm/bigint/
rem.rs

1use core::ops::Rem;
2
3use crate::vm::{Any, BigInt, IVm};
4
5impl<A: IVm> Rem for BigInt<A> {
6    type Output = Result<Self, Any<A>>;
7
8    /// The remainder of [`BigInt::div_mod`].
9    fn rem(self, rhs: Self) -> Self::Output {
10        self.div_mod(rhs).map(|(_, remainder)| remainder)
11    }
12}
13
14#[cfg(test)]
15mod tests {
16    use crate::vm::bigint::test_util::{T, int, pos};
17
18    #[test]
19    fn sign_follows_dividend() {
20        assert_eq!((int(10) % int(3)).unwrap(), int(1));
21        assert_eq!((int(-10) % int(3)).unwrap(), int(-1));
22        assert_eq!((int(10) % int(-3)).unwrap(), int(1));
23        assert_eq!((int(-10) % int(-3)).unwrap(), int(-1));
24    }
25
26    #[test]
27    fn zero_dividend() {
28        assert_eq!((int(0) % int(5)).unwrap(), T::default());
29    }
30
31    #[test]
32    fn exact_division_gives_zero() {
33        assert_eq!((int(12) % int(4)).unwrap(), T::default());
34    }
35
36    #[test]
37    fn dividend_smaller_than_divisor() {
38        assert_eq!((int(3) % int(10)).unwrap(), int(3));
39    }
40
41    #[test]
42    fn zero_divisor_throws() {
43        assert!((int(5) % int(0)).is_err());
44    }
45
46    #[test]
47    fn multi_word_remainder() {
48        // 2^64 % (2^64 - 1) = 1
49        let a = pos([0, 1]);
50        let b: T = u64::MAX.into();
51        assert_eq!((a % b).unwrap(), int(1));
52    }
53
54    #[test]
55    fn multi_word_dividend_single_word_divisor() {
56        // (3 * 2^64 + 7) % 5 = (3*2^64 mod 5 + 7) mod 5; 2^64 mod 5 == 1, so
57        // this is (3 + 7) mod 5 == 0.
58        let a = pos([7, 3]);
59        let b: T = 5u64.into();
60        assert_eq!((a % b).unwrap(), T::default());
61    }
62}