Closed
Description
Issue
Float::from_bits
is implemented as mem::transmute
, and therefore does exactly what we need in all cases.
Solution
We don't need an endian-dependent code-path: we can just use the mask 0xFFFFFFFF
to ensure it works, which will grab the least-significant 32 bits, and then create a float directly from those bits.
pub unsafe fn to_float_v1(word: u64) -> f32 {
if cfg!(target_endian = "big") {
*(&word as *const _ as *const f32).add(1)
} else {
*(&word as *const _ as *const f32)
}
}
pub fn to_float_v2(word: u64) -> f32 {
f32::from_bits((word & 0xFFFFFFFF) as u32)
}
example::to_float_v1:
movd xmm0, edi
ret
example::to_float_v2:
movd xmm0, edi
ret
The full implementation therefore could be:
diff --git a/src/parse.rs b/src/parse.rs
index 5571da7..9c592d4 100644
--- a/src/parse.rs
+++ b/src/parse.rs
@@ -1,5 +1,3 @@
-use core::mem;
-
use crate::binary::compute_float;
use crate::float::Float;
use crate::number::{parse_inf_nan, parse_number};
@@ -32,13 +30,5 @@ pub fn parse_float<F: Float>(s: &[u8]) -> Option<(F, usize)> {
if num.negative {
word |= 1_u64 << F::SIGN_INDEX;
}
- let value = unsafe {
- if cfg!(target_endian = "big") && mem::size_of::<F>() == 4 {
- *(&word as *const _ as *const F).add(1)
- } else {
- *(&word as *const _ as *const F)
- }
- };
-
- Some((value, rest))
+ Some((F::from_u64_bits(word), rest))
}
diff --git a/src/float.rs b/src/float.rs
index 39bec41..a976408 100644
--- a/src/float.rs
+++ b/src/float.rs
@@ -40,6 +40,7 @@ pub trait Float:
const MAX_MANTISSA_FAST_PATH: u64 = 2_u64 << Self::MANTISSA_EXPLICIT_BITS;
fn from_u64(v: u64) -> Self;
+ fn from_u64_bits(v: u64) -> Self;
fn pow10_fast_path(exponent: usize) -> Self;
}
@@ -67,6 +68,11 @@ impl Float for f32 {
v as _
}
+ #[inline]
+ fn from_u64_bits(v: u64) -> Self {
+ f32::from_bits((v & 0xFFFFFFFF) as u32)
+ }
+
#[inline]
fn pow10_fast_path(exponent: usize) -> Self {
#[allow(clippy::use_self)]
@@ -101,6 +107,11 @@ impl Float for f64 {
v as _
}
+ #[inline]
+ fn from_u64_bits(v: u64) -> Self {
+ f64::from_bits(v)
+ }
+
#[inline]
fn pow10_fast_path(exponent: usize) -> Self {
#[allow(clippy::use_self)]
This was tested on both little-endian and big-endian platforms using the following cross targets:
- powerpc-unknown-linux-gnu
- x86_64-unknown-linux-gnu
Metadata
Metadata
Assignees
Labels
No labels