From 32a43da68ae26bc3e22dbaca12ebb02ddc742cc7 Mon Sep 17 00:00:00 2001 From: est31 Date: Tue, 24 Jan 2017 18:15:11 +0100 Subject: [PATCH] Add functions to safely transmute float to int --- src/libstd/f32.rs | 51 +++++++++++++++++++++++++++++++++++++++++++++++ src/libstd/f64.rs | 51 +++++++++++++++++++++++++++++++++++++++++++++++ src/libstd/lib.rs | 1 + 3 files changed, 103 insertions(+) diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index dd831800683..8e7b7ee0923 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -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); + } } diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 2f02e01935a..f9a5a2705ae 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -1118,6 +1118,45 @@ fn log_wrapper 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); + } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 4f6d170560c..8de6e1a24f1 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -321,6 +321,7 @@ #![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. -- 2.44.0