about summary refs log tree commit diff
path: root/src/libcore/num
diff options
context:
space:
mode:
authorClar Charr <clar@charr.xyz>2017-12-21 20:23:47 -0500
committerClar Charr <clar@charr.xyz>2017-12-22 21:52:52 -0500
commita2cdeb58f680b87b5bdb6a17cba857ac51307c8f (patch)
treee63e0cdfb047d7c3da3610098f21db01cd993431 /src/libcore/num
parent5165ee9e209e0e70d89946ccbb7e90b9c0c3a7ac (diff)
downloadrust-a2cdeb58f680b87b5bdb6a17cba857ac51307c8f.tar.gz
rust-a2cdeb58f680b87b5bdb6a17cba857ac51307c8f.zip
Expose float from_bits and to_bits in libcore.
Diffstat (limited to 'src/libcore/num')
-rw-r--r--src/libcore/num/dec2flt/rawfp.rs39
-rw-r--r--src/libcore/num/f32.rs24
-rw-r--r--src/libcore/num/f64.rs24
-rw-r--r--src/libcore/num/mod.rs11
4 files changed, 51 insertions, 47 deletions
diff --git a/src/libcore/num/dec2flt/rawfp.rs b/src/libcore/num/dec2flt/rawfp.rs
index 12960fed045..143a05a1944 100644
--- a/src/libcore/num/dec2flt/rawfp.rs
+++ b/src/libcore/num/dec2flt/rawfp.rs
@@ -27,11 +27,10 @@
 //! Many functions in this module only handle normal numbers. The dec2flt routines conservatively
 //! take the universally-correct slow path (Algorithm M) for very small and very large numbers.
 //! That algorithm needs only next_float() which does handle subnormals and zeros.
-use u32;
 use cmp::Ordering::{Less, Equal, Greater};
+use convert::TryInto;
 use ops::{Mul, Div, Neg};
 use fmt::{Debug, LowerExp};
-use mem::transmute;
 use num::diy_float::Fp;
 use num::FpCategory::{Infinite, Zero, Subnormal, Normal, Nan};
 use num::Float;
@@ -66,12 +65,6 @@ pub trait RawFloat : Float + Copy + Debug + LowerExp
     /// Returns the mantissa, exponent and sign as integers.
     fn integer_decode(self) -> (u64, i16, i8);
 
-    /// Get the raw binary representation of the float.
-    fn transmute(self) -> u64;
-
-    /// Transmute the raw binary representation into a float.
-    fn from_bits(bits: u64) -> Self;
-
     /// Decode the float.
     fn unpack(self) -> Unpacked;
 
@@ -159,7 +152,7 @@ impl RawFloat for f32 {
 
     /// Returns the mantissa, exponent and sign as integers.
     fn integer_decode(self) -> (u64, i16, i8) {
-        let bits: u32 = unsafe { transmute(self) };
+        let bits = self.to_bits();
         let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
         let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
         let mantissa = if exponent == 0 {
@@ -172,16 +165,6 @@ impl RawFloat for f32 {
         (mantissa as u64, exponent, sign)
     }
 
-    fn transmute(self) -> u64 {
-        let bits: u32 = unsafe { transmute(self) };
-        bits as u64
-    }
-
-    fn from_bits(bits: u64) -> f32 {
-        assert!(bits < u32::MAX as u64, "f32::from_bits: too many bits");
-        unsafe { transmute(bits as u32) }
-    }
-
     fn unpack(self) -> Unpacked {
         let (sig, exp, _sig) = self.integer_decode();
         Unpacked::new(sig, exp)
@@ -210,7 +193,7 @@ impl RawFloat for f64 {
 
     /// Returns the mantissa, exponent and sign as integers.
     fn integer_decode(self) -> (u64, i16, i8) {
-        let bits: u64 = unsafe { transmute(self) };
+        let bits = self.to_bits();
         let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
         let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
         let mantissa = if exponent == 0 {
@@ -223,15 +206,6 @@ impl RawFloat for f64 {
         (mantissa, exponent, sign)
     }
 
-    fn transmute(self) -> u64 {
-        let bits: u64 = unsafe { transmute(self) };
-        bits
-    }
-
-    fn from_bits(bits: u64) -> f64 {
-        unsafe { transmute(bits) }
-    }
-
     fn unpack(self) -> Unpacked {
         let (sig, exp, _sig) = self.integer_decode();
         Unpacked::new(sig, exp)
@@ -296,14 +270,14 @@ pub fn encode_normal<T: RawFloat>(x: Unpacked) -> T {
         "encode_normal: exponent out of range");
     // Leave sign bit at 0 ("+"), our numbers are all positive
     let bits = (k_enc as u64) << T::EXPLICIT_SIG_BITS | sig_enc;
-    T::from_bits(bits)
+    T::from_bits(bits.try_into().unwrap_or_else(|_| unreachable!()))
 }
 
 /// Construct a subnormal. A mantissa of 0 is allowed and constructs zero.
 pub fn encode_subnormal<T: RawFloat>(significand: u64) -> T {
     assert!(significand < T::MIN_SIG, "encode_subnormal: not actually subnormal");
     // Encoded exponent is 0, the sign bit is 0, so we just have to reinterpret the bits.
-    T::from_bits(significand)
+    T::from_bits(significand.try_into().unwrap_or_else(|_| unreachable!()))
 }
 
 /// Approximate a bignum with an Fp. Rounds within 0.5 ULP with half-to-even.
@@ -363,8 +337,7 @@ pub fn next_float<T: RawFloat>(x: T) -> T {
         // too is exactly what we want!
         // Finally, f64::MAX + 1 = 7eff...f + 1 = 7ff0...0 = f64::INFINITY.
         Zero | Subnormal | Normal => {
-            let bits: u64 = x.transmute();
-            T::from_bits(bits + 1)
+            T::from_bits(x.to_bits() + T::Bits::from(1u8))
         }
     }
 }
diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs
index 43d38926c97..dc37bce8eb0 100644
--- a/src/libcore/num/f32.rs
+++ b/src/libcore/num/f32.rs
@@ -140,6 +140,8 @@ pub mod consts {
            reason = "stable interface is via `impl f{32,64}` in later crates",
            issue = "32110")]
 impl Float for f32 {
+    type Bits = u32;
+
     /// Returns `true` if the number is NaN.
     #[inline]
     fn is_nan(self) -> bool {
@@ -171,7 +173,7 @@ impl Float for f32 {
         const EXP_MASK: u32 = 0x7f800000;
         const MAN_MASK: u32 = 0x007fffff;
 
-        let bits: u32 = unsafe { mem::transmute(self) };
+        let bits = self.to_bits();
         match (bits & MAN_MASK, bits & EXP_MASK) {
             (0, 0) => Fp::Zero,
             (_, 0) => Fp::Subnormal,
@@ -215,12 +217,7 @@ impl Float for f32 {
     fn is_sign_negative(self) -> bool {
         // IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus
         // applies to zeros and NaNs as well.
-        #[repr(C)]
-        union F32Bytes {
-            f: f32,
-            b: u32
-        }
-        unsafe { F32Bytes { f: self }.b & 0x8000_0000 != 0 }
+        self.to_bits() & 0x8000_0000 != 0
     }
 
     /// Returns the reciprocal (multiplicative inverse) of the number.
@@ -274,4 +271,17 @@ impl Float for f32 {
         // multiplying by 1.0. Should switch to the `canonicalize` when it works.
         (if self < other || other.is_nan() { self } else { other }) * 1.0
     }
+
+    /// Raw transmutation to `u32`.
+    #[inline]
+    fn to_bits(self) -> u32 {
+        unsafe { mem::transmute(self) }
+    }
+
+    /// Raw transmutation from `u32`.
+    #[inline]
+    fn from_bits(v: u32) -> Self {
+        // It turns out the safety issues with sNaN were overblown! Hooray!
+        unsafe { mem::transmute(v) }
+    }
 }
diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs
index 4ff80a2f05d..5c217167f98 100644
--- a/src/libcore/num/f64.rs
+++ b/src/libcore/num/f64.rs
@@ -140,6 +140,8 @@ pub mod consts {
            reason = "stable interface is via `impl f{32,64}` in later crates",
            issue = "32110")]
 impl Float for f64 {
+    type Bits = u64;
+
     /// Returns `true` if the number is NaN.
     #[inline]
     fn is_nan(self) -> bool {
@@ -171,7 +173,7 @@ impl Float for f64 {
         const EXP_MASK: u64 = 0x7ff0000000000000;
         const MAN_MASK: u64 = 0x000fffffffffffff;
 
-        let bits: u64 = unsafe { mem::transmute(self) };
+        let bits = self.to_bits();
         match (bits & MAN_MASK, bits & EXP_MASK) {
             (0, 0) => Fp::Zero,
             (_, 0) => Fp::Subnormal,
@@ -213,12 +215,7 @@ impl Float for f64 {
     /// negative sign bit and negative infinity.
     #[inline]
     fn is_sign_negative(self) -> bool {
-        #[repr(C)]
-        union F64Bytes {
-            f: f64,
-            b: u64
-        }
-        unsafe { F64Bytes { f: self }.b & 0x8000_0000_0000_0000 != 0 }
+        self.to_bits() & 0x8000_0000_0000_0000 != 0
     }
 
     /// Returns the reciprocal (multiplicative inverse) of the number.
@@ -272,4 +269,17 @@ impl Float for f64 {
         // multiplying by 1.0. Should switch to the `canonicalize` when it works.
         (if self < other || other.is_nan() { self } else { other }) * 1.0
     }
+
+    /// Raw transmutation to `u64`.
+    #[inline]
+    fn to_bits(self) -> u64 {
+        unsafe { mem::transmute(self) }
+    }
+
+    /// Raw transmutation from `u64`.
+    #[inline]
+    fn from_bits(v: u64) -> Self {
+        // It turns out the safety issues with sNaN were overblown! Hooray!
+        unsafe { mem::transmute(v) }
+    }
 }
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index 851c0a0dd6f..94efde6d41d 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -2872,6 +2872,10 @@ pub enum FpCategory {
            reason = "stable interface is via `impl f{32,64}` in later crates",
            issue = "32110")]
 pub trait Float: Sized {
+    /// Type used by `to_bits` and `from_bits`.
+    #[stable(feature = "core_float_bits", since = "1.24.0")]
+    type Bits: ops::Add<Output = Self::Bits> + From<u8> + TryFrom<u64>;
+
     /// Returns `true` if this value is NaN and false otherwise.
     #[stable(feature = "core", since = "1.6.0")]
     fn is_nan(self) -> bool;
@@ -2933,6 +2937,13 @@ pub trait Float: Sized {
     /// Returns the minimum of the two numbers.
     #[stable(feature = "core_float_min_max", since="1.20.0")]
     fn min(self, other: Self) -> Self;
+
+    /// Raw transmutation to integer.
+    #[stable(feature = "core_float_bits", since="1.24.0")]
+    fn to_bits(self) -> Self::Bits;
+    /// Raw transmutation from integer.
+    #[stable(feature = "core_float_bits", since="1.24.0")]
+    fn from_bits(v: Self::Bits) -> Self;
 }
 
 macro_rules! from_str_radix_int_impl {