Aaron Kutch 4 жил өмнө
parent
commit
35e323aa00
5 өөрчлөгдсөн 36 нэмэгдсэн , 79 устгасан
  1. 4 15
      src/float/cmp.rs
  2. 5 5
      src/float/div.rs
  3. 8 3
      src/float/mod.rs
  4. 19 11
      src/float/mul.rs
  5. 0 45
      src/int/mod.rs

+ 4 - 15
src/float/cmp.rs

@@ -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;

+ 5 - 5
src/float/div.rs

@@ -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

+ 8 - 3
src/float/mod.rs

@@ -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
+            }
         }
     };
 }

+ 19 - 11
src/float/mul.rs

@@ -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;

+ 0 - 45
src/int/mod.rs

@@ -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);