diff options
| author | Brendan Zabarauskas <bjzaba@yahoo.com.au> | 2013-05-14 11:24:55 +1000 |
|---|---|---|
| committer | Brendan Zabarauskas <bjzaba@yahoo.com.au> | 2013-05-14 11:24:55 +1000 |
| commit | 44cb46f7bfb869cc44f04bc93ee11c5027be2c33 (patch) | |
| tree | c5180e007f5ebb8ac85dbfdd7c32e1db234a44a1 | |
| parent | 8d4d2b00c551301348cc09583498c02fdfbd64d7 (diff) | |
| download | rust-44cb46f7bfb869cc44f04bc93ee11c5027be2c33.tar.gz rust-44cb46f7bfb869cc44f04bc93ee11c5027be2c33.zip | |
Add ldexp and frexp functions
| -rw-r--r-- | src/libcore/num/f32.rs | 60 | ||||
| -rw-r--r-- | src/libcore/num/f64.rs | 59 | ||||
| -rw-r--r-- | src/libcore/num/float.rs | 63 | ||||
| -rw-r--r-- | src/libcore/num/num.rs | 3 |
4 files changed, 184 insertions, 1 deletions
diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index ec901d9e5f0..cb9ea94b315 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -10,6 +10,7 @@ //! Operations and constants for `f32` +use libc::c_int; use num::{Zero, One, strconv}; use num::{FPCategory, FPNaN, FPInfinite , FPZero, FPSubnormal, FPNormal}; use prelude::*; @@ -672,6 +673,25 @@ impl Float for f32 { #[inline(always)] fn max_10_exp() -> int { 38 } + /// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp` + #[inline(always)] + fn ldexp(x: f32, exp: int) -> f32 { + ldexp(x, exp as c_int) + } + + /// + /// Breaks the number into a normalized fraction and a base-2 exponent, satisfying: + /// + /// - `self = x * pow(2, exp)` + /// - `0.5 <= abs(x) < 1.0` + /// + #[inline(always)] + fn frexp(&self) -> (f32, int) { + let mut exp = 0; + let x = frexp(*self, &mut exp); + (x, exp as int) + } + /// /// Returns the exponential of the number, minus `1`, in a way that is accurate /// even if the number is close to zero @@ -1180,4 +1200,44 @@ mod tests { assert_eq!(1e-37f32.classify(), FPNormal); assert_eq!(1e-38f32.classify(), FPSubnormal); } + + #[test] + fn test_ldexp() { + // We have to use from_str until base-2 exponents + // are supported in floating-point literals + let f1: f32 = from_str_hex("1p-123").unwrap(); + let f2: f32 = from_str_hex("1p-111").unwrap(); + assert_eq!(Float::ldexp(1f32, -123), f1); + assert_eq!(Float::ldexp(1f32, -111), f2); + + assert_eq!(Float::ldexp(0f32, -123), 0f32); + assert_eq!(Float::ldexp(-0f32, -123), -0f32); + assert_eq!(Float::ldexp(Float::infinity::<f32>(), -123), + Float::infinity::<f32>()); + assert_eq!(Float::ldexp(Float::neg_infinity::<f32>(), -123), + Float::neg_infinity::<f32>()); + assert!(Float::ldexp(Float::NaN::<f32>(), -123).is_NaN()); + } + + #[test] + fn test_frexp() { + // We have to use from_str until base-2 exponents + // are supported in floating-point literals + let f1: f32 = from_str_hex("1p-123").unwrap(); + let f2: f32 = from_str_hex("1p-111").unwrap(); + let (x1, exp1) = f1.frexp(); + let (x2, exp2) = f2.frexp(); + assert_eq!((x1, exp1), (0.5f32, -122)); + assert_eq!((x2, exp2), (0.5f32, -110)); + assert_eq!(Float::ldexp(x1, exp1), f1); + assert_eq!(Float::ldexp(x2, exp2), f2); + + assert_eq!(0f32.frexp(), (0f32, 0)); + assert_eq!((-0f32).frexp(), (-0f32, 0)); + assert_eq!(match Float::infinity::<f32>().frexp() { (x, _) => x }, + Float::infinity::<f32>()) + assert_eq!(match Float::neg_infinity::<f32>().frexp() { (x, _) => x }, + Float::neg_infinity::<f32>()) + assert!(match Float::NaN::<f32>().frexp() { (x, _) => x.is_NaN() }) + } } diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index acdec7dd368..c9c1bad65f2 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -715,6 +715,25 @@ impl Float for f64 { #[inline(always)] fn max_10_exp() -> int { 308 } + /// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp` + #[inline(always)] + fn ldexp(x: f64, exp: int) -> f64 { + ldexp(x, exp as c_int) + } + + /// + /// Breaks the number into a normalized fraction and a base-2 exponent, satisfying: + /// + /// - `self = x * pow(2, exp)` + /// - `0.5 <= abs(x) < 1.0` + /// + #[inline(always)] + fn frexp(&self) -> (f64, int) { + let mut exp = 0; + let x = frexp(*self, &mut exp); + (x, exp as int) + } + /// /// Returns the exponential of the number, minus `1`, in a way that is accurate /// even if the number is close to zero @@ -1226,4 +1245,44 @@ mod tests { assert_eq!(1e-307f64.classify(), FPNormal); assert_eq!(1e-308f64.classify(), FPSubnormal); } + + #[test] + fn test_ldexp() { + // We have to use from_str until base-2 exponents + // are supported in floating-point literals + let f1: f64 = from_str_hex("1p-123").unwrap(); + let f2: f64 = from_str_hex("1p-111").unwrap(); + assert_eq!(Float::ldexp(1f64, -123), f1); + assert_eq!(Float::ldexp(1f64, -111), f2); + + assert_eq!(Float::ldexp(0f64, -123), 0f64); + assert_eq!(Float::ldexp(-0f64, -123), -0f64); + assert_eq!(Float::ldexp(Float::infinity::<f64>(), -123), + Float::infinity::<f64>()); + assert_eq!(Float::ldexp(Float::neg_infinity::<f64>(), -123), + Float::neg_infinity::<f64>()); + assert!(Float::ldexp(Float::NaN::<f64>(), -123).is_NaN()); + } + + #[test] + fn test_frexp() { + // We have to use from_str until base-2 exponents + // are supported in floating-point literals + let f1: f64 = from_str_hex("1p-123").unwrap(); + let f2: f64 = from_str_hex("1p-111").unwrap(); + let (x1, exp1) = f1.frexp(); + let (x2, exp2) = f2.frexp(); + assert_eq!((x1, exp1), (0.5f64, -122)); + assert_eq!((x2, exp2), (0.5f64, -110)); + assert_eq!(Float::ldexp(x1, exp1), f1); + assert_eq!(Float::ldexp(x2, exp2), f2); + + assert_eq!(0f64.frexp(), (0f64, 0)); + assert_eq!((-0f64).frexp(), (-0f64, 0)); + assert_eq!(match Float::infinity::<f64>().frexp() { (x, _) => x }, + Float::infinity::<f64>()) + assert_eq!(match Float::neg_infinity::<f64>().frexp() { (x, _) => x }, + Float::neg_infinity::<f64>()) + assert!(match Float::NaN::<f64>().frexp() { (x, _) => x.is_NaN() }) + } } diff --git a/src/libcore/num/float.rs b/src/libcore/num/float.rs index 879c9494105..22abc76c3d3 100644 --- a/src/libcore/num/float.rs +++ b/src/libcore/num/float.rs @@ -881,6 +881,25 @@ impl Float for float { #[inline(always)] fn max_10_exp() -> int { Float::max_10_exp::<f64>() } + /// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp` + #[inline(always)] + fn ldexp(x: float, exp: int) -> float { + Float::ldexp(x as f64, exp) as float + } + + /// + /// Breaks the number into a normalized fraction and a base-2 exponent, satisfying: + /// + /// - `self = x * pow(2, exp)` + /// - `0.5 <= abs(x) < 1.0` + /// + #[inline(always)] + fn frexp(&self) -> (float, int) { + match (*self as f64).frexp() { + (x, exp) => (x as float, exp) + } + } + /// /// Returns the exponential of the number, minus `1`, in a way that is accurate /// even if the number is close to zero @@ -895,7 +914,9 @@ impl Float for float { /// than if the operations were performed separately /// #[inline(always)] - fn ln_1p(&self) -> float { (*self as f64).ln_1p() as float } + fn ln_1p(&self) -> float { + (*self as f64).ln_1p() as float + } /// /// Fused multiply-add. Computes `(self * a) + b` with only one rounding error. This @@ -1175,6 +1196,46 @@ mod tests { } #[test] + fn test_ldexp() { + // We have to use from_str until base-2 exponents + // are supported in floating-point literals + let f1: float = from_str_hex("1p-123").unwrap(); + let f2: float = from_str_hex("1p-111").unwrap(); + assert_eq!(Float::ldexp(1f, -123), f1); + assert_eq!(Float::ldexp(1f, -111), f2); + + assert_eq!(Float::ldexp(0f, -123), 0f); + assert_eq!(Float::ldexp(-0f, -123), -0f); + assert_eq!(Float::ldexp(Float::infinity::<float>(), -123), + Float::infinity::<float>()); + assert_eq!(Float::ldexp(Float::neg_infinity::<float>(), -123), + Float::neg_infinity::<float>()); + assert!(Float::ldexp(Float::NaN::<float>(), -123).is_NaN()); + } + + #[test] + fn test_frexp() { + // We have to use from_str until base-2 exponents + // are supported in floating-point literals + let f1: float = from_str_hex("1p-123").unwrap(); + let f2: float = from_str_hex("1p-111").unwrap(); + let (x1, exp1) = f1.frexp(); + let (x2, exp2) = f2.frexp(); + assert_eq!((x1, exp1), (0.5f, -122)); + assert_eq!((x2, exp2), (0.5f, -110)); + assert_eq!(Float::ldexp(x1, exp1), f1); + assert_eq!(Float::ldexp(x2, exp2), f2); + + assert_eq!(0f.frexp(), (0f, 0)); + assert_eq!((-0f).frexp(), (-0f, 0)); + assert_eq!(match Float::infinity::<float>().frexp() { (x, _) => x }, + Float::infinity::<float>()) + assert_eq!(match Float::neg_infinity::<float>().frexp() { (x, _) => x }, + Float::neg_infinity::<float>()) + assert!(match Float::NaN::<float>().frexp() { (x, _) => x.is_NaN() }) + } + + #[test] pub fn test_to_str_exact_do_decimal() { let s = to_str_exact(5.0, 4u); assert_eq!(s, ~"5.0000"); diff --git a/src/libcore/num/num.rs b/src/libcore/num/num.rs index 18d552c273c..a15a8f1a215 100644 --- a/src/libcore/num/num.rs +++ b/src/libcore/num/num.rs @@ -284,6 +284,9 @@ pub trait Float: Real fn min_10_exp() -> int; fn max_10_exp() -> int; + fn ldexp(x: Self, exp: int) -> Self; + fn frexp(&self) -> (Self, int); + fn exp_m1(&self) -> Self; fn ln_1p(&self) -> Self; fn mul_add(&self, a: Self, b: Self) -> Self; |
