#![cfg(feature = "int")]
use puremp::random::SeedRng;
use puremp::{Int, ModInt, Nat};
fn m(v: i64, modulus: i64) -> ModInt {
ModInt::new(Int::from(v), Int::from(modulus))
}
#[test]
fn modular_operators() {
let a = m(5, 7);
let b = m(4, 7);
assert_eq!((&a + &b).to_int().to_string(), "2"); assert_eq!((&a - &b).to_int().to_string(), "1");
assert_eq!((&b - &a).to_int().to_string(), "6"); assert_eq!((&a * &b).to_int().to_string(), "6"); assert_eq!((-a.clone()).to_int().to_string(), "2");
assert_eq!(m(3, 7).inv().unwrap().to_int().to_string(), "5"); assert!(m(2, 6).inv().is_none()); assert_eq!((&a / &b).to_int(), (&a * &b.inv().unwrap()).to_int());
let p = Int::from(1000000007);
let g = ModInt::new(Int::from(123456), p.clone());
assert!(g.pow(&p.sub(&Int::ONE)).to_int().is_one()); assert_eq!(g.pow(&Int::from(-1)), g.inv().unwrap());
let x = m(2, 97);
let y = x.of(Int::from(50));
assert_eq!((&x * &y).to_int().to_string(), "3");
let mut z = m(10, 13);
z *= m(10, 13);
assert_eq!(z, m(9, 13)); assert_eq!(m(20, 13), m(7, 13));
}
#[test]
fn differential_vs_int_reference() {
let mut rng = SeedRng::new(0x0DDE_AE45_1234_5678);
let refmod = |v: &Int, m: &Int| v.rem_euclid(m);
for &bits in &[8u64, 32, 64, 96, 200, 300, 512, 1200] {
for trial in 0..40 {
let base = Int::from(Nat::random_bits(bits.max(2), &mut rng)) + Int::from(2);
for parity_even in [false, true] {
let m = if parity_even {
&base - (&base % &Int::from(2)) } else {
let e = &base - (&base % &Int::from(2));
&e + Int::from(1) };
if m < Int::from(2) {
continue;
}
let a_int = Int::from(Nat::random_bits(bits + 16, &mut rng));
let b_int = Int::from(Nat::random_bits(bits + 16, &mut rng));
let a = ModInt::new(a_int.clone(), m.clone());
let b = ModInt::new(b_int.clone(), m.clone());
assert_eq!((&a + &b).to_int(), refmod(&(&a_int + &b_int), &m));
assert_eq!((&a - &b).to_int(), refmod(&(&a_int - &b_int), &m));
assert_eq!((&b - &a).to_int(), refmod(&(&b_int - &a_int), &m));
assert_eq!((&a * &b).to_int(), refmod(&(&a_int * &b_int), &m));
assert_eq!((-a.clone()).to_int(), refmod(&(-&a_int), &m));
assert_eq!(Int::from(a.residue()), a.to_int());
assert_eq!(a.to_string(), a.to_int().to_string());
let e = Int::from(Nat::random_bits(24, &mut rng));
assert_eq!(a.pow(&e).to_int(), a_int.modpow(&e, &m));
match a.inv() {
Some(ai) => {
assert_eq!(Some(ai.to_int()), a_int.modinv(&m));
assert_eq!((&a * &ai).to_int(), refmod(&Int::ONE, &m));
assert_eq!((&b / &a).to_int(), (&b * &ai).to_int());
}
None => assert!(a_int.modinv(&m).is_none()),
}
let _ = trial;
}
}
}
}