use crate::natural::arithmetic::div_exact::limbs_modular_invert_limb;
use crate::natural::arithmetic::divisible_by::{
limbs_divisible_by, limbs_divisible_by_limb, limbs_divisible_by_val_ref,
};
use crate::natural::arithmetic::mod_op::limbs_mod_limb;
use crate::natural::arithmetic::sub::{
limbs_sub_greater_in_place_left, limbs_sub_greater_to_out, limbs_sub_limb_in_place,
limbs_sub_limb_to_out, limbs_sub_same_length_in_place_left,
limbs_sub_same_length_in_place_right, limbs_sub_same_length_to_out,
};
use crate::natural::comparison::cmp::limbs_cmp;
use crate::natural::InnerNatural::{Large, Small};
use crate::natural::Natural;
use crate::platform::{DoubleLimb, Limb, BMOD_1_TO_MOD_1_THRESHOLD};
use malachite_base::num::arithmetic::traits::{
DivisibleBy, DivisibleByPowerOf2, EqMod, EqModPowerOf2, Parity, PowerOf2, WrappingAddAssign,
};
use malachite_base::num::basic::integers::PrimitiveInt;
use malachite_base::num::conversion::traits::SplitInHalf;
use malachite_base::num::logic::traits::TrailingZeros;
use malachite_base::slices::slice_trailing_zeros;
use std::cmp::Ordering;
pub_const_test! {limbs_limb_mod_exact_odd_limb(n: Limb, d: Limb, carry: Limb) -> Limb {
if n > carry {
let result = (n - carry) % d;
if result == 0 {
0
} else {
d - result
}
} else {
(carry - n) % d
}
}}
pub_crate_test! {limbs_mod_exact_odd_limb(ns: &[Limb], d: Limb, mut carry: Limb) -> Limb {
let len = ns.len();
if len == 1 {
return limbs_limb_mod_exact_odd_limb(ns[0], d, carry);
}
let d_inv = limbs_modular_invert_limb(d);
let d_double = DoubleLimb::from(d);
let (xs_last, xs_init) = ns.split_last().unwrap();
let xs_last = *xs_last;
for x in xs_init {
let (diff, small_carry) = x.overflowing_sub(carry);
carry = (DoubleLimb::from(diff.wrapping_mul(d_inv)) * d_double).upper_half();
if small_carry {
carry.wrapping_add_assign(1);
}
}
if xs_last <= d {
if carry >= xs_last {
carry - xs_last
} else {
carry.wrapping_add(d - xs_last)
}
} else {
let (diff, small_carry) = xs_last.overflowing_sub(carry);
carry = (DoubleLimb::from(diff.wrapping_mul(d_inv)) * d_double).upper_half();
if small_carry {
carry.wrapping_add_assign(1);
}
carry
}
}}
pub_crate_test! {limbs_eq_limb_mod_limb(xs: &[Limb], y: Limb, m: Limb) -> bool {
assert_ne!(m, 0);
assert!(xs.len() > 1);
let r = if m.even() {
let twos = TrailingZeros::trailing_zeros(m);
if !xs[0].wrapping_sub(y).divisible_by_power_of_2(twos) {
return false;
}
limbs_mod_exact_odd_limb(xs, m >> twos, y)
} else {
limbs_mod_exact_odd_limb(xs, m, y)
};
r == 0 || r == m
}}
#[allow(clippy::absurd_extreme_comparisons)]
fn limbs_eq_limb_mod_helper(xs: &[Limb], y: Limb, ms: &[Limb]) -> Option<bool> {
let m_len = ms.len();
assert!(m_len > 1);
let x_len = xs.len();
assert!(x_len > 1);
assert_ne!(*xs.last().unwrap(), 0);
assert_ne!(y, 0);
assert_ne!(*ms.last().unwrap(), 0);
if m_len > x_len {
return Some(false);
}
let m_0 = ms[0];
let m_0_trailing_zeros = TrailingZeros::trailing_zeros(m_0);
if !xs[0].eq_mod_power_of_2(y, m_0_trailing_zeros) {
return Some(false);
}
if m_len == 2 && m_0 != 0 {
let m_1 = ms[1];
if m_1 < Limb::power_of_2(m_0_trailing_zeros) {
let m_0 = (m_0 >> m_0_trailing_zeros) | (m_1 << (Limb::WIDTH - m_0_trailing_zeros));
return Some(if x_len >= BMOD_1_TO_MOD_1_THRESHOLD {
let r = limbs_mod_limb(xs, m_0);
if y < m_0 {
r == y
} else {
r == y % m_0
}
} else {
let r = limbs_mod_exact_odd_limb(xs, m_0, y);
r == 0 || r == m_0
});
}
}
None
}
pub_test! {limbs_eq_limb_mod_ref_ref(xs: &[Limb], y: Limb, ms: &[Limb]) -> bool {
if let Some(equal) = limbs_eq_limb_mod_helper(xs, y, ms) {
return equal;
}
let mut scratch = vec![0; xs.len()];
assert!(!limbs_sub_limb_to_out(&mut scratch, xs, y));
scratch.truncate(scratch.len() - slice_trailing_zeros(&scratch));
scratch.len() >= ms.len() && limbs_divisible_by_val_ref(&mut scratch, ms)
}}
pub_test! {limbs_eq_limb_mod_ref_val(xs: &[Limb], y: Limb, ms: &mut [Limb]) -> bool {
if let Some(equal) = limbs_eq_limb_mod_helper(xs, y, ms) {
return equal;
}
let mut scratch = vec![0; xs.len()];
assert!(!limbs_sub_limb_to_out(&mut scratch, xs, y));
scratch.truncate(scratch.len() - slice_trailing_zeros(&scratch));
scratch.len() >= ms.len() && limbs_divisible_by(&mut scratch, ms)
}}
pub_test! {limbs_eq_limb_mod_val_ref(xs: &mut [Limb], y: Limb, ms: &[Limb]) -> bool {
if let Some(equal) = limbs_eq_limb_mod_helper(xs, y, ms) {
return equal;
}
assert!(!limbs_sub_limb_in_place(xs, y));
let new_len = xs.len() - slice_trailing_zeros(xs);
new_len >= ms.len() && limbs_divisible_by_val_ref(&mut xs[..new_len], ms)
}}
pub_test! {limbs_eq_limb_mod(xs: &mut [Limb], y: Limb, ms: &mut [Limb]) -> bool {
if let Some(equal) = limbs_eq_limb_mod_helper(xs, y, ms) {
return equal;
}
assert!(!limbs_sub_limb_in_place(xs, y));
let new_len = xs.len() - slice_trailing_zeros(xs);
new_len >= ms.len() && limbs_divisible_by(&mut xs[..new_len], ms)
}}
fn limbs_eq_mod_limb_helper(xs: &[Limb], ys: &[Limb], m: Limb) -> Option<bool> {
let x_len = xs.len();
let y_len = ys.len();
assert!(y_len > 1);
assert!(x_len >= y_len);
assert_ne!(*xs.last().unwrap(), 0);
assert_ne!(*ys.last().unwrap(), 0);
assert_ne!(m, 0);
if xs == ys {
Some(true)
} else if !xs[0].eq_mod_power_of_2(ys[0], u64::from(m.trailing_zeros())) {
Some(false)
} else {
None
}
}
pub_test! {limbs_eq_mod_limb_ref_ref(xs: &[Limb], ys: &[Limb], m: Limb) -> bool {
if xs.len() >= ys.len() {
limbs_eq_mod_limb_ref_ref_greater(xs, ys, m)
} else {
limbs_eq_mod_limb_ref_ref_greater(ys, xs, m)
}
}}
fn limbs_eq_mod_limb_ref_ref_greater(xs: &[Limb], ys: &[Limb], m: Limb) -> bool {
if let Some(equal) = limbs_eq_mod_limb_helper(xs, ys, m) {
return equal;
}
let mut scratch = vec![0; xs.len()];
if limbs_cmp(xs, ys) >= Ordering::Equal {
assert!(!limbs_sub_greater_to_out(&mut scratch, xs, ys));
} else {
assert!(!limbs_sub_same_length_to_out(&mut scratch, ys, xs));
}
scratch.truncate(scratch.len() - slice_trailing_zeros(&scratch));
if scratch.len() == 1 {
scratch[0].divisible_by(m)
} else {
limbs_divisible_by_limb(&scratch, m)
}
}
pub_test! {limbs_eq_mod_limb_ref_val(xs: &[Limb], ys: &mut [Limb], m: Limb) -> bool {
if xs.len() >= ys.len() {
limbs_eq_mod_limb_ref_val_greater(xs, ys, m)
} else {
limbs_eq_mod_limb_val_ref_greater(ys, xs, m)
}
}}
fn limbs_eq_mod_limb_ref_val_greater(xs: &[Limb], ys: &mut [Limb], m: Limb) -> bool {
if let Some(equal) = limbs_eq_mod_limb_helper(xs, ys, m) {
return equal;
}
let mut scratch;
let scratch = if limbs_cmp(xs, ys) >= Ordering::Equal {
scratch = vec![0; xs.len()];
assert!(!limbs_sub_greater_to_out(&mut scratch, xs, ys));
&mut scratch
} else {
assert!(!limbs_sub_same_length_in_place_left(ys, xs));
ys
};
let new_len = scratch.len() - slice_trailing_zeros(scratch);
if new_len == 1 {
scratch[0].divisible_by(m)
} else {
limbs_divisible_by_limb(&scratch[..new_len], m)
}
}
pub_test! {limbs_eq_mod_limb_val_ref(xs: &mut [Limb], ys: &[Limb], m: Limb) -> bool {
if xs.len() >= ys.len() {
limbs_eq_mod_limb_val_ref_greater(xs, ys, m)
} else {
limbs_eq_mod_limb_ref_val_greater(ys, xs, m)
}
}}
fn limbs_eq_mod_limb_val_ref_greater(xs: &mut [Limb], ys: &[Limb], m: Limb) -> bool {
if let Some(equal) = limbs_eq_mod_limb_helper(xs, ys, m) {
return equal;
}
if limbs_cmp(xs, ys) >= Ordering::Equal {
assert!(!limbs_sub_greater_in_place_left(xs, ys));
} else {
assert!(!limbs_sub_same_length_in_place_right(ys, xs));
}
let new_len = xs.len() - slice_trailing_zeros(xs);
if new_len == 1 {
xs[0].divisible_by(m)
} else {
limbs_divisible_by_limb(&xs[..new_len], m)
}
}
fn limbs_eq_mod_helper(xs: &[Limb], ys: &[Limb], m: &[Limb]) -> Option<bool> {
let m_len = m.len();
assert!(m_len > 1);
let x_len = xs.len();
let y_len = ys.len();
assert!(y_len > 1);
assert!(x_len >= y_len);
assert_ne!(*xs.last().unwrap(), 0);
assert_ne!(*ys.last().unwrap(), 0);
assert_ne!(*m.last().unwrap(), 0);
if xs == ys {
Some(true)
} else if m_len > x_len || !xs[0].eq_mod_power_of_2(ys[0], TrailingZeros::trailing_zeros(m[0]))
{
Some(false)
} else {
None
}
}
pub_test! {limbs_eq_mod_ref_ref_ref(xs: &[Limb], ys: &[Limb], ms: &[Limb]) -> bool {
if xs.len() >= ys.len() {
limbs_eq_mod_greater_ref_ref_ref(xs, ys, ms)
} else {
limbs_eq_mod_greater_ref_ref_ref(ys, xs, ms)
}
}}
fn limbs_eq_mod_greater_ref_ref_ref(xs: &[Limb], ys: &[Limb], ms: &[Limb]) -> bool {
if let Some(equal) = limbs_eq_mod_helper(xs, ys, ms) {
return equal;
}
let mut scratch = vec![0; xs.len()];
if limbs_cmp(xs, ys) >= Ordering::Equal {
assert!(!limbs_sub_greater_to_out(&mut scratch, xs, ys));
} else {
assert!(!limbs_sub_same_length_to_out(&mut scratch, ys, xs));
}
scratch.truncate(scratch.len() - slice_trailing_zeros(&scratch));
scratch.len() >= ms.len() && limbs_divisible_by_val_ref(&mut scratch, ms)
}
pub_test! {limbs_eq_mod_ref_ref_val(xs: &[Limb], ys: &[Limb], ms: &mut [Limb]) -> bool {
if xs.len() >= ys.len() {
limbs_eq_mod_greater_ref_ref_val(xs, ys, ms)
} else {
limbs_eq_mod_greater_ref_ref_val(ys, xs, ms)
}
}}
fn limbs_eq_mod_greater_ref_ref_val(xs: &[Limb], ys: &[Limb], ms: &mut [Limb]) -> bool {
if let Some(equal) = limbs_eq_mod_helper(xs, ys, ms) {
return equal;
}
let mut scratch = vec![0; xs.len()];
if limbs_cmp(xs, ys) >= Ordering::Equal {
assert!(!limbs_sub_greater_to_out(&mut scratch, xs, ys));
} else {
assert!(!limbs_sub_same_length_to_out(&mut scratch, ys, xs));
}
scratch.truncate(scratch.len() - slice_trailing_zeros(&scratch));
scratch.len() >= ms.len() && limbs_divisible_by(&mut scratch, ms)
}
pub_test! {limbs_eq_mod_ref_val_ref(xs: &[Limb], ys: &mut [Limb], ms: &[Limb]) -> bool {
if xs.len() >= ys.len() {
limbs_eq_mod_greater_ref_val_ref(xs, ys, ms)
} else {
limbs_eq_mod_greater_val_ref_ref(ys, xs, ms)
}
}}
fn limbs_eq_mod_greater_ref_val_ref(xs: &[Limb], ys: &mut [Limb], ms: &[Limb]) -> bool {
if let Some(equal) = limbs_eq_mod_helper(xs, ys, ms) {
return equal;
}
let mut scratch;
let scratch = if limbs_cmp(xs, ys) >= Ordering::Equal {
scratch = vec![0; xs.len()];
assert!(!limbs_sub_greater_to_out(&mut scratch, xs, ys));
&mut scratch
} else {
assert!(!limbs_sub_same_length_in_place_left(ys, xs));
ys
};
let new_len = scratch.len() - slice_trailing_zeros(scratch);
new_len >= ms.len() && limbs_divisible_by_val_ref(&mut scratch[..new_len], ms)
}
fn limbs_eq_mod_greater_val_ref_ref(xs: &mut [Limb], ys: &[Limb], ms: &[Limb]) -> bool {
if let Some(equal) = limbs_eq_mod_helper(xs, ys, ms) {
return equal;
}
if limbs_cmp(xs, ys) >= Ordering::Equal {
assert!(!limbs_sub_greater_in_place_left(xs, ys));
} else {
assert!(!limbs_sub_same_length_in_place_right(ys, xs));
}
let new_len = xs.len() - slice_trailing_zeros(xs);
new_len >= ms.len() && limbs_divisible_by_val_ref(&mut xs[..new_len], ms)
}
pub_test! {limbs_eq_mod_ref_val_val(xs: &[Limb], ys: &mut [Limb], ms: &mut [Limb]) -> bool {
if xs.len() >= ys.len() {
limbs_eq_mod_greater_ref_val_val(xs, ys, ms)
} else {
limbs_eq_mod_greater_val_ref_val(ys, xs, ms)
}
}}
fn limbs_eq_mod_greater_ref_val_val(xs: &[Limb], ys: &mut [Limb], ms: &mut [Limb]) -> bool {
if let Some(equal) = limbs_eq_mod_helper(xs, ys, ms) {
return equal;
}
let mut scratch;
let scratch = if limbs_cmp(xs, ys) >= Ordering::Equal {
scratch = vec![0; xs.len()];
assert!(!limbs_sub_greater_to_out(&mut scratch, xs, ys));
&mut scratch
} else {
assert!(!limbs_sub_same_length_in_place_left(ys, xs));
ys
};
let new_len = scratch.len() - slice_trailing_zeros(scratch);
new_len >= ms.len() && limbs_divisible_by(&mut scratch[..new_len], ms)
}
fn limbs_eq_mod_greater_val_ref_val(xs: &mut [Limb], ys: &[Limb], ms: &mut [Limb]) -> bool {
if let Some(equal) = limbs_eq_mod_helper(xs, ys, ms) {
return equal;
}
if limbs_cmp(xs, ys) >= Ordering::Equal {
assert!(!limbs_sub_greater_in_place_left(xs, ys));
} else {
assert!(!limbs_sub_same_length_in_place_right(ys, xs));
}
let new_len = xs.len() - slice_trailing_zeros(xs);
new_len >= ms.len() && limbs_divisible_by(&mut xs[..new_len], ms)
}
impl Natural {
fn eq_mod_limb(&self, other: Limb, m: Limb) -> bool {
match *self {
Natural(Small(small)) => small.eq_mod(other, m),
Natural(Large(_)) if m == 0 => false,
Natural(Large(ref limbs)) => limbs_eq_limb_mod_limb(limbs, other, m),
}
}
}
impl EqMod<Natural, Natural> for Natural {
fn eq_mod(self, other: Natural, m: Natural) -> bool {
match (self, other, m) {
(x, y, natural_zero!()) => x == y,
(x, natural_zero!(), m) => x.divisible_by(m),
(natural_zero!(), y, m) => y.divisible_by(m),
(ref x, Natural(Small(y)), Natural(Small(m))) => x.eq_mod_limb(y, m),
(Natural(Small(x)), ref y, Natural(Small(m))) => y.eq_mod_limb(x, m),
(Natural(Small(x)), Natural(Small(y)), _) => x == y,
(Natural(Large(ref mut xs)), Natural(Large(ref ys)), Natural(Small(m))) => {
limbs_eq_mod_limb_val_ref(xs, ys, m)
}
(Natural(Large(ref mut xs)), Natural(Small(y)), Natural(Large(ref mut m))) => {
limbs_eq_limb_mod(xs, y, m)
}
(Natural(Small(x)), Natural(Large(ref mut ys)), Natural(Large(ref mut m))) => {
limbs_eq_limb_mod(ys, x, m)
}
(Natural(Large(ref mut xs)), Natural(Large(ref ys)), Natural(Large(ref mut m))) => {
limbs_eq_mod_ref_val_val(ys, xs, m)
}
}
}
}
impl<'a> EqMod<Natural, &'a Natural> for Natural {
fn eq_mod(self, other: Natural, m: &'a Natural) -> bool {
match (self, other, m) {
(x, y, &natural_zero!()) => x == y,
(x, natural_zero!(), m) => x.divisible_by(m),
(natural_zero!(), y, m) => y.divisible_by(m),
(ref x, Natural(Small(y)), &Natural(Small(m))) => x.eq_mod_limb(y, m),
(Natural(Small(x)), ref y, &Natural(Small(m))) => y.eq_mod_limb(x, m),
(Natural(Small(x)), Natural(Small(y)), _) => x == y,
(Natural(Large(ref mut xs)), Natural(Large(ref ys)), &Natural(Small(m))) => {
limbs_eq_mod_limb_val_ref(xs, ys, m)
}
(Natural(Large(ref mut xs)), Natural(Small(y)), &Natural(Large(ref m))) => {
limbs_eq_limb_mod_val_ref(xs, y, m)
}
(Natural(Small(x)), Natural(Large(ref mut ys)), &Natural(Large(ref m))) => {
limbs_eq_limb_mod_val_ref(ys, x, m)
}
(Natural(Large(ref mut xs)), Natural(Large(ref ys)), &Natural(Large(ref m))) => {
limbs_eq_mod_ref_val_ref(ys, xs, m)
}
}
}
}
impl<'a> EqMod<&'a Natural, Natural> for Natural {
fn eq_mod(self, other: &'a Natural, m: Natural) -> bool {
match (self, other, m) {
(x, y, natural_zero!()) => x == *y,
(x, &natural_zero!(), m) => x.divisible_by(m),
(natural_zero!(), y, m) => y.divisible_by(m),
(ref x, &Natural(Small(y)), Natural(Small(m))) => x.eq_mod_limb(y, m),
(Natural(Small(x)), y, Natural(Small(m))) => y.eq_mod_limb(x, m),
(Natural(Small(x)), &Natural(Small(y)), _) => x == y,
(Natural(Large(ref mut xs)), &Natural(Large(ref ys)), Natural(Small(m))) => {
limbs_eq_mod_limb_val_ref(xs, ys, m)
}
(Natural(Large(ref mut xs)), &Natural(Small(y)), Natural(Large(ref mut m))) => {
limbs_eq_limb_mod(xs, y, m)
}
(Natural(Small(x)), &Natural(Large(ref ys)), Natural(Large(ref mut m))) => {
limbs_eq_limb_mod_ref_val(ys, x, m)
}
(Natural(Large(ref mut xs)), &Natural(Large(ref ys)), Natural(Large(ref mut m))) => {
limbs_eq_mod_ref_val_val(ys, xs, m)
}
}
}
}
impl<'a, 'b> EqMod<&'a Natural, &'b Natural> for Natural {
fn eq_mod(self, other: &'a Natural, m: &'b Natural) -> bool {
match (self, other, m) {
(x, y, &natural_zero!()) => x == *y,
(x, &natural_zero!(), m) => x.divisible_by(m),
(natural_zero!(), y, m) => y.divisible_by(m),
(ref x, &Natural(Small(y)), &Natural(Small(m))) => x.eq_mod_limb(y, m),
(Natural(Small(x)), y, &Natural(Small(m))) => y.eq_mod_limb(x, m),
(Natural(Small(x)), &Natural(Small(y)), _) => x == y,
(Natural(Large(ref mut xs)), &Natural(Large(ref ys)), &Natural(Small(m))) => {
limbs_eq_mod_limb_val_ref(xs, ys, m)
}
(Natural(Large(ref mut xs)), &Natural(Small(y)), &Natural(Large(ref m))) => {
limbs_eq_limb_mod_val_ref(xs, y, m)
}
(Natural(Small(x)), &Natural(Large(ref ys)), &Natural(Large(ref m))) => {
limbs_eq_limb_mod_ref_ref(ys, x, m)
}
(Natural(Large(ref mut xs)), &Natural(Large(ref ys)), &Natural(Large(ref m))) => {
limbs_eq_mod_ref_val_ref(ys, xs, m)
}
}
}
}
impl<'a> EqMod<Natural, Natural> for &'a Natural {
fn eq_mod(self, other: Natural, m: Natural) -> bool {
match (self, other, m) {
(x, y, natural_zero!()) => *x == y,
(x, natural_zero!(), m) => x.divisible_by(m),
(&natural_zero!(), y, m) => y.divisible_by(m),
(x, Natural(Small(y)), Natural(Small(m))) => x.eq_mod_limb(y, m),
(&Natural(Small(x)), ref y, Natural(Small(m))) => y.eq_mod_limb(x, m),
(&Natural(Small(x)), Natural(Small(y)), _) => x == y,
(&Natural(Large(ref xs)), Natural(Large(ref mut ys)), Natural(Small(m))) => {
limbs_eq_mod_limb_ref_val(xs, ys, m)
}
(&Natural(Large(ref xs)), Natural(Small(y)), Natural(Large(ref mut m))) => {
limbs_eq_limb_mod_ref_val(xs, y, m)
}
(&Natural(Small(x)), Natural(Large(ref mut ys)), Natural(Large(ref mut m))) => {
limbs_eq_limb_mod(ys, x, m)
}
(&Natural(Large(ref xs)), Natural(Large(ref mut ys)), Natural(Large(ref mut m))) => {
limbs_eq_mod_ref_val_val(xs, ys, m)
}
}
}
}
impl<'a, 'b> EqMod<Natural, &'b Natural> for &'a Natural {
fn eq_mod(self, other: Natural, m: &'b Natural) -> bool {
match (self, other, m) {
(x, y, &natural_zero!()) => *x == y,
(x, natural_zero!(), m) => x.divisible_by(m),
(&natural_zero!(), y, m) => y.divisible_by(m),
(x, Natural(Small(y)), &Natural(Small(m))) => x.eq_mod_limb(y, m),
(&Natural(Small(x)), ref y, &Natural(Small(m))) => y.eq_mod_limb(x, m),
(&Natural(Small(x)), Natural(Small(y)), _) => x == y,
(&Natural(Large(ref xs)), Natural(Large(ref mut ys)), &Natural(Small(m))) => {
limbs_eq_mod_limb_ref_val(xs, ys, m)
}
(&Natural(Large(ref xs)), Natural(Small(y)), &Natural(Large(ref m))) => {
limbs_eq_limb_mod_ref_ref(xs, y, m)
}
(&Natural(Small(x)), Natural(Large(ref mut ys)), &Natural(Large(ref m))) => {
limbs_eq_limb_mod_val_ref(ys, x, m)
}
(&Natural(Large(ref xs)), Natural(Large(ref mut ys)), &Natural(Large(ref m))) => {
limbs_eq_mod_ref_val_ref(xs, ys, m)
}
}
}
}
impl<'a, 'b> EqMod<&'b Natural, Natural> for &'a Natural {
fn eq_mod(self, other: &'b Natural, m: Natural) -> bool {
match (self, other, m) {
(x, y, natural_zero!()) => x == y,
(x, &natural_zero!(), m) => x.divisible_by(m),
(&natural_zero!(), y, m) => y.divisible_by(m),
(x, &Natural(Small(y)), Natural(Small(m))) => x.eq_mod_limb(y, m),
(&Natural(Small(x)), y, Natural(Small(m))) => y.eq_mod_limb(x, m),
(&Natural(Small(x)), &Natural(Small(y)), _) => x == y,
(&Natural(Large(ref xs)), &Natural(Large(ref ys)), Natural(Small(m))) => {
limbs_eq_mod_limb_ref_ref(xs, ys, m)
}
(&Natural(Large(ref xs)), &Natural(Small(y)), Natural(Large(ref mut m))) => {
limbs_eq_limb_mod_ref_val(xs, y, m)
}
(&Natural(Small(x)), &Natural(Large(ref ys)), Natural(Large(ref mut m))) => {
limbs_eq_limb_mod_ref_val(ys, x, m)
}
(&Natural(Large(ref xs)), &Natural(Large(ref ys)), Natural(Large(ref mut m))) => {
limbs_eq_mod_ref_ref_val(xs, ys, m)
}
}
}
}
impl<'a, 'b, 'c> EqMod<&'b Natural, &'c Natural> for &'a Natural {
fn eq_mod(self, other: &'b Natural, m: &'c Natural) -> bool {
match (self, other, m) {
(x, y, &natural_zero!()) => x == y,
(x, &natural_zero!(), m) => x.divisible_by(m),
(&natural_zero!(), y, m) => y.divisible_by(m),
(x, &Natural(Small(y)), &Natural(Small(m))) => x.eq_mod_limb(y, m),
(&Natural(Small(x)), y, &Natural(Small(m))) => y.eq_mod_limb(x, m),
(&Natural(Small(x)), &Natural(Small(y)), _) => x == y,
(&Natural(Large(ref xs)), &Natural(Large(ref ys)), &Natural(Small(m))) => {
limbs_eq_mod_limb_ref_ref(xs, ys, m)
}
(&Natural(Large(ref xs)), &Natural(Small(y)), &Natural(Large(ref m))) => {
limbs_eq_limb_mod_ref_ref(xs, y, m)
}
(&Natural(Small(x)), &Natural(Large(ref ys)), &Natural(Large(ref m))) => {
limbs_eq_limb_mod_ref_ref(ys, x, m)
}
(&Natural(Large(ref xs)), &Natural(Large(ref ys)), &Natural(Large(ref m))) => {
limbs_eq_mod_ref_ref_ref(xs, ys, m)
}
}
}
}