Skip to content

Commit a2cdeb5

Browse files
author
Clar Charr
committed
Expose float from_bits and to_bits in libcore.
1 parent 5165ee9 commit a2cdeb5

File tree

6 files changed

+55
-53
lines changed

6 files changed

+55
-53
lines changed

src/libcore/num/dec2flt/rawfp.rs

+6-33
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,10 @@
2727
//! Many functions in this module only handle normal numbers. The dec2flt routines conservatively
2828
//! take the universally-correct slow path (Algorithm M) for very small and very large numbers.
2929
//! That algorithm needs only next_float() which does handle subnormals and zeros.
30-
use u32;
3130
use cmp::Ordering::{Less, Equal, Greater};
31+
use convert::TryInto;
3232
use ops::{Mul, Div, Neg};
3333
use fmt::{Debug, LowerExp};
34-
use mem::transmute;
3534
use num::diy_float::Fp;
3635
use num::FpCategory::{Infinite, Zero, Subnormal, Normal, Nan};
3736
use num::Float;
@@ -66,12 +65,6 @@ pub trait RawFloat : Float + Copy + Debug + LowerExp
6665
/// Returns the mantissa, exponent and sign as integers.
6766
fn integer_decode(self) -> (u64, i16, i8);
6867

69-
/// Get the raw binary representation of the float.
70-
fn transmute(self) -> u64;
71-
72-
/// Transmute the raw binary representation into a float.
73-
fn from_bits(bits: u64) -> Self;
74-
7568
/// Decode the float.
7669
fn unpack(self) -> Unpacked;
7770

@@ -159,7 +152,7 @@ impl RawFloat for f32 {
159152

160153
/// Returns the mantissa, exponent and sign as integers.
161154
fn integer_decode(self) -> (u64, i16, i8) {
162-
let bits: u32 = unsafe { transmute(self) };
155+
let bits = self.to_bits();
163156
let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
164157
let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
165158
let mantissa = if exponent == 0 {
@@ -172,16 +165,6 @@ impl RawFloat for f32 {
172165
(mantissa as u64, exponent, sign)
173166
}
174167

175-
fn transmute(self) -> u64 {
176-
let bits: u32 = unsafe { transmute(self) };
177-
bits as u64
178-
}
179-
180-
fn from_bits(bits: u64) -> f32 {
181-
assert!(bits < u32::MAX as u64, "f32::from_bits: too many bits");
182-
unsafe { transmute(bits as u32) }
183-
}
184-
185168
fn unpack(self) -> Unpacked {
186169
let (sig, exp, _sig) = self.integer_decode();
187170
Unpacked::new(sig, exp)
@@ -210,7 +193,7 @@ impl RawFloat for f64 {
210193

211194
/// Returns the mantissa, exponent and sign as integers.
212195
fn integer_decode(self) -> (u64, i16, i8) {
213-
let bits: u64 = unsafe { transmute(self) };
196+
let bits = self.to_bits();
214197
let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
215198
let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
216199
let mantissa = if exponent == 0 {
@@ -223,15 +206,6 @@ impl RawFloat for f64 {
223206
(mantissa, exponent, sign)
224207
}
225208

226-
fn transmute(self) -> u64 {
227-
let bits: u64 = unsafe { transmute(self) };
228-
bits
229-
}
230-
231-
fn from_bits(bits: u64) -> f64 {
232-
unsafe { transmute(bits) }
233-
}
234-
235209
fn unpack(self) -> Unpacked {
236210
let (sig, exp, _sig) = self.integer_decode();
237211
Unpacked::new(sig, exp)
@@ -296,14 +270,14 @@ pub fn encode_normal<T: RawFloat>(x: Unpacked) -> T {
296270
"encode_normal: exponent out of range");
297271
// Leave sign bit at 0 ("+"), our numbers are all positive
298272
let bits = (k_enc as u64) << T::EXPLICIT_SIG_BITS | sig_enc;
299-
T::from_bits(bits)
273+
T::from_bits(bits.try_into().unwrap_or_else(|_| unreachable!()))
300274
}
301275

302276
/// Construct a subnormal. A mantissa of 0 is allowed and constructs zero.
303277
pub fn encode_subnormal<T: RawFloat>(significand: u64) -> T {
304278
assert!(significand < T::MIN_SIG, "encode_subnormal: not actually subnormal");
305279
// Encoded exponent is 0, the sign bit is 0, so we just have to reinterpret the bits.
306-
T::from_bits(significand)
280+
T::from_bits(significand.try_into().unwrap_or_else(|_| unreachable!()))
307281
}
308282

309283
/// 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 {
363337
// too is exactly what we want!
364338
// Finally, f64::MAX + 1 = 7eff...f + 1 = 7ff0...0 = f64::INFINITY.
365339
Zero | Subnormal | Normal => {
366-
let bits: u64 = x.transmute();
367-
T::from_bits(bits + 1)
340+
T::from_bits(x.to_bits() + T::Bits::from(1u8))
368341
}
369342
}
370343
}

src/libcore/num/f32.rs

+17-7
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ pub mod consts {
140140
reason = "stable interface is via `impl f{32,64}` in later crates",
141141
issue = "32110")]
142142
impl Float for f32 {
143+
type Bits = u32;
144+
143145
/// Returns `true` if the number is NaN.
144146
#[inline]
145147
fn is_nan(self) -> bool {
@@ -171,7 +173,7 @@ impl Float for f32 {
171173
const EXP_MASK: u32 = 0x7f800000;
172174
const MAN_MASK: u32 = 0x007fffff;
173175

174-
let bits: u32 = unsafe { mem::transmute(self) };
176+
let bits = self.to_bits();
175177
match (bits & MAN_MASK, bits & EXP_MASK) {
176178
(0, 0) => Fp::Zero,
177179
(_, 0) => Fp::Subnormal,
@@ -215,12 +217,7 @@ impl Float for f32 {
215217
fn is_sign_negative(self) -> bool {
216218
// IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus
217219
// applies to zeros and NaNs as well.
218-
#[repr(C)]
219-
union F32Bytes {
220-
f: f32,
221-
b: u32
222-
}
223-
unsafe { F32Bytes { f: self }.b & 0x8000_0000 != 0 }
220+
self.to_bits() & 0x8000_0000 != 0
224221
}
225222

226223
/// Returns the reciprocal (multiplicative inverse) of the number.
@@ -274,4 +271,17 @@ impl Float for f32 {
274271
// multiplying by 1.0. Should switch to the `canonicalize` when it works.
275272
(if self < other || other.is_nan() { self } else { other }) * 1.0
276273
}
274+
275+
/// Raw transmutation to `u32`.
276+
#[inline]
277+
fn to_bits(self) -> u32 {
278+
unsafe { mem::transmute(self) }
279+
}
280+
281+
/// Raw transmutation from `u32`.
282+
#[inline]
283+
fn from_bits(v: u32) -> Self {
284+
// It turns out the safety issues with sNaN were overblown! Hooray!
285+
unsafe { mem::transmute(v) }
286+
}
277287
}

src/libcore/num/f64.rs

+17-7
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ pub mod consts {
140140
reason = "stable interface is via `impl f{32,64}` in later crates",
141141
issue = "32110")]
142142
impl Float for f64 {
143+
type Bits = u64;
144+
143145
/// Returns `true` if the number is NaN.
144146
#[inline]
145147
fn is_nan(self) -> bool {
@@ -171,7 +173,7 @@ impl Float for f64 {
171173
const EXP_MASK: u64 = 0x7ff0000000000000;
172174
const MAN_MASK: u64 = 0x000fffffffffffff;
173175

174-
let bits: u64 = unsafe { mem::transmute(self) };
176+
let bits = self.to_bits();
175177
match (bits & MAN_MASK, bits & EXP_MASK) {
176178
(0, 0) => Fp::Zero,
177179
(_, 0) => Fp::Subnormal,
@@ -213,12 +215,7 @@ impl Float for f64 {
213215
/// negative sign bit and negative infinity.
214216
#[inline]
215217
fn is_sign_negative(self) -> bool {
216-
#[repr(C)]
217-
union F64Bytes {
218-
f: f64,
219-
b: u64
220-
}
221-
unsafe { F64Bytes { f: self }.b & 0x8000_0000_0000_0000 != 0 }
218+
self.to_bits() & 0x8000_0000_0000_0000 != 0
222219
}
223220

224221
/// Returns the reciprocal (multiplicative inverse) of the number.
@@ -272,4 +269,17 @@ impl Float for f64 {
272269
// multiplying by 1.0. Should switch to the `canonicalize` when it works.
273270
(if self < other || other.is_nan() { self } else { other }) * 1.0
274271
}
272+
273+
/// Raw transmutation to `u64`.
274+
#[inline]
275+
fn to_bits(self) -> u64 {
276+
unsafe { mem::transmute(self) }
277+
}
278+
279+
/// Raw transmutation from `u64`.
280+
#[inline]
281+
fn from_bits(v: u64) -> Self {
282+
// It turns out the safety issues with sNaN were overblown! Hooray!
283+
unsafe { mem::transmute(v) }
284+
}
275285
}

src/libcore/num/mod.rs

+11
Original file line numberDiff line numberDiff line change
@@ -2872,6 +2872,10 @@ pub enum FpCategory {
28722872
reason = "stable interface is via `impl f{32,64}` in later crates",
28732873
issue = "32110")]
28742874
pub trait Float: Sized {
2875+
/// Type used by `to_bits` and `from_bits`.
2876+
#[stable(feature = "core_float_bits", since = "1.24.0")]
2877+
type Bits: ops::Add<Output = Self::Bits> + From<u8> + TryFrom<u64>;
2878+
28752879
/// Returns `true` if this value is NaN and false otherwise.
28762880
#[stable(feature = "core", since = "1.6.0")]
28772881
fn is_nan(self) -> bool;
@@ -2933,6 +2937,13 @@ pub trait Float: Sized {
29332937
/// Returns the minimum of the two numbers.
29342938
#[stable(feature = "core_float_min_max", since="1.20.0")]
29352939
fn min(self, other: Self) -> Self;
2940+
2941+
/// Raw transmutation to integer.
2942+
#[stable(feature = "core_float_bits", since="1.24.0")]
2943+
fn to_bits(self) -> Self::Bits;
2944+
/// Raw transmutation from integer.
2945+
#[stable(feature = "core_float_bits", since="1.24.0")]
2946+
fn from_bits(v: Self::Bits) -> Self;
29362947
}
29372948

29382949
macro_rules! from_str_radix_int_impl {

src/libstd/f32.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -1016,7 +1016,7 @@ impl f32 {
10161016
#[stable(feature = "float_bits_conv", since = "1.20.0")]
10171017
#[inline]
10181018
pub fn to_bits(self) -> u32 {
1019-
unsafe { ::mem::transmute(self) }
1019+
num::Float::to_bits(self)
10201020
}
10211021

10221022
/// Raw transmutation from `u32`.
@@ -1060,8 +1060,7 @@ impl f32 {
10601060
#[stable(feature = "float_bits_conv", since = "1.20.0")]
10611061
#[inline]
10621062
pub fn from_bits(v: u32) -> Self {
1063-
// It turns out the safety issues with sNaN were overblown! Hooray!
1064-
unsafe { ::mem::transmute(v) }
1063+
num::Float::from_bits(v)
10651064
}
10661065
}
10671066

src/libstd/f64.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -971,7 +971,7 @@ impl f64 {
971971
#[stable(feature = "float_bits_conv", since = "1.20.0")]
972972
#[inline]
973973
pub fn to_bits(self) -> u64 {
974-
unsafe { ::mem::transmute(self) }
974+
num::Float::to_bits(self)
975975
}
976976

977977
/// Raw transmutation from `u64`.
@@ -1015,8 +1015,7 @@ impl f64 {
10151015
#[stable(feature = "float_bits_conv", since = "1.20.0")]
10161016
#[inline]
10171017
pub fn from_bits(v: u64) -> Self {
1018-
// It turns out the safety issues with sNaN were overblown! Hooray!
1019-
unsafe { ::mem::transmute(v) }
1018+
num::Float::from_bits(v)
10201019
}
10211020
}
10221021

0 commit comments

Comments
 (0)