]> git.lizzy.rs Git - rust.git/commitdiff
Add functions to safely transmute float to int
authorest31 <MTest31@outlook.com>
Tue, 24 Jan 2017 17:15:11 +0000 (18:15 +0100)
committerest31 <MTest31@outlook.com>
Tue, 18 Apr 2017 00:43:16 +0000 (02:43 +0200)
src/libstd/f32.rs
src/libstd/f64.rs
src/libstd/lib.rs

index dd8318006835f65cdf590cead33197a2e256106f..8e7b7ee0923a87d12f414f3a4b6f4bec2d7ce247 100644 (file)
@@ -1226,6 +1226,45 @@ pub fn acosh(self) -> f32 {
     pub fn atanh(self) -> f32 {
         0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
     }
+
+    /// Raw transmutation to `u32`.
+    ///
+    /// Converts the `f32` into its raw memory representation,
+    /// similar to the `transmute` function.
+    ///
+    /// Note that this function is distinct from casting.
+    ///
+    /// ```
+    /// #![feature(float_bits_conv)]
+    /// assert!((1f32).to_bits() != 1f32 as u32); // to_bits() is not casting!
+    /// assert_eq!((12.5f32).to_bits(), 0x41480000);
+    ///
+    /// ```
+    #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "0")]
+    #[inline]
+    pub fn to_bits(self) -> u32 {
+        unsafe { ::mem::transmute(self) }
+    }
+
+    /// Raw transmutation from `u32`.
+    ///
+    /// Converts the given `u32` containing the float's raw memory
+    /// representation into the `f32` type, similar to the
+    /// `transmute` function.
+    ///
+    /// Note that this function is distinct from casting.
+    ///
+    /// ```
+    /// #![feature(float_bits_conv)]
+    /// use std::f32;
+    /// let difference = (f32::from_bits(0x41480000) - 12.5).abs();
+    /// assert!(difference <= 1e-5);
+    /// ```
+    #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "0")]
+    #[inline]
+    pub fn from_bits(v: u32) -> Self {
+        unsafe { ::mem::transmute(v) }
+    }
 }
 
 #[cfg(test)]
@@ -1870,4 +1909,16 @@ fn test_real_consts() {
         assert_approx_eq!(ln_2, 2f32.ln());
         assert_approx_eq!(ln_10, 10f32.ln());
     }
+
+    #[test]
+    fn test_float_bits_conv() {
+        assert_eq!((1f32).to_bits(), 0x3f800000);
+        assert_eq!((12.5f32).to_bits(), 0x41480000);
+        assert_eq!((1337f32).to_bits(), 0x44a72000);
+        assert_eq!((-14.25f32).to_bits(), 0xc1640000);
+        assert_approx_eq!(f32::from_bits(0x3f800000), 1.0);
+        assert_approx_eq!(f32::from_bits(0x41480000), 12.5);
+        assert_approx_eq!(f32::from_bits(0x44a72000), 1337.0);
+        assert_approx_eq!(f32::from_bits(0xc1640000), -14.25);
+    }
 }
index 2f02e01935a4951438476c21db8939496eafbf85..f9a5a2705ae41e24c4c5e272762c90b2f2099e27 100644 (file)
@@ -1118,6 +1118,45 @@ fn log_wrapper<F: Fn(f64) -> f64>(self, log_fn: F) -> f64 {
             }
         }
     }
+
+    /// Raw transmutation to `u64`.
+    ///
+    /// Converts the `f64` into its raw memory representation,
+    /// similar to the `transmute` function.
+    ///
+    /// Note that this function is distinct from casting.
+    ///
+    /// ```
+    /// #![feature(float_bits_conv)]
+    /// assert!((1f64).to_bits() != 1f64 as u64); // to_bits() is not casting!
+    /// assert_eq!((12.5f64).to_bits(), 0x4029000000000000);
+    ///
+    /// ```
+    #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "0")]
+    #[inline]
+    pub fn to_bits(self) -> u64 {
+        unsafe { ::mem::transmute(self) }
+    }
+
+    /// Raw transmutation from `u64`.
+    ///
+    /// Converts the given `u64` containing the float's raw memory
+    /// representation into the `f64` type, similar to the
+    /// `transmute` function.
+    ///
+    /// Note that this function is distinct from casting.
+    ///
+    /// ```
+    /// #![feature(float_bits_conv)]
+    /// use std::f64;
+    /// let difference = (f64::from_bits(0x4029000000000000) - 12.5).abs();
+    /// assert!(difference <= 1e-5);
+    /// ```
+    #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "0")]
+    #[inline]
+    pub fn from_bits(v: u64) -> Self {
+        unsafe { ::mem::transmute(v) }
+    }
 }
 
 #[cfg(test)]
@@ -1755,4 +1794,16 @@ fn test_real_consts() {
         assert_approx_eq!(ln_2, 2f64.ln());
         assert_approx_eq!(ln_10, 10f64.ln());
     }
+
+    #[test]
+    fn test_float_bits_conv() {
+        assert_eq!((1f64).to_bits(), 0x3ff0000000000000);
+        assert_eq!((12.5f64).to_bits(), 0x4029000000000000);
+        assert_eq!((1337f64).to_bits(), 0x4094e40000000000);
+        assert_eq!((-14.25f64).to_bits(), 0xc02c800000000000);
+        assert_approx_eq!(f64::from_bits(0x3ff0000000000000), 1.0);
+        assert_approx_eq!(f64::from_bits(0x4029000000000000), 12.5);
+        assert_approx_eq!(f64::from_bits(0x4094e40000000000), 1337.0);
+        assert_approx_eq!(f64::from_bits(0xc02c800000000000), -14.25);
+    }
 }
index 4f6d170560c1da65d190ef738e2006ed4d3f4435..8de6e1a24f1f2d7f705bafb092255fea2389a7fe 100644 (file)
 #![feature(zero_one)]
 #![cfg_attr(test, feature(update_panic_count))]
 #![cfg_attr(stage0, feature(pub_restricted))]
+#![cfg_attr(test, feature(float_bits_conv))]
 
 // Explicitly import the prelude. The compiler uses this same unstable attribute
 // to import the prelude implicitly when building crates that depend on std.