use crate::natural::Natural;
use crate::natural::arithmetic::mul::limbs_mul;
use crate::natural::arithmetic::sub::{limbs_sub_greater_in_place_left, limbs_sub_limb_in_place};
use crate::natural::comparison::cmp::limbs_cmp;
use crate::platform::{DoubleLimb, Limb};
use alloc::vec::Vec;
use core::cmp::Ordering::*;
use core::fmt::Display;
use malachite_base::num::arithmetic::traits::{
CheckedSubMul, SubMul, SubMulAssign, WrappingAddAssign,
};
use malachite_base::num::conversion::traits::SplitInHalf;
pub_crate_test! {limbs_sub_mul_limb_greater(
xs: &[Limb],
ys: &[Limb],
z: Limb
) -> Option<Vec<Limb>> {
let ys_len = ys.len();
let mut result = xs.to_vec();
let borrow = limbs_sub_mul_limb_same_length_in_place_left(&mut result[..ys_len], ys, z);
if borrow == 0 {
Some(result)
} else if xs.len() == ys_len || limbs_sub_limb_in_place(&mut result[ys_len..], borrow) {
None
} else {
Some(result)
}
}}
pub_crate_test! {limbs_sub_mul_limb_same_length_in_place_left(
xs: &mut [Limb],
ys: &[Limb],
z: Limb
) -> Limb {
assert_eq!(xs.len(), ys.len());
let mut borrow = 0;
let z = DoubleLimb::from(z);
for (x, &y) in xs.iter_mut().zip(ys.iter()) {
let (upper, mut lower) = (DoubleLimb::from(y) * z).split_in_half();
lower.wrapping_add_assign(borrow);
if lower < borrow {
borrow = upper.wrapping_add(1);
} else {
borrow = upper;
}
lower = x.wrapping_sub(lower);
if lower > *x {
borrow.wrapping_add_assign(1);
}
*x = lower;
}
borrow
}}
pub_crate_test! {limbs_sub_mul_limb_greater_in_place_left(
xs: &mut [Limb],
ys: &[Limb],
limb: Limb
) -> Limb {
let (xs_lo, xs_hi) = xs.split_at_mut(ys.len());
let borrow = limbs_sub_mul_limb_same_length_in_place_left(xs_lo, ys, limb);
if borrow == 0 || xs_hi.is_empty() {
borrow
} else {
Limb::from(limbs_sub_limb_in_place(xs_hi, borrow))
}
}}
pub_crate_test! {limbs_sub_mul_limb_same_length_in_place_right(
xs: &[Limb],
ys: &mut [Limb],
z: Limb,
) -> Limb {
assert_eq!(xs.len(), ys.len());
let mut borrow = 0;
let z = DoubleLimb::from(z);
for (&x, y) in xs.iter().zip(ys.iter_mut()) {
let (upper, mut lower) = (DoubleLimb::from(*y) * z).split_in_half();
lower.wrapping_add_assign(borrow);
if lower < borrow {
borrow = upper.wrapping_add(1);
} else {
borrow = upper;
}
lower = x.wrapping_sub(lower);
if lower > x {
borrow.wrapping_add_assign(1);
}
*y = lower;
}
borrow
}}
pub_test! {limbs_sub_mul_limb_greater_in_place_right(
xs: &[Limb],
ys: &mut Vec<Limb>,
z: Limb
) -> Limb {
let ys_len = ys.len();
let (xs_lo, xs_hi) = xs.split_at(ys_len);
let borrow = limbs_sub_mul_limb_same_length_in_place_right(xs_lo, ys, z);
if xs_hi.is_empty() {
borrow
} else {
ys.extend(&xs[ys_len..]);
if borrow == 0 {
0
} else {
Limb::from(limbs_sub_limb_in_place(&mut ys[ys_len..], borrow))
}
}
}}
pub_crate_test! {limbs_sub_mul(xs: &[Limb], ys: &[Limb], zs: &[Limb]) -> Option<Vec<Limb>> {
let mut xs = xs.to_vec();
if limbs_sub_mul_in_place_left(&mut xs, ys, zs) {
None
} else {
Some(xs)
}
}}
pub_crate_test! {limbs_sub_mul_in_place_left(xs: &mut [Limb], ys: &[Limb], zs: &[Limb]) -> bool {
assert!(ys.len() > 1);
assert!(zs.len() > 1);
let mut scratch = limbs_mul(ys, zs);
assert!(xs.len() >= scratch.len() - 1);
if *scratch.last().unwrap() == 0 {
scratch.pop();
}
let borrow = limbs_cmp(xs, &scratch) == Less;
if !borrow {
assert!(!limbs_sub_greater_in_place_left(xs, &scratch));
}
borrow
}}
fn sub_mul_panic<S: Display, T: Display, U: Display>(a: S, b: T, c: U) -> ! {
panic!("Cannot perform sub_mul. a: {a}, b: {b}, c: {c}");
}
impl SubMul<Self, Self> for Natural {
type Output = Self;
fn sub_mul(self, y: Self, z: Self) -> Self {
self.checked_sub_mul(y, z)
.expect("Natural sub_mul_assign cannot have a negative result")
}
}
impl<'a> SubMul<Self, &'a Self> for Natural {
type Output = Self;
fn sub_mul(self, y: Self, z: &'a Self) -> Self {
self.checked_sub_mul(y, z)
.expect("Natural sub_mul_assign cannot have a negative result")
}
}
impl<'a> SubMul<&'a Self, Self> for Natural {
type Output = Self;
fn sub_mul(self, y: &'a Self, z: Self) -> Self {
self.checked_sub_mul(y, z)
.expect("Natural sub_mul_assign cannot have a negative result")
}
}
impl<'a, 'b> SubMul<&'a Self, &'b Self> for Natural {
type Output = Self;
fn sub_mul(self, y: &'a Self, z: &'b Self) -> Self {
self.checked_sub_mul(y, z)
.expect("Natural sub_mul_assign cannot have a negative result")
}
}
impl SubMul<&Natural, &Natural> for &Natural {
type Output = Natural;
fn sub_mul(self, y: &Natural, z: &Natural) -> Natural {
self.checked_sub_mul(y, z).unwrap_or_else(|| {
sub_mul_panic(self, y, z);
})
}
}
impl SubMulAssign<Self, Self> for Natural {
fn sub_mul_assign(&mut self, y: Self, z: Self) {
assert!(
!self.sub_mul_assign_no_panic(y, z),
"Natural sub_mul_assign cannot have a negative result"
);
}
}
impl<'a> SubMulAssign<Self, &'a Self> for Natural {
fn sub_mul_assign(&mut self, y: Self, z: &'a Self) {
assert!(
!self.sub_mul_assign_val_ref_no_panic(y, z),
"Natural sub_mul_assign cannot have a negative result"
);
}
}
impl<'a> SubMulAssign<&'a Self, Self> for Natural {
fn sub_mul_assign(&mut self, y: &'a Self, z: Self) {
assert!(
!self.sub_mul_assign_ref_val_no_panic(y, z),
"Natural sub_mul_assign cannot have a negative result"
);
}
}
impl<'a, 'b> SubMulAssign<&'a Self, &'b Self> for Natural {
fn sub_mul_assign(&mut self, y: &'a Self, z: &'b Self) {
assert!(
!self.sub_mul_assign_ref_ref_no_panic(y, z),
"Natural sub_mul_assign cannot have a negative result"
);
}
}