qfall_math/integer/z/arithmetic/
modulo.rs

1// Copyright © 2025 Marcel Luca Schmidt, Marvin Beckmann
2//
3// This file is part of qFALL-math.
4//
5// qFALL-math is free software: you can redistribute it and/or modify it under
6// the terms of the Mozilla Public License Version 2.0 as published by the
7// Mozilla Foundation. See <https://mozilla.org/en-US/MPL/2.0/>.
8
9//! Implementation of the [`Rem`] trait for [`Z`] values.
10
11use flint_sys::{fmpz::fmpz_mod, fmpz_mod::fmpz_mod_set_fmpz};
12
13use super::super::Z;
14use crate::{
15    integer_mod_q::Modulus,
16    macros::arithmetics::{
17        arithmetic_between_types, arithmetic_trait_borrowed_to_owned,
18        arithmetic_trait_mixed_borrowed_owned,
19    },
20};
21use std::ops::Rem;
22
23impl Rem for &Z {
24    type Output = Z;
25    /// Computes `self` mod `modulus` as long as `modulus` is greater than 1.
26    /// For negative values of `self`, the smallest positive representative is returned.
27    ///
28    /// Parameters:
29    /// - `modulus`: specifies a non-zero integer
30    ///   over which the positive remainder is computed
31    ///
32    /// Returns `self` mod `modulus` as a [`Z`] instance.
33    ///
34    /// # Examples
35    /// ```
36    /// use qfall_math::integer::Z;
37    ///
38    /// let a: Z = Z::from(42);
39    /// let b: Z = Z::from(24);
40    ///
41    /// let c: Z = a % b;
42    /// ```
43    ///
44    /// # Panics ...
45    /// - if `modulus` is smaller than `2`.
46    fn rem(self, modulus: Self) -> Self::Output {
47        assert!(modulus > &1, "Modulus can not be smaller than 2.");
48        let mut out = Z::default();
49        unsafe { fmpz_mod(&mut out.value, &self.value, &modulus.value) };
50        out
51    }
52}
53
54impl Rem<&Modulus> for &Z {
55    type Output = Z;
56    /// Computes `self` mod `modulus` as long as `modulus` is greater than 1.
57    /// For negative values of `self`, the smallest positive representative is returned.
58    ///
59    /// Parameters:
60    /// - `modulus`: specifies a non-zero integer
61    ///   over which the positive remainder is computed
62    ///
63    /// Returns `self` mod `modulus` as a [`Z`] instance.
64    ///
65    /// # Examples
66    /// ```
67    /// use qfall_math::integer::Z;
68    /// use qfall_math::integer_mod_q::Modulus;
69    ///
70    /// let a: Z = Z::from(42);
71    /// let b = Modulus::from(24);
72    ///
73    /// let c: Z = a % &b;
74    /// ```
75    fn rem(self, modulus: &Modulus) -> Self::Output {
76        let mut out = Z::default();
77        unsafe {
78            fmpz_mod_set_fmpz(
79                &mut out.value,
80                &self.value,
81                modulus.get_fmpz_mod_ctx_struct(),
82            )
83        };
84        out
85    }
86}
87
88arithmetic_trait_borrowed_to_owned!(Rem, rem, Z, Z, Z);
89arithmetic_trait_mixed_borrowed_owned!(Rem, rem, Z, Z, Z);
90arithmetic_trait_borrowed_to_owned!(Rem, rem, Z, Modulus, Z);
91arithmetic_trait_mixed_borrowed_owned!(Rem, rem, Z, Modulus, Z);
92arithmetic_between_types!(Rem, rem, Z, Z, i64 i32 i16 i8 u64 u32 u16 u8);
93
94#[cfg(test)]
95mod test_rem {
96    use super::Z;
97    use crate::integer_mod_q::Modulus;
98
99    /// Testing modulo for two [`Z`]
100    #[test]
101    fn rem() {
102        let a: Z = Z::from(42);
103        let b: Z = Z::from(24);
104        let c1: Z = a.clone() % b;
105        let c2: Z = a % Modulus::from(24);
106        assert_eq!(c1, 18);
107        assert_eq!(c2, 18);
108    }
109
110    /// Testing modulo for borrowed [`Z`]
111    #[test]
112    fn rem_borrow() {
113        let a: Z = Z::from(42);
114        let b: Z = Z::from(24);
115        let c1: Z = &a % &b;
116        let c2: Z = &a % &Modulus::from(24);
117        assert_eq!(c1, 18);
118        assert_eq!(c2, 18);
119    }
120
121    /// Testing modulo for borrowed and owned
122    #[test]
123    fn rem_first_borrowed() {
124        let a: Z = Z::from(42);
125        let b: Z = Z::from(24);
126        let c1: Z = &a % b;
127        let c2: Z = &a % Modulus::from(24);
128        assert_eq!(c1, 18);
129        assert_eq!(c2, 18);
130    }
131
132    /// Testing modulo for owned and borrowed
133    #[test]
134    fn rem_second_borrowed() {
135        let a: Z = Z::from(42);
136        let b: Z = Z::from(24);
137        let c1: Z = a.clone() % &b;
138        let c2: Z = a % &Modulus::from(24);
139        assert_eq!(c1, 18);
140        assert_eq!(c2, 18);
141    }
142
143    /// Testing modulo for negative values
144    #[test]
145    fn rem_negative_representation() {
146        let a: Z = Z::from(-2);
147        let b: Z = Z::from(24);
148        let c1: Z = a.clone() % &b;
149        let c2: Z = &a % &Modulus::from(24);
150        assert_eq!(c1, 22);
151        assert_eq!(c2, 22);
152    }
153
154    /// Testing modulo for large numbers
155    #[test]
156    fn rem_large_numbers() {
157        let a: Z = Z::from(u64::MAX);
158        let b: Z = Z::from(u64::MAX - 2);
159
160        let c1: Z = a.clone() % &b;
161        let c2: Z = a % &Modulus::from(u64::MAX - 2);
162        assert_eq!(c1, 2);
163        assert_eq!(c2, 2);
164    }
165
166    /// Ensures that computing modulo a negative number results in a panic
167    #[test]
168    #[should_panic]
169    fn rem_negative_error() {
170        let a: Z = Z::from(42);
171        let b: Z = Z::from(-24);
172        _ = &a % &b;
173    }
174
175    /// Ensures that computing modulo 0 results in a panic
176    #[test]
177    #[should_panic]
178    fn zero_modulus() {
179        _ = Z::from(15) % 0;
180    }
181
182    /// Ensures that `modulo` is available for several types.
183    #[test]
184    fn availability() {
185        let _ = Z::ONE % 2u8;
186        let _ = Z::ONE % 2u16;
187        let _ = Z::ONE % 2u32;
188        let _ = Z::ONE % 2u64;
189        let _ = Z::ONE % 2i8;
190        let _ = Z::ONE % 2i16;
191        let _ = Z::ONE % 2i32;
192        let _ = Z::ONE % 2i64;
193        let _ = Z::ONE % Z::from(2);
194        let _ = Z::ONE % Modulus::from(2);
195
196        let _ = &Z::ONE % 2u8;
197        let _ = 1u8 % Z::from(2);
198        let _ = 1u8 % &Z::from(2);
199    }
200}