malachite-nz 0.3.2

The bignum types Natural and Integer, with efficient algorithms partially derived from GMP and FLINT
Documentation
use malachite_base::num::arithmetic::traits::{
    CeilingDivMod, CeilingMod, CeilingModAssign, DivMod, DivRem, Mod, ModAssign, NegMod,
};
use malachite_base::num::basic::integers::PrimitiveInt;
use malachite_base::num::basic::traits::{NegativeOne, One, Zero};
use malachite_base::num::comparison::traits::PartialOrdAbs;
use malachite_base::test_util::generators::common::GenConfig;
use malachite_base::test_util::generators::signed_pair_gen_var_4;
use malachite_nz::integer::Integer;
use malachite_nz::platform::{Limb, SignedLimb};
use malachite_nz::test_util::generators::{
    integer_gen, integer_gen_var_8, integer_pair_gen_var_1, integer_pair_gen_var_2,
    natural_pair_gen_var_5,
};
use num::{BigInt, Integer as NumInteger};
use rug::ops::RemRounding;
use std::str::FromStr;

#[test]
fn test_mod() {
    let test = |s, t, remainder| {
        let u = Integer::from_str(s).unwrap();
        let v = Integer::from_str(t).unwrap();

        let mut x = u.clone();
        x.mod_assign(v.clone());
        assert!(x.is_valid());
        assert_eq!(x.to_string(), remainder);

        let mut x = u.clone();
        x.mod_assign(&v);
        assert!(x.is_valid());
        assert_eq!(x.to_string(), remainder);

        let r = u.clone().mod_op(v.clone());
        assert!(r.is_valid());
        assert_eq!(r.to_string(), remainder);

        let r = u.clone().mod_op(&v);
        assert!(r.is_valid());
        assert_eq!(r.to_string(), remainder);

        let r = (&u).mod_op(v.clone());
        assert!(r.is_valid());
        assert_eq!(r.to_string(), remainder);

        let r = (&u).mod_op(&v);
        assert!(r.is_valid());
        assert_eq!(r.to_string(), remainder);

        let r = BigInt::from_str(s)
            .unwrap()
            .mod_floor(&BigInt::from_str(t).unwrap());
        assert_eq!(r.to_string(), remainder);

        let r = rug::Integer::from_str(s)
            .unwrap()
            .rem_floor(rug::Integer::from_str(t).unwrap());
        assert_eq!(r.to_string(), remainder);

        assert_eq!(u.div_mod(v).1.to_string(), remainder);
    };
    test("0", "1", "0");
    test("0", "123", "0");
    test("1", "1", "0");
    test("123", "1", "0");
    test("123", "123", "0");
    test("123", "456", "123");
    test("456", "123", "87");
    test("4294967295", "4294967295", "0");
    test("4294967295", "4294967295", "0");
    test("1000000000000", "1", "0");
    test("1000000000000", "3", "1");
    test("1000000000000", "123", "100");
    test("1000000000000", "4294967295", "3567587560");
    test("1000000000000000000000000", "1", "0");
    test("1000000000000000000000000", "3", "1");
    test("1000000000000000000000000", "123", "37");
    test("1000000000000000000000000", "4294967295", "3167723695");
    test("1000000000000000000000000", "1234567890987", "530068894399");
    test(
        "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
        0",
        "1234567890987654321234567890987654321",
        "779655053998040854338961591319296066",
    );
    test(
        "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
        0",
        "316049380092839506236049380092839506176",
        "37816691783627670491375998320948925696",
    );
    test(
        "253640751230376270397812803167",
        "2669936877441",
        "1520301762334",
    );
    test(
        "3768477692975601",
        "11447376614057827956",
        "3768477692975601",
    );
    test("3356605361737854", "3081095617839357", "275509743898497");
    test(
        "1098730198198174614195",
        "953382298040157850476",
        "145347900158016763719",
    );
    test(
        "69738658860594537152875081748",
        "69738658860594537152875081748",
        "0",
    );
    test(
        "1000000000000000000000000",
        "1000000000000000000000000",
        "0",
    );
    test("0", "1000000000000000000000000", "0");
    test("123", "1000000000000000000000000", "123");

    test("0", "-1", "0");
    test("0", "-123", "0");
    test("1", "-1", "0");
    test("123", "-1", "0");
    test("123", "-123", "0");
    test("123", "-456", "-333");
    test("456", "-123", "-36");
    test("4294967295", "-1", "0");
    test("4294967295", "-4294967295", "0");
    test("1000000000000", "-1", "0");
    test("1000000000000", "-3", "-2");
    test("1000000000000", "-123", "-23");
    test("1000000000000", "-4294967295", "-727379735");
    test("1000000000000000000000000", "-1", "0");
    test("1000000000000000000000000", "-3", "-2");
    test("1000000000000000000000000", "-123", "-86");
    test("1000000000000000000000000", "-4294967295", "-1127243600");
    test(
        "1000000000000000000000000",
        "-1234567890987",
        "-704498996588",
    );
    test(
        "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
         0",
        "-1234567890987654321234567890987654321",
        "-454912836989613466895606299668358255",
    );
    test(
        "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
         0",
        "-316049380092839506236049380092839506176",
        "-278232688309211835744673381771890580480",
    );
    test(
        "253640751230376270397812803167",
        "-2669936877441",
        "-1149635115107",
    );
    test(
        "3768477692975601",
        "-11447376614057827956",
        "-11443608136364852355",
    );
    test("3356605361737854", "-3081095617839357", "-2805585873940860");
    test(
        "1098730198198174614195",
        "-953382298040157850476",
        "-808034397882141086757",
    );
    test(
        "69738658860594537152875081748",
        "-69738658860594537152875081748",
        "0",
    );
    test(
        "1000000000000000000000000",
        "-1000000000000000000000000",
        "0",
    );
    test("0", "-1000000000000000000000000", "0");
    test(
        "123",
        "-1000000000000000000000000",
        "-999999999999999999999877",
    );

    test("-1", "1", "0");
    test("-123", "1", "0");
    test("-123", "123", "0");
    test("-123", "456", "333");
    test("-456", "123", "36");
    test("-4294967295", "-1", "0");
    test("-4294967295", "4294967295", "0");
    test("-1000000000000", "1", "0");
    test("-1000000000000", "3", "2");
    test("-1000000000000", "123", "23");
    test("-1000000000000", "4294967295", "727379735");
    test("-1000000000000000000000000", "1", "0");
    test("-1000000000000000000000000", "3", "2");
    test("-1000000000000000000000000", "123", "86");
    test("-1000000000000000000000000", "4294967295", "1127243600");
    test(
        "-1000000000000000000000000",
        "1234567890987",
        "704498996588",
    );
    test(
        "-10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
         00",
        "1234567890987654321234567890987654321",
        "454912836989613466895606299668358255",
    );
    test(
        "-10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
         00",
        "316049380092839506236049380092839506176",
        "278232688309211835744673381771890580480",
    );
    test(
        "-253640751230376270397812803167",
        "2669936877441",
        "1149635115107",
    );
    test(
        "-3768477692975601",
        "11447376614057827956",
        "11443608136364852355",
    );
    test("-3356605361737854", "3081095617839357", "2805585873940860");
    test(
        "-1098730198198174614195",
        "953382298040157850476",
        "808034397882141086757",
    );
    test(
        "-69738658860594537152875081748",
        "69738658860594537152875081748",
        "0",
    );
    test(
        "-1000000000000000000000000",
        "1000000000000000000000000",
        "0",
    );
    test(
        "-123",
        "1000000000000000000000000",
        "999999999999999999999877",
    );

    test("-1", "-1", "0");
    test("-123", "-1", "0");
    test("-123", "-123", "0");
    test("-123", "-456", "-123");
    test("-456", "-123", "-87");
    test("-4294967295", "-1", "0");
    test("-4294967295", "-4294967295", "0");
    test("-1000000000000", "-1", "0");
    test("-1000000000000", "-3", "-1");
    test("-1000000000000", "-123", "-100");
    test("-1000000000000", "-4294967295", "-3567587560");
    test("-1000000000000000000000000", "-1", "0");
    test("-1000000000000000000000000", "-3", "-1");
    test("-1000000000000000000000000", "-123", "-37");
    test("-1000000000000000000000000", "-4294967295", "-3167723695");
    test(
        "-1000000000000000000000000",
        "-1234567890987",
        "-530068894399",
    );
    test(
        "-10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
        00",
        "-1234567890987654321234567890987654321",
        "-779655053998040854338961591319296066",
    );
    test(
        "-10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
        00",
        "-316049380092839506236049380092839506176",
        "-37816691783627670491375998320948925696",
    );
    test(
        "-253640751230376270397812803167",
        "-2669936877441",
        "-1520301762334",
    );
    test(
        "-3768477692975601",
        "-11447376614057827956",
        "-3768477692975601",
    );
    test("-3356605361737854", "-3081095617839357", "-275509743898497");
    test(
        "-1098730198198174614195",
        "-953382298040157850476",
        "-145347900158016763719",
    );
    test(
        "-69738658860594537152875081748",
        "-69738658860594537152875081748",
        "0",
    );
    test(
        "-1000000000000000000000000",
        "-1000000000000000000000000",
        "0",
    );
    test("-123", "-1000000000000000000000000", "-123");
}

#[test]
#[should_panic]
fn mod_assign_fail() {
    Integer::from(10).mod_assign(Integer::ZERO);
}

#[test]
#[should_panic]
fn mod_assign_ref_fail() {
    Integer::from(10).mod_assign(&Integer::ZERO);
}

#[test]
#[should_panic]
fn mod_fail() {
    Integer::from(10).mod_op(Integer::ZERO);
}

#[test]
#[should_panic]
fn mod_val_ref_fail() {
    Integer::from(10).mod_op(&Integer::ZERO);
}

#[test]
#[should_panic]
fn mod_ref_val_fail() {
    (&Integer::from(10)).mod_op(Integer::ZERO);
}

#[test]
#[should_panic]
fn mod_ref_ref_fail() {
    (&Integer::from(10)).mod_op(&Integer::ZERO);
}

#[test]
fn test_rem() {
    let test = |s, t, remainder| {
        let u = Integer::from_str(s).unwrap();
        let v = Integer::from_str(t).unwrap();

        let mut x = u.clone();
        x %= v.clone();
        assert!(x.is_valid());
        assert_eq!(x.to_string(), remainder);

        let mut x = u.clone();
        x %= &v;
        assert!(x.is_valid());
        assert_eq!(x.to_string(), remainder);

        let r = u.clone() % v.clone();
        assert!(r.is_valid());
        assert_eq!(r.to_string(), remainder);

        let r = u.clone() % &v;
        assert!(r.is_valid());
        assert_eq!(r.to_string(), remainder);

        let r = &u % v.clone();
        assert!(r.is_valid());
        assert_eq!(r.to_string(), remainder);

        let r = &u % &v;
        assert!(r.is_valid());
        assert_eq!(r.to_string(), remainder);

        let r = BigInt::from_str(s).unwrap() % &BigInt::from_str(t).unwrap();
        assert_eq!(r.to_string(), remainder);

        let r = rug::Integer::from_str(s).unwrap() % rug::Integer::from_str(t).unwrap();
        assert_eq!(r.to_string(), remainder);

        assert_eq!(u.div_rem(v).1.to_string(), remainder);
    };
    test("0", "1", "0");
    test("0", "123", "0");
    test("1", "1", "0");
    test("123", "1", "0");
    test("123", "123", "0");
    test("123", "456", "123");
    test("456", "123", "87");
    test("4294967295", "1", "0");
    test("4294967295", "4294967295", "0");
    test("1000000000000", "1", "0");
    test("1000000000000", "3", "1");
    test("1000000000000", "123", "100");
    test("1000000000000", "4294967295", "3567587560");
    test("1000000000000000000000000", "1", "0");
    test("1000000000000000000000000", "3", "1");
    test("1000000000000000000000000", "123", "37");
    test("1000000000000000000000000", "4294967295", "3167723695");
    test("1000000000000000000000000", "1234567890987", "530068894399");
    test(
        "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
        0",
        "1234567890987654321234567890987654321",
        "779655053998040854338961591319296066",
    );
    test(
        "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
        0",
        "316049380092839506236049380092839506176",
        "37816691783627670491375998320948925696",
    );
    test(
        "253640751230376270397812803167",
        "2669936877441",
        "1520301762334",
    );
    test(
        "3768477692975601",
        "11447376614057827956",
        "3768477692975601",
    );
    test("3356605361737854", "3081095617839357", "275509743898497");
    test(
        "1098730198198174614195",
        "953382298040157850476",
        "145347900158016763719",
    );
    test(
        "69738658860594537152875081748",
        "69738658860594537152875081748",
        "0",
    );
    test(
        "1000000000000000000000000",
        "1000000000000000000000000",
        "0",
    );
    test("0", "1000000000000000000000000", "0");
    test("123", "1000000000000000000000000", "123");

    test("0", "-1", "0");
    test("0", "-123", "0");
    test("1", "-1", "0");
    test("123", "-1", "0");
    test("123", "-123", "0");
    test("123", "-456", "123");
    test("456", "-123", "87");
    test("4294967295", "-1", "0");
    test("4294967295", "-4294967295", "0");
    test("1000000000000", "-1", "0");
    test("1000000000000", "-3", "1");
    test("1000000000000", "-123", "100");
    test("1000000000000", "-4294967295", "3567587560");
    test("1000000000000000000000000", "-1", "0");
    test("1000000000000000000000000", "-3", "1");
    test("1000000000000000000000000", "-123", "37");
    test("1000000000000000000000000", "-4294967295", "3167723695");
    test(
        "1000000000000000000000000",
        "-1234567890987",
        "530068894399",
    );
    test(
        "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
        0",
        "-1234567890987654321234567890987654321",
        "779655053998040854338961591319296066",
    );
    test(
        "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
        0",
        "-316049380092839506236049380092839506176",
        "37816691783627670491375998320948925696",
    );
    test(
        "253640751230376270397812803167",
        "-2669936877441",
        "1520301762334",
    );
    test(
        "3768477692975601",
        "-11447376614057827956",
        "3768477692975601",
    );
    test("3356605361737854", "-3081095617839357", "275509743898497");
    test(
        "1098730198198174614195",
        "-953382298040157850476",
        "145347900158016763719",
    );
    test(
        "69738658860594537152875081748",
        "-69738658860594537152875081748",
        "0",
    );
    test(
        "1000000000000000000000000",
        "-1000000000000000000000000",
        "0",
    );
    test("0", "-1000000000000000000000000", "0");
    test("123", "-1000000000000000000000000", "123");

    test("-1", "1", "0");
    test("-123", "1", "0");
    test("-123", "123", "0");
    test("-123", "456", "-123");
    test("-456", "123", "-87");
    test("-4294967295", "1", "0");
    test("-4294967295", "4294967295", "0");
    test("-1000000000000", "1", "0");
    test("-1000000000000", "3", "-1");
    test("-1000000000000", "123", "-100");
    test("-1000000000000", "4294967295", "-3567587560");
    test("-1000000000000000000000000", "1", "0");
    test("-1000000000000000000000000", "3", "-1");
    test("-1000000000000000000000000", "123", "-37");
    test("-1000000000000000000000000", "4294967295", "-3167723695");
    test(
        "-1000000000000000000000000",
        "1234567890987",
        "-530068894399",
    );
    test(
        "-10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
        00",
        "1234567890987654321234567890987654321",
        "-779655053998040854338961591319296066",
    );
    test(
        "-10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
        00",
        "316049380092839506236049380092839506176",
        "-37816691783627670491375998320948925696",
    );
    test(
        "-253640751230376270397812803167",
        "2669936877441",
        "-1520301762334",
    );
    test(
        "-3768477692975601",
        "11447376614057827956",
        "-3768477692975601",
    );
    test("-3356605361737854", "3081095617839357", "-275509743898497");
    test(
        "-1098730198198174614195",
        "953382298040157850476",
        "-145347900158016763719",
    );
    test(
        "-69738658860594537152875081748",
        "69738658860594537152875081748",
        "0",
    );
    test(
        "-1000000000000000000000000",
        "1000000000000000000000000",
        "0",
    );
    test("-123", "1000000000000000000000000", "-123");

    test("-1", "-1", "0");
    test("-123", "-1", "0");
    test("-123", "-123", "0");
    test("-123", "-456", "-123");
    test("-456", "-123", "-87");
    test("-4294967295", "-1", "0");
    test("-4294967295", "-4294967295", "0");
    test("-1000000000000", "-1", "0");
    test("-1000000000000", "-3", "-1");
    test("-1000000000000", "-123", "-100");
    test("-1000000000000", "-4294967295", "-3567587560");
    test("-1000000000000000000000000", "-1", "0");
    test("-1000000000000000000000000", "-3", "-1");
    test("-1000000000000000000000000", "-123", "-37");
    test("-1000000000000000000000000", "-4294967295", "-3167723695");
    test(
        "-1000000000000000000000000",
        "-1234567890987",
        "-530068894399",
    );
    test(
        "-10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
        00",
        "-1234567890987654321234567890987654321",
        "-779655053998040854338961591319296066",
    );
    test(
        "-10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
        00",
        "-316049380092839506236049380092839506176",
        "-37816691783627670491375998320948925696",
    );
    test(
        "-253640751230376270397812803167",
        "-2669936877441",
        "-1520301762334",
    );
    test(
        "-3768477692975601",
        "-11447376614057827956",
        "-3768477692975601",
    );
    test("-3356605361737854", "-3081095617839357", "-275509743898497");
    test(
        "-1098730198198174614195",
        "-953382298040157850476",
        "-145347900158016763719",
    );
    test(
        "-69738658860594537152875081748",
        "-69738658860594537152875081748",
        "0",
    );
    test(
        "-1000000000000000000000000",
        "-1000000000000000000000000",
        "0",
    );
    test("-123", "-1000000000000000000000000", "-123");
}

#[test]
#[should_panic]
fn rem_assign_fail() {
    let mut x = Integer::from(10);
    x %= Integer::ZERO;
}

#[test]
#[should_panic]
fn rem_assign_ref_fail() {
    let mut x = Integer::from(10);
    x %= &Integer::ZERO;
}

#[test]
#[should_panic]
#[allow(unused_must_use, clippy::unnecessary_operation)]
fn rem_fail() {
    Integer::from(10) % Integer::ZERO;
}

#[test]
#[should_panic]
#[allow(unused_must_use, clippy::unnecessary_operation)]
fn rem_val_ref_fail() {
    Integer::from(10) % &Integer::ZERO;
}

#[test]
#[should_panic]
#[allow(unused_must_use, clippy::unnecessary_operation)]
fn rem_ref_val_fail() {
    &Integer::from(10) % Integer::ZERO;
}

#[test]
#[should_panic]
#[allow(unused_must_use, clippy::unnecessary_operation)]
fn rem_ref_ref_fail() {
    &Integer::from(10) % &Integer::ZERO;
}

#[test]
fn test_ceiling_mod() {
    let test = |s, t, remainder| {
        let u = Integer::from_str(s).unwrap();
        let v = Integer::from_str(t).unwrap();

        let mut x = u.clone();
        x.ceiling_mod_assign(v.clone());
        assert!(x.is_valid());
        assert_eq!(x.to_string(), remainder);

        let mut x = u.clone();
        x.ceiling_mod_assign(&v);
        assert!(x.is_valid());
        assert_eq!(x.to_string(), remainder);

        let r = u.clone().ceiling_mod(v.clone());
        assert!(r.is_valid());
        assert_eq!(r.to_string(), remainder);

        let r = u.clone().ceiling_mod(&v);
        assert!(r.is_valid());
        assert_eq!(r.to_string(), remainder);

        let r = (&u).ceiling_mod(v.clone());
        assert!(r.is_valid());
        assert_eq!(r.to_string(), remainder);

        let r = (&u).ceiling_mod(&v);
        assert!(r.is_valid());
        assert_eq!(r.to_string(), remainder);

        let r = rug::Integer::from_str(s)
            .unwrap()
            .rem_ceil(rug::Integer::from_str(t).unwrap());
        assert_eq!(r.to_string(), remainder);

        assert_eq!(u.ceiling_div_mod(v).1.to_string(), remainder);
    };
    test("0", "1", "0");
    test("0", "123", "0");
    test("1", "1", "0");
    test("123", "1", "0");
    test("123", "123", "0");
    test("123", "456", "-333");
    test("456", "123", "-36");
    test("4294967295", "1", "0");
    test("4294967295", "4294967295", "0");
    test("1000000000000", "1", "0");
    test("1000000000000", "3", "-2");
    test("1000000000000", "123", "-23");
    test("1000000000000", "4294967295", "-727379735");
    test("1000000000000000000000000", "1", "0");
    test("1000000000000000000000000", "3", "-2");
    test("1000000000000000000000000", "123", "-86");
    test("1000000000000000000000000", "4294967295", "-1127243600");
    test(
        "1000000000000000000000000",
        "1234567890987",
        "-704498996588",
    );
    test(
        "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
         00",
        "1234567890987654321234567890987654321",
        "-454912836989613466895606299668358255",
    );
    test(
        "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
         00",
        "316049380092839506236049380092839506176",
        "-278232688309211835744673381771890580480",
    );
    test(
        "253640751230376270397812803167",
        "2669936877441",
        "-1149635115107",
    );
    test(
        "3768477692975601",
        "11447376614057827956",
        "-11443608136364852355",
    );
    test("3356605361737854", "3081095617839357", "-2805585873940860");
    test(
        "1098730198198174614195",
        "953382298040157850476",
        "-808034397882141086757",
    );
    test(
        "69738658860594537152875081748",
        "69738658860594537152875081748",
        "0",
    );
    test(
        "1000000000000000000000000",
        "1000000000000000000000000",
        "0",
    );
    test("0", "1000000000000000000000000", "0");
    test(
        "123",
        "1000000000000000000000000",
        "-999999999999999999999877",
    );

    test("0", "-1", "0");
    test("0", "-123", "0");
    test("1", "-1", "0");
    test("123", "-1", "0");
    test("123", "-123", "0");
    test("123", "-456", "123");
    test("456", "-123", "87");
    test("4294967295", "-1", "0");
    test("4294967295", "-4294967295", "0");
    test("1000000000000", "-1", "0");
    test("1000000000000", "-3", "1");
    test("1000000000000", "-123", "100");
    test("1000000000000", "-4294967295", "3567587560");
    test("1000000000000000000000000", "-1", "0");
    test("1000000000000000000000000", "-3", "1");
    test("1000000000000000000000000", "-123", "37");
    test("1000000000000000000000000", "-4294967295", "3167723695");
    test(
        "1000000000000000000000000",
        "-1234567890987",
        "530068894399",
    );
    test(
        "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
        0",
        "-1234567890987654321234567890987654321",
        "779655053998040854338961591319296066",
    );
    test(
        "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
        0",
        "-316049380092839506236049380092839506176",
        "37816691783627670491375998320948925696",
    );
    test(
        "253640751230376270397812803167",
        "-2669936877441",
        "1520301762334",
    );
    test(
        "3768477692975601",
        "-11447376614057827956",
        "3768477692975601",
    );
    test("3356605361737854", "-3081095617839357", "275509743898497");
    test(
        "1098730198198174614195",
        "-953382298040157850476",
        "145347900158016763719",
    );
    test(
        "69738658860594537152875081748",
        "-69738658860594537152875081748",
        "0",
    );
    test(
        "1000000000000000000000000",
        "-1000000000000000000000000",
        "0",
    );
    test("0", "-1000000000000000000000000", "0");
    test("123", "-1000000000000000000000000", "123");

    test("-1", "1", "0");
    test("-123", "1", "0");
    test("-123", "123", "0");
    test("-123", "456", "-123");
    test("-456", "123", "-87");
    test("-4294967295", "1", "0");
    test("-4294967295", "4294967295", "0");
    test("-1000000000000", "1", "0");
    test("-1000000000000", "3", "-1");
    test("-1000000000000", "123", "-100");
    test("-1000000000000", "4294967295", "-3567587560");
    test("-1000000000000000000000000", "1", "0");
    test("-1000000000000000000000000", "3", "-1");
    test("-1000000000000000000000000", "123", "-37");
    test("-1000000000000000000000000", "4294967295", "-3167723695");
    test(
        "-1000000000000000000000000",
        "1234567890987",
        "-530068894399",
    );
    test(
        "-10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
        00",
        "1234567890987654321234567890987654321",
        "-779655053998040854338961591319296066",
    );
    test(
        "-10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
        00",
        "316049380092839506236049380092839506176",
        "-37816691783627670491375998320948925696",
    );
    test(
        "-253640751230376270397812803167",
        "2669936877441",
        "-1520301762334",
    );
    test(
        "-3768477692975601",
        "11447376614057827956",
        "-3768477692975601",
    );
    test("-3356605361737854", "3081095617839357", "-275509743898497");
    test(
        "-1098730198198174614195",
        "953382298040157850476",
        "-145347900158016763719",
    );
    test(
        "-69738658860594537152875081748",
        "69738658860594537152875081748",
        "0",
    );
    test(
        "-1000000000000000000000000",
        "1000000000000000000000000",
        "0",
    );
    test("0", "1000000000000000000000000", "0");
    test("-123", "1000000000000000000000000", "-123");

    test("-1", "-1", "0");
    test("-123", "-1", "0");
    test("-123", "-123", "0");
    test("-123", "-456", "333");
    test("-456", "-123", "36");
    test("-4294967295", "-1", "0");
    test("-4294967295", "-4294967295", "0");
    test("-1000000000000", "-1", "0");
    test("-1000000000000", "-3", "2");
    test("-1000000000000", "-123", "23");
    test("-1000000000000", "-4294967295", "727379735");
    test("-1000000000000000000000000", "-1", "0");
    test("-1000000000000000000000000", "-3", "2");
    test("-1000000000000000000000000", "-123", "86");
    test("-1000000000000000000000000", "-4294967295", "1127243600");
    test(
        "-1000000000000000000000000",
        "-1234567890987",
        "704498996588",
    );
    test(
        "-10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
         00",
        "-1234567890987654321234567890987654321",
        "454912836989613466895606299668358255",
    );
    test(
        "-10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\
         00",
        "-316049380092839506236049380092839506176",
        "278232688309211835744673381771890580480",
    );
    test(
        "-253640751230376270397812803167",
        "-2669936877441",
        "1149635115107",
    );
    test(
        "-3768477692975601",
        "-11447376614057827956",
        "11443608136364852355",
    );
    test("-3356605361737854", "-3081095617839357", "2805585873940860");
    test(
        "-1098730198198174614195",
        "-953382298040157850476",
        "808034397882141086757",
    );
    test(
        "-69738658860594537152875081748",
        "-69738658860594537152875081748",
        "0",
    );
    test(
        "-1000000000000000000000000",
        "-1000000000000000000000000",
        "0",
    );
    test("0", "-1000000000000000000000000", "0");
    test(
        "-123",
        "-1000000000000000000000000",
        "999999999999999999999877",
    );
}

#[test]
#[should_panic]
fn ceiling_mod_assign_fail() {
    Integer::from(10).ceiling_mod_assign(Integer::ZERO);
}

#[test]
#[should_panic]
fn ceiling_mod_assign_ref_fail() {
    Integer::from(10).ceiling_mod_assign(&Integer::ZERO);
}

#[test]
#[should_panic]
fn ceiling_mod_fail() {
    Integer::from(10).ceiling_mod(Integer::ZERO);
}

#[test]
#[should_panic]
fn ceiling_mod_val_ref_fail() {
    Integer::from(10).ceiling_mod(&Integer::ZERO);
}

#[test]
#[should_panic]
fn ceiling_mod_ref_val_fail() {
    (&Integer::from(10)).ceiling_mod(Integer::ZERO);
}

#[test]
#[should_panic]
fn ceiling_mod_ref_ref_fail() {
    (&Integer::from(10)).ceiling_mod(&Integer::ZERO);
}

fn mod_properties_helper(x: Integer, y: Integer) {
    let mut mut_x = x.clone();
    mut_x.mod_assign(&y);
    assert!(mut_x.is_valid());
    let remainder = mut_x;

    let mut mut_x = x.clone();
    mut_x.mod_assign(y.clone());
    let remainder_alt = mut_x;
    assert!(remainder_alt.is_valid());
    assert_eq!(remainder_alt, remainder);

    let remainder_alt = (&x).mod_op(&y);
    assert!(remainder_alt.is_valid());
    assert_eq!(remainder_alt, remainder);

    let remainder_alt = (&x).mod_op(y.clone());
    assert!(remainder_alt.is_valid());
    assert_eq!(remainder_alt, remainder);

    let remainder_alt = x.clone().mod_op(&y);
    assert!(remainder_alt.is_valid());
    assert_eq!(remainder_alt, remainder);

    let remainder_alt = x.clone().mod_op(y.clone());
    assert!(remainder_alt.is_valid());
    assert_eq!(remainder_alt, remainder);

    assert_eq!((&x).div_mod(&y).1, remainder);

    let num_remainder = BigInt::from(&x).mod_floor(&BigInt::from(&y));
    assert_eq!(Integer::from(&num_remainder), remainder);

    let rug_remainder = rug::Integer::from(&x).rem_floor(rug::Integer::from(&y));
    assert_eq!(Integer::from(&rug_remainder), remainder);

    assert!(remainder.lt_abs(&y));
    assert!(remainder == 0 || (remainder > 0) == (y > 0));

    assert_eq!((-&x).mod_op(&y), -(&x).ceiling_mod(&y));
    assert_eq!((&x).mod_op(-&y), x.ceiling_mod(y));
}

#[test]
fn mod_properties() {
    let mut config = GenConfig::new();
    config.insert("mean_bits_n", 2048);
    config.insert("mean_stripe_n", 16 << Limb::LOG_WIDTH);
    integer_pair_gen_var_1()
        .test_properties_with_config(&config, |(x, y)| mod_properties_helper(x, y));

    integer_pair_gen_var_2()
        .test_properties_with_config(&config, |(x, y)| mod_properties_helper(x, y));

    integer_gen().test_properties(|x| {
        assert_eq!((&x).mod_op(Integer::ONE), 0);
        assert_eq!(x.mod_op(Integer::NEGATIVE_ONE), 0);
    });

    integer_gen_var_8().test_properties(|ref x| {
        assert_eq!(x.mod_op(Integer::ONE), 0);
        assert_eq!(x.mod_op(Integer::NEGATIVE_ONE), 0);
        assert_eq!(x.mod_op(x), 0);
        assert_eq!(x.mod_op(-x), 0);
        assert_eq!(Integer::ZERO.mod_op(x), 0);
        if *x > 1 {
            assert_eq!(Integer::ONE.mod_op(x), 1);
            assert_eq!(Integer::NEGATIVE_ONE.mod_op(x), x - Integer::ONE);
        }
    });

    natural_pair_gen_var_5().test_properties(|(x, y)| {
        assert_eq!(Integer::from(&x).mod_op(Integer::from(&y)), x.mod_op(y));
    });

    signed_pair_gen_var_4::<SignedLimb>().test_properties(|(x, y)| {
        assert_eq!(Integer::from(x).mod_op(Integer::from(y)), x.mod_op(y));
    });
}

fn rem_properties_helper(x: Integer, y: Integer) {
    let mut mut_x = x.clone();
    mut_x %= &y;
    assert!(mut_x.is_valid());
    let remainder = mut_x;

    let mut mut_x = x.clone();
    mut_x %= y.clone();
    assert!(mut_x.is_valid());
    assert_eq!(mut_x, remainder);

    let remainder_alt = &x % &y;
    assert!(remainder_alt.is_valid());
    assert_eq!(remainder_alt, remainder);

    let remainder_alt = &x % y.clone();
    assert!(remainder_alt.is_valid());
    assert_eq!(remainder_alt, remainder);

    let remainder_alt = x.clone() % &y;
    assert!(remainder_alt.is_valid());
    assert_eq!(remainder_alt, remainder);

    let remainder_alt = x.clone() % y.clone();
    assert!(remainder_alt.is_valid());
    assert_eq!(remainder_alt, remainder);

    assert_eq!((&x).div_rem(&y).1, remainder);

    let num_remainder = BigInt::from(&x) % &BigInt::from(&y);
    assert_eq!(Integer::from(&num_remainder), remainder);

    let rug_remainder = rug::Integer::from(&x) % rug::Integer::from(&y);
    assert_eq!(Integer::from(&rug_remainder), remainder);

    assert!(remainder.lt_abs(&y));
    assert!(remainder == 0 || (remainder > 0) == (x > 0));

    assert_eq!((-&x) % &y, -&remainder);
    assert_eq!(x % (-y), remainder);
}

#[test]
fn rem_properties() {
    let mut config = GenConfig::new();
    config.insert("mean_bits_n", 2048);
    config.insert("mean_stripe_n", 16 << Limb::LOG_WIDTH);
    integer_pair_gen_var_1()
        .test_properties_with_config(&config, |(x, y)| rem_properties_helper(x, y));

    integer_pair_gen_var_2()
        .test_properties_with_config(&config, |(x, y)| rem_properties_helper(x, y));

    integer_gen().test_properties(|x| {
        assert_eq!(&x % Integer::ONE, 0);
        assert_eq!(x % Integer::NEGATIVE_ONE, 0);
    });

    integer_gen_var_8().test_properties(|ref x| {
        assert_eq!(x % Integer::ONE, 0);
        assert_eq!(x % Integer::NEGATIVE_ONE, 0);
        assert_eq!(x % x, 0);
        assert_eq!(x % -x, 0);
        assert_eq!(Integer::ZERO % x, 0);
        if *x > 1 {
            assert_eq!(Integer::ONE % x, 1);
            assert_eq!(Integer::NEGATIVE_ONE % x, -1);
        }
    });

    natural_pair_gen_var_5().test_properties(|(x, y)| {
        assert_eq!(Integer::from(&x) % Integer::from(&y), x % y);
    });

    signed_pair_gen_var_4::<SignedLimb>().test_properties(|(x, y)| {
        assert_eq!(Integer::from(x) % Integer::from(y), x % y);
    });
}

fn ceiling_mod_properties_helper(x: Integer, y: Integer) {
    let mut mut_x = x.clone();
    mut_x.ceiling_mod_assign(&y);
    assert!(mut_x.is_valid());
    let remainder = mut_x;

    let mut mut_x = x.clone();
    mut_x.ceiling_mod_assign(y.clone());
    let remainder_alt = mut_x;
    assert!(remainder_alt.is_valid());
    assert_eq!(remainder_alt, remainder);

    let remainder_alt = (&x).ceiling_mod(&y);
    assert!(remainder_alt.is_valid());
    assert_eq!(remainder_alt, remainder);

    let remainder_alt = (&x).ceiling_mod(y.clone());
    assert!(remainder_alt.is_valid());
    assert_eq!(remainder_alt, remainder);

    let remainder_alt = x.clone().ceiling_mod(&y);
    assert!(remainder_alt.is_valid());
    assert_eq!(remainder_alt, remainder);

    let remainder_alt = x.clone().ceiling_mod(y.clone());
    assert!(remainder_alt.is_valid());
    assert_eq!(remainder_alt, remainder);

    assert_eq!((&x).ceiling_div_mod(&y).1, remainder);

    let rug_remainder = rug::Integer::from(&x).rem_ceil(rug::Integer::from(&y));
    assert_eq!(Integer::from(&rug_remainder), remainder);

    assert!(remainder.lt_abs(&y));
    assert!(remainder == 0 || (remainder >= 0) != (y > 0));

    assert_eq!((-&x).ceiling_mod(&y), -(&x).mod_op(&y));
    assert_eq!((&x).ceiling_mod(-&y), x.mod_op(y));
}

#[test]
fn ceiling_mod_properties() {
    let mut config = GenConfig::new();
    config.insert("mean_bits_n", 2048);
    config.insert("mean_stripe_n", 16 << Limb::LOG_WIDTH);
    integer_pair_gen_var_1()
        .test_properties_with_config(&config, |(x, y)| ceiling_mod_properties_helper(x, y));

    integer_pair_gen_var_2()
        .test_properties_with_config(&config, |(x, y)| ceiling_mod_properties_helper(x, y));

    integer_gen().test_properties(|x| {
        assert_eq!((&x).ceiling_mod(Integer::ONE), 0);
        assert_eq!(x.ceiling_mod(Integer::NEGATIVE_ONE), 0);
    });

    integer_gen_var_8().test_properties(|ref x| {
        assert_eq!(x.ceiling_mod(Integer::ONE), 0);
        assert_eq!(x.ceiling_mod(Integer::NEGATIVE_ONE), 0);
        assert_eq!(x.ceiling_mod(x), 0);
        assert_eq!(x.ceiling_mod(-x), 0);
        assert_eq!(Integer::ZERO.ceiling_mod(x), 0);
    });

    natural_pair_gen_var_5().test_properties(|(x, y)| {
        assert_eq!(
            Integer::from(&x).ceiling_mod(Integer::from(&y)),
            -x.neg_mod(y)
        );
    });

    signed_pair_gen_var_4::<SignedLimb>().test_properties(|(x, y)| {
        assert_eq!(
            Integer::from(x).ceiling_mod(Integer::from(y)),
            x.ceiling_mod(y)
        );
    });
}