diff options
| author | est31 <MTest31@outlook.com> | 2017-03-30 01:49:06 +0200 |
|---|---|---|
| committer | est31 <MTest31@outlook.com> | 2017-04-18 02:43:16 +0200 |
| commit | 3993eb4a276079af826c75e233e1a1d2ab93de13 (patch) | |
| tree | 0183aa6b45f9f2bfc525f5fc253107967efceb7e /src/libstd | |
| parent | fc028b81803277f7552355052bb277b10a066249 (diff) | |
| download | rust-3993eb4a276079af826c75e233e1a1d2ab93de13.tar.gz rust-3993eb4a276079af826c75e233e1a1d2ab93de13.zip | |
Preserve sNaN payload when converting them to quiet NaNs
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/f32.rs | 32 | ||||
| -rw-r--r-- | 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 40bf7f17c3a..8759f103dff 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 80bc149b1a4..a4645c3a70f 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) } } } |
