Skip to content

Commit 84745b4

Browse files
committed
auto merge of #6463 : bjz/rust/numeric-traits, r=thestinger
This is part of the numeric trait reform tracked on issue #4819
2 parents 5a2f65f + 3515b49 commit 84745b4

File tree

4 files changed

+445
-1
lines changed

4 files changed

+445
-1
lines changed

src/libcore/num/f32.rs

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
//! Operations and constants for `f32`
1212
13+
use libc::c_int;
1314
use num::{Zero, One, strconv};
1415
use num::{FPCategory, FPNaN, FPInfinite , FPZero, FPSubnormal, FPNormal};
1516
use prelude::*;
@@ -450,6 +451,57 @@ impl Hyperbolic for f32 {
450451

451452
#[inline(always)]
452453
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+
}
453505
}
454506

455507
impl Real for f32 {
@@ -620,6 +672,25 @@ impl Float for f32 {
620672
#[inline(always)]
621673
fn max_10_exp() -> int { 38 }
622674

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+
623694
///
624695
/// Returns the exponential of the number, minus `1`, in a way that is accurate
625696
/// even if the number is close to zero
@@ -972,6 +1043,43 @@ mod tests {
9721043
assert_approx_eq!((-1.7f32).fract(), -0.7f32);
9731044
}
9741045
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+
9751083
#[test]
9761084
fn test_real_consts() {
9771085
assert_approx_eq!(Real::two_pi::<f32>(), 2f32 * Real::pi::<f32>());
@@ -1091,4 +1199,44 @@ mod tests {
10911199
assert_eq!(1e-37f32.classify(), FPNormal);
10921200
assert_eq!(1e-38f32.classify(), FPSubnormal);
10931201
}
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+
}
10941242
}

src/libcore/num/f64.rs

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,57 @@ impl Hyperbolic for f64 {
463463

464464
#[inline(always)]
465465
fn tanh(&self) -> f64 { tanh(*self) }
466+
467+
///
468+
/// Inverse hyperbolic sine
469+
///
470+
/// # Returns
471+
///
472+
/// - on success, the inverse hyperbolic sine of `self` will be returned
473+
/// - `self` if `self` is `0.0`, `-0.0`, `infinity`, or `neg_infinity`
474+
/// - `NaN` if `self` is `NaN`
475+
///
476+
#[inline(always)]
477+
fn asinh(&self) -> f64 {
478+
match *self {
479+
neg_infinity => neg_infinity,
480+
x => (x + ((x * x) + 1.0).sqrt()).ln(),
481+
}
482+
}
483+
484+
///
485+
/// Inverse hyperbolic cosine
486+
///
487+
/// # Returns
488+
///
489+
/// - on success, the inverse hyperbolic cosine of `self` will be returned
490+
/// - `infinity` if `self` is `infinity`
491+
/// - `NaN` if `self` is `NaN` or `self < 1.0` (including `neg_infinity`)
492+
///
493+
#[inline(always)]
494+
fn acosh(&self) -> f64 {
495+
match *self {
496+
x if x < 1.0 => Float::NaN(),
497+
x => (x + ((x * x) - 1.0).sqrt()).ln(),
498+
}
499+
}
500+
501+
///
502+
/// Inverse hyperbolic tangent
503+
///
504+
/// # Returns
505+
///
506+
/// - on success, the inverse hyperbolic tangent of `self` will be returned
507+
/// - `self` if `self` is `0.0` or `-0.0`
508+
/// - `infinity` if `self` is `1.0`
509+
/// - `neg_infinity` if `self` is `-1.0`
510+
/// - `NaN` if the `self` is `NaN` or outside the domain of `-1.0 <= self <= 1.0`
511+
/// (including `infinity` and `neg_infinity`)
512+
///
513+
#[inline(always)]
514+
fn atanh(&self) -> f64 {
515+
0.5 * ((2.0 * *self) / (1.0 - *self)).ln_1p()
516+
}
466517
}
467518

468519
impl Real for f64 {
@@ -663,6 +714,25 @@ impl Float for f64 {
663714
#[inline(always)]
664715
fn max_10_exp() -> int { 308 }
665716

717+
/// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp`
718+
#[inline(always)]
719+
fn ldexp(x: f64, exp: int) -> f64 {
720+
ldexp(x, exp as c_int)
721+
}
722+
723+
///
724+
/// Breaks the number into a normalized fraction and a base-2 exponent, satisfying:
725+
///
726+
/// - `self = x * pow(2, exp)`
727+
/// - `0.5 <= abs(x) < 1.0`
728+
///
729+
#[inline(always)]
730+
fn frexp(&self) -> (f64, int) {
731+
let mut exp = 0;
732+
let x = frexp(*self, &mut exp);
733+
(x, exp as int)
734+
}
735+
666736
///
667737
/// Returns the exponential of the number, minus `1`, in a way that is accurate
668738
/// even if the number is close to zero
@@ -1019,6 +1089,43 @@ mod tests {
10191089
assert_approx_eq!((-1.7f64).fract(), -0.7f64);
10201090
}
10211091
1092+
#[test]
1093+
fn test_asinh() {
1094+
assert_eq!(0.0f64.asinh(), 0.0f64);
1095+
assert_eq!((-0.0f64).asinh(), -0.0f64);
1096+
assert_eq!(Float::infinity::<f64>().asinh(), Float::infinity::<f64>());
1097+
assert_eq!(Float::neg_infinity::<f64>().asinh(), Float::neg_infinity::<f64>());
1098+
assert!(Float::NaN::<f64>().asinh().is_NaN());
1099+
assert_approx_eq!(2.0f64.asinh(), 1.443635475178810342493276740273105f64);
1100+
assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64);
1101+
}
1102+
1103+
#[test]
1104+
fn test_acosh() {
1105+
assert_eq!(1.0f64.acosh(), 0.0f64);
1106+
assert!(0.999f64.acosh().is_NaN());
1107+
assert_eq!(Float::infinity::<f64>().acosh(), Float::infinity::<f64>());
1108+
assert!(Float::neg_infinity::<f64>().acosh().is_NaN());
1109+
assert!(Float::NaN::<f64>().acosh().is_NaN());
1110+
assert_approx_eq!(2.0f64.acosh(), 1.31695789692481670862504634730796844f64);
1111+
assert_approx_eq!(3.0f64.acosh(), 1.76274717403908605046521864995958461f64);
1112+
}
1113+
1114+
#[test]
1115+
fn test_atanh() {
1116+
assert_eq!(0.0f64.atanh(), 0.0f64);
1117+
assert_eq!((-0.0f64).atanh(), -0.0f64);
1118+
assert_eq!(1.0f64.atanh(), Float::infinity::<f64>());
1119+
assert_eq!((-1.0f64).atanh(), Float::neg_infinity::<f64>());
1120+
assert!(2f64.atanh().atanh().is_NaN());
1121+
assert!((-2f64).atanh().atanh().is_NaN());
1122+
assert!(Float::infinity::<f64>().atanh().is_NaN());
1123+
assert!(Float::neg_infinity::<f64>().atanh().is_NaN());
1124+
assert!(Float::NaN::<f64>().atanh().is_NaN());
1125+
assert_approx_eq!(0.5f64.atanh(), 0.54930614433405484569762261846126285f64);
1126+
assert_approx_eq!((-0.5f64).atanh(), -0.54930614433405484569762261846126285f64);
1127+
}
1128+
10221129
#[test]
10231130
fn test_real_consts() {
10241131
assert_approx_eq!(Real::two_pi::<f64>(), 2.0 * Real::pi::<f64>());
@@ -1137,4 +1244,44 @@ mod tests {
11371244
assert_eq!(1e-307f64.classify(), FPNormal);
11381245
assert_eq!(1e-308f64.classify(), FPSubnormal);
11391246
}
1247+
1248+
#[test]
1249+
fn test_ldexp() {
1250+
// We have to use from_str until base-2 exponents
1251+
// are supported in floating-point literals
1252+
let f1: f64 = from_str_hex("1p-123").unwrap();
1253+
let f2: f64 = from_str_hex("1p-111").unwrap();
1254+
assert_eq!(Float::ldexp(1f64, -123), f1);
1255+
assert_eq!(Float::ldexp(1f64, -111), f2);
1256+
1257+
assert_eq!(Float::ldexp(0f64, -123), 0f64);
1258+
assert_eq!(Float::ldexp(-0f64, -123), -0f64);
1259+
assert_eq!(Float::ldexp(Float::infinity::<f64>(), -123),
1260+
Float::infinity::<f64>());
1261+
assert_eq!(Float::ldexp(Float::neg_infinity::<f64>(), -123),
1262+
Float::neg_infinity::<f64>());
1263+
assert!(Float::ldexp(Float::NaN::<f64>(), -123).is_NaN());
1264+
}
1265+
1266+
#[test]
1267+
fn test_frexp() {
1268+
// We have to use from_str until base-2 exponents
1269+
// are supported in floating-point literals
1270+
let f1: f64 = from_str_hex("1p-123").unwrap();
1271+
let f2: f64 = from_str_hex("1p-111").unwrap();
1272+
let (x1, exp1) = f1.frexp();
1273+
let (x2, exp2) = f2.frexp();
1274+
assert_eq!((x1, exp1), (0.5f64, -122));
1275+
assert_eq!((x2, exp2), (0.5f64, -110));
1276+
assert_eq!(Float::ldexp(x1, exp1), f1);
1277+
assert_eq!(Float::ldexp(x2, exp2), f2);
1278+
1279+
assert_eq!(0f64.frexp(), (0f64, 0));
1280+
assert_eq!((-0f64).frexp(), (-0f64, 0));
1281+
assert_eq!(match Float::infinity::<f64>().frexp() { (x, _) => x },
1282+
Float::infinity::<f64>())
1283+
assert_eq!(match Float::neg_infinity::<f64>().frexp() { (x, _) => x },
1284+
Float::neg_infinity::<f64>())
1285+
assert!(match Float::NaN::<f64>().frexp() { (x, _) => x.is_NaN() })
1286+
}
11401287
}

0 commit comments

Comments
 (0)