use crate::number::{ SmallUInt, BigUInt,
BigUInt_Modular, BigUInt_Prime, BigUInt_Panic_Free };
macro_rules! biguint_calc_assign_to_calc
{
($me:expr, $func:expr) => {
let mut res = Self::from_array($me.get_number().clone());
$func(&mut res);
return res;
};
($me:expr, $func:expr, $rhs:expr) => {
let mut res = Self::from_array($me.get_number().clone());
$func(&mut res, $rhs);
return res;
};
($me:expr, $func:expr, $rhs:expr, $modulus:expr) => {
let mut res = Self::from_array($me.get_number().clone());
$func(&mut res, $rhs, $modulus);
return res;
}
}
macro_rules! biguint_calc_assign_to_calc_div
{
($me:expr, $func:expr, $rhs:expr) => {
let (quotient, _) = $func($me, $rhs);
return quotient;
}
}
macro_rules! biguint_calc_assign_to_calc_rem
{
($me:expr, $func:expr, $rhs:expr) => {
let (_, remainder) = $func($me, $rhs);
return remainder;
}
}
macro_rules! calc_to_calc_assign
{
($me:expr, $func:expr) => {
let res = $func($me);
$me.set_number(res.get_number());
$me.set_all_flags(res.get_all_flags());
};
($me:expr, $func:expr, $rhs:expr) => {
let res = $func($me, $rhs);
$me.set_number(res.get_number());
$me.set_all_flags(res.get_all_flags());
}
}
macro_rules! panic_free_modular_calc_assign
{
($me:expr, $func:expr, $rhs:expr, $modulus:expr) => {
if $modulus.is_zero_or_one()
{
$me.set_zero();
$me.set_undefined();
}
else
{
$func($me, $rhs, $modulus);
}
}
}
macro_rules! panic_free_calc_div_rem_assign
{
($me:expr, $func:expr, $rhs:expr) => {
let res = $func($me, $rhs);
$me.set_number(res.get_number());
$me.set_flag_bit(res.get_all_flags());
}
}
macro_rules! if_rhs_is_zero
{
($me:expr, $rhs:expr) => {
let mut q: Self;
let mut r = Self::zero();
r.set_all_flags(Self::DIVIDED_BY_ZERO);
if Self::is_zero($me)
{
q = Self::zero();
q.set_all_flags(Self::UNDEFINED | Self::DIVIDED_BY_ZERO);
}
else
{
q = Self::max();
q.set_all_flags(Self::INFINITY | Self::DIVIDED_BY_ZERO);
}
return (q, r);
}
}
macro_rules! panic_free_calc_pow_assign
{
($me:expr, $func:expr, $exp:expr) => {
if $me.is_zero() && $exp.is_zero()
{
$me.set_zero();
$me.set_undefined();
return;
}
$func($me, $exp);
}
}
macro_rules! general_panic_free_calc_iroot
{
($me:expr, $func:expr, $exp:expr) => {
if $exp.is_zero()
{
let mut res;
if $me.is_zero_or_one()
{
res = Self::zero();
res.set_undefined();
}
else
{
res = Self::max();
res.set_all_flags(Self::UNDEFINED | Self::INFINITY);
}
return res;
}
else if $me.is_zero()
{
return Self::zero();
}
else if $me.is_one()
{
return Self::one();
}
else
{
return $func($me, $exp);
}
}
}
macro_rules! general_panic_free_calc_ilog
{
($me:expr, $func:expr, $base:expr) => {
if $me.is_zero()
{
let mut res = Self::zero();
res.set_undefined();
return res;
}
else if $me.is_one()
{
if $base.is_zero_or_one()
{
let mut res = Self::zero();
res.set_undefined();
return res;
}
}
else if $base.is_zero_or_one()
{
let mut res = Self::max();
res.set_flag_bit(Self::INFINITY | Self::UNDEFINED);
return res;
}
return $func($me, $base);
}
}
impl<T, const N: usize> BigUInt_Panic_Free<T, N> for BigUInt<T, N>
where T: SmallUInt
{
fn panic_free_modular_add_uint<U>(&self, rhs: U, modulus: &Self) -> Self
where U: SmallUInt
{
biguint_calc_assign_to_calc!(self, Self::panic_free_modular_add_assign_uint, rhs, modulus);
}
fn panic_free_modular_add_assign_uint<U>(&mut self, rhs: U, modulus: &Self)
where U: SmallUInt
{
panic_free_modular_calc_assign!(self, Self::common_modular_add_assign_uint, rhs, modulus);
}
fn panic_free_modular_add(&self, rhs: &Self, modulus: &Self) -> Self
{
biguint_calc_assign_to_calc!(self, Self::panic_free_modular_add_assign, rhs, modulus);
}
fn panic_free_modular_add_assign(&mut self, rhs: &Self, modulus: &Self)
{
panic_free_modular_calc_assign!(self, Self::common_modular_add_assign, rhs, modulus);
}
fn panic_free_modular_sub_uint<U>(&self, rhs: U, modulus: &Self) -> Self
where U: SmallUInt
{
biguint_calc_assign_to_calc!(self, Self::panic_free_modular_sub_assign_uint, rhs, modulus);
}
fn panic_free_modular_sub_assign_uint<U>(&mut self, rhs: U, modulus: &Self)
where U: SmallUInt
{
panic_free_modular_calc_assign!(self, Self::common_modular_sub_assign_uint, rhs, modulus);
}
fn panic_free_modular_sub(&self, rhs: &Self, modulus: &Self) -> Self
{
biguint_calc_assign_to_calc!(self, Self::panic_free_modular_sub_assign, rhs, modulus);
}
fn panic_free_modular_sub_assign(&mut self, rhs: &Self, modulus: &Self)
{
panic_free_modular_calc_assign!(self, Self::common_modular_sub_assign, rhs, modulus);
}
fn panic_free_modular_mul_uint<U>(&self, rhs: U, modulus: &Self) -> Self
where U: SmallUInt
{
biguint_calc_assign_to_calc!(self, Self::panic_free_modular_mul_assign_uint, rhs, modulus);
}
fn panic_free_modular_mul_assign_uint<U>(&mut self, rhs: U, modulus: &Self)
where U: SmallUInt
{
panic_free_modular_calc_assign!(self, Self::common_modular_mul_assign_uint, rhs, modulus);
}
fn panic_free_modular_mul(&self, rhs: &Self, modulus: &Self) -> Self
{
biguint_calc_assign_to_calc!(self, Self::panic_free_modular_mul_assign, rhs, modulus);
}
fn panic_free_modular_mul_assign(&mut self, rhs: &Self, modulus: &Self)
{
panic_free_modular_calc_assign!(self, Self::common_modular_mul_assign, rhs, modulus);
}
fn panic_free_divide_fully_uint<U>(&self, rhs: U) -> (Self, Self)
where U: SmallUInt
{
if rhs.is_zero()
{
if_rhs_is_zero!(self, rhs);
}
else
{
let (q, rem) = self.common_divide_fully_uint(rhs);
let r = Self::from_uint(rem);
(q, r)
}
}
fn panic_free_div_uint<U>(&self, rhs: U) -> Self
where U: SmallUInt
{
biguint_calc_assign_to_calc_div!(self, Self::panic_free_divide_fully_uint, rhs);
}
fn panic_free_div_assign_uint<U>(&mut self, rhs: U)
where U: SmallUInt
{
panic_free_calc_div_rem_assign!(self, Self::panic_free_div_uint, rhs);
}
fn panic_free_modular_div_uint<U>(&self, rhs: U, modulus: &Self) -> Self
where U: SmallUInt
{
biguint_calc_assign_to_calc!(self, Self::panic_free_modular_div_assign_uint, rhs, modulus);
}
fn panic_free_modular_div_assign_uint<U>(&mut self, rhs: U, modulus: &Self)
where U: SmallUInt
{
let mut terminated = false;
let mut mrhs = rhs;
if !modulus.is_zero_or_one()
{
if *self >= *modulus
{
self.wrapping_rem_assign(modulus);
self.reset_all_flags();
}
if modulus.le_uint(rhs)
{
let modu = modulus.into_uint::<U>();
mrhs = rhs.wrapping_rem(modu);
}
}
if mrhs.is_zero()
{
if self.is_zero()
{
self.set_zero();
self.set_flag_bit(Self::UNDEFINED | Self::DIVIDED_BY_ZERO);
}
else
{
self.set_max();
self.set_flag_bit(Self::INFINITY | Self::DIVIDED_BY_ZERO);
}
terminated = true;
}
if modulus.is_zero_or_one()
{
self.set_zero();
self.set_undefined();
return;
}
if terminated
{ return; }
let flags = self.get_all_flags();
if *self >= *modulus
{
self.wrapping_rem_assign(modulus);
self.reset_all_flags();
}
if mrhs.length_in_bytes() > T::size_in_bytes()
{
self.modular_div_assign(&Self::from_uint(rhs), modulus);
}
else if modulus.gt_uint(rhs)
{
self.wrapping_div_assign_uint(mrhs);
}
else
{
let modu = modulus.into_uint::<U>();
let mself = self.into_uint::<U>().wrapping_rem(modu);
self.set_uint(mself.wrapping_div(mrhs));
}
self.set_flag_bit(flags);
}
fn panic_free_divide_fully(&self, rhs: &Self) -> (Self, Self)
{
if rhs.is_zero()
{ if_rhs_is_zero!(self, rhs); }
else
{ self.common_divide_fully(rhs) }
}
fn panic_free_div(&self, rhs: &Self) -> Self
{
biguint_calc_assign_to_calc_div!(self, Self::panic_free_divide_fully, rhs);
}
fn panic_free_div_assign(&mut self, rhs: &Self)
{
panic_free_calc_div_rem_assign!(self, Self::panic_free_div, rhs);
}
fn panic_free_modular_div(&self, rhs: &Self, modulus: &Self) -> Self
{
biguint_calc_assign_to_calc!(self, Self::panic_free_modular_div_assign, rhs, modulus);
}
fn panic_free_modular_div_assign(&mut self, rhs: &Self, modulus: &Self)
{
let mut terminated = false;
let mut mrhs = rhs.clone();
let flags = self.get_all_flags();
if !modulus.is_zero_or_one()
{
if *self >= *modulus
{
self.wrapping_rem_assign(modulus);
self.reset_all_flags();
}
if modulus.le(rhs)
{ mrhs.wrapping_rem_assign(modulus); }
}
if mrhs.is_zero()
{
if self.is_zero()
{
self.set_zero();
self.set_flag_bit(Self::UNDEFINED | Self::DIVIDED_BY_ZERO);
}
else
{
self.set_max();
self.set_flag_bit(Self::INFINITY | Self::DIVIDED_BY_ZERO);
}
terminated = true;
}
if modulus.is_zero_or_one()
{
self.set_zero();
self.set_undefined();
return;
}
if terminated
{ return; }
self.wrapping_div_assign(&mrhs);
self.set_flag_bit(flags);
}
fn panic_free_rem_uint<U>(&self, rhs: U) -> Self
where U: SmallUInt
{
biguint_calc_assign_to_calc_rem!(self, Self::panic_free_divide_fully_uint, rhs);
}
fn panic_free_rem_assign_uint<U>(&mut self, rhs: U)
where U: SmallUInt
{
panic_free_calc_div_rem_assign!(self, Self::panic_free_rem_uint, rhs);
}
fn panic_free_modular_rem_uint<U>(&self, rhs: U, modulus: &Self) -> Self
where U: SmallUInt
{
biguint_calc_assign_to_calc!(self, Self::panic_free_modular_rem_assign_uint, rhs, modulus);
}
fn panic_free_modular_rem_assign_uint<U>(&mut self, rhs: U, modulus: &Self)
where U: SmallUInt
{
let mut terminated = false;
let mut mrhs = rhs;
let flags = self.get_all_flags();
if !modulus.is_zero_or_one()
{
if *self >= *modulus
{
self.wrapping_rem_assign(modulus);
self.reset_all_flags();
}
if modulus.le_uint(rhs)
{
let modu = modulus.into_uint::<U>();
mrhs = rhs.wrapping_rem(modu);
}
}
if mrhs.is_zero()
{
self.set_zero();
self.set_divided_by_zero();
terminated = true;
}
if modulus.is_zero_or_one()
{
if !terminated
{ self.set_zero(); }
self.set_undefined();
terminated = true;
}
if terminated
{
self.set_flag_bit(flags);
return;
}
if rhs.length_in_bytes() > T::size_in_bytes()
{
self.panic_free_modular_rem_assign(&Self::from_uint(rhs), modulus);
}
else if modulus.gt_uint(rhs)
{
self.wrapping_rem_assign_uint(rhs);
}
else {
let modu = modulus.into_uint::<U>();
let mself = self.into_uint::<U>().wrapping_rem(modu);
self.set_uint(mself.wrapping_rem(mrhs));
}
self.set_flag_bit(flags);
}
fn panic_free_rem(&self, rhs: &Self) -> Self
{
biguint_calc_assign_to_calc_rem!(self, Self::panic_free_divide_fully, rhs);
}
fn panic_free_rem_assign(&mut self, rhs: &Self)
{
panic_free_calc_div_rem_assign!(self, Self::panic_free_rem, rhs);
}
fn panic_free_modular_rem(&self, rhs: &Self, modulus: &Self) -> Self
{
biguint_calc_assign_to_calc!(self, Self::panic_free_modular_rem_assign, rhs, modulus);
}
fn panic_free_modular_rem_assign(&mut self, rhs: &Self, modulus: &Self)
{
let mut terminated = false;
let mut mrhs = rhs.clone();
let flags = self.get_all_flags();
if !modulus.is_zero_or_one()
{
if *self >= *modulus
{
self.wrapping_rem_assign(modulus);
self.reset_all_flags();
}
if *rhs >= *modulus
{ mrhs = rhs.wrapping_rem(modulus); }
}
if mrhs.is_zero()
{
self.set_zero();
self.set_divided_by_zero();
terminated = true;
}
if modulus.is_zero_or_one()
{
if !terminated
{ self.set_zero(); }
self.set_undefined();
terminated = true;
}
if terminated
{
self.set_flag_bit(flags);
return;
}
self.wrapping_rem_assign(&mrhs);
self.set_flag_bit(flags);
}
fn panic_free_pow_uint<U>(&self, exp: U) -> Self
where U: SmallUInt
{
biguint_calc_assign_to_calc!(self, Self::panic_free_pow_assign_uint, exp);
}
fn panic_free_pow_assign_uint<U>(&mut self, exp: U)
where U: SmallUInt
{
panic_free_calc_pow_assign!(self, Self::common_pow_assign_uint, exp);
}
fn panic_free_modular_pow_uint<U>(&self, exp: U, modulus: &Self) -> Self
where U: SmallUInt
{
biguint_calc_assign_to_calc!(self, Self::panic_free_modular_pow_assign_uint, exp, modulus);
}
fn panic_free_modular_pow_assign_uint<U>(&mut self, exp: U, modulus: &Self)
where U: SmallUInt
{
if modulus.is_zero_or_one() || (self.is_zero() && exp.is_zero())
{
self.set_zero();
self.set_undefined();
return;
}
if *self >= *modulus
{ self.wrapping_rem_assign(modulus); }
let mut mexp = exp;
if modulus.le_uint(exp)
{
let modu = modulus.into_uint::<U>();
mexp = exp.wrapping_rem(modu);
}
if self.is_zero() && mexp.is_zero()
{
self.set_zero();
self.set_undefined();
return;
}
self.common_modular_pow_assign_uint(mexp, modulus);
}
fn panic_free_pow(&self, exp: &Self) -> Self
{
biguint_calc_assign_to_calc!(self, Self::panic_free_pow_assign, exp);
}
fn panic_free_pow_assign(&mut self, exp: &Self)
{
panic_free_calc_pow_assign!(self, Self::common_pow_assign, exp);
}
fn panic_free_modular_pow(&self, exp: &Self, modulus: &Self) -> Self
{
biguint_calc_assign_to_calc!(self, Self::panic_free_modular_pow_assign, exp, modulus);
}
fn panic_free_modular_pow_assign(&mut self, exp: &Self, modulus: &Self)
{
if modulus.is_zero_or_one() || (self.is_zero() && exp.is_zero())
{
self.set_zero();
self.set_undefined();
return;
}
if *self >= *modulus
{ self.wrapping_rem_assign(modulus); }
let mut mexp = exp.clone();
if *modulus <= *exp
{ mexp.wrapping_rem_assign(&modulus); }
if self.is_zero() && mexp.is_zero()
{
self.set_zero();
self.set_undefined();
return;
}
self.common_modular_pow_assign(&mexp, modulus);
}
fn panic_free_iroot_uint<U>(&self, exp: U) -> Self
where U: SmallUInt
{
general_panic_free_calc_iroot!(self, Self::common_iroot_uint, exp);
}
fn panic_free_iroot_assign_uint<U>(&mut self, exp: U)
where U: SmallUInt
{
calc_to_calc_assign!(self, Self::panic_free_iroot_uint, exp);
}
fn panic_free_iroot(&self, exp: &Self) -> Self
{
general_panic_free_calc_iroot!(self, Self::common_iroot, exp);
}
fn panic_free_iroot_assign(&mut self, exp: &Self)
{
calc_to_calc_assign!(self, Self::panic_free_iroot, exp);
}
fn panic_free_ilog_uint<U>(&self, base: U) -> Self
where U: SmallUInt
{
general_panic_free_calc_ilog!(self, Self::common_ilog_uint, base);
}
fn panic_free_ilog_assign_uint<U>(&mut self, base: U)
where U: SmallUInt
{
calc_to_calc_assign!(self, Self::panic_free_ilog_uint, base);
}
fn panic_free_ilog(&self, base: &Self) -> Self
{
general_panic_free_calc_ilog!(self, Self::common_ilog, base);
}
fn panic_free_ilog_assign(&mut self, base: &Self)
{
calc_to_calc_assign!(self, Self::panic_free_ilog, base);
}
fn panic_free_ilog2(&self) -> Self
{
if self.is_zero()
{
let mut res = Self::zero();
res.set_undefined();
return res;
}
Self::from_uint(self.length_in_bits() as u64 - self.leading_zeros() as u64 - 1_u64)
}
fn panic_free_ilog2_assign(&mut self)
{
calc_to_calc_assign!(self, Self::panic_free_ilog2);
}
#[inline]
fn panic_free_ilog10(&self) -> Self
{
self.panic_free_ilog_uint(10_u8)
}
#[inline]
fn panic_free_ilog10_assign(&mut self)
{
self.panic_free_ilog_assign_uint(10_u8);
}
fn panic_free_gcd_uint<U>(&self, other: U) -> Self
where U: SmallUInt
{
if self.is_zero() || other.is_zero()
{
let mut res = Self::zero();
res.set_undefined();
res
}
else
{
self.common_gcd_uint(other)
}
}
fn panic_free_gcd_assign_uint<U>(&mut self, other: U)
where U: SmallUInt
{
calc_to_calc_assign!(self, Self::panic_free_gcd_uint, other);
}
fn panic_free_gcd(&self, other: &Self) -> Self
{
if self.is_zero() || other.is_zero()
{
let mut res = Self::zero();
res.set_undefined();
res
}
else
{
self.common_gcd(other)
}
}
fn panic_free_gcd_assign(&mut self, other: &Self)
{
calc_to_calc_assign!(self, Self::panic_free_gcd, other);
}
fn panic_free_lcm_uint<U>(&self, other: U) -> Self
where U: SmallUInt
{
if self.is_zero() || other.is_zero()
{
let mut res = Self::zero();
res.set_undefined();
res
}
else
{
self.wrapping_div(&self.gcd_uint(other)).wrapping_mul_uint(other)
}
}
fn panic_free_lcm_assign_uint<U>(&mut self, other: U)
where U: SmallUInt
{
calc_to_calc_assign!(self, Self::panic_free_lcm_uint, other);
}
fn panic_free_lcm(&self, other: &Self) -> Self
{
if self.is_zero() || other.is_zero()
{
let mut res = Self::zero();
res.set_undefined();
res
}
else
{
self.wrapping_div(&self.gcd(&other)).wrapping_mul(&other)
}
}
fn panic_free_lcm_assign(&mut self, other: &Self)
{
calc_to_calc_assign!(self, Self::panic_free_lcm, other);
}
fn panic_free_next_multiple_of_uint<U>(&self, rhs: U) -> Self
where U: SmallUInt
{
biguint_calc_assign_to_calc!(self, Self::panic_free_next_multiple_of_assign_uint, rhs);
}
fn panic_free_next_multiple_of_assign_uint<U>(&mut self, rhs: U)
where U: SmallUInt
{
if rhs == U::zero()
{
self.set_zero();
self.set_undefined();
}
else
{
self.common_next_multiple_of_assign_uint(rhs);
}
}
fn panic_free_modular_next_multiple_of_uint<U>(&self, rhs: U, modulus: &Self) -> Self
where U: SmallUInt
{
biguint_calc_assign_to_calc!(self, Self::panic_free_modular_next_multiple_of_assign_uint, rhs, modulus);
}
fn panic_free_modular_next_multiple_of_assign_uint<U>(&mut self, rhs: U, modulus: &Self)
where U: SmallUInt
{
if modulus.is_zero_or_one() || rhs.is_zero()
{
self.set_zero();
self.set_undefined();
return;
}
else if modulus.le_uint(rhs)
{
let modu = modulus.into_uint::<U>();
if rhs.wrapping_rem(modu).is_zero()
{
self.set_zero();
self.set_undefined();
return;
}
}
self.common_modular_next_multiple_of_assign_uint(rhs, modulus);
}
fn panic_free_next_multiple_of(&self, rhs: &Self) -> Self
{
biguint_calc_assign_to_calc!(self, Self::panic_free_next_multiple_of_assign, rhs);
}
fn panic_free_next_multiple_of_assign(&mut self, rhs: &Self)
{
if rhs.is_zero()
{
self.set_zero();
self.set_undefined();
return;
}
self.common_next_multiple_of_assign(rhs);
}
fn panic_free_modular_next_multiple_of(&self, rhs: &Self, modulus: &Self) -> Self
{
biguint_calc_assign_to_calc!(self, Self::panic_free_modular_next_multiple_of_assign, rhs, modulus);
}
fn panic_free_modular_next_multiple_of_assign(&mut self, rhs: &Self, modulus: &Self)
{
if modulus.is_zero_or_one() || rhs.is_zero() || rhs.wrapping_rem(modulus).is_zero()
{
self.set_zero();
self.set_undefined();
return;
}
self.common_modular_next_multiple_of_assign(rhs, modulus);
}
}