use crate::{CheckedMul, Choice, Concat, CtOption, Int, Uint};
use core::ops::Mul;
impl<const LIMBS: usize> Int<LIMBS> {
#[deprecated(since = "0.7.0", note = "please use `widening_mul_unsigned` instead")]
#[must_use]
pub const fn split_mul_unsigned<const RHS_LIMBS: usize>(
&self,
rhs: &Uint<RHS_LIMBS>,
) -> (Uint<{ LIMBS }>, Uint<{ RHS_LIMBS }>, Choice) {
self.widening_mul_unsigned(rhs)
}
#[must_use]
pub const fn widening_mul_unsigned<const RHS_LIMBS: usize>(
&self,
rhs: &Uint<RHS_LIMBS>,
) -> (Uint<{ LIMBS }>, Uint<{ RHS_LIMBS }>, Choice) {
let (lhs_abs, lhs_sgn) = self.abs_sign();
let (lo, hi) = lhs_abs.widening_mul(rhs);
(lo, hi, lhs_sgn)
}
#[deprecated(
since = "0.7.0",
note = "please use `Uint::widening_mul_signed` instead"
)]
#[must_use]
pub const fn split_mul_unsigned_right<const RHS_LIMBS: usize>(
&self,
rhs: &Uint<RHS_LIMBS>,
) -> (Uint<{ RHS_LIMBS }>, Uint<{ LIMBS }>, Choice) {
rhs.widening_mul_signed(self)
}
#[deprecated(
since = "0.7.0",
note = "please use `Uint::widening_mul_signed` instead"
)]
#[must_use]
pub const fn widening_mul_unsigned_right<const RHS_LIMBS: usize>(
&self,
rhs: &Uint<RHS_LIMBS>,
) -> (Uint<{ RHS_LIMBS }>, Uint<{ LIMBS }>, Choice) {
rhs.widening_mul_signed(self)
}
#[must_use]
pub const fn concatenating_mul_unsigned<const RHS_LIMBS: usize, const WIDE_LIMBS: usize>(
&self,
rhs: &Uint<RHS_LIMBS>,
) -> Int<WIDE_LIMBS>
where
Uint<LIMBS>: Concat<RHS_LIMBS, Output = Uint<WIDE_LIMBS>>,
{
let (lhs_abs, lhs_sign) = self.abs_sign();
let product_abs = lhs_abs.concatenating_mul(rhs);
*product_abs.wrapping_neg_if(lhs_sign).as_int()
}
#[deprecated(since = "0.7.0", note = "please use `Uint::checked_mul(_int)` instead")]
#[must_use]
pub fn checked_mul_unsigned_right<const RHS_LIMBS: usize>(
&self,
rhs: &Uint<RHS_LIMBS>,
) -> CtOption<Int<RHS_LIMBS>> {
rhs.checked_mul_signed(self)
}
#[must_use]
pub fn checked_mul_unsigned<const RHS_LIMBS: usize>(
&self,
rhs: &Uint<RHS_LIMBS>,
) -> CtOption<Int<LIMBS>> {
let (abs_lhs, lhs_sgn) = self.abs_sign();
Self::new_from_abs_opt_sign(abs_lhs.checked_mul(rhs), lhs_sgn)
}
}
impl<const LIMBS: usize, const RHS_LIMBS: usize> CheckedMul<Uint<RHS_LIMBS>> for Int<LIMBS> {
#[inline]
fn checked_mul(&self, rhs: &Uint<RHS_LIMBS>) -> CtOption<Self> {
self.checked_mul_unsigned(rhs)
}
}
impl<const LIMBS: usize, const RHS_LIMBS: usize> Mul<Uint<RHS_LIMBS>> for Int<LIMBS> {
type Output = Int<LIMBS>;
fn mul(self, rhs: Uint<RHS_LIMBS>) -> Self {
self.mul(&rhs)
}
}
impl<const LIMBS: usize, const RHS_LIMBS: usize> Mul<&Uint<RHS_LIMBS>> for Int<LIMBS> {
type Output = Int<LIMBS>;
fn mul(self, rhs: &Uint<RHS_LIMBS>) -> Self {
(&self).mul(rhs)
}
}
impl<const LIMBS: usize, const RHS_LIMBS: usize> Mul<Uint<RHS_LIMBS>> for &Int<LIMBS> {
type Output = Int<LIMBS>;
fn mul(self, rhs: Uint<RHS_LIMBS>) -> Self::Output {
self.mul(&rhs)
}
}
impl<const LIMBS: usize, const RHS_LIMBS: usize> Mul<&Uint<RHS_LIMBS>> for &Int<LIMBS> {
type Output = Int<LIMBS>;
fn mul(self, rhs: &Uint<RHS_LIMBS>) -> Self::Output {
self.checked_mul_unsigned(rhs)
.expect("attempted to multiply with overflow")
}
}
#[cfg(test)]
mod tests {
use crate::{I128, I256, U128, U256};
#[test]
fn test_checked_mul_unsigned() {
let result = I128::MIN.checked_mul_unsigned(&U128::ZERO);
assert_eq!(result.unwrap(), I128::ZERO);
let result = I128::MIN.checked_mul_unsigned(&U128::ONE);
assert_eq!(result.unwrap(), I128::MIN);
let result = I128::MIN.checked_mul_unsigned(&U128::MAX);
assert!(bool::from(result.is_none()));
let result = I128::MINUS_ONE.checked_mul_unsigned(&U128::ZERO);
assert_eq!(result.unwrap(), I128::ZERO);
let result = I128::MINUS_ONE.checked_mul_unsigned(&U128::ONE);
assert_eq!(result.unwrap(), I128::MINUS_ONE);
let result = I128::MINUS_ONE.checked_mul_unsigned(&U128::MAX);
assert!(bool::from(result.is_none()));
let result = I128::ZERO.checked_mul_unsigned(&U128::ZERO);
assert_eq!(result.unwrap(), I128::ZERO);
let result = I128::ZERO.checked_mul_unsigned(&U128::ONE);
assert_eq!(result.unwrap(), I128::ZERO);
let result = I128::ZERO.checked_mul_unsigned(&U128::MAX);
assert_eq!(result.unwrap(), I128::ZERO);
let result = I128::ONE.checked_mul_unsigned(&U128::ZERO);
assert_eq!(result.unwrap(), I128::ZERO);
let result = I128::ONE.checked_mul_unsigned(&U128::ONE);
assert_eq!(result.unwrap(), I128::ONE);
let result = I128::ONE.checked_mul_unsigned(&U128::MAX);
assert!(bool::from(result.is_none()));
let result = I128::MAX.checked_mul_unsigned(&U128::ZERO);
assert_eq!(result.unwrap(), I128::ZERO);
let result = I128::MAX.checked_mul_unsigned(&U128::ONE);
assert_eq!(result.unwrap(), I128::MAX);
let result = I128::MAX.checked_mul_unsigned(&U128::MAX);
assert!(bool::from(result.is_none()));
}
#[test]
#[allow(deprecated)]
fn test_checked_mul_unsigned_right() {
let result = I256::MIN.checked_mul_unsigned_right(&U128::ZERO);
assert!(bool::from(result.is_some()));
assert_eq!(result.unwrap(), I128::ZERO);
let result = I128::MIN.checked_mul_unsigned_right(&U256::ZERO);
assert!(bool::from(result.is_some()));
assert_eq!(result.unwrap(), I256::ZERO);
let result = I256::MIN.checked_mul_unsigned_right(&U128::ONE);
assert!(bool::from(result.is_none()));
let result = I128::MIN.checked_mul_unsigned_right(&U256::ONE);
assert!(bool::from(result.is_some()));
assert_eq!(result.unwrap(), I128::MIN.resize());
let result = I256::ONE.checked_mul_unsigned_right(I128::MAX.as_uint());
assert!(bool::from(result.is_some()));
assert_eq!(result.unwrap(), I128::MAX.resize());
let result = I128::ONE.checked_mul_unsigned_right(I256::MAX.as_uint());
assert!(bool::from(result.is_some()));
assert_eq!(result.unwrap(), I256::MAX);
let result = I256::ONE.checked_mul_unsigned_right(&U128::MAX);
assert!(bool::from(result.is_none()));
let result = I128::MIN.checked_mul_unsigned_right(&U256::MAX);
assert!(bool::from(result.is_none()));
}
#[test]
fn test_concatenating_mul_unsigned() {
assert_eq!(
I128::MIN.concatenating_mul_unsigned(&U128::ZERO),
I256::ZERO
);
assert_eq!(
I128::MIN.concatenating_mul_unsigned(&U128::ONE),
I256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80000000000000000000000000000000")
);
assert_eq!(
I128::MIN.concatenating_mul_unsigned(&U128::MAX),
I256::from_be_hex("8000000000000000000000000000000080000000000000000000000000000000")
);
assert_eq!(
I128::MINUS_ONE.concatenating_mul_unsigned(&U128::ZERO),
I256::ZERO
);
assert_eq!(
I128::MINUS_ONE.concatenating_mul_unsigned(&U128::ONE),
I256::MINUS_ONE
);
assert_eq!(
I128::MINUS_ONE.concatenating_mul_unsigned(&U128::MAX),
I256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000001")
);
assert_eq!(
I128::ZERO.concatenating_mul_unsigned(&U128::ZERO),
I256::ZERO
);
assert_eq!(
I128::ZERO.concatenating_mul_unsigned(&U128::ONE),
I256::ZERO
);
assert_eq!(
I128::ZERO.concatenating_mul_unsigned(&U128::MAX),
I256::ZERO
);
assert_eq!(
I128::ONE.concatenating_mul_unsigned(&U128::ZERO),
I256::ZERO
);
assert_eq!(I128::ONE.concatenating_mul_unsigned(&U128::ONE), I256::ONE);
assert_eq!(
I128::ONE.concatenating_mul_unsigned(&U128::MAX),
I256::from_be_hex("00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
);
assert_eq!(
I128::MAX.concatenating_mul_unsigned(&U128::ZERO),
I256::ZERO
);
assert_eq!(
I128::MAX.concatenating_mul_unsigned(&U128::ONE),
I256::from_be_hex("000000000000000000000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
);
assert_eq!(
I128::MAX.concatenating_mul_unsigned(&U128::MAX),
I256::from_be_hex("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE80000000000000000000000000000001")
);
}
}