Auto merge of #46931 - clarcharr:float_bits_core, r=alexcrichton
Expose float from_bits and to_bits in libcore. These methods have no dependencies on libm and thus should be offered in libcore.
This commit is contained in:
commit
a538fe7ce7
@ -27,11 +27,10 @@
|
|||||||
//! Many functions in this module only handle normal numbers. The dec2flt routines conservatively
|
//! 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.
|
//! 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.
|
//! That algorithm needs only next_float() which does handle subnormals and zeros.
|
||||||
use u32;
|
|
||||||
use cmp::Ordering::{Less, Equal, Greater};
|
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 fmt::{Debug, LowerExp};
|
||||||
use mem::transmute;
|
|
||||||
use num::diy_float::Fp;
|
use num::diy_float::Fp;
|
||||||
use num::FpCategory::{Infinite, Zero, Subnormal, Normal, Nan};
|
use num::FpCategory::{Infinite, Zero, Subnormal, Normal, Nan};
|
||||||
use num::Float;
|
use num::Float;
|
||||||
@ -56,22 +55,27 @@ impl Unpacked {
|
|||||||
///
|
///
|
||||||
/// Should **never ever** be implemented for other types or be used outside the dec2flt module.
|
/// 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.
|
/// Inherits from `Float` because there is some overlap, but all the reused methods are trivial.
|
||||||
pub trait RawFloat : Float + Copy + Debug + LowerExp
|
pub trait RawFloat
|
||||||
+ Mul<Output=Self> + Div<Output=Self> + Neg<Output=Self>
|
: 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 INFINITY: Self;
|
||||||
const NAN: Self;
|
const NAN: Self;
|
||||||
const ZERO: 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.
|
/// Returns the mantissa, exponent and sign as integers.
|
||||||
fn integer_decode(self) -> (u64, i16, i8);
|
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.
|
/// Decode the float.
|
||||||
fn unpack(self) -> Unpacked;
|
fn unpack(self) -> Unpacked;
|
||||||
|
|
||||||
@ -149,6 +153,8 @@ macro_rules! other_constants {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RawFloat for f32 {
|
impl RawFloat for f32 {
|
||||||
|
type RawBits = u32;
|
||||||
|
|
||||||
const SIG_BITS: u8 = 24;
|
const SIG_BITS: u8 = 24;
|
||||||
const EXP_BITS: u8 = 8;
|
const EXP_BITS: u8 = 8;
|
||||||
const CEIL_LOG5_OF_MAX_SIG: i16 = 11;
|
const CEIL_LOG5_OF_MAX_SIG: i16 = 11;
|
||||||
@ -159,7 +165,7 @@ impl RawFloat for f32 {
|
|||||||
|
|
||||||
/// Returns the mantissa, exponent and sign as integers.
|
/// Returns the mantissa, exponent and sign as integers.
|
||||||
fn integer_decode(self) -> (u64, i16, i8) {
|
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 sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
|
||||||
let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
|
let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
|
||||||
let mantissa = if exponent == 0 {
|
let mantissa = if exponent == 0 {
|
||||||
@ -172,16 +178,6 @@ impl RawFloat for f32 {
|
|||||||
(mantissa as u64, exponent, sign)
|
(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 {
|
fn unpack(self) -> Unpacked {
|
||||||
let (sig, exp, _sig) = self.integer_decode();
|
let (sig, exp, _sig) = self.integer_decode();
|
||||||
Unpacked::new(sig, exp)
|
Unpacked::new(sig, exp)
|
||||||
@ -200,6 +196,8 @@ impl RawFloat for f32 {
|
|||||||
|
|
||||||
|
|
||||||
impl RawFloat for f64 {
|
impl RawFloat for f64 {
|
||||||
|
type RawBits = u64;
|
||||||
|
|
||||||
const SIG_BITS: u8 = 53;
|
const SIG_BITS: u8 = 53;
|
||||||
const EXP_BITS: u8 = 11;
|
const EXP_BITS: u8 = 11;
|
||||||
const CEIL_LOG5_OF_MAX_SIG: i16 = 23;
|
const CEIL_LOG5_OF_MAX_SIG: i16 = 23;
|
||||||
@ -210,7 +208,7 @@ impl RawFloat for f64 {
|
|||||||
|
|
||||||
/// Returns the mantissa, exponent and sign as integers.
|
/// Returns the mantissa, exponent and sign as integers.
|
||||||
fn integer_decode(self) -> (u64, i16, i8) {
|
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 sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
|
||||||
let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
|
let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
|
||||||
let mantissa = if exponent == 0 {
|
let mantissa = if exponent == 0 {
|
||||||
@ -223,15 +221,6 @@ impl RawFloat for f64 {
|
|||||||
(mantissa, exponent, sign)
|
(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 {
|
fn unpack(self) -> Unpacked {
|
||||||
let (sig, exp, _sig) = self.integer_decode();
|
let (sig, exp, _sig) = self.integer_decode();
|
||||||
Unpacked::new(sig, exp)
|
Unpacked::new(sig, exp)
|
||||||
@ -296,14 +285,14 @@ pub fn encode_normal<T: RawFloat>(x: Unpacked) -> T {
|
|||||||
"encode_normal: exponent out of range");
|
"encode_normal: exponent out of range");
|
||||||
// Leave sign bit at 0 ("+"), our numbers are all positive
|
// Leave sign bit at 0 ("+"), our numbers are all positive
|
||||||
let bits = (k_enc as u64) << T::EXPLICIT_SIG_BITS | sig_enc;
|
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.
|
/// Construct a subnormal. A mantissa of 0 is allowed and constructs zero.
|
||||||
pub fn encode_subnormal<T: RawFloat>(significand: u64) -> T {
|
pub fn encode_subnormal<T: RawFloat>(significand: u64) -> T {
|
||||||
assert!(significand < T::MIN_SIG, "encode_subnormal: not actually subnormal");
|
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.
|
// 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.
|
/// 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!
|
// too is exactly what we want!
|
||||||
// Finally, f64::MAX + 1 = 7eff...f + 1 = 7ff0...0 = f64::INFINITY.
|
// Finally, f64::MAX + 1 = 7eff...f + 1 = 7ff0...0 = f64::INFINITY.
|
||||||
Zero | Subnormal | Normal => {
|
Zero | Subnormal | Normal => {
|
||||||
let bits: u64 = x.transmute();
|
T::from_bits(x.to_bits() + T::Bits::from(1u8))
|
||||||
T::from_bits(bits + 1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,6 +145,8 @@ pub mod consts {
|
|||||||
reason = "stable interface is via `impl f{32,64}` in later crates",
|
reason = "stable interface is via `impl f{32,64}` in later crates",
|
||||||
issue = "32110")]
|
issue = "32110")]
|
||||||
impl Float for f32 {
|
impl Float for f32 {
|
||||||
|
type Bits = u32;
|
||||||
|
|
||||||
/// Returns `true` if the number is NaN.
|
/// Returns `true` if the number is NaN.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_nan(self) -> bool {
|
fn is_nan(self) -> bool {
|
||||||
@ -176,7 +178,7 @@ impl Float for f32 {
|
|||||||
const EXP_MASK: u32 = 0x7f800000;
|
const EXP_MASK: u32 = 0x7f800000;
|
||||||
const MAN_MASK: u32 = 0x007fffff;
|
const MAN_MASK: u32 = 0x007fffff;
|
||||||
|
|
||||||
let bits: u32 = unsafe { mem::transmute(self) };
|
let bits = self.to_bits();
|
||||||
match (bits & MAN_MASK, bits & EXP_MASK) {
|
match (bits & MAN_MASK, bits & EXP_MASK) {
|
||||||
(0, 0) => Fp::Zero,
|
(0, 0) => Fp::Zero,
|
||||||
(_, 0) => Fp::Subnormal,
|
(_, 0) => Fp::Subnormal,
|
||||||
@ -220,12 +222,7 @@ impl Float for f32 {
|
|||||||
fn is_sign_negative(self) -> bool {
|
fn is_sign_negative(self) -> bool {
|
||||||
// IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus
|
// IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus
|
||||||
// applies to zeros and NaNs as well.
|
// applies to zeros and NaNs as well.
|
||||||
#[repr(C)]
|
self.to_bits() & 0x8000_0000 != 0
|
||||||
union F32Bytes {
|
|
||||||
f: f32,
|
|
||||||
b: u32
|
|
||||||
}
|
|
||||||
unsafe { F32Bytes { f: self }.b & 0x8000_0000 != 0 }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the reciprocal (multiplicative inverse) of the number.
|
/// Returns the reciprocal (multiplicative inverse) of the number.
|
||||||
@ -279,4 +276,17 @@ impl Float for f32 {
|
|||||||
// multiplying by 1.0. Should switch to the `canonicalize` when it works.
|
// multiplying by 1.0. Should switch to the `canonicalize` when it works.
|
||||||
(if other.is_nan() || self < other { self } else { other }) * 1.0
|
(if other.is_nan() || self < other { 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) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,6 +145,8 @@ pub mod consts {
|
|||||||
reason = "stable interface is via `impl f{32,64}` in later crates",
|
reason = "stable interface is via `impl f{32,64}` in later crates",
|
||||||
issue = "32110")]
|
issue = "32110")]
|
||||||
impl Float for f64 {
|
impl Float for f64 {
|
||||||
|
type Bits = u64;
|
||||||
|
|
||||||
/// Returns `true` if the number is NaN.
|
/// Returns `true` if the number is NaN.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_nan(self) -> bool {
|
fn is_nan(self) -> bool {
|
||||||
@ -176,7 +178,7 @@ impl Float for f64 {
|
|||||||
const EXP_MASK: u64 = 0x7ff0000000000000;
|
const EXP_MASK: u64 = 0x7ff0000000000000;
|
||||||
const MAN_MASK: u64 = 0x000fffffffffffff;
|
const MAN_MASK: u64 = 0x000fffffffffffff;
|
||||||
|
|
||||||
let bits: u64 = unsafe { mem::transmute(self) };
|
let bits = self.to_bits();
|
||||||
match (bits & MAN_MASK, bits & EXP_MASK) {
|
match (bits & MAN_MASK, bits & EXP_MASK) {
|
||||||
(0, 0) => Fp::Zero,
|
(0, 0) => Fp::Zero,
|
||||||
(_, 0) => Fp::Subnormal,
|
(_, 0) => Fp::Subnormal,
|
||||||
@ -218,12 +220,7 @@ impl Float for f64 {
|
|||||||
/// negative sign bit and negative infinity.
|
/// negative sign bit and negative infinity.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_sign_negative(self) -> bool {
|
fn is_sign_negative(self) -> bool {
|
||||||
#[repr(C)]
|
self.to_bits() & 0x8000_0000_0000_0000 != 0
|
||||||
union F64Bytes {
|
|
||||||
f: f64,
|
|
||||||
b: u64
|
|
||||||
}
|
|
||||||
unsafe { F64Bytes { f: self }.b & 0x8000_0000_0000_0000 != 0 }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the reciprocal (multiplicative inverse) of the number.
|
/// Returns the reciprocal (multiplicative inverse) of the number.
|
||||||
@ -277,4 +274,17 @@ impl Float for f64 {
|
|||||||
// multiplying by 1.0. Should switch to the `canonicalize` when it works.
|
// multiplying by 1.0. Should switch to the `canonicalize` when it works.
|
||||||
(if other.is_nan() || self < other { self } else { other }) * 1.0
|
(if other.is_nan() || self < other { 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) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2880,6 +2880,10 @@ pub enum FpCategory {
|
|||||||
reason = "stable interface is via `impl f{32,64}` in later crates",
|
reason = "stable interface is via `impl f{32,64}` in later crates",
|
||||||
issue = "32110")]
|
issue = "32110")]
|
||||||
pub trait Float: Sized {
|
pub trait Float: Sized {
|
||||||
|
/// Type used by `to_bits` and `from_bits`.
|
||||||
|
#[stable(feature = "core_float_bits", since = "1.24.0")]
|
||||||
|
type Bits;
|
||||||
|
|
||||||
/// Returns `true` if this value is NaN and false otherwise.
|
/// Returns `true` if this value is NaN and false otherwise.
|
||||||
#[stable(feature = "core", since = "1.6.0")]
|
#[stable(feature = "core", since = "1.6.0")]
|
||||||
fn is_nan(self) -> bool;
|
fn is_nan(self) -> bool;
|
||||||
@ -2941,6 +2945,13 @@ pub trait Float: Sized {
|
|||||||
/// Returns the minimum of the two numbers.
|
/// Returns the minimum of the two numbers.
|
||||||
#[stable(feature = "core_float_min_max", since="1.20.0")]
|
#[stable(feature = "core_float_min_max", since="1.20.0")]
|
||||||
fn min(self, other: Self) -> Self;
|
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 {
|
macro_rules! from_str_radix_int_impl {
|
||||||
|
@ -1015,7 +1015,7 @@ impl f32 {
|
|||||||
#[stable(feature = "float_bits_conv", since = "1.20.0")]
|
#[stable(feature = "float_bits_conv", since = "1.20.0")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_bits(self) -> u32 {
|
pub fn to_bits(self) -> u32 {
|
||||||
unsafe { ::mem::transmute(self) }
|
num::Float::to_bits(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Raw transmutation from `u32`.
|
/// Raw transmutation from `u32`.
|
||||||
@ -1059,8 +1059,7 @@ impl f32 {
|
|||||||
#[stable(feature = "float_bits_conv", since = "1.20.0")]
|
#[stable(feature = "float_bits_conv", since = "1.20.0")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_bits(v: u32) -> Self {
|
pub fn from_bits(v: u32) -> Self {
|
||||||
// It turns out the safety issues with sNaN were overblown! Hooray!
|
num::Float::from_bits(v)
|
||||||
unsafe { ::mem::transmute(v) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -970,7 +970,7 @@ impl f64 {
|
|||||||
#[stable(feature = "float_bits_conv", since = "1.20.0")]
|
#[stable(feature = "float_bits_conv", since = "1.20.0")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_bits(self) -> u64 {
|
pub fn to_bits(self) -> u64 {
|
||||||
unsafe { ::mem::transmute(self) }
|
num::Float::to_bits(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Raw transmutation from `u64`.
|
/// Raw transmutation from `u64`.
|
||||||
@ -1014,8 +1014,7 @@ impl f64 {
|
|||||||
#[stable(feature = "float_bits_conv", since = "1.20.0")]
|
#[stable(feature = "float_bits_conv", since = "1.20.0")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_bits(v: u64) -> Self {
|
pub fn from_bits(v: u64) -> Self {
|
||||||
// It turns out the safety issues with sNaN were overblown! Hooray!
|
num::Float::from_bits(v)
|
||||||
unsafe { ::mem::transmute(v) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user