From 32a43da68ae26bc3e22dbaca12ebb02ddc742cc7 Mon Sep 17 00:00:00 2001 From: est31 Date: Tue, 24 Jan 2017 18:15:11 +0100 Subject: [PATCH 1/8] 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 dd8318006835f..8e7b7ee0923a8 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -1226,6 +1226,45 @@ impl 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 @@ mod tests { 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 2f02e01935a49..f9a5a2705ae41 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -1118,6 +1118,45 @@ impl 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 @@ mod tests { 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 4f6d170560c1d..8de6e1a24f1f2 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. From 82eead0d0b687c79cc79029e45325aecd9c9ef73 Mon Sep 17 00:00:00 2001 From: est31 Date: Tue, 24 Jan 2017 20:49:33 +0100 Subject: [PATCH 2/8] Return Err(()) when trying to convert sNaN representation to float --- src/libstd/f32.rs | 24 +++++++++++++++++------- src/libstd/f64.rs | 24 +++++++++++++++++------- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 8e7b7ee0923a8..ec0547662ccca 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -1254,16 +1254,26 @@ impl f32 { /// /// Note that this function is distinct from casting. /// + /// Returns `Err(())` if the representation of a signaling NaN "sNaN" + /// float, is passed to the function. + /// /// ``` /// #![feature(float_bits_conv)] /// use std::f32; - /// let difference = (f32::from_bits(0x41480000) - 12.5).abs(); + /// let v = f32::from_bits(0x41480000).unwrap(); + /// let difference = (v - 12.5).abs(); /// assert!(difference <= 1e-5); + /// // Example for a signaling NaN value: + /// assert_eq!(f32::from_bits(0x7F800001), Err(())); /// ``` #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "0")] #[inline] - pub fn from_bits(v: u32) -> Self { - unsafe { ::mem::transmute(v) } + pub fn from_bits(v: u32) -> Result { + match v { + 0x7F800001 ... 0x7FBFFFFF | + 0xFF800001 ... 0xFFBFFFFF => Err(()), + _ => Ok(unsafe { ::mem::transmute(v) }), + } } } @@ -1916,9 +1926,9 @@ mod tests { 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); + assert_approx_eq!(f32::from_bits(0x3f800000).unwrap(), 1.0); + assert_approx_eq!(f32::from_bits(0x41480000).unwrap(), 12.5); + assert_approx_eq!(f32::from_bits(0x44a72000).unwrap(), 1337.0); + assert_approx_eq!(f32::from_bits(0xc1640000).unwrap(), -14.25); } } diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index f9a5a2705ae41..456ea9c14112d 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -1146,16 +1146,26 @@ impl f64 { /// /// Note that this function is distinct from casting. /// + /// Returns `Err(())` if the representation of a signaling NaN "sNaN" + /// float, is passed to the function. + /// /// ``` /// #![feature(float_bits_conv)] /// use std::f64; - /// let difference = (f64::from_bits(0x4029000000000000) - 12.5).abs(); + /// let v = f64::from_bits(0x4029000000000000).unwrap(); + /// let difference = (v - 12.5).abs(); /// assert!(difference <= 1e-5); + /// // Example for a signaling NaN value: + /// assert_eq!(f64::from_bits(0x7FF0000000000001), Err(())); /// ``` #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "0")] #[inline] - pub fn from_bits(v: u64) -> Self { - unsafe { ::mem::transmute(v) } + pub fn from_bits(v: u64) -> Result { + match v { + 0x7FF0000000000001 ... 0x7FF7FFFFFFFFFFFF | + 0xFFF0000000000001 ... 0xFFF7FFFFFFFFFFFF => Err(()), + _ => Ok(unsafe { ::mem::transmute(v) }), + } } } @@ -1801,9 +1811,9 @@ mod tests { 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); + assert_approx_eq!(f64::from_bits(0x3ff0000000000000).unwrap(), 1.0); + assert_approx_eq!(f64::from_bits(0x4029000000000000).unwrap(), 12.5); + assert_approx_eq!(f64::from_bits(0x4094e40000000000).unwrap(), 1337.0); + assert_approx_eq!(f64::from_bits(0xc02c800000000000).unwrap(), -14.25); } } From 56760abf3b0202a74fcfb1b62bc53cfbddd8259c Mon Sep 17 00:00:00 2001 From: est31 Date: Tue, 24 Jan 2017 21:28:12 +0100 Subject: [PATCH 3/8] Add examples heading --- src/libstd/f32.rs | 4 ++++ src/libstd/f64.rs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index ec0547662ccca..5ec01e2e215cc 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -1234,6 +1234,8 @@ impl f32 { /// /// Note that this function is distinct from casting. /// + /// # Examples + /// /// ``` /// #![feature(float_bits_conv)] /// assert!((1f32).to_bits() != 1f32 as u32); // to_bits() is not casting! @@ -1257,6 +1259,8 @@ impl f32 { /// Returns `Err(())` if the representation of a signaling NaN "sNaN" /// float, is passed to the function. /// + /// # Examples + /// /// ``` /// #![feature(float_bits_conv)] /// use std::f32; diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 456ea9c14112d..96d38f67ee214 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -1126,6 +1126,8 @@ impl f64 { /// /// Note that this function is distinct from casting. /// + /// # Examples + /// /// ``` /// #![feature(float_bits_conv)] /// assert!((1f64).to_bits() != 1f64 as u64); // to_bits() is not casting! @@ -1149,6 +1151,8 @@ impl f64 { /// Returns `Err(())` if the representation of a signaling NaN "sNaN" /// float, is passed to the function. /// + /// # Examples + /// /// ``` /// #![feature(float_bits_conv)] /// use std::f64; From bdab5cdc6336793968d790b1512fdfeeed2260e4 Mon Sep 17 00:00:00 2001 From: est31 Date: Mon, 13 Mar 2017 10:25:50 +0100 Subject: [PATCH 4/8] assert_ne and tracking issue --- src/libstd/f32.rs | 6 +++--- src/libstd/f64.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 5ec01e2e215cc..76b629fb1d4cd 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -1238,11 +1238,11 @@ impl f32 { /// /// ``` /// #![feature(float_bits_conv)] - /// assert!((1f32).to_bits() != 1f32 as u32); // to_bits() is not casting! + /// assert_ne!((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")] + #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "40470")] #[inline] pub fn to_bits(self) -> u32 { unsafe { ::mem::transmute(self) } @@ -1270,7 +1270,7 @@ impl f32 { /// // Example for a signaling NaN value: /// assert_eq!(f32::from_bits(0x7F800001), Err(())); /// ``` - #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "0")] + #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "40470")] #[inline] pub fn from_bits(v: u32) -> Result { match v { diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 96d38f67ee214..f553e580f0fa9 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -1134,7 +1134,7 @@ impl f64 { /// assert_eq!((12.5f64).to_bits(), 0x4029000000000000); /// /// ``` - #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "0")] + #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "40470")] #[inline] pub fn to_bits(self) -> u64 { unsafe { ::mem::transmute(self) } @@ -1162,7 +1162,7 @@ impl f64 { /// // Example for a signaling NaN value: /// assert_eq!(f64::from_bits(0x7FF0000000000001), Err(())); /// ``` - #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "0")] + #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "40470")] #[inline] pub fn from_bits(v: u64) -> Result { match v { From fc028b81803277f7552355052bb277b10a066249 Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 29 Mar 2017 02:39:59 +0200 Subject: [PATCH 5/8] Convert sNaN to quiet NaN instead of returning errors --- src/libstd/f32.rs | 30 ++++++++++++++++++------------ src/libstd/f64.rs | 30 ++++++++++++++++++------------ 2 files changed, 36 insertions(+), 24 deletions(-) diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 76b629fb1d4cd..40bf7f17c3aa6 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -1254,29 +1254,35 @@ impl f32 { /// representation into the `f32` type, similar to the /// `transmute` function. /// - /// Note that this function is distinct from casting. + /// There is only one difference to a bare `transmute`: + /// Due to the implications onto Rust's safety promises being + /// uncertain, if the representation of a signaling NaN "sNaN" float + /// is passed to the function, a quiet NaN will be returned + /// instead. /// - /// Returns `Err(())` if the representation of a signaling NaN "sNaN" - /// float, is passed to the function. + /// Note that this function is distinct from casting. /// /// # Examples /// /// ``` /// #![feature(float_bits_conv)] /// use std::f32; - /// let v = f32::from_bits(0x41480000).unwrap(); + /// let v = f32::from_bits(0x41480000); /// let difference = (v - 12.5).abs(); /// assert!(difference <= 1e-5); /// // Example for a signaling NaN value: - /// assert_eq!(f32::from_bits(0x7F800001), Err(())); + /// let snan = 0x7F800001; + /// assert_ne!(f32::from_bits(snan).to_bits(), snan); /// ``` #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "40470")] #[inline] - pub fn from_bits(v: u32) -> Result { + pub fn from_bits(v: u32) -> Self { match v { + // sNaN limits source: + // https://www.doc.ic.ac.uk/~eedwards/compsys/float/nan.html 0x7F800001 ... 0x7FBFFFFF | - 0xFF800001 ... 0xFFBFFFFF => Err(()), - _ => Ok(unsafe { ::mem::transmute(v) }), + 0xFF800001 ... 0xFFBFFFFF => ::f32::NAN, + _ => unsafe { ::mem::transmute(v) }, } } } @@ -1930,9 +1936,9 @@ mod tests { 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).unwrap(), 1.0); - assert_approx_eq!(f32::from_bits(0x41480000).unwrap(), 12.5); - assert_approx_eq!(f32::from_bits(0x44a72000).unwrap(), 1337.0); - assert_approx_eq!(f32::from_bits(0xc1640000).unwrap(), -14.25); + 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 f553e580f0fa9..80bc149b1a40a 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -1146,29 +1146,35 @@ impl f64 { /// representation into the `f64` type, similar to the /// `transmute` function. /// - /// Note that this function is distinct from casting. + /// There is only one difference to a bare `transmute`: + /// Due to the implications onto Rust's safety promises being + /// uncertain, if the representation of a signaling NaN "sNaN" float + /// is passed to the function, a quiet NaN will be returned + /// instead. /// - /// Returns `Err(())` if the representation of a signaling NaN "sNaN" - /// float, is passed to the function. + /// Note that this function is distinct from casting. /// /// # Examples /// /// ``` /// #![feature(float_bits_conv)] /// use std::f64; - /// let v = f64::from_bits(0x4029000000000000).unwrap(); + /// let v = f64::from_bits(0x4029000000000000); /// let difference = (v - 12.5).abs(); /// assert!(difference <= 1e-5); /// // Example for a signaling NaN value: - /// assert_eq!(f64::from_bits(0x7FF0000000000001), Err(())); + /// let snan = 0x7FF0000000000001; + /// assert_ne!(f64::from_bits(snan).to_bits(), snan); /// ``` #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "40470")] #[inline] - pub fn from_bits(v: u64) -> Result { + pub fn from_bits(v: u64) -> Self { match v { + // sNaN limits source: + // https://www.doc.ic.ac.uk/~eedwards/compsys/float/nan.html 0x7FF0000000000001 ... 0x7FF7FFFFFFFFFFFF | - 0xFFF0000000000001 ... 0xFFF7FFFFFFFFFFFF => Err(()), - _ => Ok(unsafe { ::mem::transmute(v) }), + 0xFFF0000000000001 ... 0xFFF7FFFFFFFFFFFF => ::f64::NAN, + _ => unsafe { ::mem::transmute(v) }, } } } @@ -1815,9 +1821,9 @@ mod tests { 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).unwrap(), 1.0); - assert_approx_eq!(f64::from_bits(0x4029000000000000).unwrap(), 12.5); - assert_approx_eq!(f64::from_bits(0x4094e40000000000).unwrap(), 1337.0); - assert_approx_eq!(f64::from_bits(0xc02c800000000000).unwrap(), -14.25); + 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); } } From 3993eb4a276079af826c75e233e1a1d2ab93de13 Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 30 Mar 2017 01:49:06 +0200 Subject: [PATCH 6/8] Preserve sNaN payload when converting them to quiet NaNs --- src/libstd/f32.rs | 32 +++++++++++++++++++++++++------- src/libstd/f64.rs | 17 ++++++++++------- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 40bf7f17c3aa6..8759f103dff1f 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -1276,14 +1276,17 @@ impl f32 { /// ``` #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "40470")] #[inline] - pub fn from_bits(v: u32) -> Self { - match v { - // sNaN limits source: - // https://www.doc.ic.ac.uk/~eedwards/compsys/float/nan.html - 0x7F800001 ... 0x7FBFFFFF | - 0xFF800001 ... 0xFFBFFFFF => ::f32::NAN, - _ => unsafe { ::mem::transmute(v) }, + pub fn from_bits(mut v: u32) -> Self { + const EXP_MASK: u32 = 0x7F800000; + const QNAN_MASK: u32 = 0x00400000; + const FRACT_MASK: u32 = 0x007FFFFF; + if v & EXP_MASK == EXP_MASK && v & FRACT_MASK != 0 { + // If we have a NaN value, we + // convert signaling NaN values to quiet NaN + // by setting the the highest bit of the fraction + v |= QNAN_MASK; } + unsafe { ::mem::transmute(v) } } } @@ -1941,4 +1944,19 @@ mod tests { assert_approx_eq!(f32::from_bits(0x44a72000), 1337.0); assert_approx_eq!(f32::from_bits(0xc1640000), -14.25); } + #[test] + fn test_snan_masking() { + let snan: u32 = 0x7F801337; + const PAYLOAD_MASK: u32 = 0x003FFFFF; + const QNAN_MASK: u32 = 0x00400000; + let nan_masked_fl = f32::from_bits(snan); + let nan_masked = nan_masked_fl.to_bits(); + // Ensure that signaling NaNs don't stay the same + assert_ne!(nan_masked, snan); + // Ensure that we have a quiet NaN + assert_ne!(nan_masked & QNAN_MASK, 0); + assert!(nan_masked_fl.is_nan()); + // Ensure the payload wasn't touched during conversion + assert_eq!(nan_masked & PAYLOAD_MASK, snan & PAYLOAD_MASK); + } } diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 80bc149b1a40a..a4645c3a70f97 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -1168,14 +1168,17 @@ impl f64 { /// ``` #[unstable(feature = "float_bits_conv", reason = "recently added", issue = "40470")] #[inline] - pub fn from_bits(v: u64) -> Self { - match v { - // sNaN limits source: - // https://www.doc.ic.ac.uk/~eedwards/compsys/float/nan.html - 0x7FF0000000000001 ... 0x7FF7FFFFFFFFFFFF | - 0xFFF0000000000001 ... 0xFFF7FFFFFFFFFFFF => ::f64::NAN, - _ => unsafe { ::mem::transmute(v) }, + pub fn from_bits(mut v: u64) -> Self { + const EXP_MASK: u64 = 0x7FF0000000000000; + const QNAN_MASK: u64 = 0x0001000000000000; + const FRACT_MASK: u64 = 0x000FFFFFFFFFFFFF; + if v & EXP_MASK == EXP_MASK && v & FRACT_MASK != 0 { + // If we have a NaN value, we + // convert signaling NaN values to quiet NaN + // by setting the the highest bit of the fraction + v |= QNAN_MASK; } + unsafe { ::mem::transmute(v) } } } From 873a3b0363fd8f211f720c3b021a4e1c4c11f754 Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 31 Mar 2017 00:40:02 +0200 Subject: [PATCH 7/8] Allow us to remove masking in the future --- src/libstd/f32.rs | 4 ++-- src/libstd/f64.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 8759f103dff1f..316e6841c4fea 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -1257,8 +1257,8 @@ impl f32 { /// There is only one difference to a bare `transmute`: /// Due to the implications onto Rust's safety promises being /// uncertain, if the representation of a signaling NaN "sNaN" float - /// is passed to the function, a quiet NaN will be returned - /// instead. + /// is passed to the function, the implementation is allowed to + /// return a quiet NaN instead. /// /// Note that this function is distinct from casting. /// diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index a4645c3a70f97..be55cb80c92fa 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -1149,8 +1149,8 @@ impl f64 { /// There is only one difference to a bare `transmute`: /// Due to the implications onto Rust's safety promises being /// uncertain, if the representation of a signaling NaN "sNaN" float - /// is passed to the function, a quiet NaN will be returned - /// instead. + /// is passed to the function, the implementation is allowed to + /// return a quiet NaN instead. /// /// Note that this function is distinct from casting. /// From 0c148153f4de0c32206582ed9b51346f9769f10c Mon Sep 17 00:00:00 2001 From: est31 Date: Tue, 18 Apr 2017 02:55:47 +0200 Subject: [PATCH 8/8] Add float_bits_conv to unstable book --- src/doc/unstable-book/src/SUMMARY.md | 1 + src/doc/unstable-book/src/float-bits-conv.md | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 src/doc/unstable-book/src/float-bits-conv.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 42af79b8bb07f..173845047946c 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -72,6 +72,7 @@ - [fd](fd.md) - [fd_read](fd-read.md) - [fixed_size_array](fixed-size-array.md) +- [float_bits_conv](float-bits-conv.md) - [float_extras](float-extras.md) - [flt2dec](flt2dec.md) - [fmt_flags_align](fmt-flags-align.md) diff --git a/src/doc/unstable-book/src/float-bits-conv.md b/src/doc/unstable-book/src/float-bits-conv.md new file mode 100644 index 0000000000000..f519545ac78b5 --- /dev/null +++ b/src/doc/unstable-book/src/float-bits-conv.md @@ -0,0 +1,7 @@ +# `float_bits_conv` + +The tracking issue for this feature is: [#40470] + +[#40470]: https://github.com/rust-lang/rust/issues/40470 + +------------------------