Browse Source

Use {float}::to_bits instead of mem::transmute

Josh Stone 2 years ago
parent
commit
fd601a8d4d
2 changed files with 24 additions and 39 deletions
  1. 6 21
      src/float.rs
  2. 18 18
      tests/cast.rs

+ 6 - 21
src/float.rs

@@ -1,4 +1,3 @@
-use core::mem;
 use core::num::FpCategory;
 use core::ops::{Add, Div, Neg};
 
@@ -766,9 +765,7 @@ impl FloatCore for f32 {
         const EXP_MASK: u32 = 0x7f800000;
         const MAN_MASK: u32 = 0x007fffff;
 
-        // Safety: this identical to the implementation of f32::to_bits(),
-        // which is only available starting at Rust 1.20
-        let bits: u32 = unsafe { mem::transmute(self) };
+        let bits: u32 = self.to_bits();
         match (bits & MAN_MASK, bits & EXP_MASK) {
             (0, 0) => FpCategory::Zero,
             (_, 0) => FpCategory::Subnormal,
@@ -783,10 +780,7 @@ impl FloatCore for f32 {
     fn is_sign_negative(self) -> bool {
         const SIGN_MASK: u32 = 0x80000000;
 
-        // Safety: this identical to the implementation of f32::to_bits(),
-        // which is only available starting at Rust 1.20
-        let bits: u32 = unsafe { mem::transmute(self) };
-        bits & SIGN_MASK != 0
+        self.to_bits() & SIGN_MASK != 0
     }
 
     #[inline]
@@ -868,9 +862,7 @@ impl FloatCore for f64 {
         const EXP_MASK: u64 = 0x7ff0000000000000;
         const MAN_MASK: u64 = 0x000fffffffffffff;
 
-        // Safety: this identical to the implementation of f64::to_bits(),
-        // which is only available starting at Rust 1.20
-        let bits: u64 = unsafe { mem::transmute(self) };
+        let bits: u64 = self.to_bits();
         match (bits & MAN_MASK, bits & EXP_MASK) {
             (0, 0) => FpCategory::Zero,
             (_, 0) => FpCategory::Subnormal,
@@ -885,10 +877,7 @@ impl FloatCore for f64 {
     fn is_sign_negative(self) -> bool {
         const SIGN_MASK: u64 = 0x8000000000000000;
 
-        // Safety: this identical to the implementation of f64::to_bits(),
-        // which is only available starting at Rust 1.20
-        let bits: u64 = unsafe { mem::transmute(self) };
-        bits & SIGN_MASK != 0
+        self.to_bits() & SIGN_MASK != 0
     }
 
     #[inline]
@@ -2026,9 +2015,7 @@ macro_rules! float_impl_libm {
 }
 
 fn integer_decode_f32(f: f32) -> (u64, i16, i8) {
-    // Safety: this identical to the implementation of f32::to_bits(),
-    // which is only available starting at Rust 1.20
-    let bits: u32 = unsafe { mem::transmute(f) };
+    let bits: u32 = f.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 {
@@ -2042,9 +2029,7 @@ fn integer_decode_f32(f: f32) -> (u64, i16, i8) {
 }
 
 fn integer_decode_f64(f: f64) -> (u64, i16, i8) {
-    // Safety: this identical to the implementation of f64::to_bits(),
-    // which is only available starting at Rust 1.20
-    let bits: u64 = unsafe { mem::transmute(f) };
+    let bits: u64 = f.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 {

+ 18 - 18
tests/cast.rs

@@ -171,9 +171,9 @@ macro_rules! float_test_edge {
         let small = if $t::MIN == 0 || mem::size_of::<$t>() < mem::size_of::<$f>() {
             $t::MIN as $f - 1.0
         } else {
-            ($t::MIN as $f).raw_offset(1).floor()
+            ($t::MIN as $f).raw_inc().floor()
         };
-        let fmin = small.raw_offset(-1);
+        let fmin = small.raw_dec();
         dbg!("  testing min {}\n\tvs. {:.0}\n\tand {:.0}", $t::MIN, fmin, small);
         assert_eq!(Some($t::MIN), cast::<$f, $t>($t::MIN as $f));
         assert_eq!(Some($t::MIN), cast::<$f, $t>(fmin));
@@ -183,11 +183,11 @@ macro_rules! float_test_edge {
             ($t::MAX, $t::MAX as $f + 1.0)
         } else {
             let large = $t::MAX as $f; // rounds up!
-            let max = large.raw_offset(-1) as $t; // the next smallest possible
+            let max = large.raw_dec() as $t; // the next smallest possible
             assert_eq!(max.count_ones(), $f::MANTISSA_DIGITS);
             (max, large)
         };
-        let fmax = large.raw_offset(-1);
+        let fmax = large.raw_dec();
         dbg!("  testing max {}\n\tvs. {:.0}\n\tand {:.0}", max, fmax, large);
         assert_eq!(Some(max), cast::<$f, $t>(max as $f));
         assert_eq!(Some(max), cast::<$f, $t>(fmax));
@@ -201,27 +201,27 @@ macro_rules! float_test_edge {
 }
 
 trait RawOffset: Sized {
-    type Raw;
-    fn raw_offset(self, offset: Self::Raw) -> Self;
+    fn raw_inc(self) -> Self;
+    fn raw_dec(self) -> Self;
 }
 
 impl RawOffset for f32 {
-    type Raw = i32;
-    fn raw_offset(self, offset: Self::Raw) -> Self {
-        unsafe {
-            let raw: Self::Raw = mem::transmute(self);
-            mem::transmute(raw + offset)
-        }
+    fn raw_inc(self) -> Self {
+        Self::from_bits(self.to_bits() + 1)
+    }
+
+    fn raw_dec(self) -> Self {
+        Self::from_bits(self.to_bits() - 1)
     }
 }
 
 impl RawOffset for f64 {
-    type Raw = i64;
-    fn raw_offset(self, offset: Self::Raw) -> Self {
-        unsafe {
-            let raw: Self::Raw = mem::transmute(self);
-            mem::transmute(raw + offset)
-        }
+    fn raw_inc(self) -> Self {
+        Self::from_bits(self.to_bits() + 1)
+    }
+
+    fn raw_dec(self) -> Self {
+        Self::from_bits(self.to_bits() - 1)
     }
 }