New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Expose float from_bits and to_bits in libcore. #46931
Changes from all commits
File filter...
Jump to…
Diff settings
| @@ -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 ops::{Mul, Div, Neg}; | |||
| use convert::{TryFrom, TryInto}; | |||
| use ops::{Add, 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; | |||
| @@ -56,22 +55,27 @@ impl Unpacked { | |||
| /// | |||
| /// 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<Output=Self> + Div<Output=Self> + Neg<Output=Self> | |||
| pub trait RawFloat | |||
| : Float | |||
| + Copy | |||
| + Debug | |||
| + LowerExp | |||
| + Mul<Output=Self> | |||
| + Div<Output=Self> | |||
| + Neg<Output=Self> | |||
| where | |||
| Self: Float<Bits = <Self as RawFloat>::RawBits> | |||
| { | |||
| const INFINITY: Self; | |||
| const NAN: Self; | |||
| const ZERO: Self; | |||
|
|
|||
| /// Same as `Float::Bits` with extra traits. | |||
| type RawBits: Add<Output = Self::RawBits> + From<u8> + TryFrom<u64>; | |||
|
|
|||
| /// 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; | |||
|
|
|||
| @@ -149,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; | |||
| @@ -159,7 +165,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 +178,6 @@ impl RawFloat for f32 { | |||
| (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) | |||
| @@ -200,6 +196,8 @@ impl RawFloat for f32 { | |||
|
|
|||
|
|
|||
| 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; | |||
| @@ -210,7 +208,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 +221,6 @@ impl RawFloat for f64 { | |||
| (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 +285,14 @@ pub fn encode_normal<T: RawFloat>(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<T: RawFloat>(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!())) | |||
rkruppe
Member
|
|||
| } | |||
|
|
|||
| /// Approximate a bignum with an Fp. Rounds within 0.5 ULP with half-to-even. | |||
| @@ -363,8 +352,7 @@ pub fn next_float<T: RawFloat>(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)) | |||
clarfon
Author
Contributor
|
|||
| } | |||
| } | |||
| } | |||
This seems to be a step back, isn't there a way to keep this using just from_bits? Do you know if it has any performance impact?
The assertion
assert!(bits < u32::MAX as u64, "f32::from_bits: too many bits");from the old code has been lost, but I suppose it is unreachable here.