Skip to content

Overhaul split integer handling and fix numerous issues #384

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

Merged
merged 8 commits into from
Dec 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
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
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
6 changes: 3 additions & 3 deletions src/float/conv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ macro_rules! int_to_float {
let mant_dig = <$fty>::SIGNIFICAND_BITS + 1;
let exponent_bias = <$fty>::EXPONENT_BIAS;

let n = <$ity>::BITS;
let n = <$ity as Int>::BITS;
let (s, a) = i.extract_sign();
let mut a = a;

Expand All @@ -21,7 +21,7 @@ macro_rules! int_to_float {
// exponent
let mut e = sd - 1;

if <$ity>::BITS < mant_dig {
if <$ity as Int>::BITS < mant_dig {
return <$fty>::from_parts(
s,
(e + exponent_bias) as <$fty as Float>::Int,
Expand Down Expand Up @@ -165,7 +165,7 @@ macro_rules! float_to_int {
let f = $f;
let fixint_min = <$ity>::min_value();
let fixint_max = <$ity>::max_value();
let fixint_bits = <$ity>::BITS as usize;
let fixint_bits = <$ity as Int>::BITS as usize;
let fixint_unsigned = fixint_min == 0;

let sign_bit = <$fty>::SIGN_MASK;
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
20 changes: 11 additions & 9 deletions src/float/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use core::mem;
use core::ops;

use super::int::Int;
Expand All @@ -13,7 +12,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 +66,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,10 +79,11 @@ 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
// https://github.com/rust-lang/rfcs/issues/1424
macro_rules! float_impl {
($ty:ident, $ity:ident, $sity:ident, $bits:expr, $significand_bits:expr) => {
impl Float for $ty {
Expand All @@ -101,12 +101,11 @@ macro_rules! float_impl {
const EXPONENT_MASK: Self::Int = !(Self::SIGN_MASK | Self::SIGNIFICAND_MASK);

fn repr(self) -> Self::Int {
unsafe { mem::transmute(self) }
self.to_bits()
}
fn signed_repr(self) -> Self::SignedInt {
unsafe { mem::transmute(self) }
self.to_bits() as Self::SignedInt
}
#[cfg(test)]
fn eq_repr(self, rhs: Self) -> bool {
if self.is_nan() && rhs.is_nan() {
true
Expand All @@ -115,7 +114,7 @@ macro_rules! float_impl {
}
}
fn from_repr(a: Self::Int) -> Self {
unsafe { mem::transmute(a) }
Self::from_bits(a)
}
fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self {
Self::from_repr(
Expand All @@ -133,6 +132,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
84 changes: 23 additions & 61 deletions src/int/addsub.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,16 @@
use int::Int;
use int::LargeInt;
use int::{DInt, Int};

trait UAddSub: LargeInt {
trait UAddSub: DInt {
fn uadd(self, other: Self) -> Self {
let (low, carry) = self.low().overflowing_add(other.low());
let high = self.high().wrapping_add(other.high());
let carry = if carry {
Self::HighHalf::ONE
} else {
Self::HighHalf::ZERO
};
Self::from_parts(low, high.wrapping_add(carry))
let (lo, carry) = self.lo().overflowing_add(other.lo());
let hi = self.hi().wrapping_add(other.hi());
let carry = if carry { Self::H::ONE } else { Self::H::ZERO };
Self::from_lo_hi(lo, hi.wrapping_add(carry))
}
fn uadd_one(self) -> Self {
let (low, carry) = self.low().overflowing_add(Self::LowHalf::ONE);
let carry = if carry {
Self::HighHalf::ONE
} else {
Self::HighHalf::ZERO
};
Self::from_parts(low, self.high().wrapping_add(carry))
let (lo, carry) = self.lo().overflowing_add(Self::H::ONE);
let carry = if carry { Self::H::ONE } else { Self::H::ZERO };
Self::from_lo_hi(lo, self.hi().wrapping_add(carry))
}
fn usub(self, other: Self) -> Self {
let uneg = (!other).uadd_one();
Expand Down Expand Up @@ -48,19 +39,9 @@ trait Addo: AddSub
where
<Self as Int>::UnsignedInt: UAddSub,
{
fn addo(self, other: Self, overflow: &mut i32) -> Self {
*overflow = 0;
let result = AddSub::add(self, other);
if other >= Self::ZERO {
if result < self {
*overflow = 1;
}
} else {
if result >= self {
*overflow = 1;
}
}
result
fn addo(self, other: Self) -> (Self, bool) {
let sum = AddSub::add(self, other);
(sum, (other < Self::ZERO) != (sum < self))
}
}

Expand All @@ -71,19 +52,9 @@ trait Subo: AddSub
where
<Self as Int>::UnsignedInt: UAddSub,
{
fn subo(self, other: Self, overflow: &mut i32) -> Self {
*overflow = 0;
let result = AddSub::sub(self, other);
if other >= Self::ZERO {
if result > self {
*overflow = 1;
}
} else {
if result <= self {
*overflow = 1;
}
}
result
fn subo(self, other: Self) -> (Self, bool) {
let sum = AddSub::sub(self, other);
(sum, (other < Self::ZERO) != (self < sum))
}
}

Expand All @@ -92,43 +63,34 @@ impl Subo for u128 {}

intrinsics! {
pub extern "C" fn __rust_i128_add(a: i128, b: i128) -> i128 {
__rust_u128_add(a as _, b as _) as _
AddSub::add(a,b)
}

pub extern "C" fn __rust_i128_addo(a: i128, b: i128) -> (i128, bool) {
let mut oflow = 0;
let r = a.addo(b, &mut oflow);
(r, oflow != 0)
a.addo(b)
}

pub extern "C" fn __rust_u128_add(a: u128, b: u128) -> u128 {
a.add(b)
AddSub::add(a,b)
}

pub extern "C" fn __rust_u128_addo(a: u128, b: u128) -> (u128, bool) {
let mut oflow = 0;
let r = a.addo(b, &mut oflow);
(r, oflow != 0)
a.addo(b)
}


pub extern "C" fn __rust_i128_sub(a: i128, b: i128) -> i128 {
__rust_u128_sub(a as _, b as _) as _
AddSub::sub(a,b)
}

pub extern "C" fn __rust_i128_subo(a: i128, b: i128) -> (i128, bool) {
let mut oflow = 0;
let r = a.subo(b, &mut oflow);
(r, oflow != 0)
a.subo(b)
}

pub extern "C" fn __rust_u128_sub(a: u128, b: u128) -> u128 {
a.sub(b)
AddSub::sub(a,b)
}

pub extern "C" fn __rust_u128_subo(a: u128, b: u128) -> (u128, bool) {
let mut oflow = 0;
let r = a.subo(b, &mut oflow);
(r, oflow != 0)
a.subo(b)
}
}
Loading