diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index a872a6388ba46..21e55af39ebba 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::*; @@ -450,6 +451,57 @@ impl Hyperbolic for f32 { #[inline(always)] fn tanh(&self) -> f32 { tanh(*self) } + + /// + /// Inverse hyperbolic sine + /// + /// # Returns + /// + /// - on success, the inverse hyperbolic sine of `self` will be returned + /// - `self` if `self` is `0.0`, `-0.0`, `infinity`, or `neg_infinity` + /// - `NaN` if `self` is `NaN` + /// + #[inline(always)] + fn asinh(&self) -> f32 { + match *self { + neg_infinity => neg_infinity, + x => (x + ((x * x) + 1.0).sqrt()).ln(), + } + } + + /// + /// Inverse hyperbolic cosine + /// + /// # Returns + /// + /// - on success, the inverse hyperbolic cosine of `self` will be returned + /// - `infinity` if `self` is `infinity` + /// - `NaN` if `self` is `NaN` or `self < 1.0` (including `neg_infinity`) + /// + #[inline(always)] + fn acosh(&self) -> f32 { + match *self { + x if x < 1.0 => Float::NaN(), + x => (x + ((x * x) - 1.0).sqrt()).ln(), + } + } + + /// + /// Inverse hyperbolic tangent + /// + /// # Returns + /// + /// - on success, the inverse hyperbolic tangent of `self` will be returned + /// - `self` if `self` is `0.0` or `-0.0` + /// - `infinity` if `self` is `1.0` + /// - `neg_infinity` if `self` is `-1.0` + /// - `NaN` if the `self` is `NaN` or outside the domain of `-1.0 <= self <= 1.0` + /// (including `infinity` and `neg_infinity`) + /// + #[inline(always)] + fn atanh(&self) -> f32 { + 0.5 * ((2.0 * *self) / (1.0 - *self)).ln_1p() + } } impl Real for f32 { @@ -620,6 +672,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 @@ -972,6 +1043,43 @@ mod tests { assert_approx_eq!((-1.7f32).fract(), -0.7f32); } + #[test] + fn test_asinh() { + assert_eq!(0.0f32.asinh(), 0.0f32); + assert_eq!((-0.0f32).asinh(), -0.0f32); + assert_eq!(Float::infinity::().asinh(), Float::infinity::()); + assert_eq!(Float::neg_infinity::().asinh(), Float::neg_infinity::()); + assert!(Float::NaN::().asinh().is_NaN()); + assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32); + assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32); + } + + #[test] + fn test_acosh() { + assert_eq!(1.0f32.acosh(), 0.0f32); + assert!(0.999f32.acosh().is_NaN()); + assert_eq!(Float::infinity::().acosh(), Float::infinity::()); + assert!(Float::neg_infinity::().acosh().is_NaN()); + assert!(Float::NaN::().acosh().is_NaN()); + assert_approx_eq!(2.0f32.acosh(), 1.31695789692481670862504634730796844f32); + assert_approx_eq!(3.0f32.acosh(), 1.76274717403908605046521864995958461f32); + } + + #[test] + fn test_atanh() { + assert_eq!(0.0f32.atanh(), 0.0f32); + assert_eq!((-0.0f32).atanh(), -0.0f32); + assert_eq!(1.0f32.atanh(), Float::infinity::()); + assert_eq!((-1.0f32).atanh(), Float::neg_infinity::()); + assert!(2f64.atanh().atanh().is_NaN()); + assert!((-2f64).atanh().atanh().is_NaN()); + assert!(Float::infinity::().atanh().is_NaN()); + assert!(Float::neg_infinity::().atanh().is_NaN()); + assert!(Float::NaN::().atanh().is_NaN()); + assert_approx_eq!(0.5f32.atanh(), 0.54930614433405484569762261846126285f32); + assert_approx_eq!((-0.5f32).atanh(), -0.54930614433405484569762261846126285f32); + } + #[test] fn test_real_consts() { assert_approx_eq!(Real::two_pi::(), 2f32 * Real::pi::()); @@ -1091,4 +1199,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::(), -123), + Float::infinity::()); + assert_eq!(Float::ldexp(Float::neg_infinity::(), -123), + Float::neg_infinity::()); + assert!(Float::ldexp(Float::NaN::(), -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::().frexp() { (x, _) => x }, + Float::infinity::()) + assert_eq!(match Float::neg_infinity::().frexp() { (x, _) => x }, + Float::neg_infinity::()) + assert!(match Float::NaN::().frexp() { (x, _) => x.is_NaN() }) + } } diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 8a17ae91934bb..3c9df4040d8ea 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -463,6 +463,57 @@ impl Hyperbolic for f64 { #[inline(always)] fn tanh(&self) -> f64 { tanh(*self) } + + /// + /// Inverse hyperbolic sine + /// + /// # Returns + /// + /// - on success, the inverse hyperbolic sine of `self` will be returned + /// - `self` if `self` is `0.0`, `-0.0`, `infinity`, or `neg_infinity` + /// - `NaN` if `self` is `NaN` + /// + #[inline(always)] + fn asinh(&self) -> f64 { + match *self { + neg_infinity => neg_infinity, + x => (x + ((x * x) + 1.0).sqrt()).ln(), + } + } + + /// + /// Inverse hyperbolic cosine + /// + /// # Returns + /// + /// - on success, the inverse hyperbolic cosine of `self` will be returned + /// - `infinity` if `self` is `infinity` + /// - `NaN` if `self` is `NaN` or `self < 1.0` (including `neg_infinity`) + /// + #[inline(always)] + fn acosh(&self) -> f64 { + match *self { + x if x < 1.0 => Float::NaN(), + x => (x + ((x * x) - 1.0).sqrt()).ln(), + } + } + + /// + /// Inverse hyperbolic tangent + /// + /// # Returns + /// + /// - on success, the inverse hyperbolic tangent of `self` will be returned + /// - `self` if `self` is `0.0` or `-0.0` + /// - `infinity` if `self` is `1.0` + /// - `neg_infinity` if `self` is `-1.0` + /// - `NaN` if the `self` is `NaN` or outside the domain of `-1.0 <= self <= 1.0` + /// (including `infinity` and `neg_infinity`) + /// + #[inline(always)] + fn atanh(&self) -> f64 { + 0.5 * ((2.0 * *self) / (1.0 - *self)).ln_1p() + } } impl Real for f64 { @@ -663,6 +714,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 @@ -1019,6 +1089,43 @@ mod tests { assert_approx_eq!((-1.7f64).fract(), -0.7f64); } + #[test] + fn test_asinh() { + assert_eq!(0.0f64.asinh(), 0.0f64); + assert_eq!((-0.0f64).asinh(), -0.0f64); + assert_eq!(Float::infinity::().asinh(), Float::infinity::()); + assert_eq!(Float::neg_infinity::().asinh(), Float::neg_infinity::()); + assert!(Float::NaN::().asinh().is_NaN()); + assert_approx_eq!(2.0f64.asinh(), 1.443635475178810342493276740273105f64); + assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64); + } + + #[test] + fn test_acosh() { + assert_eq!(1.0f64.acosh(), 0.0f64); + assert!(0.999f64.acosh().is_NaN()); + assert_eq!(Float::infinity::().acosh(), Float::infinity::()); + assert!(Float::neg_infinity::().acosh().is_NaN()); + assert!(Float::NaN::().acosh().is_NaN()); + assert_approx_eq!(2.0f64.acosh(), 1.31695789692481670862504634730796844f64); + assert_approx_eq!(3.0f64.acosh(), 1.76274717403908605046521864995958461f64); + } + + #[test] + fn test_atanh() { + assert_eq!(0.0f64.atanh(), 0.0f64); + assert_eq!((-0.0f64).atanh(), -0.0f64); + assert_eq!(1.0f64.atanh(), Float::infinity::()); + assert_eq!((-1.0f64).atanh(), Float::neg_infinity::()); + assert!(2f64.atanh().atanh().is_NaN()); + assert!((-2f64).atanh().atanh().is_NaN()); + assert!(Float::infinity::().atanh().is_NaN()); + assert!(Float::neg_infinity::().atanh().is_NaN()); + assert!(Float::NaN::().atanh().is_NaN()); + assert_approx_eq!(0.5f64.atanh(), 0.54930614433405484569762261846126285f64); + assert_approx_eq!((-0.5f64).atanh(), -0.54930614433405484569762261846126285f64); + } + #[test] fn test_real_consts() { assert_approx_eq!(Real::two_pi::(), 2.0 * Real::pi::()); @@ -1137,4 +1244,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::(), -123), + Float::infinity::()); + assert_eq!(Float::ldexp(Float::neg_infinity::(), -123), + Float::neg_infinity::()); + assert!(Float::ldexp(Float::NaN::(), -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::().frexp() { (x, _) => x }, + Float::infinity::()) + assert_eq!(match Float::neg_infinity::().frexp() { (x, _) => x }, + Float::neg_infinity::()) + assert!(match Float::NaN::().frexp() { (x, _) => x.is_NaN() }) + } } diff --git a/src/libcore/num/float.rs b/src/libcore/num/float.rs index e6a2ed7ea9759..22abc76c3d328 100644 --- a/src/libcore/num/float.rs +++ b/src/libcore/num/float.rs @@ -585,6 +585,51 @@ impl Hyperbolic for float { fn tanh(&self) -> float { (*self as f64).tanh() as float } + + /// + /// Inverse hyperbolic sine + /// + /// # Returns + /// + /// - on success, the inverse hyperbolic sine of `self` will be returned + /// - `self` if `self` is `0.0`, `-0.0`, `infinity`, or `neg_infinity` + /// - `NaN` if `self` is `NaN` + /// + #[inline(always)] + fn asinh(&self) -> float { + (*self as f64).asinh() as float + } + + /// + /// Inverse hyperbolic cosine + /// + /// # Returns + /// + /// - on success, the inverse hyperbolic cosine of `self` will be returned + /// - `infinity` if `self` is `infinity` + /// - `NaN` if `self` is `NaN` or `self < 1.0` (including `neg_infinity`) + /// + #[inline(always)] + fn acosh(&self) -> float { + (*self as f64).acosh() as float + } + + /// + /// Inverse hyperbolic tangent + /// + /// # Returns + /// + /// - on success, the inverse hyperbolic tangent of `self` will be returned + /// - `self` if `self` is `0.0` or `-0.0` + /// - `infinity` if `self` is `1.0` + /// - `neg_infinity` if `self` is `-1.0` + /// - `NaN` if the `self` is `NaN` or outside the domain of `-1.0 <= self <= 1.0` + /// (including `infinity` and `neg_infinity`) + /// + #[inline(always)] + fn atanh(&self) -> float { + (*self as f64).atanh() as float + } } impl Real for float { @@ -836,6 +881,25 @@ impl Float for float { #[inline(always)] fn max_10_exp() -> int { Float::max_10_exp::() } + /// 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 @@ -850,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 @@ -972,6 +1038,43 @@ mod tests { assert_approx_eq!((-1.7f).fract(), -0.7f); } + #[test] + fn test_asinh() { + assert_eq!(0.0f.asinh(), 0.0f); + assert_eq!((-0.0f).asinh(), -0.0f); + assert_eq!(Float::infinity::().asinh(), Float::infinity::()); + assert_eq!(Float::neg_infinity::().asinh(), Float::neg_infinity::()); + assert!(Float::NaN::().asinh().is_NaN()); + assert_approx_eq!(2.0f.asinh(), 1.443635475178810342493276740273105f); + assert_approx_eq!((-2.0f).asinh(), -1.443635475178810342493276740273105f); + } + + #[test] + fn test_acosh() { + assert_eq!(1.0f.acosh(), 0.0f); + assert!(0.999f.acosh().is_NaN()); + assert_eq!(Float::infinity::().acosh(), Float::infinity::()); + assert!(Float::neg_infinity::().acosh().is_NaN()); + assert!(Float::NaN::().acosh().is_NaN()); + assert_approx_eq!(2.0f.acosh(), 1.31695789692481670862504634730796844f); + assert_approx_eq!(3.0f.acosh(), 1.76274717403908605046521864995958461f); + } + + #[test] + fn test_atanh() { + assert_eq!(0.0f.atanh(), 0.0f); + assert_eq!((-0.0f).atanh(), -0.0f); + assert_eq!(1.0f.atanh(), Float::infinity::()); + assert_eq!((-1.0f).atanh(), Float::neg_infinity::()); + assert!(2f64.atanh().atanh().is_NaN()); + assert!((-2f64).atanh().atanh().is_NaN()); + assert!(Float::infinity::().atanh().is_NaN()); + assert!(Float::neg_infinity::().atanh().is_NaN()); + assert!(Float::NaN::().atanh().is_NaN()); + assert_approx_eq!(0.5f.atanh(), 0.54930614433405484569762261846126285f); + assert_approx_eq!((-0.5f).atanh(), -0.54930614433405484569762261846126285f); + } + #[test] fn test_real_consts() { assert_approx_eq!(Real::two_pi::(), 2f * Real::pi::()); @@ -1092,6 +1195,46 @@ mod tests { assert_eq!(1e-308f.classify(), FPSubnormal); } + #[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::(), -123), + Float::infinity::()); + assert_eq!(Float::ldexp(Float::neg_infinity::(), -123), + Float::neg_infinity::()); + assert!(Float::ldexp(Float::NaN::(), -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::().frexp() { (x, _) => x }, + Float::infinity::()) + assert_eq!(match Float::neg_infinity::().frexp() { (x, _) => x }, + Float::neg_infinity::()) + assert!(match Float::NaN::().frexp() { (x, _) => x.is_NaN() }) + } + #[test] pub fn test_to_str_exact_do_decimal() { let s = to_str_exact(5.0, 4u); diff --git a/src/libcore/num/num.rs b/src/libcore/num/num.rs index 50ba55039d408..a15a8f1a2153e 100644 --- a/src/libcore/num/num.rs +++ b/src/libcore/num/num.rs @@ -133,6 +133,9 @@ pub trait Hyperbolic: Exponential { fn sinh(&self) -> Self; fn cosh(&self) -> Self; fn tanh(&self) -> Self; + fn asinh(&self) -> Self; + fn acosh(&self) -> Self; + fn atanh(&self) -> Self; } /// @@ -281,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;