Expose float from_bits and to_bits in libcore.

This commit is contained in:
Clar Charr 2017-12-21 20:23:47 -05:00
parent 5165ee9e20
commit a2cdeb58f6
6 changed files with 55 additions and 53 deletions

View file

@ -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 @@ 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)
@ -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 @@ 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 +270,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!()))
}
/// Approximate a bignum with an Fp. Rounds within 0.5 ULP with half-to-even.
@ -363,8 +337,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))
}
}
}

View file

@ -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 @@ impl Float for f32 {
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 @@ impl Float for f32 {
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 @@ impl Float for 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) }
}
}

View file

@ -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 @@ impl Float for f64 {
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 @@ impl Float for f64 {
/// 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 @@ impl Float for 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) }
}
}

View file

@ -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<Output = Self::Bits> + From<u8> + TryFrom<u64>;
/// 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 {

View file

@ -1016,7 +1016,7 @@ impl 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 @@ impl f32 {
#[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)
}
}

View file

@ -971,7 +971,7 @@ impl 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 @@ impl f64 {
#[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)
}
}