From a2cdeb58f680b87b5bdb6a17cba857ac51307c8f Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Thu, 21 Dec 2017 20:23:47 -0500 Subject: [PATCH 1/2] Expose float from_bits and to_bits in libcore. --- src/libcore/num/dec2flt/rawfp.rs | 39 +++++--------------------------- src/libcore/num/f32.rs | 24 ++++++++++++++------ src/libcore/num/f64.rs | 24 ++++++++++++++------ src/libcore/num/mod.rs | 11 +++++++++ src/libstd/f32.rs | 5 ++-- src/libstd/f64.rs | 5 ++-- 6 files changed, 55 insertions(+), 53 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 @@ fn integer_decode(self) -> (u64, i16, i8) { (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 @@ fn integer_decode(self) -> (u64, i16, i8) { (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(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(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(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 @@ fn classify(self) -> Fp { 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 @@ fn is_sign_positive(self) -> bool { 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 @@ fn min(self, other: f32) -> 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 @@ fn classify(self) -> Fp { 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 @@ fn is_sign_positive(self) -> bool { /// 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 @@ fn min(self, other: f64) -> 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 + From + TryFrom; + /// 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 { diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index e5b1394f070..18eb2a27b91 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -1016,7 +1016,7 @@ pub fn atanh(self) -> f32 { #[stable(feature = "float_bits_conv", since = "1.20.0")] #[inline] pub fn to_bits(self) -> u32 { - unsafe { ::mem::transmute(self) } + num::Float::to_bits(self) } /// Raw transmutation from `u32`. @@ -1060,8 +1060,7 @@ pub fn to_bits(self) -> u32 { #[stable(feature = "float_bits_conv", since = "1.20.0")] #[inline] pub fn from_bits(v: u32) -> Self { - // It turns out the safety issues with sNaN were overblown! Hooray! - unsafe { ::mem::transmute(v) } + num::Float::from_bits(v) } } diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index f4d804fd508..cabb2c48054 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -971,7 +971,7 @@ fn log_wrapper f64>(self, log_fn: F) -> f64 { #[stable(feature = "float_bits_conv", since = "1.20.0")] #[inline] pub fn to_bits(self) -> u64 { - unsafe { ::mem::transmute(self) } + num::Float::to_bits(self) } /// Raw transmutation from `u64`. @@ -1015,8 +1015,7 @@ pub fn to_bits(self) -> u64 { #[stable(feature = "float_bits_conv", since = "1.20.0")] #[inline] pub fn from_bits(v: u64) -> Self { - // It turns out the safety issues with sNaN were overblown! Hooray! - unsafe { ::mem::transmute(v) } + num::Float::from_bits(v) } } From 556fb02e43a16de50764af55db20f64ac17e7f23 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Sat, 23 Dec 2017 17:51:06 -0500 Subject: [PATCH 2/2] Move Bits constraints to RawFloat::RawBits --- src/libcore/num/dec2flt/rawfp.rs | 23 +++++++++++++++++++---- src/libcore/num/mod.rs | 2 +- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/libcore/num/dec2flt/rawfp.rs b/src/libcore/num/dec2flt/rawfp.rs index 143a05a1944..77180233a23 100644 --- a/src/libcore/num/dec2flt/rawfp.rs +++ b/src/libcore/num/dec2flt/rawfp.rs @@ -28,8 +28,8 @@ //! 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 cmp::Ordering::{Less, Equal, Greater}; -use convert::TryInto; -use ops::{Mul, Div, Neg}; +use convert::{TryFrom, TryInto}; +use ops::{Add, Mul, Div, Neg}; use fmt::{Debug, LowerExp}; use num::diy_float::Fp; use num::FpCategory::{Infinite, Zero, Subnormal, Normal, Nan}; @@ -55,13 +55,24 @@ pub fn new(sig: u64, k: i16) -> Self { /// /// Should **never ever** be implemented for other types or be used outside the dec2flt module. /// Inherits from `Float` because there is some overlap, but all the reused methods are trivial. -pub trait RawFloat : Float + Copy + Debug + LowerExp - + Mul + Div + Neg +pub trait RawFloat + : Float + + Copy + + Debug + + LowerExp + + Mul + + Div + + Neg +where + Self: Float::RawBits> { const INFINITY: Self; const NAN: Self; const ZERO: Self; + /// Same as `Float::Bits` with extra traits. + type RawBits: Add + From + TryFrom; + /// Returns the mantissa, exponent and sign as integers. fn integer_decode(self) -> (u64, i16, i8); @@ -142,6 +153,8 @@ macro_rules! other_constants { } impl RawFloat for f32 { + type RawBits = u32; + const SIG_BITS: u8 = 24; const EXP_BITS: u8 = 8; const CEIL_LOG5_OF_MAX_SIG: i16 = 11; @@ -183,6 +196,8 @@ fn short_fast_pow10(e: usize) -> Self { impl RawFloat for f64 { + type RawBits = u64; + const SIG_BITS: u8 = 53; const EXP_BITS: u8 = 11; const CEIL_LOG5_OF_MAX_SIG: i16 = 23; diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 94efde6d41d..ebf8a9597fe 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -2874,7 +2874,7 @@ pub enum FpCategory { 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 + From + TryFrom; + type Bits; /// Returns `true` if this value is NaN and false otherwise. #[stable(feature = "core", since = "1.6.0")]