Skip to content

Commit

Permalink
Merge pull request #384 from AaronKutch/issue-367
Browse files Browse the repository at this point in the history
  • Loading branch information
Amanieu committed Dec 8, 2020
2 parents c975b0e + c2ff1b3 commit b8c2585
Show file tree
Hide file tree
Showing 24 changed files with 1,334 additions and 451 deletions.
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

0 comments on commit b8c2585

Please sign in to comment.