|
10 | 10 |
|
11 | 11 | //! Operations and constants for `f32`
|
12 | 12 |
|
| 13 | +use libc::c_int; |
13 | 14 | use num::{Zero, One, strconv};
|
14 | 15 | use num::{FPCategory, FPNaN, FPInfinite , FPZero, FPSubnormal, FPNormal};
|
15 | 16 | use prelude::*;
|
@@ -450,6 +451,57 @@ impl Hyperbolic for f32 {
|
450 | 451 |
|
451 | 452 | #[inline(always)]
|
452 | 453 | fn tanh(&self) -> f32 { tanh(*self) }
|
| 454 | + |
| 455 | + /// |
| 456 | + /// Inverse hyperbolic sine |
| 457 | + /// |
| 458 | + /// # Returns |
| 459 | + /// |
| 460 | + /// - on success, the inverse hyperbolic sine of `self` will be returned |
| 461 | + /// - `self` if `self` is `0.0`, `-0.0`, `infinity`, or `neg_infinity` |
| 462 | + /// - `NaN` if `self` is `NaN` |
| 463 | + /// |
| 464 | + #[inline(always)] |
| 465 | + fn asinh(&self) -> f32 { |
| 466 | + match *self { |
| 467 | + neg_infinity => neg_infinity, |
| 468 | + x => (x + ((x * x) + 1.0).sqrt()).ln(), |
| 469 | + } |
| 470 | + } |
| 471 | + |
| 472 | + /// |
| 473 | + /// Inverse hyperbolic cosine |
| 474 | + /// |
| 475 | + /// # Returns |
| 476 | + /// |
| 477 | + /// - on success, the inverse hyperbolic cosine of `self` will be returned |
| 478 | + /// - `infinity` if `self` is `infinity` |
| 479 | + /// - `NaN` if `self` is `NaN` or `self < 1.0` (including `neg_infinity`) |
| 480 | + /// |
| 481 | + #[inline(always)] |
| 482 | + fn acosh(&self) -> f32 { |
| 483 | + match *self { |
| 484 | + x if x < 1.0 => Float::NaN(), |
| 485 | + x => (x + ((x * x) - 1.0).sqrt()).ln(), |
| 486 | + } |
| 487 | + } |
| 488 | + |
| 489 | + /// |
| 490 | + /// Inverse hyperbolic tangent |
| 491 | + /// |
| 492 | + /// # Returns |
| 493 | + /// |
| 494 | + /// - on success, the inverse hyperbolic tangent of `self` will be returned |
| 495 | + /// - `self` if `self` is `0.0` or `-0.0` |
| 496 | + /// - `infinity` if `self` is `1.0` |
| 497 | + /// - `neg_infinity` if `self` is `-1.0` |
| 498 | + /// - `NaN` if the `self` is `NaN` or outside the domain of `-1.0 <= self <= 1.0` |
| 499 | + /// (including `infinity` and `neg_infinity`) |
| 500 | + /// |
| 501 | + #[inline(always)] |
| 502 | + fn atanh(&self) -> f32 { |
| 503 | + 0.5 * ((2.0 * *self) / (1.0 - *self)).ln_1p() |
| 504 | + } |
453 | 505 | }
|
454 | 506 |
|
455 | 507 | impl Real for f32 {
|
@@ -620,6 +672,25 @@ impl Float for f32 {
|
620 | 672 | #[inline(always)]
|
621 | 673 | fn max_10_exp() -> int { 38 }
|
622 | 674 |
|
| 675 | + /// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp` |
| 676 | + #[inline(always)] |
| 677 | + fn ldexp(x: f32, exp: int) -> f32 { |
| 678 | + ldexp(x, exp as c_int) |
| 679 | + } |
| 680 | + |
| 681 | + /// |
| 682 | + /// Breaks the number into a normalized fraction and a base-2 exponent, satisfying: |
| 683 | + /// |
| 684 | + /// - `self = x * pow(2, exp)` |
| 685 | + /// - `0.5 <= abs(x) < 1.0` |
| 686 | + /// |
| 687 | + #[inline(always)] |
| 688 | + fn frexp(&self) -> (f32, int) { |
| 689 | + let mut exp = 0; |
| 690 | + let x = frexp(*self, &mut exp); |
| 691 | + (x, exp as int) |
| 692 | + } |
| 693 | + |
623 | 694 | ///
|
624 | 695 | /// Returns the exponential of the number, minus `1`, in a way that is accurate
|
625 | 696 | /// even if the number is close to zero
|
@@ -972,6 +1043,43 @@ mod tests {
|
972 | 1043 | assert_approx_eq!((-1.7f32).fract(), -0.7f32);
|
973 | 1044 | }
|
974 | 1045 |
|
| 1046 | + #[test] |
| 1047 | + fn test_asinh() { |
| 1048 | + assert_eq!(0.0f32.asinh(), 0.0f32); |
| 1049 | + assert_eq!((-0.0f32).asinh(), -0.0f32); |
| 1050 | + assert_eq!(Float::infinity::<f32>().asinh(), Float::infinity::<f32>()); |
| 1051 | + assert_eq!(Float::neg_infinity::<f32>().asinh(), Float::neg_infinity::<f32>()); |
| 1052 | + assert!(Float::NaN::<f32>().asinh().is_NaN()); |
| 1053 | + assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32); |
| 1054 | + assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32); |
| 1055 | + } |
| 1056 | +
|
| 1057 | + #[test] |
| 1058 | + fn test_acosh() { |
| 1059 | + assert_eq!(1.0f32.acosh(), 0.0f32); |
| 1060 | + assert!(0.999f32.acosh().is_NaN()); |
| 1061 | + assert_eq!(Float::infinity::<f32>().acosh(), Float::infinity::<f32>()); |
| 1062 | + assert!(Float::neg_infinity::<f32>().acosh().is_NaN()); |
| 1063 | + assert!(Float::NaN::<f32>().acosh().is_NaN()); |
| 1064 | + assert_approx_eq!(2.0f32.acosh(), 1.31695789692481670862504634730796844f32); |
| 1065 | + assert_approx_eq!(3.0f32.acosh(), 1.76274717403908605046521864995958461f32); |
| 1066 | + } |
| 1067 | +
|
| 1068 | + #[test] |
| 1069 | + fn test_atanh() { |
| 1070 | + assert_eq!(0.0f32.atanh(), 0.0f32); |
| 1071 | + assert_eq!((-0.0f32).atanh(), -0.0f32); |
| 1072 | + assert_eq!(1.0f32.atanh(), Float::infinity::<f32>()); |
| 1073 | + assert_eq!((-1.0f32).atanh(), Float::neg_infinity::<f32>()); |
| 1074 | + assert!(2f64.atanh().atanh().is_NaN()); |
| 1075 | + assert!((-2f64).atanh().atanh().is_NaN()); |
| 1076 | + assert!(Float::infinity::<f64>().atanh().is_NaN()); |
| 1077 | + assert!(Float::neg_infinity::<f64>().atanh().is_NaN()); |
| 1078 | + assert!(Float::NaN::<f32>().atanh().is_NaN()); |
| 1079 | + assert_approx_eq!(0.5f32.atanh(), 0.54930614433405484569762261846126285f32); |
| 1080 | + assert_approx_eq!((-0.5f32).atanh(), -0.54930614433405484569762261846126285f32); |
| 1081 | + } |
| 1082 | +
|
975 | 1083 | #[test]
|
976 | 1084 | fn test_real_consts() {
|
977 | 1085 | assert_approx_eq!(Real::two_pi::<f32>(), 2f32 * Real::pi::<f32>());
|
@@ -1091,4 +1199,44 @@ mod tests {
|
1091 | 1199 | assert_eq!(1e-37f32.classify(), FPNormal);
|
1092 | 1200 | assert_eq!(1e-38f32.classify(), FPSubnormal);
|
1093 | 1201 | }
|
| 1202 | +
|
| 1203 | + #[test] |
| 1204 | + fn test_ldexp() { |
| 1205 | + // We have to use from_str until base-2 exponents |
| 1206 | + // are supported in floating-point literals |
| 1207 | + let f1: f32 = from_str_hex("1p-123").unwrap(); |
| 1208 | + let f2: f32 = from_str_hex("1p-111").unwrap(); |
| 1209 | + assert_eq!(Float::ldexp(1f32, -123), f1); |
| 1210 | + assert_eq!(Float::ldexp(1f32, -111), f2); |
| 1211 | +
|
| 1212 | + assert_eq!(Float::ldexp(0f32, -123), 0f32); |
| 1213 | + assert_eq!(Float::ldexp(-0f32, -123), -0f32); |
| 1214 | + assert_eq!(Float::ldexp(Float::infinity::<f32>(), -123), |
| 1215 | + Float::infinity::<f32>()); |
| 1216 | + assert_eq!(Float::ldexp(Float::neg_infinity::<f32>(), -123), |
| 1217 | + Float::neg_infinity::<f32>()); |
| 1218 | + assert!(Float::ldexp(Float::NaN::<f32>(), -123).is_NaN()); |
| 1219 | + } |
| 1220 | +
|
| 1221 | + #[test] |
| 1222 | + fn test_frexp() { |
| 1223 | + // We have to use from_str until base-2 exponents |
| 1224 | + // are supported in floating-point literals |
| 1225 | + let f1: f32 = from_str_hex("1p-123").unwrap(); |
| 1226 | + let f2: f32 = from_str_hex("1p-111").unwrap(); |
| 1227 | + let (x1, exp1) = f1.frexp(); |
| 1228 | + let (x2, exp2) = f2.frexp(); |
| 1229 | + assert_eq!((x1, exp1), (0.5f32, -122)); |
| 1230 | + assert_eq!((x2, exp2), (0.5f32, -110)); |
| 1231 | + assert_eq!(Float::ldexp(x1, exp1), f1); |
| 1232 | + assert_eq!(Float::ldexp(x2, exp2), f2); |
| 1233 | + |
| 1234 | + assert_eq!(0f32.frexp(), (0f32, 0)); |
| 1235 | + assert_eq!((-0f32).frexp(), (-0f32, 0)); |
| 1236 | + assert_eq!(match Float::infinity::<f32>().frexp() { (x, _) => x }, |
| 1237 | + Float::infinity::<f32>()) |
| 1238 | + assert_eq!(match Float::neg_infinity::<f32>().frexp() { (x, _) => x }, |
| 1239 | + Float::neg_infinity::<f32>()) |
| 1240 | + assert!(match Float::NaN::<f32>().frexp() { (x, _) => x.is_NaN() }) |
| 1241 | + } |
1094 | 1242 | }
|
0 commit comments