Skip to content

Commit 8d4d2b0

Browse files
committed
Add inverse hyperbolic functions
1 parent 830b945 commit 8d4d2b0

File tree

4 files changed

+263
-0
lines changed

4 files changed

+263
-0
lines changed

src/libcore/num/f32.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,58 @@ impl Hyperbolic for f32 {
450450

451451
#[inline(always)]
452452
fn tanh(&self) -> f32 { tanh(*self) }
453+
454+
///
455+
/// Inverse hyperbolic sine
456+
///
457+
/// # Returns
458+
///
459+
/// - on success, the inverse hyperbolic sine of `self` will be returned
460+
/// - `self` if `self` is `0.0`, `-0.0`, `infinity`, or `neg_infinity`
461+
/// - `NaN` if `self` is `NaN`
462+
///
463+
#[inline(always)]
464+
fn asinh(&self) -> f32 {
465+
match *self {
466+
infinity => infinity,
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 {
@@ -972,6 +1024,43 @@ mod tests {
9721024
assert_approx_eq!((-1.7f32).fract(), -0.7f32);
9731025
}
9741026

1027+
#[test]
1028+
fn test_asinh() {
1029+
assert_eq!(0.0f32.asinh(), 0.0f32);
1030+
assert_eq!((-0.0f32).asinh(), -0.0f32);
1031+
assert_eq!(Float::infinity::<f32>().asinh(), Float::infinity::<f32>());
1032+
assert_eq!(Float::neg_infinity::<f32>().asinh(), Float::neg_infinity::<f32>());
1033+
assert!(Float::NaN::<f32>().asinh().is_NaN());
1034+
assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32);
1035+
assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32);
1036+
}
1037+
1038+
#[test]
1039+
fn test_acosh() {
1040+
assert_eq!(1.0f32.acosh(), 0.0f32);
1041+
assert!(0.999f32.acosh().is_NaN());
1042+
assert_eq!(Float::infinity::<f32>().acosh(), Float::infinity::<f32>());
1043+
assert!(Float::neg_infinity::<f32>().acosh().is_NaN());
1044+
assert!(Float::NaN::<f32>().acosh().is_NaN());
1045+
assert_approx_eq!(2.0f32.acosh(), 1.31695789692481670862504634730796844f32);
1046+
assert_approx_eq!(3.0f32.acosh(), 1.76274717403908605046521864995958461f32);
1047+
}
1048+
1049+
#[test]
1050+
fn test_atanh() {
1051+
assert_eq!(0.0f32.atanh(), 0.0f32);
1052+
assert_eq!((-0.0f32).atanh(), -0.0f32);
1053+
assert_eq!(1.0f32.atanh(), Float::infinity::<f32>());
1054+
assert_eq!((-1.0f32).atanh(), Float::neg_infinity::<f32>());
1055+
assert!(2f64.atanh().atanh().is_NaN());
1056+
assert!((-2f64).atanh().atanh().is_NaN());
1057+
assert!(Float::infinity::<f64>().atanh().is_NaN());
1058+
assert!(Float::neg_infinity::<f64>().atanh().is_NaN());
1059+
assert!(Float::NaN::<f32>().atanh().is_NaN());
1060+
assert_approx_eq!(0.5f32.atanh(), 0.54930614433405484569762261846126285f32);
1061+
assert_approx_eq!((-0.5f32).atanh(), -0.54930614433405484569762261846126285f32);
1062+
}
1063+
9751064
#[test]
9761065
fn test_real_consts() {
9771066
assert_approx_eq!(Real::two_pi::<f32>(), 2f32 * Real::pi::<f32>());

src/libcore/num/f64.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,58 @@ 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+
infinity => infinity,
480+
neg_infinity => neg_infinity,
481+
x => (x + ((x * x) + 1.0).sqrt()).ln(),
482+
}
483+
}
484+
485+
///
486+
/// Inverse hyperbolic cosine
487+
///
488+
/// # Returns
489+
///
490+
/// - on success, the inverse hyperbolic cosine of `self` will be returned
491+
/// - `infinity` if `self` is `infinity`
492+
/// - `NaN` if `self` is `NaN` or `self < 1.0` (including `neg_infinity`)
493+
///
494+
#[inline(always)]
495+
fn acosh(&self) -> f64 {
496+
match *self {
497+
x if x < 1.0 => Float::NaN(),
498+
x => (x + ((x * x) - 1.0).sqrt()).ln(),
499+
}
500+
}
501+
502+
///
503+
/// Inverse hyperbolic tangent
504+
///
505+
/// # Returns
506+
///
507+
/// - on success, the inverse hyperbolic tangent of `self` will be returned
508+
/// - `self` if `self` is `0.0` or `-0.0`
509+
/// - `infinity` if `self` is `1.0`
510+
/// - `neg_infinity` if `self` is `-1.0`
511+
/// - `NaN` if the `self` is `NaN` or outside the domain of `-1.0 <= self <= 1.0`
512+
/// (including `infinity` and `neg_infinity`)
513+
///
514+
#[inline(always)]
515+
fn atanh(&self) -> f64 {
516+
0.5 * ((2.0 * *self) / (1.0 - *self)).ln_1p()
517+
}
466518
}
467519

468520
impl Real for f64 {
@@ -1019,6 +1071,43 @@ mod tests {
10191071
assert_approx_eq!((-1.7f64).fract(), -0.7f64);
10201072
}
10211073

1074+
#[test]
1075+
fn test_asinh() {
1076+
assert_eq!(0.0f64.asinh(), 0.0f64);
1077+
assert_eq!((-0.0f64).asinh(), -0.0f64);
1078+
assert_eq!(Float::infinity::<f64>().asinh(), Float::infinity::<f64>());
1079+
assert_eq!(Float::neg_infinity::<f64>().asinh(), Float::neg_infinity::<f64>());
1080+
assert!(Float::NaN::<f64>().asinh().is_NaN());
1081+
assert_approx_eq!(2.0f64.asinh(), 1.443635475178810342493276740273105f64);
1082+
assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64);
1083+
}
1084+
1085+
#[test]
1086+
fn test_acosh() {
1087+
assert_eq!(1.0f64.acosh(), 0.0f64);
1088+
assert!(0.999f64.acosh().is_NaN());
1089+
assert_eq!(Float::infinity::<f64>().acosh(), Float::infinity::<f64>());
1090+
assert!(Float::neg_infinity::<f64>().acosh().is_NaN());
1091+
assert!(Float::NaN::<f64>().acosh().is_NaN());
1092+
assert_approx_eq!(2.0f64.acosh(), 1.31695789692481670862504634730796844f64);
1093+
assert_approx_eq!(3.0f64.acosh(), 1.76274717403908605046521864995958461f64);
1094+
}
1095+
1096+
#[test]
1097+
fn test_atanh() {
1098+
assert_eq!(0.0f64.atanh(), 0.0f64);
1099+
assert_eq!((-0.0f64).atanh(), -0.0f64);
1100+
assert_eq!(1.0f64.atanh(), Float::infinity::<f64>());
1101+
assert_eq!((-1.0f64).atanh(), Float::neg_infinity::<f64>());
1102+
assert!(2f64.atanh().atanh().is_NaN());
1103+
assert!((-2f64).atanh().atanh().is_NaN());
1104+
assert!(Float::infinity::<f64>().atanh().is_NaN());
1105+
assert!(Float::neg_infinity::<f64>().atanh().is_NaN());
1106+
assert!(Float::NaN::<f64>().atanh().is_NaN());
1107+
assert_approx_eq!(0.5f64.atanh(), 0.54930614433405484569762261846126285f64);
1108+
assert_approx_eq!((-0.5f64).atanh(), -0.54930614433405484569762261846126285f64);
1109+
}
1110+
10221111
#[test]
10231112
fn test_real_consts() {
10241113
assert_approx_eq!(Real::two_pi::<f64>(), 2.0 * Real::pi::<f64>());

src/libcore/num/float.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,51 @@ impl Hyperbolic for float {
585585
fn tanh(&self) -> float {
586586
(*self as f64).tanh() as float
587587
}
588+
589+
///
590+
/// Inverse hyperbolic sine
591+
///
592+
/// # Returns
593+
///
594+
/// - on success, the inverse hyperbolic sine of `self` will be returned
595+
/// - `self` if `self` is `0.0`, `-0.0`, `infinity`, or `neg_infinity`
596+
/// - `NaN` if `self` is `NaN`
597+
///
598+
#[inline(always)]
599+
fn asinh(&self) -> float {
600+
(*self as f64).asinh() as float
601+
}
602+
603+
///
604+
/// Inverse hyperbolic cosine
605+
///
606+
/// # Returns
607+
///
608+
/// - on success, the inverse hyperbolic cosine of `self` will be returned
609+
/// - `infinity` if `self` is `infinity`
610+
/// - `NaN` if `self` is `NaN` or `self < 1.0` (including `neg_infinity`)
611+
///
612+
#[inline(always)]
613+
fn acosh(&self) -> float {
614+
(*self as f64).acosh() as float
615+
}
616+
617+
///
618+
/// Inverse hyperbolic tangent
619+
///
620+
/// # Returns
621+
///
622+
/// - on success, the inverse hyperbolic tangent of `self` will be returned
623+
/// - `self` if `self` is `0.0` or `-0.0`
624+
/// - `infinity` if `self` is `1.0`
625+
/// - `neg_infinity` if `self` is `-1.0`
626+
/// - `NaN` if the `self` is `NaN` or outside the domain of `-1.0 <= self <= 1.0`
627+
/// (including `infinity` and `neg_infinity`)
628+
///
629+
#[inline(always)]
630+
fn atanh(&self) -> float {
631+
(*self as f64).atanh() as float
632+
}
588633
}
589634
590635
impl Real for float {
@@ -972,6 +1017,43 @@ mod tests {
9721017
assert_approx_eq!((-1.7f).fract(), -0.7f);
9731018
}
9741019
1020+
#[test]
1021+
fn test_asinh() {
1022+
assert_eq!(0.0f.asinh(), 0.0f);
1023+
assert_eq!((-0.0f).asinh(), -0.0f);
1024+
assert_eq!(Float::infinity::<float>().asinh(), Float::infinity::<float>());
1025+
assert_eq!(Float::neg_infinity::<float>().asinh(), Float::neg_infinity::<float>());
1026+
assert!(Float::NaN::<float>().asinh().is_NaN());
1027+
assert_approx_eq!(2.0f.asinh(), 1.443635475178810342493276740273105f);
1028+
assert_approx_eq!((-2.0f).asinh(), -1.443635475178810342493276740273105f);
1029+
}
1030+
1031+
#[test]
1032+
fn test_acosh() {
1033+
assert_eq!(1.0f.acosh(), 0.0f);
1034+
assert!(0.999f.acosh().is_NaN());
1035+
assert_eq!(Float::infinity::<float>().acosh(), Float::infinity::<float>());
1036+
assert!(Float::neg_infinity::<float>().acosh().is_NaN());
1037+
assert!(Float::NaN::<float>().acosh().is_NaN());
1038+
assert_approx_eq!(2.0f.acosh(), 1.31695789692481670862504634730796844f);
1039+
assert_approx_eq!(3.0f.acosh(), 1.76274717403908605046521864995958461f);
1040+
}
1041+
1042+
#[test]
1043+
fn test_atanh() {
1044+
assert_eq!(0.0f.atanh(), 0.0f);
1045+
assert_eq!((-0.0f).atanh(), -0.0f);
1046+
assert_eq!(1.0f.atanh(), Float::infinity::<float>());
1047+
assert_eq!((-1.0f).atanh(), Float::neg_infinity::<float>());
1048+
assert!(2f64.atanh().atanh().is_NaN());
1049+
assert!((-2f64).atanh().atanh().is_NaN());
1050+
assert!(Float::infinity::<f64>().atanh().is_NaN());
1051+
assert!(Float::neg_infinity::<f64>().atanh().is_NaN());
1052+
assert!(Float::NaN::<float>().atanh().is_NaN());
1053+
assert_approx_eq!(0.5f.atanh(), 0.54930614433405484569762261846126285f);
1054+
assert_approx_eq!((-0.5f).atanh(), -0.54930614433405484569762261846126285f);
1055+
}
1056+
9751057
#[test]
9761058
fn test_real_consts() {
9771059
assert_approx_eq!(Real::two_pi::<float>(), 2f * Real::pi::<float>());

src/libcore/num/num.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,9 @@ pub trait Hyperbolic: Exponential {
133133
fn sinh(&self) -> Self;
134134
fn cosh(&self) -> Self;
135135
fn tanh(&self) -> Self;
136+
fn asinh(&self) -> Self;
137+
fn acosh(&self) -> Self;
138+
fn atanh(&self) -> Self;
136139
}
137140

138141
///

0 commit comments

Comments
 (0)