use crate::natural::Natural;
use crate::platform::Limb;
use alloc::vec::Vec;
use core::fmt::Display;
use core::ops::{Sub, SubAssign};
use malachite_base::num::arithmetic::traits::CheckedSub;
use malachite_base::num::basic::unsigneds::PrimitiveUnsigned;
pub_crate_test! {limbs_sub_limb(xs: &[Limb], mut y: Limb) -> (Vec<Limb>, bool) {
let len = xs.len();
let mut out = Vec::with_capacity(len);
for i in 0..len {
let (diff, overflow) = xs[i].overflowing_sub(y);
out.push(diff);
if overflow {
y = 1;
} else {
y = 0;
out.extend_from_slice(&xs[i + 1..]);
break;
}
}
(out, y != 0)
}}
pub_crate_test! {limbs_sub_limb_to_out(out: &mut [Limb], xs: &[Limb], mut y: Limb) -> bool {
let len = xs.len();
assert!(out.len() >= len);
for i in 0..len {
let overflow;
(out[i], overflow) = xs[i].overflowing_sub(y);
if overflow {
y = 1;
} else {
y = 0;
let copy_index = i + 1;
out[copy_index..len].copy_from_slice(&xs[copy_index..]);
break;
}
}
y != 0
}}
pub_crate_test! {limbs_sub_limb_in_place<T: PrimitiveUnsigned>(xs: &mut [T], mut y: T) -> bool {
for x in &mut *xs {
if x.overflowing_sub_assign(y) {
y = T::ONE;
} else {
return false;
}
}
y != T::ZERO
}}
#[inline]
pub(crate) fn sub_with_borrow(x: Limb, y: Limb, borrow: bool) -> (Limb, bool) {
let (diff, borrow_1) = x.overflowing_sub(y);
let (diff, borrow_2) = diff.overflowing_sub(Limb::from(borrow));
(diff, borrow_1 | borrow_2)
}
pub_crate_test! {limbs_sub(xs: &[Limb], ys: &[Limb]) -> (Vec<Limb>, bool) {
let xs_len = xs.len();
let ys_len = ys.len();
assert!(xs_len >= ys_len);
let mut out = vec![0; xs_len];
let mut borrow = limbs_sub_same_length_to_out(&mut out, &xs[..ys_len], ys);
if xs_len != ys_len {
out[ys_len..].copy_from_slice(&xs[ys_len..]);
if borrow {
borrow = limbs_sub_limb_in_place(&mut out[ys_len..], 1);
}
}
(out, borrow)
}}
pub_crate_test! {limbs_sub_same_length_to_out(out: &mut [Limb], xs: &[Limb], ys: &[Limb]) -> bool {
limbs_sub_same_length_with_borrow_in_to_out(out, xs, ys, false)
}}
pub_crate_test! {limbs_sub_greater_to_out(out: &mut [Limb], xs: &[Limb], ys: &[Limb]) -> bool {
let xs_len = xs.len();
let ys_len = ys.len();
assert!(out.len() >= xs_len);
let (xs_lo, xs_hi) = xs.split_at(ys_len);
let borrow = limbs_sub_same_length_to_out(out, xs_lo, ys);
if xs_len == ys_len {
borrow
} else if borrow {
limbs_sub_limb_to_out(&mut out[ys_len..], xs_hi, 1)
} else {
out[ys_len..xs_len].copy_from_slice(xs_hi);
false
}
}}
pub_crate_test! {limbs_sub_same_length_in_place_left(xs: &mut [Limb], ys: &[Limb]) -> bool {
limbs_sub_same_length_with_borrow_in_in_place_left(xs, ys, false)
}}
pub_crate_test! {limbs_sub_greater_in_place_left(xs: &mut [Limb], ys: &[Limb]) -> bool {
let xs_len = xs.len();
let ys_len = ys.len();
let (xs_lo, xs_hi) = xs.split_at_mut(ys_len);
let borrow = limbs_sub_same_length_in_place_left(xs_lo, ys);
if xs_len == ys_len {
borrow
} else if borrow {
limbs_sub_limb_in_place(xs_hi, 1)
} else {
false
}
}}
pub_crate_test! {limbs_sub_same_length_in_place_right(xs: &[Limb], ys: &mut [Limb]) -> bool {
limbs_sub_same_length_with_borrow_in_in_place_right(xs, ys, false)
}}
pub_crate_test! {limbs_slice_sub_in_place_right(xs: &[Limb], ys: &mut [Limb], len: usize) -> bool {
let xs_len = xs.len();
assert_eq!(xs_len, ys.len());
let (xs_lo, xs_hi) = xs.split_at(len);
let (ys_lo, ys_hi) = ys.split_at_mut(len);
let borrow = limbs_sub_same_length_in_place_right(xs_lo, ys_lo);
if xs_len == len {
borrow
} else if borrow {
limbs_sub_limb_to_out(ys_hi, xs_hi, 1)
} else {
ys_hi.copy_from_slice(xs_hi);
false
}
}}
pub_crate_test! {limbs_vec_sub_in_place_right(xs: &[Limb], ys: &mut Vec<Limb>) -> bool {
let xs_len = xs.len();
let ys_len = ys.len();
assert!(xs_len >= ys_len);
let (xs_lo, xs_hi) = xs.split_at(ys_len);
let borrow = limbs_sub_same_length_in_place_right(xs_lo, ys);
if xs_len == ys_len {
borrow
} else {
ys.extend_from_slice(xs_hi);
if borrow {
limbs_sub_limb_in_place(&mut ys[ys_len..], 1)
} else {
false
}
}
}}
pub_crate_test! {limbs_sub_same_length_in_place_with_overlap(
xs: &mut [Limb],
right_start: usize
) -> bool {
let len = xs.len() - right_start;
if right_start >= len {
let (xs_lo, xs_hi) = xs.split_at_mut(right_start);
limbs_sub_same_length_in_place_left(&mut xs_lo[..len], &xs_hi[..len])
} else {
let mut borrow = false;
for i in 0..len {
(xs[i], borrow) = sub_with_borrow(xs[i], xs[i + right_start], borrow);
}
borrow
}
}}
pub_crate_test! {limbs_sub_same_length_to_out_with_overlap(xs: &mut [Limb], ys: &[Limb]) -> bool {
let xs_len = xs.len();
let ys_len = ys.len();
assert!(xs_len >= ys_len);
let right_start = xs_len - ys_len;
if right_start >= ys_len {
let (xs_lo, xs_hi) = xs.split_at_mut(right_start);
limbs_sub_same_length_to_out(xs_lo, xs_hi, ys)
} else {
let mut borrow = false;
for i in 0..ys_len {
(xs[i], borrow) = sub_with_borrow(xs[i + right_start], ys[i], borrow);
}
borrow
}
}}
pub_crate_test! {limbs_sub_same_length_with_borrow_in_to_out(
out: &mut [Limb],
xs: &[Limb],
ys: &[Limb],
borrow_in: bool,
) -> bool {
let len = xs.len();
assert_eq!(len, ys.len());
assert!(out.len() >= len);
let mut borrow = borrow_in;
let mut out_chunks = out[..len].chunks_exact_mut(4);
let mut xs_chunks = xs.chunks_exact(4);
let mut ys_chunks = ys.chunks_exact(4);
for ((o, x), y) in (&mut out_chunks).zip(&mut xs_chunks).zip(&mut ys_chunks) {
for i in 0..4 {
(o[i], borrow) = sub_with_borrow(x[i], y[i], borrow);
}
}
for ((o, &x), &y) in out_chunks
.into_remainder()
.iter_mut()
.zip(xs_chunks.remainder().iter())
.zip(ys_chunks.remainder().iter())
{
(*o, borrow) = sub_with_borrow(x, y, borrow);
}
borrow
}}
pub_crate_test! {limbs_sub_same_length_with_borrow_in_in_place_left(
xs: &mut [Limb],
ys: &[Limb],
borrow_in: bool,
) -> bool {
assert_eq!(xs.len(), ys.len());
let mut borrow = borrow_in;
let mut xs_chunks = xs.chunks_exact_mut(4);
let mut ys_chunks = ys.chunks_exact(4);
for (x, y) in (&mut xs_chunks).zip(&mut ys_chunks) {
for i in 0..4 {
(x[i], borrow) = sub_with_borrow(x[i], y[i], borrow);
}
}
for (x, &y) in xs_chunks
.into_remainder()
.iter_mut()
.zip(ys_chunks.remainder().iter())
{
(*x, borrow) = sub_with_borrow(*x, y, borrow);
}
borrow
}}
pub_crate_test! {limbs_sub_same_length_with_borrow_in_in_place_right(
xs: &[Limb],
ys: &mut [Limb],
borrow_in: bool,
) -> bool {
assert_eq!(xs.len(), ys.len());
let mut borrow = borrow_in;
let mut xs_chunks = xs.chunks_exact(4);
let mut ys_chunks = ys.chunks_exact_mut(4);
for (x, y) in (&mut xs_chunks).zip(&mut ys_chunks) {
for i in 0..4 {
(y[i], borrow) = sub_with_borrow(x[i], y[i], borrow);
}
}
for (&x, y) in xs_chunks
.remainder()
.iter()
.zip(ys_chunks.into_remainder().iter_mut())
{
(*y, borrow) = sub_with_borrow(x, *y, borrow);
}
borrow
}}
fn sub_panic<S: Display, T: Display>(x: S, y: T) -> ! {
panic!("Cannot subtract a number from a smaller number. self: {x}, other: {y}");
}
impl Natural {
pub(crate) fn sub_limb(self, other: Limb) -> Self {
self.checked_sub_limb(other)
.expect("Cannot subtract a Limb from a smaller Natural")
}
pub(crate) fn sub_limb_ref(&self, other: Limb) -> Self {
self.checked_sub_limb_ref(other).unwrap_or_else(|| {
sub_panic(self, other);
})
}
#[cfg(feature = "float_helpers")]
pub fn sub_assign_at_limb(&mut self, i: usize, y: Limb) {
if i == 0 {
*self -= Self::from(y);
return;
}
let xs = self.promote_in_place();
if xs.len() <= i {
xs.resize(i + 1, 0);
}
assert!(!limbs_sub_limb_in_place(&mut xs[i..], y));
self.trim();
}
}
impl Sub<Self> for Natural {
type Output = Self;
fn sub(self, other: Self) -> Self {
self.checked_sub(other)
.expect("Cannot subtract a Natural from a smaller Natural")
}
}
impl Sub<&Self> for Natural {
type Output = Self;
fn sub(self, other: &Self) -> Self {
self.checked_sub(other)
.expect("Cannot subtract a Natural from a smaller Natural")
}
}
impl Sub<Natural> for &Natural {
type Output = Natural;
fn sub(self, other: Natural) -> Natural {
self.checked_sub(other)
.expect("Cannot subtract a Natural from a smaller Natural")
}
}
impl Sub<&Natural> for &Natural {
type Output = Natural;
fn sub(self, other: &Natural) -> Natural {
self.checked_sub(other).unwrap_or_else(|| {
sub_panic(self, other);
})
}
}
impl SubAssign<Self> for Natural {
fn sub_assign(&mut self, other: Self) {
assert!(
!self.sub_assign_no_panic(other),
"Cannot subtract a Natural from a smaller Natural"
);
}
}
impl SubAssign<&Self> for Natural {
fn sub_assign(&mut self, other: &Self) {
assert!(
!self.sub_assign_ref_no_panic(other),
"Cannot subtract a Natural from a smaller Natural"
);
}
}