Remove WideInt

This commit is contained in:
Aaron Kutch 2020-12-01 23:16:26 -06:00
parent fac884b0c4
commit cb4e9755b8
5 changed files with 36 additions and 79 deletions

View file

@ -1,7 +1,7 @@
#![allow(unreachable_code)]
use float::Float;
use int::{CastInto, Int};
use int::Int;
#[derive(Clone, Copy)]
enum Result {
@ -31,13 +31,7 @@ impl Result {
}
}
fn cmp<F: Float>(a: F, b: F) -> Result
where
u32: CastInto<F::Int>,
F::Int: CastInto<u32>,
i32: CastInto<F::Int>,
F::Int: CastInto<i32>,
{
fn cmp<F: Float>(a: F, b: F) -> Result {
let one = F::Int::ONE;
let zero = F::Int::ZERO;
let szero = F::SignedInt::ZERO;
@ -90,13 +84,8 @@ where
}
}
}
fn unord<F: Float>(a: F, b: F) -> bool
where
u32: CastInto<F::Int>,
F::Int: CastInto<u32>,
i32: CastInto<F::Int>,
F::Int: CastInto<i32>,
{
fn unord<F: Float>(a: F, b: F) -> bool {
let one = F::Int::ONE;
let sign_bit = F::SIGN_MASK as F::Int;

View file

@ -1,5 +1,5 @@
use float::Float;
use int::{CastInto, Int, WideInt};
use int::{CastInto, DInt, HInt, Int};
fn div32<F: Float>(a: F, b: F) -> F
where
@ -7,7 +7,7 @@ where
F::Int: CastInto<u32>,
i32: CastInto<F::Int>,
F::Int: CastInto<i32>,
F::Int: WideInt,
F::Int: HInt,
{
let one = F::Int::ONE;
let zero = F::Int::ZERO;
@ -156,7 +156,7 @@ where
// is the error in the reciprocal of b scaled by the maximum
// possible value of a. As a consequence of this error bound,
// either q or nextafter(q) is the correctly rounded
let (mut quotient, _) = <F::Int as WideInt>::wide_mul(a_significand << 1, reciprocal.cast());
let mut quotient = (a_significand << 1).widen_mul(reciprocal.cast()).hi();
// Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0).
// In either case, we are going to compute a residual of the form
@ -211,7 +211,7 @@ where
F::Int: CastInto<u64>,
i64: CastInto<F::Int>,
F::Int: CastInto<i64>,
F::Int: WideInt,
F::Int: HInt,
{
let one = F::Int::ONE;
let zero = F::Int::ZERO;
@ -394,7 +394,7 @@ where
// We need a 64 x 64 multiply high to compute q, which isn't a basic
// operation in C, so we need to be a little bit fussy.
let (mut quotient, _) = <F::Int as WideInt>::wide_mul(a_significand << 2, reciprocal.cast());
let mut quotient = (a_significand << 2).widen_mul(reciprocal.cast()).hi();
// Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0).
// In either case, we are going to compute a residual of the form

View file

@ -13,7 +13,8 @@ pub mod pow;
pub mod sub;
/// Trait for some basic operations on floats
pub(crate) trait Float:
#[doc(hidden)]
pub trait Float:
Copy
+ PartialEq
+ PartialOrd
@ -66,7 +67,6 @@ pub(crate) trait Float:
/// Returns `self` transmuted to `Self::SignedInt`
fn signed_repr(self) -> Self::SignedInt;
#[cfg(test)]
/// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be
/// represented in multiple different ways. This method returns `true` if two NaNs are
/// compared.
@ -80,6 +80,9 @@ pub(crate) trait Float:
/// Returns (normalized exponent, normalized significand)
fn normalize(significand: Self::Int) -> (i32, Self::Int);
/// Returns if `self` is subnormal
fn is_subnormal(&self) -> bool;
}
// FIXME: Some of this can be removed if RFC Issue #1424 is resolved
@ -106,7 +109,6 @@ macro_rules! float_impl {
fn signed_repr(self) -> Self::SignedInt {
unsafe { mem::transmute(self) }
}
#[cfg(test)]
fn eq_repr(self, rhs: Self) -> bool {
if self.is_nan() && rhs.is_nan() {
true
@ -133,6 +135,9 @@ macro_rules! float_impl {
significand << shift as Self::Int,
)
}
fn is_subnormal(&self) -> bool {
(self.repr() & Self::EXPONENT_MASK) == Self::Int::ZERO
}
}
};
}

View file

@ -1,5 +1,5 @@
use float::Float;
use int::{CastInto, Int, WideInt};
use int::{CastInto, DInt, HInt, Int};
fn mul<F: Float>(a: F, b: F) -> F
where
@ -7,7 +7,7 @@ where
F::Int: CastInto<u32>,
i32: CastInto<F::Int>,
F::Int: CastInto<i32>,
F::Int: WideInt,
F::Int: HInt,
{
let one = F::Int::ONE;
let zero = F::Int::ZERO;
@ -112,8 +112,9 @@ where
// have (exponentBits + 2) integral digits, all but two of which must be
// zero. Normalizing this result is just a conditional left-shift by one
// and bumping the exponent accordingly.
let (mut product_high, mut product_low) =
<F::Int as WideInt>::wide_mul(a_significand, b_significand << exponent_bits);
let (mut product_low, mut product_high) = a_significand
.widen_mul(b_significand << exponent_bits)
.lo_hi();
let a_exponent_i32: i32 = a_exponent.cast();
let b_exponent_i32: i32 = b_exponent.cast();
@ -126,7 +127,8 @@ where
if (product_high & implicit_bit) != zero {
product_exponent = product_exponent.wrapping_add(1);
} else {
<F::Int as WideInt>::wide_shift_left(&mut product_high, &mut product_low, 1);
product_high = (product_high << 1) | (product_low >> (bits - 1));
product_low <<= 1;
}
// If we have overflowed the type, return +/- infinity.
@ -142,17 +144,23 @@ where
// handle this case separately, but we make it a special case to
// simplify the shift logic.
let shift = one.wrapping_sub(product_exponent.cast()).cast();
if shift >= bits as i32 {
if shift >= bits {
return F::from_repr(product_sign);
}
// Otherwise, shift the significand of the result so that the round
// bit is the high bit of productLo.
<F::Int as WideInt>::wide_shift_right_with_sticky(
&mut product_high,
&mut product_low,
shift,
)
if shift < bits {
let sticky = product_low << (bits - shift);
product_low = product_high << (bits - shift) | product_low >> shift | sticky;
product_high >>= shift;
} else if shift < (2 * bits) {
let sticky = product_high << (2 * bits - shift) | product_low;
product_low = product_high >> (shift - bits) | sticky;
product_high = zero;
} else {
product_high = zero;
}
} else {
// Result is normal before rounding; insert the exponent.
product_high &= significand_mask;

View file

@ -408,48 +408,3 @@ cast_into!(u64);
cast_into!(i64);
cast_into!(u128);
cast_into!(i128);
pub(crate) trait WideInt: Int {
type Output: Int;
fn wide_mul(self, other: Self) -> (Self, Self);
fn wide_shift_left(&mut self, low: &mut Self, count: i32);
fn wide_shift_right_with_sticky(&mut self, low: &mut Self, count: i32);
}
macro_rules! impl_wide_int {
($ty:ty, $tywide:ty, $bits:expr) => {
impl WideInt for $ty {
type Output = $ty;
fn wide_mul(self, other: Self) -> (Self, Self) {
let product = (self as $tywide).wrapping_mul(other as $tywide);
((product >> ($bits as $ty)) as $ty, product as $ty)
}
fn wide_shift_left(&mut self, low: &mut Self, count: i32) {
*self = (*self << count) | (*low >> ($bits - count));
*low = *low << count;
}
fn wide_shift_right_with_sticky(&mut self, low: &mut Self, count: i32) {
if count < $bits {
let sticky = *low << ($bits - count);
*low = *self << ($bits - count) | *low >> count | sticky;
*self = *self >> count;
} else if count < 2 * $bits {
let sticky = *self << (2 * $bits - count) | *low;
*low = *self >> (count - $bits) | sticky;
*self = 0;
} else {
let sticky = *self | *low;
*self = sticky;
*self = 0;
}
}
}
};
}
impl_wide_int!(u32, u64, 32);
impl_wide_int!(u64, u128, 64);