use crate::{I256, Rounding, U256};
impl I256 {
#[inline]
pub const fn min(self, other: Self) -> Self {
if self.const_lt(other) { self } else { other }
}
#[inline]
pub const fn max(self, other: Self) -> Self {
if self.const_gt(other) { self } else { other }
}
#[inline]
pub const fn clamp(self, min: Self, max: Self) -> Self {
if min.const_gt(max) {
panic!("min must be less than or equal to max");
}
self.max(min).min(max)
}
#[inline]
pub const fn average(self, other: Self) -> Self {
let xor = self.const_bitxor(other);
let floor = self.const_bitand(other).wrapping_add(xor.wrapping_shr(1));
if floor.is_negative() && xor.bit(0) {
floor.wrapping_add(Self::ONE)
} else {
floor
}
}
#[inline]
pub const fn checked_mul_div(x: Self, y: Self, d: Self) -> Option<Self> {
match Self::mul_div_parts(x, y, d) {
Some((q, _, _)) => Some(q),
None => None,
}
}
#[inline]
pub const fn mul_div(x: Self, y: Self, d: Self) -> Self {
match Self::checked_mul_div(x, y, d) {
Some(v) => v,
None => {
if d.is_zero() {
panic!("attempt to divide by zero");
}
panic!("mul_div quotient out of range for I256");
}
}
}
#[inline]
pub const fn checked_mul_div_rounding(
x: Self,
y: Self,
d: Self,
rounding: Rounding,
) -> Option<Self> {
let (q, inexact, negative) = match Self::mul_div_parts(x, y, d) {
Some(v) => v,
None => return None,
};
if !inexact || !rounding.rounds_away_from_zero(negative) {
return Some(q);
}
if negative {
q.checked_sub(Self::ONE)
} else {
q.checked_add(Self::ONE)
}
}
#[inline]
pub const fn mul_div_rounding(
x: Self,
y: Self,
d: Self,
rounding: Rounding,
) -> Self {
match Self::checked_mul_div_rounding(x, y, d, rounding) {
Some(v) => v,
None => {
if d.is_zero() {
panic!("attempt to divide by zero");
}
panic!("mul_div quotient out of range for I256");
}
}
}
#[inline]
const fn mul_div_parts(
x: Self,
y: Self,
d: Self,
) -> Option<(Self, bool, bool)> {
let negative = (x.is_negative() != y.is_negative()) != d.is_negative();
let (mag, rem) = match U256::mul_div_parts(
x.unsigned_abs(),
y.unsigned_abs(),
d.unsigned_abs(),
) {
Some(v) => v,
None => return None,
};
let limit = if negative {
U256::ONE.wrapping_shl(255)
} else {
Self::MAX.cast_unsigned()
};
if mag.const_gt(limit) {
return None;
}
let q = if negative { mag.wrapping_neg() } else { mag };
Some((q.cast_signed(), !rem.is_zero(), negative))
}
}