Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overhaul split integer handling and fix numerous issues #384

Merged
merged 8 commits into from
Dec 8, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Remove WideInt
  • Loading branch information
AaronKutch committed Dec 8, 2020
commit 35e323aa0097208d4b7db75fcb8d73d0c83ff3d3
19 changes: 4 additions & 15 deletions src/float/cmp.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![allow(unreachable_code)]

use float::Float;
use int::{CastInto, Int};
use int::Int;

#[derive(Clone, Copy)]
enum Result {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
10 changes: 5 additions & 5 deletions src/float/div.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use float::Float;
use int::{CastInto, Int, WideInt};
use int::{CastInto, DInt, HInt, Int};

fn div32<F: Float>(a: F, b: F) -> F
where
u32: CastInto<F::Int>,
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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
11 changes: 8 additions & 3 deletions src/float/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
}
}
};
}
Expand Down
30 changes: 19 additions & 11 deletions src/float/mul.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use float::Float;
use int::{CastInto, Int, WideInt};
use int::{CastInto, DInt, HInt, Int};

fn mul<F: Float>(a: F, b: F) -> F
where
u32: CastInto<F::Int>,
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;
Expand Down Expand Up @@ -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();
Expand All @@ -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.
Expand All @@ -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;
Expand Down
45 changes: 0 additions & 45 deletions src/int/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);