#[inline(always)]
pub(crate) fn i128_divrem_by_u64_with_mode(
n: i128,
m_mag: u64,
mode: crate::support::rounding::RoundingMode,
) -> i128 {
debug_assert!(m_mag != 0, "i128_divrem_by_u64_with_mode: m_mag = 0");
let n_neg = n < 0;
let un = n.unsigned_abs();
let (q_mag, r_mag) = {
let hi = (un >> 64) as u64;
let lo = un as u64;
if hi == 0 {
let q = lo / m_mag;
let r = lo % m_mag;
(q as u128, r)
} else {
let q_hi = hi / m_mag;
let r_hi = hi % m_mag;
let cur = ((r_hi as u128) << 64) | (lo as u128);
let q_lo_u128 = cur / (m_mag as u128);
let r = cur - q_lo_u128 * (m_mag as u128);
let q = ((q_hi as u128) << 64) | (q_lo_u128 & u128::from(u64::MAX));
(q, r as u64)
}
};
if r_mag == 0 {
return if n_neg {
-(q_mag as i128)
} else {
q_mag as i128
};
}
let abs_r = r_mag as u128;
let abs_m = m_mag as u128;
let comp = abs_m - abs_r;
let cmp_r = abs_r.cmp(&comp);
let q_is_odd = (q_mag & 1) != 0;
let result_positive = !n_neg;
let bump = crate::support::rounding::should_bump(mode, cmp_r, q_is_odd, result_positive);
let bumped_mag = if bump { q_mag + 1 } else { q_mag };
if n_neg {
-(bumped_mag as i128)
} else {
bumped_mag as i128
}
}
macro_rules! round_with_mode_wide {
($n:expr, $m:expr, $W:ty, $mode:expr) => {{
let n = $n;
let m = $m;
let mode = $mode;
let (q, r) = n.div_rem(m);
let zero = <$W>::from_i128(0);
if r == zero {
q
} else {
let one = <$W>::from_i128(1);
let abs_r = if r < zero { -r } else { r };
let abs_m = if m < zero { -m } else { m };
let comp = abs_m - abs_r;
let cmp_r = abs_r.cmp(&comp);
let q_is_odd = {
let two = <$W>::from_i128(2);
(q % two) != zero
};
let result_positive = (n < zero) == (m < zero);
if $crate::support::rounding::should_bump(mode, cmp_r, q_is_odd, result_positive) {
if result_positive { q + one } else { q - one }
} else {
q
}
}
}};
}
pub(crate) use round_with_mode_wide;
macro_rules! decl_decimal_arithmetic {
(wide $Type:ident, $Storage:ty, $Wider:ty) => {
$crate::macros::arithmetic::decl_decimal_arithmetic!(@common $Type, $Storage);
impl<const SCALE: u32> ::core::ops::Mul for $Type<SCALE> {
type Output = Self;
#[inline]
fn mul(self, rhs: Self) -> Self {
self.mul_with(rhs, $crate::support::rounding::DEFAULT_ROUNDING_MODE)
}
}
impl<const SCALE: u32> ::core::ops::MulAssign for $Type<SCALE> {
#[inline]
fn mul_assign(&mut self, rhs: Self) {
*self = *self * rhs;
}
}
impl<const SCALE: u32> ::core::ops::Div for $Type<SCALE> {
type Output = Self;
#[inline]
fn div(self, rhs: Self) -> Self {
self.div_with(rhs, $crate::support::rounding::DEFAULT_ROUNDING_MODE)
}
}
impl<const SCALE: u32> $Type<SCALE> {
#[inline]
pub fn mul_with(self, rhs: Self, mode: $crate::support::rounding::RoundingMode) -> Self {
Self($crate::policy::mul::dispatch::<_, SCALE>(self.0, rhs.0, mode))
}
#[inline]
pub fn div_with(self, rhs: Self, mode: $crate::support::rounding::RoundingMode) -> Self {
Self($crate::policy::div::dispatch::<_, SCALE>(self.0, rhs.0, mode))
}
}
impl<const SCALE: u32> ::core::ops::DivAssign for $Type<SCALE> {
#[inline]
fn div_assign(&mut self, rhs: Self) {
*self = *self / rhs;
}
}
};
(@common $Type:ident, $Storage:ty) => {
impl<const SCALE: u32> ::core::ops::Add for $Type<SCALE> {
type Output = Self;
#[inline]
fn add(self, rhs: Self) -> Self {
use $crate::policy::add::AddPolicy as _;
self.add_impl(rhs)
}
}
impl<const SCALE: u32> ::core::ops::AddAssign for $Type<SCALE> {
#[inline]
fn add_assign(&mut self, rhs: Self) {
*self = *self + rhs;
}
}
impl<const SCALE: u32> ::core::ops::Sub for $Type<SCALE> {
type Output = Self;
#[inline]
fn sub(self, rhs: Self) -> Self {
use $crate::policy::sub::SubPolicy as _;
self.sub_impl(rhs)
}
}
impl<const SCALE: u32> ::core::ops::SubAssign for $Type<SCALE> {
#[inline]
fn sub_assign(&mut self, rhs: Self) {
*self = *self - rhs;
}
}
impl<const SCALE: u32> ::core::ops::Neg for $Type<SCALE> {
type Output = Self;
#[inline]
fn neg(self) -> Self {
use $crate::policy::neg::NegPolicy as _;
self.neg_impl()
}
}
impl<const SCALE: u32> ::core::ops::Rem for $Type<SCALE> {
type Output = Self;
#[inline]
fn rem(self, rhs: Self) -> Self {
use $crate::policy::rem::RemPolicy as _;
self.rem_impl(rhs)
}
}
impl<const SCALE: u32> ::core::ops::RemAssign for $Type<SCALE> {
#[inline]
fn rem_assign(&mut self, rhs: Self) {
*self = *self % rhs;
}
}
};
}
pub(crate) use decl_decimal_arithmetic;