add overflowing arithmetic ops
This commit is contained in:
parent
ab78ff4076
commit
35ca259c4e
395
src/lib.rs
395
src/lib.rs
|
@ -75,6 +75,7 @@ additional terms or conditions.
|
||||||
mod display;
|
mod display;
|
||||||
mod traits;
|
mod traits;
|
||||||
|
|
||||||
|
use std::cmp::Ordering;
|
||||||
use std::f32;
|
use std::f32;
|
||||||
use std::f64;
|
use std::f64;
|
||||||
use std::iter::{Product, Sum};
|
use std::iter::{Product, Sum};
|
||||||
|
@ -94,6 +95,13 @@ macro_rules! if_signed {
|
||||||
(Unsigned => $($rem:tt)+) => {
|
(Unsigned => $($rem:tt)+) => {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
macro_rules! if_unsigned {
|
||||||
|
(Signed => $($rem:tt)+) => {
|
||||||
|
};
|
||||||
|
(Unsigned => $($rem:tt)+) => {
|
||||||
|
$($rem)+
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! refs {
|
macro_rules! refs {
|
||||||
(impl $Imp:ident for $Fixed:ident($Inner:ty) { $method:ident }) => {
|
(impl $Imp:ident for $Fixed:ident($Inner:ty) { $method:ident }) => {
|
||||||
|
@ -181,6 +189,40 @@ macro_rules! pass_one {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! pass_method {
|
||||||
|
($comment:expr, $Fixed:ident($Inner:ty) => fn $method:ident()) => {
|
||||||
|
#[doc = $comment]
|
||||||
|
#[inline]
|
||||||
|
pub fn $method() -> $Fixed {
|
||||||
|
$Fixed(<$Inner>::$method())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
($comment:expr, $Fixed:ident($Inner:ty) => fn $method:ident(self)) => {
|
||||||
|
#[doc = $comment]
|
||||||
|
#[inline]
|
||||||
|
pub fn $method(self) -> $Fixed {
|
||||||
|
$Fixed(<$Inner>::$method(self.0))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
($comment:expr, $Fixed:ident($Inner:ty) => fn $method:ident(self) -> $ret_ty:ty) => {
|
||||||
|
#[doc = $comment]
|
||||||
|
#[inline]
|
||||||
|
pub fn $method(self) -> $ret_ty {
|
||||||
|
<$Inner>::$method(self.0)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(
|
||||||
|
$comment:expr,
|
||||||
|
$Fixed:ident($Inner:ty) => fn $method:ident(self, $param:ident: $param_ty:ty)
|
||||||
|
) => {
|
||||||
|
#[doc = $comment]
|
||||||
|
#[inline]
|
||||||
|
pub fn $method(self, $param: $param_ty) -> $Fixed {
|
||||||
|
$Fixed(<$Inner>::$method(self.0, $param))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! shift {
|
macro_rules! shift {
|
||||||
(impl $Imp:ident < $Rhs:ty > for $Fixed:ident($Inner:ty) { $method:ident }) => {
|
(impl $Imp:ident < $Rhs:ty > for $Fixed:ident($Inner:ty) { $method:ident }) => {
|
||||||
impl $Imp<$Rhs> for $Fixed {
|
impl $Imp<$Rhs> for $Fixed {
|
||||||
|
@ -345,6 +387,216 @@ macro_rules! fixed {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $Fixed {
|
impl $Fixed {
|
||||||
|
pass_method! {
|
||||||
|
"Returns the smallest value that can be represented.",
|
||||||
|
$Fixed($Inner) => fn min_value()
|
||||||
|
}
|
||||||
|
pass_method! {
|
||||||
|
"Returns the largest value that can be represented.",
|
||||||
|
$Fixed($Inner) => fn max_value()
|
||||||
|
}
|
||||||
|
pass_method! {
|
||||||
|
"Returns the number of ones in the binary representation.",
|
||||||
|
$Fixed($Inner) => fn count_ones(self) -> u32
|
||||||
|
}
|
||||||
|
pass_method! {
|
||||||
|
"Returns the number of zeros in the binary representation.",
|
||||||
|
$Fixed($Inner) => fn count_zeros(self) -> u32
|
||||||
|
}
|
||||||
|
pass_method! {
|
||||||
|
"Returns the number of leading zeros in the binary representation.",
|
||||||
|
$Fixed($Inner) => fn leading_zeros(self) -> u32
|
||||||
|
}
|
||||||
|
pass_method! {
|
||||||
|
"Returns the number of trailing zeros in the binary representation.",
|
||||||
|
$Fixed($Inner) => fn trailing_zeros(self) -> u32
|
||||||
|
}
|
||||||
|
pass_method! {
|
||||||
|
"Shifts to the left by `n` bits, wrapping the truncated bits to the right end.",
|
||||||
|
$Fixed($Inner) => fn rotate_left(self, n: u32)
|
||||||
|
}
|
||||||
|
pass_method! {
|
||||||
|
"Shifts to the right by `n` bits, wrapping the truncated bits to the left end.",
|
||||||
|
$Fixed($Inner) => fn rotate_right(self, n: u32)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checked negation.
|
||||||
|
#[inline]
|
||||||
|
pub fn checked_neg(self) -> Option<$Fixed> {
|
||||||
|
<$Inner>::checked_neg(self.0).map($Fixed::from_bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checked fixed-point addition.
|
||||||
|
#[inline]
|
||||||
|
pub fn checked_add(self, rhs: $Fixed) -> Option<$Fixed> {
|
||||||
|
<$Inner>::checked_add(self.0, rhs.0).map($Fixed::from_bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checked fixed-point subtraction.
|
||||||
|
#[inline]
|
||||||
|
pub fn checked_sub(self, rhs: $Fixed) -> Option<$Fixed> {
|
||||||
|
<$Inner>::checked_sub(self.0, rhs.0).map($Fixed::from_bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checked fixed-point multiplication.
|
||||||
|
#[inline]
|
||||||
|
pub fn checked_mul(self, rhs: $Fixed) -> Option<$Fixed> {
|
||||||
|
let (ans, dir) = self.0.mul_dir(rhs.0);
|
||||||
|
match dir {
|
||||||
|
Ordering::Equal => Some($Fixed(ans)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checked fixed-point division.
|
||||||
|
#[inline]
|
||||||
|
pub fn checked_div(self, rhs: $Fixed) -> Option<$Fixed> {
|
||||||
|
let (ans, dir) = self.0.div_dir(rhs.0);
|
||||||
|
match dir {
|
||||||
|
Ordering::Equal => Some($Fixed(ans)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checked fixed-point left shift.
|
||||||
|
#[inline]
|
||||||
|
pub fn checked_shl(self, rhs: u32) -> Option<$Fixed> {
|
||||||
|
<$Inner>::checked_shl(self.0, rhs).map($Fixed::from_bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checked fixed-point right shift.
|
||||||
|
#[inline]
|
||||||
|
pub fn checked_shr(self, rhs: u32) -> Option<$Fixed> {
|
||||||
|
<$Inner>::checked_shr(self.0, rhs).map($Fixed::from_bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Saturating fixed-point addition.
|
||||||
|
#[inline]
|
||||||
|
pub fn saturating_add(self, rhs: $Fixed) -> $Fixed {
|
||||||
|
$Fixed(<$Inner>::saturating_add(self.0, rhs.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Saturating fixed-point subtraction.
|
||||||
|
#[inline]
|
||||||
|
pub fn saturating_sub(self, rhs: $Fixed) -> $Fixed {
|
||||||
|
$Fixed(<$Inner>::saturating_sub(self.0, rhs.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Saturating fixed-point multiplication.
|
||||||
|
#[inline]
|
||||||
|
pub fn saturating_mul(self, rhs: $Fixed) -> $Fixed {
|
||||||
|
let (ans, dir) = self.0.mul_dir(rhs.0);
|
||||||
|
match dir {
|
||||||
|
Ordering::Equal => $Fixed(ans),
|
||||||
|
Ordering::Less => $Fixed::max_value(),
|
||||||
|
Ordering::Greater => $Fixed::min_value(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Saturating fixed-point division.
|
||||||
|
#[inline]
|
||||||
|
pub fn saturating_div(self, rhs: $Fixed) -> $Fixed {
|
||||||
|
let (ans, dir) = self.0.div_dir(rhs.0);
|
||||||
|
match dir {
|
||||||
|
Ordering::Equal => $Fixed(ans),
|
||||||
|
Ordering::Less => $Fixed::max_value(),
|
||||||
|
Ordering::Greater => $Fixed::min_value(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrapping negation.
|
||||||
|
#[inline]
|
||||||
|
pub fn wrapping_neg(self) -> $Fixed {
|
||||||
|
$Fixed(<$Inner>::wrapping_neg(self.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrapping fixed-point addition.
|
||||||
|
#[inline]
|
||||||
|
pub fn wrapping_add(self, rhs: $Fixed) -> $Fixed {
|
||||||
|
$Fixed(<$Inner>::wrapping_add(self.0, rhs.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrapping fixed-point subtraction.
|
||||||
|
#[inline]
|
||||||
|
pub fn wrapping_sub(self, rhs: $Fixed) -> $Fixed {
|
||||||
|
$Fixed(<$Inner>::wrapping_sub(self.0, rhs.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrapping fixed-point multiplication.
|
||||||
|
#[inline]
|
||||||
|
pub fn wrapping_mul(self, rhs: $Fixed) -> $Fixed {
|
||||||
|
let (ans, _dir) = self.0.mul_dir(rhs.0);
|
||||||
|
$Fixed(ans)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrapping fixed-point division.
|
||||||
|
#[inline]
|
||||||
|
pub fn wrapping_div(self, rhs: $Fixed) -> $Fixed {
|
||||||
|
let (ans, _dir) = self.0.div_dir(rhs.0);
|
||||||
|
$Fixed(ans)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrapping fixed-point left shift.
|
||||||
|
#[inline]
|
||||||
|
pub fn wrapping_shl(self, rhs: u32) -> $Fixed {
|
||||||
|
$Fixed(<$Inner>::wrapping_shl(self.0, rhs))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrapping fixed-point right shift.
|
||||||
|
#[inline]
|
||||||
|
pub fn wrapping_shr(self, rhs: u32) -> $Fixed {
|
||||||
|
$Fixed(<$Inner>::wrapping_shr(self.0, rhs))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Overflowing negation.
|
||||||
|
#[inline]
|
||||||
|
pub fn overflowing_neg(self) -> ($Fixed, bool) {
|
||||||
|
let (ans, o) = <$Inner>::overflowing_neg(self.0);
|
||||||
|
($Fixed(ans), o)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Overflowing fixed-point addition.
|
||||||
|
#[inline]
|
||||||
|
pub fn overflowing_add(self, rhs: $Fixed) -> ($Fixed, bool) {
|
||||||
|
let (ans, o) = <$Inner>::overflowing_add(self.0, rhs.0);
|
||||||
|
($Fixed(ans), o)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Overflowing fixed-point subtraction.
|
||||||
|
#[inline]
|
||||||
|
pub fn overflowing_sub(self, rhs: $Fixed) -> ($Fixed, bool) {
|
||||||
|
let (ans, o) = <$Inner>::overflowing_sub(self.0, rhs.0);
|
||||||
|
($Fixed(ans), o)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Overflowing fixed-point multiplication.
|
||||||
|
#[inline]
|
||||||
|
pub fn overflowing_mul(self, rhs: $Fixed) -> ($Fixed, bool) {
|
||||||
|
let (ans, dir) = self.0.mul_dir(rhs.0);
|
||||||
|
($Fixed(ans), dir != Ordering::Equal)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Overflowing fixed-point division.
|
||||||
|
#[inline]
|
||||||
|
pub fn overflowing_div(self, rhs: $Fixed) -> ($Fixed, bool) {
|
||||||
|
let (ans, dir) = self.0.div_dir(rhs.0);
|
||||||
|
($Fixed(ans), dir != Ordering::Equal)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Overflowing fixed-point left shift.
|
||||||
|
#[inline]
|
||||||
|
pub fn overflowing_shl(self, rhs: u32) -> ($Fixed, bool) {
|
||||||
|
let (ans, o) = <$Inner>::overflowing_shl(self.0, rhs);
|
||||||
|
($Fixed(ans), o)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Overflowing fixed-point right shift.
|
||||||
|
#[inline]
|
||||||
|
pub fn overflowing_shr(self, rhs: u32) -> ($Fixed, bool) {
|
||||||
|
let (ans, o) = <$Inner>::overflowing_shr(self.0, rhs);
|
||||||
|
($Fixed(ans), o)
|
||||||
|
}
|
||||||
|
|
||||||
doc_comment! {
|
doc_comment! {
|
||||||
concat!(
|
concat!(
|
||||||
"Creates a fixed-point number of type `",
|
"Creates a fixed-point number of type `",
|
||||||
|
@ -390,7 +642,9 @@ macro_rules! fixed {
|
||||||
type Output = $Fixed;
|
type Output = $Fixed;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mul(self, rhs: $Fixed) -> $Fixed {
|
fn mul(self, rhs: $Fixed) -> $Fixed {
|
||||||
$Fixed(<$Inner as MulDiv>::mul(self.0, rhs.0))
|
let (ans, dir) = self.0.mul_dir(rhs.0);
|
||||||
|
debug_assert!(dir == Ordering::Equal, "overflow");
|
||||||
|
$Fixed(ans)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -399,7 +653,7 @@ macro_rules! fixed {
|
||||||
impl MulAssign<$Fixed> for $Fixed {
|
impl MulAssign<$Fixed> for $Fixed {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mul_assign(&mut self, rhs: $Fixed) {
|
fn mul_assign(&mut self, rhs: $Fixed) {
|
||||||
self.0 = <$Inner as MulDiv>::mul(self.0, rhs.0)
|
*self = <$Fixed as Mul>::mul(*self, rhs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -409,7 +663,9 @@ macro_rules! fixed {
|
||||||
type Output = $Fixed;
|
type Output = $Fixed;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn div(self, rhs: $Fixed) -> $Fixed {
|
fn div(self, rhs: $Fixed) -> $Fixed {
|
||||||
$Fixed(<$Inner as MulDiv>::div(self.0, rhs.0))
|
let (ans, dir) = self.0.div_dir(rhs.0);
|
||||||
|
debug_assert!(dir == Ordering::Equal, "overflow");
|
||||||
|
$Fixed(ans)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,7 +674,7 @@ macro_rules! fixed {
|
||||||
impl DivAssign<$Fixed> for $Fixed {
|
impl DivAssign<$Fixed> for $Fixed {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn div_assign(&mut self, rhs: $Fixed) {
|
fn div_assign(&mut self, rhs: $Fixed) {
|
||||||
self.0 = <$Inner as MulDiv>::div(self.0, rhs.0)
|
*self = <$Fixed as Div>::div(*self, rhs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,7 +735,6 @@ macro_rules! fixed {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fixed! { "An eight-bit fixed-point unsigned integer", FixedU8(u8), Unsigned }
|
fixed! { "An eight-bit fixed-point unsigned integer", FixedU8(u8), Unsigned }
|
||||||
fixed! { "A 16-bit fixed-point unsigned integer", FixedU16(u16), Unsigned }
|
fixed! { "A 16-bit fixed-point unsigned integer", FixedU16(u16), Unsigned }
|
||||||
fixed! { "A 32-bit fixed-point unsigned integer", FixedU32(u32), Unsigned }
|
fixed! { "A 32-bit fixed-point unsigned integer", FixedU32(u32), Unsigned }
|
||||||
|
@ -491,32 +746,49 @@ fixed! { "A 32-bit fixed-point signed integer", FixedI32(i32), Signed }
|
||||||
fixed! { "A 64-bit fixed-point signed integer", FixedI64(i64), Signed }
|
fixed! { "A 64-bit fixed-point signed integer", FixedI64(i64), Signed }
|
||||||
fixed! { "A 128-bit fixed-point signed integer", FixedI128(i128), Signed }
|
fixed! { "A 128-bit fixed-point signed integer", FixedI128(i128), Signed }
|
||||||
|
|
||||||
trait MulDiv {
|
trait MulDivDir: Sized {
|
||||||
fn mul(self, rhs: Self) -> Self;
|
fn mul_dir(self, rhs: Self) -> (Self, Ordering);
|
||||||
fn div(self, rhs: Self) -> Self;
|
fn div_dir(self, rhs: Self) -> (Self, Ordering);
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! mul_div_widen {
|
macro_rules! mul_div_widen {
|
||||||
($Single:ty, $Double:ty) => {
|
($Single:ty, $Double:ty, $Signedness:tt) => {
|
||||||
impl MulDiv for $Single {
|
impl MulDivDir for $Single {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mul(self, rhs: $Single) -> $Single {
|
fn mul_dir(self, rhs: $Single) -> ($Single, Ordering) {
|
||||||
const BITS: u32 = mem::size_of::<$Single>() as u32 * 8;
|
const BITS: u32 = mem::size_of::<$Single>() as u32 * 8;
|
||||||
const I: u32 = BITS - F;
|
const I: u32 = BITS - F;
|
||||||
let lhs2 = self as $Double;
|
let lhs2 = self as $Double;
|
||||||
let rhs2 = rhs as $Double << I;
|
let rhs2 = rhs as $Double << I;
|
||||||
let prod2 = lhs2 * rhs2;
|
let (prod2, overflow) = lhs2.overflowing_mul(rhs2);
|
||||||
(prod2 >> BITS) as $Single
|
let dir;
|
||||||
|
if_unsigned! { $Signedness => {
|
||||||
|
dir = if !overflow {
|
||||||
|
Ordering::Equal
|
||||||
|
} else {
|
||||||
|
Ordering::Less
|
||||||
|
};
|
||||||
|
} }
|
||||||
|
if_signed! { $Signedness => {
|
||||||
|
dir = if !overflow {
|
||||||
|
Ordering::Equal
|
||||||
|
} else if (self < 0) == (rhs < 0) {
|
||||||
|
Ordering::Less
|
||||||
|
} else {
|
||||||
|
Ordering::Greater
|
||||||
|
};
|
||||||
|
} }
|
||||||
|
((prod2 >> BITS) as $Single, dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn div(self, rhs: $Single) -> $Single {
|
fn div_dir(self, rhs: $Single) -> ($Single, Ordering) {
|
||||||
let lhs2 = self as $Double << F;
|
let lhs2 = self as $Double << F;
|
||||||
let rhs2 = rhs as $Double;
|
let rhs2 = rhs as $Double;
|
||||||
let quot2 = lhs2 / rhs2;
|
let quot2 = lhs2 / rhs2;
|
||||||
let quot = quot2 as $Single;
|
let quot = quot2 as $Single;
|
||||||
debug_assert!(quot as $Double == quot2, "overflow");
|
let dir = (quot as $Double).cmp("2);
|
||||||
quot
|
(quot, dir)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -527,7 +799,7 @@ trait FallbackHelper: Sized {
|
||||||
fn hi_lo(self) -> (Self, Self);
|
fn hi_lo(self) -> (Self, Self);
|
||||||
fn shift_lo_up(self) -> Self;
|
fn shift_lo_up(self) -> Self;
|
||||||
fn shift_lo_up_unsigned(self) -> Self::Unsigned;
|
fn shift_lo_up_unsigned(self) -> Self::Unsigned;
|
||||||
fn combine_lo_then_shl(self, lo: Self::Unsigned, shift: u32) -> Self;
|
fn combine_lo_then_shl(self, lo: Self::Unsigned, shift: u32) -> (Self, Ordering);
|
||||||
fn carrying_add(self, other: Self) -> (Self, Self);
|
fn carrying_add(self, other: Self) -> (Self, Self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -551,18 +823,16 @@ impl FallbackHelper for u128 {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn combine_lo_then_shl(self, lo: u128, shift: u32) -> u128 {
|
fn combine_lo_then_shl(self, lo: u128, shift: u32) -> (u128, Ordering) {
|
||||||
if shift == 128 {
|
if shift == 128 {
|
||||||
return self;
|
return (self, Ordering::Equal);
|
||||||
}
|
}
|
||||||
if shift == 0 {
|
if shift == 0 {
|
||||||
debug_assert!(self == 0, "overflow");
|
return (lo, 0.cmp(&self));
|
||||||
return lo;
|
|
||||||
}
|
}
|
||||||
let lo = lo >> shift;
|
let lo = lo >> shift;
|
||||||
let hi = self << (128 - shift);
|
let hi = self << (128 - shift);
|
||||||
debug_assert!(self >> shift == 0, "overflow");
|
(lo | hi, 0.cmp(&(self >> shift)))
|
||||||
lo | hi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -593,20 +863,18 @@ impl FallbackHelper for i128 {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn combine_lo_then_shl(self, lo: u128, shift: u32) -> i128 {
|
fn combine_lo_then_shl(self, lo: u128, shift: u32) -> (i128, Ordering) {
|
||||||
if shift == 128 {
|
if shift == 128 {
|
||||||
return self;
|
return (self, Ordering::Equal);
|
||||||
}
|
}
|
||||||
if shift == 0 {
|
if shift == 0 {
|
||||||
let ans = lo as i128;
|
let ans = lo as i128;
|
||||||
debug_assert!(ans >> 64 >> 64 == self, "overflow");
|
return (ans, (ans >> 64 >> 64).cmp(&self));
|
||||||
return ans;
|
|
||||||
}
|
}
|
||||||
let lo = (lo >> shift) as i128;
|
let lo = (lo >> shift) as i128;
|
||||||
let hi = self << (128 - shift);
|
let hi = self << (128 - shift);
|
||||||
let ans = lo | hi;
|
let ans = lo | hi;
|
||||||
debug_assert!(ans >> 64 >> 64 == self >> shift, "overflow");
|
(ans, (ans >> 64 >> 64).cmp(&(self >> shift)))
|
||||||
ans
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -626,11 +894,29 @@ impl FallbackHelper for i128 {
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! mul_div_fallback {
|
macro_rules! mul_div_fallback {
|
||||||
($Single:ty) => {
|
($Single:ty, $Signedness:tt) => {
|
||||||
impl MulDiv for $Single {
|
impl MulDivDir for $Single {
|
||||||
fn mul(self, rhs: $Single) -> $Single {
|
fn mul_dir(self, rhs: $Single) -> ($Single, Ordering) {
|
||||||
if F == 0 {
|
if F == 0 {
|
||||||
self * rhs
|
let (ans, overflow) = self.overflowing_mul(rhs);
|
||||||
|
let dir;
|
||||||
|
if_unsigned! { $Signedness => {
|
||||||
|
dir = if !overflow {
|
||||||
|
Ordering::Equal
|
||||||
|
} else {
|
||||||
|
Ordering::Less
|
||||||
|
};
|
||||||
|
} }
|
||||||
|
if_signed! { $Signedness => {
|
||||||
|
dir = if !overflow {
|
||||||
|
Ordering::Equal
|
||||||
|
} else if (self < 0) == (rhs < 0) {
|
||||||
|
Ordering::Less
|
||||||
|
} else {
|
||||||
|
Ordering::Greater
|
||||||
|
};
|
||||||
|
} }
|
||||||
|
(ans, dir)
|
||||||
} else {
|
} else {
|
||||||
let (lh, ll) = self.hi_lo();
|
let (lh, ll) = self.hi_lo();
|
||||||
let (rh, rl) = rhs.hi_lo();
|
let (rh, rl) = rhs.hi_lo();
|
||||||
|
@ -651,10 +937,27 @@ macro_rules! mul_div_fallback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
fn div_dir(self, rhs: $Single) -> ($Single, Ordering) {
|
||||||
fn div(self, rhs: $Single) -> $Single {
|
|
||||||
if F == 0 {
|
if F == 0 {
|
||||||
self / rhs
|
let (ans, overflow) = self.overflowing_div(rhs);
|
||||||
|
let dir;
|
||||||
|
if_unsigned! { $Signedness => {
|
||||||
|
dir = if !overflow {
|
||||||
|
Ordering::Equal
|
||||||
|
} else {
|
||||||
|
Ordering::Less
|
||||||
|
};
|
||||||
|
} }
|
||||||
|
if_signed! { $Signedness => {
|
||||||
|
dir = if !overflow {
|
||||||
|
Ordering::Equal
|
||||||
|
} else if (self < 0) == (rhs < 0) {
|
||||||
|
Ordering::Less
|
||||||
|
} else {
|
||||||
|
Ordering::Greater
|
||||||
|
};
|
||||||
|
} }
|
||||||
|
(ans, dir)
|
||||||
} else {
|
} else {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
@ -663,16 +966,16 @@ macro_rules! mul_div_fallback {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
mul_div_widen! { u8, u16 }
|
mul_div_widen! { u8, u16, Unsigned }
|
||||||
mul_div_widen! { u16, u32 }
|
mul_div_widen! { u16, u32, Unsigned }
|
||||||
mul_div_widen! { u32, u64 }
|
mul_div_widen! { u32, u64, Unsigned }
|
||||||
mul_div_widen! { u64, u128 }
|
mul_div_widen! { u64, u128, Unsigned }
|
||||||
mul_div_fallback! { u128 }
|
mul_div_fallback! { u128, Unsigned }
|
||||||
mul_div_widen! { i8, i16 }
|
mul_div_widen! { i8, i16, Signed }
|
||||||
mul_div_widen! { i16, i32 }
|
mul_div_widen! { i16, i32, Signed }
|
||||||
mul_div_widen! { i32, i64 }
|
mul_div_widen! { i32, i64, Signed }
|
||||||
mul_div_widen! { i64, i128 }
|
mul_div_widen! { i64, i128, Signed }
|
||||||
mul_div_fallback! { i128 }
|
mul_div_fallback! { i128, Signed }
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
Loading…
Reference in New Issue