macro_rules! round_with_mode_native {
($n:expr, $m:expr, $mode:expr) => {{
let n = $n;
let m = $m;
let mode = $mode;
let q = n / m;
let r = n % m;
if r == 0 {
q
} else {
let abs_r = if r < 0 { -r } else { r };
let abs_m = if m < 0 { -m } else { m };
let comp = abs_m - abs_r;
let cmp_r = abs_r.cmp(&comp);
let q_is_odd = (q & 1) != 0;
let result_positive = (n < 0) == (m < 0);
if $crate::rounding::should_bump(mode, cmp_r, q_is_odd, result_positive) {
if result_positive {
q + 1
} else {
q - 1
}
} else {
q
}
}
}};
}
pub(crate) use round_with_mode_native;
#[cfg(any(feature = "d76", feature = "d153", feature = "d307", feature = "wide", feature = "x-wide"))]
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 = n / m;
let r = n % 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::rounding::should_bump(mode, cmp_r, q_is_odd, result_positive) {
if result_positive {
q + one
} else {
q - one
}
} else {
q
}
}
}};
}
#[cfg(any(feature = "d76", feature = "d153", feature = "d307", feature = "wide", feature = "x-wide"))]
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::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::rounding::DEFAULT_ROUNDING_MODE)
}
}
impl<const SCALE: u32> $Type<SCALE> {
#[inline]
pub fn mul_with(self, rhs: Self, mode: $crate::rounding::RoundingMode) -> Self {
let n: $Wider = self.0.widen_mul::<$Wider>(rhs.0);
let scaled = if SCALE == 0 {
n
} else if SCALE <= 38 {
$crate::mg_divide::div_wide_pow10_with::<$Wider>(n, SCALE, mode)
} else {
let m: $Wider = $Type::<SCALE>::multiplier().resize::<$Wider>();
$crate::macros::arithmetic::round_with_mode_wide!(n, m, $Wider, mode)
};
Self(scaled.resize::<$Storage>())
}
#[inline]
pub fn div_with(self, rhs: Self, mode: $crate::rounding::RoundingMode) -> Self {
let b: $Wider = rhs.0.resize::<$Wider>();
let n: $Wider = self.0.widen_mul::<$Wider>($Type::<SCALE>::multiplier());
let result =
$crate::macros::arithmetic::round_with_mode_wide!(n, b, $Wider, mode);
Self(result.resize::<$Storage>())
}
}
impl<const SCALE: u32> ::core::ops::DivAssign for $Type<SCALE> {
#[inline]
fn div_assign(&mut self, rhs: Self) {
*self = *self / rhs;
}
}
};
($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::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::rounding::DEFAULT_ROUNDING_MODE)
}
}
impl<const SCALE: u32> $Type<SCALE> {
#[inline]
pub fn mul_with(self, rhs: Self, mode: $crate::rounding::RoundingMode) -> Self {
let a = self.0 as $Wider;
let b = rhs.0 as $Wider;
let m = (10 as $Wider).pow(SCALE);
let n = a * b;
let scaled =
$crate::macros::arithmetic::round_with_mode_native!(n, m, mode);
Self(scaled as $Storage)
}
#[inline]
pub fn div_with(self, rhs: Self, mode: $crate::rounding::RoundingMode) -> Self {
let a = self.0 as $Wider;
let b = rhs.0 as $Wider;
let m = (10 as $Wider).pow(SCALE);
let n = a * m;
let result =
$crate::macros::arithmetic::round_with_mode_native!(n, b, mode);
Self(result as $Storage)
}
}
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 {
Self(self.0 + rhs.0)
}
}
impl<const SCALE: u32> ::core::ops::AddAssign for $Type<SCALE> {
#[inline]
fn add_assign(&mut self, rhs: Self) {
self.0 = self.0 + rhs.0;
}
}
impl<const SCALE: u32> ::core::ops::Sub for $Type<SCALE> {
type Output = Self;
#[inline]
fn sub(self, rhs: Self) -> Self {
Self(self.0 - rhs.0)
}
}
impl<const SCALE: u32> ::core::ops::SubAssign for $Type<SCALE> {
#[inline]
fn sub_assign(&mut self, rhs: Self) {
self.0 = self.0 - rhs.0;
}
}
impl<const SCALE: u32> ::core::ops::Neg for $Type<SCALE> {
type Output = Self;
#[inline]
fn neg(self) -> Self {
Self(-self.0)
}
}
impl<const SCALE: u32> ::core::ops::Rem for $Type<SCALE> {
type Output = Self;
#[inline]
fn rem(self, rhs: Self) -> Self {
Self(self.0 % rhs.0)
}
}
impl<const SCALE: u32> ::core::ops::RemAssign for $Type<SCALE> {
#[inline]
fn rem_assign(&mut self, rhs: Self) {
self.0 = self.0 % rhs.0;
}
}
};
}
pub(crate) use decl_decimal_arithmetic;