use crate::digit;
use crate::errors::div_zero;
use crate::{doc, ExpType};
macro_rules! overflowing {
($BUint: ident, $BInt: ident, $Digit: ident) => {
#[doc = doc::overflowing::impl_desc!()]
impl<const N: usize> $BInt<N> {
#[doc = doc::overflowing::overflowing_add!(I)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) {
let mut out = Self::ZERO;
let mut carry = false;
let self_digits = self.bits.digits;
let rhs_digits = rhs.bits.digits;
let mut i = 0;
while i < Self::N_MINUS_1 {
let (sum, c) =
digit::$Digit::carrying_add(self_digits[i], rhs_digits[i], carry);
out.bits.digits[i] = sum;
carry = c;
i += 1;
}
let (sum, carry) = digit::$Digit::carrying_add_signed(
self_digits[Self::N_MINUS_1] as digit::$Digit::SignedDigit,
rhs_digits[Self::N_MINUS_1] as digit::$Digit::SignedDigit,
carry,
);
out.bits.digits[Self::N_MINUS_1] = sum as $Digit;
(out, carry)
}
#[doc = doc::overflowing::overflowing_add_unsigned!(I)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn overflowing_add_unsigned(self, rhs: $BUint<N>) -> (Self, bool) {
let rhs = Self::from_bits(rhs);
let (sum, overflow) = self.overflowing_add(rhs);
(sum, rhs.is_negative() != overflow)
}
#[doc = doc::overflowing::overflowing_sub!(I)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
let mut out = Self::ZERO;
let mut borrow = false;
let self_digits = self.bits.digits;
let rhs_digits = rhs.bits.digits;
let mut i = 0;
while i < Self::N_MINUS_1 {
let (sub, b) =
digit::$Digit::borrowing_sub(self_digits[i], rhs_digits[i], borrow);
out.bits.digits[i] = sub;
borrow = b;
i += 1;
}
let (sub, borrow) = digit::$Digit::borrowing_sub_signed(
self_digits[Self::N_MINUS_1] as digit::$Digit::SignedDigit,
rhs_digits[Self::N_MINUS_1] as digit::$Digit::SignedDigit,
borrow,
);
out.bits.digits[Self::N_MINUS_1] = sub as $Digit;
(out, borrow)
}
#[doc = doc::overflowing::overflowing_sub_unsigned!(I)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn overflowing_sub_unsigned(self, rhs: $BUint<N>) -> (Self, bool) {
let rhs = Self::from_bits(rhs);
let (sum, overflow) = self.overflowing_sub(rhs);
(sum, rhs.is_negative() != overflow)
}
const BITS_MINUS_1: ExpType = (Self::BITS - 1) as ExpType;
#[doc = doc::overflowing::overflowing_mul!(I)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
let (uint, overflow) = self.unsigned_abs().overflowing_mul(rhs.unsigned_abs());
let out = Self::from_bits(uint);
if self.is_negative() == rhs.is_negative() {
(out, overflow || out.is_negative())
} else {
match out.checked_neg() {
Some(n) => (n, overflow || out.is_negative()),
None => (out, overflow),
}
}
}
#[inline]
pub(crate) const fn div_rem_unchecked(self, rhs: Self) -> (Self, Self) {
if self.eq(&Self::MIN) && rhs.is_one() {
return (self, Self::ZERO);
}
let (div, rem) = self.unsigned_abs().div_rem_unchecked(rhs.unsigned_abs());
let (div, rem) = (Self::from_bits(div), Self::from_bits(rem));
match (self.is_negative(), rhs.is_negative()) {
(false, false) => (div, rem),
(false, true) => (div.neg(), rem),
(true, false) => (div.neg(), rem.neg()),
(true, true) => (div, rem.neg()),
}
}
#[doc = doc::overflowing::overflowing_div!(I)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) {
if rhs.is_zero() {
div_zero!()
}
if self.eq(&Self::MIN) {
if rhs.eq(&Self::NEG_ONE) {
return (self, true);
} else if rhs.is_one() {
return (self, false);
}
}
(self.div_rem_unchecked(rhs).0, false)
}
#[doc = doc::overflowing::overflowing_div_euclid!(I)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) {
if rhs.is_zero() {
div_zero!()
}
if self.eq(&Self::MIN) {
if rhs.eq(&Self::NEG_ONE) {
return (self, true);
} else if rhs.is_one() {
return (self, false);
}
}
let (div, rem) = self.div_rem_unchecked(rhs);
if self.is_negative() {
let r_neg = rhs.is_negative();
if !rem.is_zero() {
if r_neg {
return (div.add(Self::ONE), false);
} else {
return (div.sub(Self::ONE), false);
};
}
}
(div, false)
}
#[doc = doc::overflowing::overflowing_rem!(I)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) {
if rhs.is_zero() {
div_zero!()
}
if self.eq(&Self::MIN) && rhs.eq(&Self::NEG_ONE) {
(Self::ZERO, true)
} else {
(self.div_rem_unchecked(rhs).1, false)
}
}
#[doc = doc::overflowing::overflowing_rem_euclid!(I)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) {
if rhs.is_zero() {
div_zero!()
}
if self.eq(&Self::MIN) && rhs.eq(&Self::NEG_ONE) {
(Self::ZERO, true)
} else {
let mut rem = self.div_rem_unchecked(rhs).1;
if rem.is_negative() {
if rhs.is_negative() {
rem = rem.wrapping_sub(rhs);
} else {
rem = rem.wrapping_add(rhs);
}
}
(rem, false)
}
}
#[doc = doc::overflowing::overflowing_neg!(I)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn overflowing_neg(mut self) -> (Self, bool) {
let mut i = 0;
while i < N - 1 {
let (s, o) = (!self.bits.digits[i]).overflowing_add(1); self.bits.digits[i] = s;
if !o {
i += 1;
while i < N {
self.bits.digits[i] = !self.bits.digits[i];
i += 1;
}
return (self, false);
}
i += 1;
}
let (s, o) =
(!self.bits.digits[i] as digit::$Digit::SignedDigit).overflowing_add(1);
self.bits.digits[i] = s as $Digit;
(self, o)
}
#[doc = doc::overflowing::overflowing_shl!(I)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn overflowing_shl(self, rhs: ExpType) -> (Self, bool) {
let (uint, overflow) = self.bits.overflowing_shl(rhs);
(Self::from_bits(uint), overflow)
}
#[doc = doc::overflowing::overflowing_shr!(I)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn overflowing_shr(self, rhs: ExpType) -> (Self, bool) {
let bits = self.to_bits();
let (overflow, shift) = if rhs >= Self::BITS {
(true, rhs & Self::BITS_MINUS_1)
} else {
(false, rhs)
};
let u = unsafe {
if self.is_negative() {
$BUint::unchecked_shr_pad_internal::<true>(bits, shift)
} else {
$BUint::unchecked_shr_pad_internal::<false>(bits, shift)
}
};
(Self::from_bits(u), overflow)
}
#[doc = doc::overflowing::overflowing_abs!(I)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn overflowing_abs(self) -> (Self, bool) {
if self.is_negative() {
self.overflowing_neg()
} else {
(self, false)
}
}
#[doc = doc::overflowing::overflowing_pow!(I)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn overflowing_pow(self, pow: ExpType) -> (Self, bool) {
let (u, mut overflow) = self.unsigned_abs().overflowing_pow(pow);
let out_neg = self.is_negative() && pow & 1 == 1;
let mut out = Self::from_bits(u);
if out_neg {
out = out.wrapping_neg();
overflow = overflow || !out.is_negative();
} else {
overflow = overflow || out.is_negative();
}
(out, overflow)
}
}
};
}
crate::macro_impl!(overflowing);