// Copyright © 2024 Mikhail Hogrefe
//
// This file is part of Malachite.
//
// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
// 3 of the License, or (at your option) any later version. See .
use malachite_base::num::arithmetic::traits::{ModPowerOf2, ModPowerOf2IsReduced};
use malachite_base::num::basic::signeds::PrimitiveSigned;
use malachite_base::num::basic::traits::Zero;
use malachite_base::num::basic::unsigneds::PrimitiveUnsigned;
use malachite_base::num::conversion::traits::{ExactFrom, WrappingFrom};
use malachite_base::test_util::generators::{
signed_gen, signed_unsigned_pair_gen_var_1, signed_unsigned_pair_gen_var_10,
signed_unsigned_pair_gen_var_11, signed_unsigned_pair_gen_var_4, unsigned_gen,
unsigned_pair_gen_var_2, unsigned_pair_gen_var_20, unsigned_triple_gen_var_13,
unsigned_triple_gen_var_4,
};
use std::cmp::min;
use std::fmt::Debug;
use std::panic::catch_unwind;
#[test]
fn test_mod_power_of_2_and_rem_power_of_2_unsigned() {
fn test(x: T, pow: u64, out: T) {
assert_eq!(x.mod_power_of_2(pow), out);
let mut mut_x = x;
mut_x.mod_power_of_2_assign(pow);
assert_eq!(mut_x, out);
assert_eq!(x.rem_power_of_2(pow), out);
let mut mut_x = x;
mut_x.rem_power_of_2_assign(pow);
assert_eq!(mut_x, out);
}
test::(0, 0, 0);
test::(260, 8, 4);
test::(1611, 4, 11);
test::(123, 100, 123);
test::(1000000000000, 0, 0);
test::(1000000000000, 12, 0);
test::(1000000000001, 12, 1);
test::(999999999999, 12, 4095);
test::(1000000000000, 15, 4096);
test::(1000000000000, 100, 1000000000000);
test::(1000000000000000000000000, 40, 1020608380928);
test::(1000000000000000000000000, 64, 2003764205206896640);
test::(u32::MAX, 31, 0x7fffffff);
test::(u32::MAX, 32, u32::MAX);
test::(0xffffffff, 33, 0xffffffff);
test::(0x100000000, 31, 0);
test::(0x100000000, 32, 0);
test::(0x100000000, 33, 0x100000000);
test::(0x100000001, 31, 1);
test::(0x100000001, 32, 1);
test::(0x100000001, 33, 0x100000001);
}
#[test]
fn test_mod_power_of_2_signed() {
fn test + PrimitiveSigned>(
x: S,
pow: u64,
out: U,
) {
assert_eq!(x.mod_power_of_2(pow), out);
}
test::<_, i8>(0, 0, 0);
test::<_, i16>(2, 1, 0);
test::<_, i32>(260, 8, 4);
test::<_, i16>(1611, 4, 11);
test::<_, i8>(123, 100, 123);
test::<_, i64>(1000000000000, 0, 0);
test::<_, i64>(1000000000000, 12, 0);
test::<_, i64>(1000000000001, 12, 1);
test::<_, i64>(999999999999, 12, 4095);
test::<_, i64>(1000000000000, 15, 4096);
test::<_, i64>(1000000000000, 100, 1000000000000);
test::<_, i128>(1000000000000000000000000, 40, 1020608380928);
test::<_, i128>(1000000000000000000000000, 64, 2003764205206896640);
test::<_, i32>(0x7fffffff, 30, 0x3fffffff);
test::<_, i32>(0x7fffffff, 31, 0x7fffffff);
test::<_, isize>(0x7fffffff, 32, 0x7fffffff);
test::<_, i64>(0x80000000, 30, 0);
test::<_, i64>(0x80000000, 31, 0);
test::<_, i64>(0x80000000, 32, 0x80000000);
test::<_, i64>(0x80000001, 30, 1);
test::<_, i64>(0x80000001, 31, 1);
test::<_, i64>(0x80000001, 32, 0x80000001);
test::<_, i64>(0xffffffff, 31, 0x7fffffff);
test::<_, i64>(0xffffffff, 32, 0xffffffff);
test::<_, i64>(0xffffffff, 33, 0xffffffff);
test::<_, i64>(0x100000000, 31, 0);
test::<_, i64>(0x100000000, 32, 0);
test::<_, i64>(0x100000000, 33, 0x100000000);
test::<_, i64>(0x100000001, 31, 1);
test::<_, i64>(0x100000001, 32, 1);
test::<_, i64>(0x100000001, 33, 0x100000001);
test::<_, i8>(-2, 1, 0);
test::<_, i16>(-260, 8, 252);
test::<_, i32>(-1611, 4, 5);
test::<_, i128>(-123, 100, 1267650600228229401496703205253);
test::<_, i64>(-1000000000000, 0, 0);
test::<_, i64>(-1000000000000, 12, 0);
test::<_, i64>(-1000000000001, 12, 4095);
test::<_, i64>(-999999999999, 12, 1);
test::<_, i64>(-1000000000000, 15, 0x7000);
test::<_, i128>(-1000000000000, 100, 1267650600228229400496703205376);
test::<_, i128>(-1000000000000000000000000, 40, 78903246848);
test::<_, i128>(-1000000000000000000000000, 64, 16442979868502654976);
test::<_, i32>(-0x7fffffff, 30, 1);
test::<_, i32>(-0x7fffffff, 31, 1);
test::<_, i32>(-0x7fffffff, 32, 0x80000001);
test::<_, isize>(-0x80000000, 30, 0);
test::<_, isize>(-0x80000000, 31, 0);
test::<_, isize>(-0x80000000, 32, 0x80000000);
test::<_, i64>(-0x80000001, 30, 0x3fffffff);
test::<_, i64>(-0x80000001, 31, 0x7fffffff);
test::<_, i64>(-0x80000001, 32, 0x7fffffff);
test::<_, i64>(-0xffffffff, 31, 1);
test::<_, i64>(-0xffffffff, 32, 1);
test::<_, i64>(-0xffffffff, 33, 0x100000001);
test::<_, i64>(-0x100000000, 31, 0);
test::<_, i64>(-0x100000000, 32, 0);
test::<_, i64>(-0x100000000, 33, 0x100000000);
test::<_, i64>(-0x100000001, 31, 0x7fffffff);
test::<_, i64>(-0x100000001, 32, 0xffffffff);
test::<_, i64>(-0x100000001, 33, 0xffffffff);
}
fn mod_power_of_2_signed_fail_helper() {
assert_panic!(T::NEGATIVE_ONE.mod_power_of_2(200));
}
#[test]
fn mod_power_of_2_signed_fail() {
apply_fn_to_signeds!(mod_power_of_2_signed_fail_helper);
}
#[test]
fn test_mod_power_of_2_assign_signed() {
fn test(x: T, pow: u64, out: T) {
let mut mut_x = x;
mut_x.mod_power_of_2_assign(pow);
assert_eq!(mut_x, out);
}
test::(0, 0, 0);
test::(2, 1, 0);
test::(260, 8, 4);
test::(1611, 4, 11);
test::(123, 100, 123);
test::(1000000000000, 0, 0);
test::(1000000000000, 12, 0);
test::(1000000000001, 12, 1);
test::(999999999999, 12, 4095);
test::(1000000000000, 15, 4096);
test::(1000000000000, 100, 1000000000000);
test::(1000000000000000000000000, 40, 1020608380928);
test::(1000000000000000000000000, 64, 2003764205206896640);
test::(0x7fffffff, 30, 0x3fffffff);
test::(0x7fffffff, 31, 0x7fffffff);
test::(0x7fffffff, 32, 0x7fffffff);
test::(0x80000000, 30, 0);
test::(0x80000000, 31, 0);
test::(0x80000000, 32, 0x80000000);
test::(0x80000001, 30, 1);
test::(0x80000001, 31, 1);
test::(0x80000001, 32, 0x80000001);
test::(0xffffffff, 31, 0x7fffffff);
test::(0xffffffff, 32, 0xffffffff);
test::(0xffffffff, 33, 0xffffffff);
test::(0x100000000, 31, 0);
test::(0x100000000, 32, 0);
test::(0x100000000, 33, 0x100000000);
test::(0x100000001, 31, 1);
test::(0x100000001, 32, 1);
test::(0x100000001, 33, 0x100000001);
test::(-2, 1, 0);
test::(-260, 8, 252);
test::(-1611, 4, 5);
test::(-123, 100, 1267650600228229401496703205253);
test::(-1000000000000, 0, 0);
test::(-1000000000000, 12, 0);
test::(-1000000000001, 12, 4095);
test::(-999999999999, 12, 1);
test::(-1000000000000, 15, 0x7000);
test::(-1000000000000, 100, 1267650600228229400496703205376);
test::(-1000000000000000000000000, 40, 78903246848);
test::(-1000000000000000000000000, 64, 16442979868502654976);
test::(-0x7fffffff, 30, 1);
test::(-0x7fffffff, 31, 1);
test::(-0x7fffffff, 32, 0x80000001);
test::(-0x80000000, 30, 0);
test::(-0x80000000, 31, 0);
test::(-0x80000000, 32, 0x80000000);
test::(-0x80000001, 30, 0x3fffffff);
test::(-0x80000001, 31, 0x7fffffff);
test::(-0x80000001, 32, 0x7fffffff);
test::(-0xffffffff, 31, 1);
test::(-0xffffffff, 32, 1);
test::(-0xffffffff, 33, 0x100000001);
test::(-0x100000000, 31, 0);
test::(-0x100000000, 32, 0);
test::(-0x100000000, 33, 0x100000000);
test::(-0x100000001, 31, 0x7fffffff);
test::(-0x100000001, 32, 0xffffffff);
test::(-0x100000001, 33, 0xffffffff);
}
fn mod_power_of_2_assign_signed_fail_helper() {
assert_panic!({
let mut x = T::NEGATIVE_ONE;
x.mod_power_of_2_assign(200);
});
assert_panic!({
let mut x = T::MIN;
x.mod_power_of_2_assign(T::WIDTH);
});
}
#[test]
fn mod_power_of_2_assign_signed_fail() {
apply_fn_to_signeds!(mod_power_of_2_assign_signed_fail_helper);
}
#[test]
fn test_rem_power_of_2_signed() {
fn test(x: T, pow: u64, out: T) {
assert_eq!(x.rem_power_of_2(pow), out);
let mut mut_x = x;
mut_x.rem_power_of_2_assign(pow);
assert_eq!(mut_x, out);
}
test::(0, 0, 0);
test::(2, 1, 0);
test::(260, 8, 4);
test::(1611, 4, 11);
test::(123, 100, 123);
test::(1000000000000, 0, 0);
test::(1000000000000, 12, 0);
test::(1000000000001, 12, 1);
test::(999999999999, 12, 4095);
test::(1000000000000, 15, 4096);
test::(1000000000000, 100, 1000000000000);
test::(1000000000000000000000000, 40, 1020608380928);
test::(1000000000000000000000000, 64, 2003764205206896640);
test::(0x7fffffff, 30, 0x3fffffff);
test::(0x7fffffff, 31, 0x7fffffff);
test::(0x7fffffff, 32, 0x7fffffff);
test::(0x80000000, 30, 0);
test::(0x80000000, 31, 0);
test::(0x80000000, 32, 0x80000000);
test::(0x80000001, 30, 1);
test::(0x80000001, 31, 1);
test::(0x80000001, 32, 0x80000001);
test::(0xffffffff, 31, 0x7fffffff);
test::(0xffffffff, 32, 0xffffffff);
test::(0xffffffff, 33, 0xffffffff);
test::(0x100000000, 31, 0);
test::(0x100000000, 32, 0);
test::(0x100000000, 33, 0x100000000);
test::(0x100000001, 31, 1);
test::(0x100000001, 32, 1);
test::(0x100000001, 33, 0x100000001);
test::(-2, 1, 0);
test::(-260, 8, -4);
test::(-1611, 4, -11);
test::(-123, 100, -123);
test::(-1000000000000, 0, 0);
test::(-1000000000000, 12, 0);
test::(-1000000000001, 12, -1);
test::(-999999999999, 12, -4095);
test::(-1000000000000, 15, -4096);
test::(-1000000000000, 100, -1000000000000);
test::(-1000000000000000000000000, 40, -1020608380928);
test::(-1000000000000000000000000, 64, -2003764205206896640);
test::(-0x7fffffff, 30, -0x3fffffff);
test::(-0x7fffffff, 31, -0x7fffffff);
test::(-0x7fffffff, 32, -0x7fffffff);
test::(-0x80000000, 30, 0);
test::(-0x80000000, 31, 0);
test::(-0x80000000, 32, -0x80000000);
test::(-0x80000001, 30, -1);
test::(-0x80000001, 31, -1);
test::(-0x80000001, 32, -0x80000001);
test::(-0xffffffff, 31, -0x7fffffff);
test::(-0xffffffff, 32, -0xffffffff);
test::(-0xffffffff, 33, -0xffffffff);
test::(-0x100000000, 31, 0);
test::(-0x100000000, 32, 0);
test::(-0x100000000, 33, -0x100000000);
test::(-0x100000001, 31, -1);
test::(-0x100000001, 32, -1);
test::(-0x100000001, 33, -0x100000001);
}
#[test]
fn test_neg_mod_power_of_2_unsigned() {
fn test(x: T, pow: u64, out: T) {
assert_eq!(x.neg_mod_power_of_2(pow), out);
let mut mut_x = x;
mut_x.neg_mod_power_of_2_assign(pow);
assert_eq!(mut_x, out);
}
test::(0, 0, 0);
test::(260, 8, 252);
test::(1611, 4, 5);
test::(1, 32, u32::MAX);
test::(123, 100, 1267650600228229401496703205253);
test::(1000000000000, 0, 0);
test::(1000000000000, 12, 0);
test::(1000000000001, 12, 4095);
test::(999999999999, 12, 1);
test::(1000000000000, 15, 0x7000);
test::(1000000000000, 100, 1267650600228229400496703205376);
test::(1000000000000000000000000, 40, 78903246848);
test::(1000000000000000000000000, 64, 16442979868502654976);
test::(u32::MAX, 31, 1);
test::(0xffffffff, 32, 1);
test::(0xffffffff, 33, 0x100000001);
test::(0x100000000, 31, 0);
test::(0x100000000, 32, 0);
test::(0x100000000, 33, 0x100000000);
test::(0x100000001, 31, 0x7fffffff);
test::(0x100000001, 32, 0xffffffff);
test::(0x100000001, 33, 0xffffffff);
}
fn neg_mod_power_of_2_fail_helper() {
assert_panic!(T::ONE.neg_mod_power_of_2(200));
assert_panic!(T::MAX.neg_mod_power_of_2(T::WIDTH + 1));
assert_panic!({
let mut x = T::ONE;
x.neg_mod_power_of_2_assign(200);
});
assert_panic!({
let mut x = T::MAX;
x.neg_mod_power_of_2_assign(T::WIDTH + 1);
});
}
#[test]
fn neg_mod_power_of_2_fail() {
apply_fn_to_unsigneds!(neg_mod_power_of_2_fail_helper);
}
#[test]
fn test_ceiling_mod_power_of_2_signed() {
fn test(x: T, pow: u64, out: T) {
assert_eq!(x.ceiling_mod_power_of_2(pow), out);
let mut mut_x = x;
mut_x.ceiling_mod_power_of_2_assign(pow);
assert_eq!(mut_x, out);
}
test::(0, 0, 0);
test::(2, 1, 0);
test::(260, 8, -252);
test::(1611, 4, -5);
test::(123, 100, -1267650600228229401496703205253);
test::(1000000000000, 0, 0);
test::(1000000000000, 12, 0);
test::(1000000000001, 12, -4095);
test::(999999999999, 12, -1);
test::(1000000000000, 15, -0x7000);
test::(1000000000000, 100, -1267650600228229400496703205376);
test::(1000000000000000000000000, 40, -78903246848);
test::(1000000000000000000000000, 64, -16442979868502654976);
test::(0x7fffffff, 30, -1);
test::(0x7fffffff, 31, -1);
test::(0x7fffffff, 32, -0x80000001);
test::(0x80000000, 30, 0);
test::(0x80000000, 31, 0);
test::(0x80000000, 32, -0x80000000);
test::(0x80000001, 30, -0x3fffffff);
test::(0x80000001, 31, -0x7fffffff);
test::(0x80000001, 32, -0x7fffffff);
test::(0xffffffff, 31, -1);
test::(0xffffffff, 32, -1);
test::(0xffffffff, 33, -0x100000001);
test::(0x100000000, 31, 0);
test::(0x100000000, 32, 0);
test::(0x100000000, 33, -0x100000000);
test::(0x100000001, 31, -0x7fffffff);
test::(0x100000001, 32, -0xffffffff);
test::(0x100000001, 33, -0xffffffff);
test::(-2, 1, 0);
test::(-260, 8, -4);
test::(-1611, 4, -11);
test::(-123, 100, -123);
test::(-1000000000000, 0, 0);
test::(-1000000000000, 12, 0);
test::(-1000000000001, 12, -1);
test::(-999999999999, 12, -4095);
test::(-1000000000000, 15, -4096);
test::(-1000000000000, 100, -1000000000000);
test::(-1000000000000000000000000, 40, -1020608380928);
test::(-1000000000000000000000000, 64, -2003764205206896640);
test::(-0x7fffffff, 30, -0x3fffffff);
test::(-0x7fffffff, 31, -0x7fffffff);
test::(-0x7fffffff, 32, -0x7fffffff);
test::(-0x80000000, 31, 0);
test::(-0x80000000, 30, 0);
test::(-0x80000000, 31, 0);
test::(-0x80000000, 32, -0x80000000);
test::(-0x80000001, 30, -1);
test::(-0x80000001, 31, -1);
test::(-0x80000001, 32, -0x80000001);
test::(-0xffffffff, 31, -0x7fffffff);
test::(-0xffffffff, 32, -0xffffffff);
test::(-0xffffffff, 33, -0xffffffff);
test::(-0x100000000, 31, 0);
test::(-0x100000000, 32, 0);
test::(-0x100000000, 33, -0x100000000);
test::(-0x100000001, 31, -1);
test::(-0x100000001, 32, -1);
test::(-0x100000001, 33, -0x100000001);
}
fn ceiling_mod_power_of_2_fail_helper() {
assert_panic!(T::ONE.ceiling_mod_power_of_2(T::WIDTH));
assert_panic!(T::MIN.ceiling_mod_power_of_2(T::WIDTH));
assert_panic!({
let mut x = T::ONE;
x.ceiling_mod_power_of_2_assign(T::WIDTH);
});
assert_panic!({
let mut x = T::MIN;
x.ceiling_mod_power_of_2_assign(T::WIDTH);
});
}
#[test]
fn ceiling_mod_power_of_2_fail() {
apply_fn_to_signeds!(ceiling_mod_power_of_2_fail_helper);
}
fn mod_power_of_2_properties_helper_unsigned() {
unsigned_pair_gen_var_2::().test_properties(|(n, pow)| {
let mut mut_n = n;
mut_n.mod_power_of_2_assign(pow);
let result = mut_n;
assert!(result.mod_power_of_2_is_reduced(pow));
assert_eq!(n.mod_power_of_2(pow), result);
let mut mut_n = n;
mut_n.rem_power_of_2_assign(pow);
assert_eq!(mut_n, result);
assert_eq!(n.rem_power_of_2(pow), result);
assert!(result <= n);
assert_eq!(result == T::ZERO, n.divisible_by_power_of_2(pow));
assert_eq!(result.mod_power_of_2(pow), result);
});
unsigned_triple_gen_var_4::().test_properties(|(x, y, pow)| {
assert_eq!(
x.wrapping_add(y).mod_power_of_2(pow),
x.mod_power_of_2(pow)
.wrapping_add(y.mod_power_of_2(pow))
.mod_power_of_2(pow)
);
assert_eq!(
x.wrapping_mul(y).mod_power_of_2(pow),
x.mod_power_of_2(pow)
.wrapping_mul(y.mod_power_of_2(pow))
.mod_power_of_2(pow)
);
});
unsigned_triple_gen_var_13::().test_properties(|(n, u, v)| {
assert_eq!(
n.mod_power_of_2(u).mod_power_of_2(v),
n.mod_power_of_2(min(u, v))
);
});
unsigned_gen::().test_properties(|n| {
assert_eq!(n.mod_power_of_2(0), T::ZERO);
});
unsigned_gen().test_properties(|pow| {
assert_eq!(T::ZERO.mod_power_of_2(pow), T::ZERO);
});
}
fn mod_power_of_2_properties_helper_signed()
where
::Output: ExactFrom + PrimitiveUnsigned,
{
signed_unsigned_pair_gen_var_10::().test_properties(|(n, pow)| {
let result = n.mod_power_of_2(pow);
assert!(result.mod_power_of_2_is_reduced(pow));
assert_eq!(
result == ::Output::ZERO,
n.divisible_by_power_of_2(pow)
);
assert_eq!(result.mod_power_of_2(pow), result);
});
signed_unsigned_pair_gen_var_4::().test_properties(|(n, pow)| {
let mut mut_n = n;
mut_n.mod_power_of_2_assign(pow);
let result = mut_n;
assert_eq!(
n.mod_power_of_2(pow),
::Output::exact_from(result)
);
assert!(result >= T::ZERO);
assert_eq!(result == T::ZERO, n.divisible_by_power_of_2(pow));
assert_eq!(
result.mod_power_of_2(pow),
::Output::exact_from(result)
);
});
signed_gen::().test_properties(|n| {
assert_eq!(n.mod_power_of_2(0), ::Output::ZERO);
});
unsigned_gen().test_properties(|pow| {
assert_eq!(
T::ZERO.mod_power_of_2(pow),
::Output::ZERO
);
});
}
#[test]
fn mod_power_of_2_properties() {
apply_fn_to_unsigneds!(mod_power_of_2_properties_helper_unsigned);
apply_fn_to_signeds!(mod_power_of_2_properties_helper_signed);
}
fn rem_power_of_2_properties_helper() {
signed_unsigned_pair_gen_var_1::