use flint_sys::{fmpz::fmpz_mod, fmpz_mod::fmpz_mod_set_fmpz};
use super::super::Z;
use crate::{
integer_mod_q::Modulus,
macros::arithmetics::{
arithmetic_between_types, arithmetic_trait_borrowed_to_owned,
arithmetic_trait_mixed_borrowed_owned,
},
};
use std::ops::Rem;
impl Rem for &Z {
type Output = Z;
fn rem(self, modulus: Self) -> Self::Output {
assert!(modulus > &1, "Modulus can not be smaller than 2.");
let mut out = Z::default();
unsafe { fmpz_mod(&mut out.value, &self.value, &modulus.value) };
out
}
}
impl Rem<&Modulus> for &Z {
type Output = Z;
fn rem(self, modulus: &Modulus) -> Self::Output {
let mut out = Z::default();
unsafe {
fmpz_mod_set_fmpz(
&mut out.value,
&self.value,
modulus.get_fmpz_mod_ctx_struct(),
)
};
out
}
}
arithmetic_trait_borrowed_to_owned!(Rem, rem, Z, Z, Z);
arithmetic_trait_mixed_borrowed_owned!(Rem, rem, Z, Z, Z);
arithmetic_trait_borrowed_to_owned!(Rem, rem, Z, Modulus, Z);
arithmetic_trait_mixed_borrowed_owned!(Rem, rem, Z, Modulus, Z);
arithmetic_between_types!(Rem, rem, Z, Z, i64 i32 i16 i8 u64 u32 u16 u8);
#[cfg(test)]
mod test_rem {
use super::Z;
use crate::integer_mod_q::Modulus;
#[test]
fn rem() {
let a: Z = Z::from(42);
let b: Z = Z::from(24);
let c1: Z = a.clone() % b;
let c2: Z = a % Modulus::from(24);
assert_eq!(c1, 18);
assert_eq!(c2, 18);
}
#[test]
fn rem_borrow() {
let a: Z = Z::from(42);
let b: Z = Z::from(24);
let c1: Z = &a % &b;
let c2: Z = &a % &Modulus::from(24);
assert_eq!(c1, 18);
assert_eq!(c2, 18);
}
#[test]
fn rem_first_borrowed() {
let a: Z = Z::from(42);
let b: Z = Z::from(24);
let c1: Z = &a % b;
let c2: Z = &a % Modulus::from(24);
assert_eq!(c1, 18);
assert_eq!(c2, 18);
}
#[test]
fn rem_second_borrowed() {
let a: Z = Z::from(42);
let b: Z = Z::from(24);
let c1: Z = a.clone() % &b;
let c2: Z = a % &Modulus::from(24);
assert_eq!(c1, 18);
assert_eq!(c2, 18);
}
#[test]
fn rem_negative_representation() {
let a: Z = Z::from(-2);
let b: Z = Z::from(24);
let c1: Z = a.clone() % &b;
let c2: Z = &a % &Modulus::from(24);
assert_eq!(c1, 22);
assert_eq!(c2, 22);
}
#[test]
fn rem_large_numbers() {
let a: Z = Z::from(u64::MAX);
let b: Z = Z::from(u64::MAX - 2);
let c1: Z = a.clone() % &b;
let c2: Z = a % &Modulus::from(u64::MAX - 2);
assert_eq!(c1, 2);
assert_eq!(c2, 2);
}
#[test]
#[should_panic]
fn rem_negative_error() {
let a: Z = Z::from(42);
let b: Z = Z::from(-24);
_ = &a % &b;
}
#[test]
#[should_panic]
fn zero_modulus() {
_ = Z::from(15) % 0;
}
#[test]
fn availability() {
let _ = Z::ONE % 2u8;
let _ = Z::ONE % 2u16;
let _ = Z::ONE % 2u32;
let _ = Z::ONE % 2u64;
let _ = Z::ONE % 2i8;
let _ = Z::ONE % 2i16;
let _ = Z::ONE % 2i32;
let _ = Z::ONE % 2i64;
let _ = Z::ONE % Z::from(2);
let _ = Z::ONE % Modulus::from(2);
let _ = &Z::ONE % 2u8;
let _ = 1u8 % Z::from(2);
let _ = 1u8 % &Z::from(2);
}
}