Skip to content

Commit 64bcfd2

Browse files
committed
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.
2 parents edb9e85 + 30a9c6e commit 64bcfd2

File tree

3 files changed

+60
-0
lines changed

3 files changed

+60
-0
lines changed

src/libstd/num/f32.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,23 @@ impl Float for f32 {
708708
fn next_after(&self, other: f32) -> f32 {
709709
next_after(*self, other)
710710
}
711+
712+
/// Returns the mantissa, exponent and sign as integers.
713+
fn integer_decode(&self) -> (u64, i16, i8) {
714+
let bits: u32 = unsafe {
715+
::cast::transmute(*self)
716+
};
717+
let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
718+
let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
719+
let mantissa = if exponent == 0 {
720+
(bits & 0x7fffff) << 1
721+
} else {
722+
(bits & 0x7fffff) | 0x800000
723+
};
724+
// Exponent bias + mantissa shift
725+
exponent -= 127 + 23;
726+
(mantissa as u64, exponent, sign)
727+
}
711728
}
712729

713730
//
@@ -1273,4 +1290,16 @@ mod tests {
12731290
assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf)
12741291
assert!(match nan.frexp() { (x, _) => x.is_nan() })
12751292
}
1293+
1294+
#[test]
1295+
fn test_integer_decode() {
1296+
assert_eq!(3.14159265359f32.integer_decode(), (13176795u64, -22i16, 1i8));
1297+
assert_eq!((-8573.5918555f32).integer_decode(), (8779358u64, -10i16, -1i8));
1298+
assert_eq!(2f32.pow(&100.0).integer_decode(), (8388608u64, 77i16, 1i8));
1299+
assert_eq!(0f32.integer_decode(), (0u64, -150i16, 1i8));
1300+
assert_eq!((-0f32).integer_decode(), (0u64, -150i16, -1i8));
1301+
assert_eq!(INFINITY.integer_decode(), (8388608u64, 105i16, 1i8));
1302+
assert_eq!(NEG_INFINITY.integer_decode(), (8388608u64, 105i16, -1i8));
1303+
assert_eq!(NAN.integer_decode(), (12582912u64, 105i16, 1i8));
1304+
}
12761305
}

src/libstd/num/f64.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -756,6 +756,23 @@ impl Float for f64 {
756756
fn next_after(&self, other: f64) -> f64 {
757757
next_after(*self, other)
758758
}
759+
760+
/// Returns the mantissa, exponent and sign as integers.
761+
fn integer_decode(&self) -> (u64, i16, i8) {
762+
let bits: u64 = unsafe {
763+
::cast::transmute(*self)
764+
};
765+
let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
766+
let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
767+
let mantissa = if exponent == 0 {
768+
(bits & 0xfffffffffffff) << 1
769+
} else {
770+
(bits & 0xfffffffffffff) | 0x10000000000000
771+
};
772+
// Exponent bias + mantissa shift
773+
exponent -= 1023 + 52;
774+
(mantissa, exponent, sign)
775+
}
759776
}
760777

761778
//
@@ -1323,4 +1340,16 @@ mod tests {
13231340
assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf)
13241341
assert!(match nan.frexp() { (x, _) => x.is_nan() })
13251342
}
1343+
1344+
#[test]
1345+
fn test_integer_decode() {
1346+
assert_eq!(3.14159265359f64.integer_decode(), (7074237752028906u64, -51i16, 1i8));
1347+
assert_eq!((-8573.5918555f64).integer_decode(), (4713381968463931u64, -39i16, -1i8));
1348+
assert_eq!(2f64.pow(&100.0).integer_decode(), (4503599627370496u64, 48i16, 1i8));
1349+
assert_eq!(0f64.integer_decode(), (0u64, -1075i16, 1i8));
1350+
assert_eq!((-0f64).integer_decode(), (0u64, -1075i16, -1i8));
1351+
assert_eq!(INFINITY.integer_decode(), (4503599627370496u64, 972i16, 1i8));
1352+
assert_eq!(NEG_INFINITY.integer_decode(), (4503599627370496, 972, -1));
1353+
assert_eq!(NAN.integer_decode(), (6755399441055744u64, 972i16, 1i8));
1354+
}
13261355
}

src/libstd/num/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,8 @@ pub trait Float: Real
532532
fn ln_1p(&self) -> Self;
533533
fn mul_add(&self, a: Self, b: Self) -> Self;
534534
fn next_after(&self, other: Self) -> Self;
535+
536+
fn integer_decode(&self) -> (u64, i16, i8);
535537
}
536538

537539
/// Returns the exponential of the number, minus `1`, `exp(n) - 1`, in a way

0 commit comments

Comments
 (0)