about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-12-04 18:46:21 -0800
committerbors <bors@rust-lang.org>2013-12-04 18:46:21 -0800
commit64bcfd246ca0a7522069bad9f6217ec3e783db8e (patch)
tree29d84af1290b370489369d86174ee85fcbd24e6b /src/libstd
parentedb9e85ce2e3708abe3a81d9645054e3eab85395 (diff)
parent30a9c6e4904f1d74b5ece97a422a0f1b148f4ba1 (diff)
downloadrust-64bcfd246ca0a7522069bad9f6217ec3e783db8e.tar.gz
rust-64bcfd246ca0a7522069bad9f6217ec3e783db8e.zip
auto merge of #10803 : vmx/rust/integer-decode, r=cmr
The `integer_decode()` function decodes a float (f32/f64)
into integers containing the mantissa, exponent and sign.

It's needed for `rationalize()` implementation of #9838.

The code got ported from ABCL [1].

[1] http://abcl.org/trac/browser/trunk/abcl/src/org/armedbear/lisp/FloatFunctions.java?rev=14465#L94

I got the permission to use this code for Rust from Peter Graves (the ABCL copyright holder) . If there's any further IP clearance needed, let me know.
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/num/f32.rs29
-rw-r--r--src/libstd/num/f64.rs29
-rw-r--r--src/libstd/num/mod.rs2
3 files changed, 60 insertions, 0 deletions
diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs
index 53bd2d3dc08..92eb4a80fca 100644
--- a/src/libstd/num/f32.rs
+++ b/src/libstd/num/f32.rs
@@ -708,6 +708,23 @@ impl Float for f32 {
     fn next_after(&self, other: f32) -> f32 {
         next_after(*self, other)
     }
+
+    /// Returns the mantissa, exponent and sign as integers.
+    fn integer_decode(&self) -> (u64, i16, i8) {
+        let bits: u32 = unsafe {
+            ::cast::transmute(*self)
+        };
+        let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
+        let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
+        let mantissa = if exponent == 0 {
+            (bits & 0x7fffff) << 1
+        } else {
+            (bits & 0x7fffff) | 0x800000
+        };
+        // Exponent bias + mantissa shift
+        exponent -= 127 + 23;
+        (mantissa as u64, exponent, sign)
+    }
 }
 
 //
@@ -1273,4 +1290,16 @@ mod tests {
         assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf)
         assert!(match nan.frexp() { (x, _) => x.is_nan() })
     }
+
+    #[test]
+    fn test_integer_decode() {
+        assert_eq!(3.14159265359f32.integer_decode(), (13176795u64, -22i16, 1i8));
+        assert_eq!((-8573.5918555f32).integer_decode(), (8779358u64, -10i16, -1i8));
+        assert_eq!(2f32.pow(&100.0).integer_decode(), (8388608u64, 77i16, 1i8));
+        assert_eq!(0f32.integer_decode(), (0u64, -150i16, 1i8));
+        assert_eq!((-0f32).integer_decode(), (0u64, -150i16, -1i8));
+        assert_eq!(INFINITY.integer_decode(), (8388608u64, 105i16, 1i8));
+        assert_eq!(NEG_INFINITY.integer_decode(), (8388608u64, 105i16, -1i8));
+        assert_eq!(NAN.integer_decode(), (12582912u64, 105i16, 1i8));
+    }
 }
diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs
index 49b20b2c4f4..2dfb23283df 100644
--- a/src/libstd/num/f64.rs
+++ b/src/libstd/num/f64.rs
@@ -756,6 +756,23 @@ impl Float for f64 {
     fn next_after(&self, other: f64) -> f64 {
         next_after(*self, other)
     }
+
+    /// Returns the mantissa, exponent and sign as integers.
+    fn integer_decode(&self) -> (u64, i16, i8) {
+        let bits: u64 = unsafe {
+            ::cast::transmute(*self)
+        };
+        let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
+        let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
+        let mantissa = if exponent == 0 {
+            (bits & 0xfffffffffffff) << 1
+        } else {
+            (bits & 0xfffffffffffff) | 0x10000000000000
+        };
+        // Exponent bias + mantissa shift
+        exponent -= 1023 + 52;
+        (mantissa, exponent, sign)
+    }
 }
 
 //
@@ -1323,4 +1340,16 @@ mod tests {
         assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf)
         assert!(match nan.frexp() { (x, _) => x.is_nan() })
     }
+
+    #[test]
+    fn test_integer_decode() {
+        assert_eq!(3.14159265359f64.integer_decode(), (7074237752028906u64, -51i16, 1i8));
+        assert_eq!((-8573.5918555f64).integer_decode(), (4713381968463931u64, -39i16, -1i8));
+        assert_eq!(2f64.pow(&100.0).integer_decode(), (4503599627370496u64, 48i16, 1i8));
+        assert_eq!(0f64.integer_decode(), (0u64, -1075i16, 1i8));
+        assert_eq!((-0f64).integer_decode(), (0u64, -1075i16, -1i8));
+        assert_eq!(INFINITY.integer_decode(), (4503599627370496u64, 972i16, 1i8));
+        assert_eq!(NEG_INFINITY.integer_decode(), (4503599627370496, 972, -1));
+        assert_eq!(NAN.integer_decode(), (6755399441055744u64, 972i16, 1i8));
+    }
 }
diff --git a/src/libstd/num/mod.rs b/src/libstd/num/mod.rs
index 456011d5172..79efe5934d5 100644
--- a/src/libstd/num/mod.rs
+++ b/src/libstd/num/mod.rs
@@ -532,6 +532,8 @@ pub trait Float: Real
     fn ln_1p(&self) -> Self;
     fn mul_add(&self, a: Self, b: Self) -> Self;
     fn next_after(&self, other: Self) -> Self;
+
+    fn integer_decode(&self) -> (u64, i16, i8);
 }
 
 /// Returns the exponential of the number, minus `1`, `exp(n) - 1`, in a way