Skip to content

Commit 32a43da

Browse files
committed
Add functions to safely transmute float to int
1 parent 5516bcc commit 32a43da

File tree

3 files changed

+103
-0
lines changed

3 files changed

+103
-0
lines changed

src/libstd/f32.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1226,6 +1226,45 @@ impl f32 {
12261226
pub fn atanh(self) -> f32 {
12271227
0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
12281228
}
1229+
1230+
/// Raw transmutation to `u32`.
1231+
///
1232+
/// Converts the `f32` into its raw memory representation,
1233+
/// similar to the `transmute` function.
1234+
///
1235+
/// Note that this function is distinct from casting.
1236+
///
1237+
/// ```
1238+
/// #![feature(float_bits_conv)]
1239+
/// assert!((1f32).to_bits() != 1f32 as u32); // to_bits() is not casting!
1240+
/// assert_eq!((12.5f32).to_bits(), 0x41480000);
1241+
///
1242+
/// ```
1243+
#[unstable(feature = "float_bits_conv", reason = "recently added", issue = "0")]
1244+
#[inline]
1245+
pub fn to_bits(self) -> u32 {
1246+
unsafe { ::mem::transmute(self) }
1247+
}
1248+
1249+
/// Raw transmutation from `u32`.
1250+
///
1251+
/// Converts the given `u32` containing the float's raw memory
1252+
/// representation into the `f32` type, similar to the
1253+
/// `transmute` function.
1254+
///
1255+
/// Note that this function is distinct from casting.
1256+
///
1257+
/// ```
1258+
/// #![feature(float_bits_conv)]
1259+
/// use std::f32;
1260+
/// let difference = (f32::from_bits(0x41480000) - 12.5).abs();
1261+
/// assert!(difference <= 1e-5);
1262+
/// ```
1263+
#[unstable(feature = "float_bits_conv", reason = "recently added", issue = "0")]
1264+
#[inline]
1265+
pub fn from_bits(v: u32) -> Self {
1266+
unsafe { ::mem::transmute(v) }
1267+
}
12291268
}
12301269

12311270
#[cfg(test)]
@@ -1870,4 +1909,16 @@ mod tests {
18701909
assert_approx_eq!(ln_2, 2f32.ln());
18711910
assert_approx_eq!(ln_10, 10f32.ln());
18721911
}
1912+
1913+
#[test]
1914+
fn test_float_bits_conv() {
1915+
assert_eq!((1f32).to_bits(), 0x3f800000);
1916+
assert_eq!((12.5f32).to_bits(), 0x41480000);
1917+
assert_eq!((1337f32).to_bits(), 0x44a72000);
1918+
assert_eq!((-14.25f32).to_bits(), 0xc1640000);
1919+
assert_approx_eq!(f32::from_bits(0x3f800000), 1.0);
1920+
assert_approx_eq!(f32::from_bits(0x41480000), 12.5);
1921+
assert_approx_eq!(f32::from_bits(0x44a72000), 1337.0);
1922+
assert_approx_eq!(f32::from_bits(0xc1640000), -14.25);
1923+
}
18731924
}

src/libstd/f64.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,6 +1118,45 @@ impl f64 {
11181118
}
11191119
}
11201120
}
1121+
1122+
/// Raw transmutation to `u64`.
1123+
///
1124+
/// Converts the `f64` into its raw memory representation,
1125+
/// similar to the `transmute` function.
1126+
///
1127+
/// Note that this function is distinct from casting.
1128+
///
1129+
/// ```
1130+
/// #![feature(float_bits_conv)]
1131+
/// assert!((1f64).to_bits() != 1f64 as u64); // to_bits() is not casting!
1132+
/// assert_eq!((12.5f64).to_bits(), 0x4029000000000000);
1133+
///
1134+
/// ```
1135+
#[unstable(feature = "float_bits_conv", reason = "recently added", issue = "0")]
1136+
#[inline]
1137+
pub fn to_bits(self) -> u64 {
1138+
unsafe { ::mem::transmute(self) }
1139+
}
1140+
1141+
/// Raw transmutation from `u64`.
1142+
///
1143+
/// Converts the given `u64` containing the float's raw memory
1144+
/// representation into the `f64` type, similar to the
1145+
/// `transmute` function.
1146+
///
1147+
/// Note that this function is distinct from casting.
1148+
///
1149+
/// ```
1150+
/// #![feature(float_bits_conv)]
1151+
/// use std::f64;
1152+
/// let difference = (f64::from_bits(0x4029000000000000) - 12.5).abs();
1153+
/// assert!(difference <= 1e-5);
1154+
/// ```
1155+
#[unstable(feature = "float_bits_conv", reason = "recently added", issue = "0")]
1156+
#[inline]
1157+
pub fn from_bits(v: u64) -> Self {
1158+
unsafe { ::mem::transmute(v) }
1159+
}
11211160
}
11221161

11231162
#[cfg(test)]
@@ -1755,4 +1794,16 @@ mod tests {
17551794
assert_approx_eq!(ln_2, 2f64.ln());
17561795
assert_approx_eq!(ln_10, 10f64.ln());
17571796
}
1797+
1798+
#[test]
1799+
fn test_float_bits_conv() {
1800+
assert_eq!((1f64).to_bits(), 0x3ff0000000000000);
1801+
assert_eq!((12.5f64).to_bits(), 0x4029000000000000);
1802+
assert_eq!((1337f64).to_bits(), 0x4094e40000000000);
1803+
assert_eq!((-14.25f64).to_bits(), 0xc02c800000000000);
1804+
assert_approx_eq!(f64::from_bits(0x3ff0000000000000), 1.0);
1805+
assert_approx_eq!(f64::from_bits(0x4029000000000000), 12.5);
1806+
assert_approx_eq!(f64::from_bits(0x4094e40000000000), 1337.0);
1807+
assert_approx_eq!(f64::from_bits(0xc02c800000000000), -14.25);
1808+
}
17581809
}

src/libstd/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,7 @@
321321
#![feature(zero_one)]
322322
#![cfg_attr(test, feature(update_panic_count))]
323323
#![cfg_attr(stage0, feature(pub_restricted))]
324+
#![cfg_attr(test, feature(float_bits_conv))]
324325

325326
// Explicitly import the prelude. The compiler uses this same unstable attribute
326327
// to import the prelude implicitly when building crates that depend on std.

0 commit comments

Comments
 (0)