diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index bd4bff98db7e..38ebeac413b3 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -394,7 +394,6 @@ pub trait F64Ext: private::Sealed + Sized { fn sinh(self) -> Self; - #[cfg(todo)] fn cosh(self) -> Self; fn tanh(self) -> Self; @@ -569,7 +568,6 @@ impl F64Ext for f64 { sinh(self) } - #[cfg(todo)] #[inline] fn cosh(self) -> Self { cosh(self) diff --git a/library/compiler-builtins/libm/src/math/cosh.rs b/library/compiler-builtins/libm/src/math/cosh.rs new file mode 100644 index 000000000000..f3f7fbfbeb16 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/cosh.rs @@ -0,0 +1,33 @@ +use super::exp; +use super::expm1; +use super::k_expo2; + +#[inline] +pub fn cosh(mut x: f64) -> f64 { + /* |x| */ + let mut ix = x.to_bits(); + ix &= 0x7fffffffffffffff; + x = f64::from_bits(ix); + let w = ix >> 32; + + /* |x| < log(2) */ + if w < 0x3fe62e42 { + if w < 0x3ff00000 - (26 << 20) { + let x1p120 = f64::from_bits(0x4770000000000000); + force_eval!(x + x1p120); + return 1.; + } + let t = expm1(x); // exponential minus 1 + return 1. + t * t / (2. * (1. + t)); + } + + /* |x| < log(DBL_MAX) */ + if w < 0x40862e42 { + let t = exp(x); + /* note: if x>log(0x1p26) then the 1/t is not needed */ + return 0.5 * (t + 1. / t); + } + + /* |x| > log(DBL_MAX) or nan */ + k_expo2(x) +} diff --git a/library/compiler-builtins/libm/src/math/k_expo2.rs b/library/compiler-builtins/libm/src/math/k_expo2.rs new file mode 100644 index 000000000000..e295c7a53462 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/k_expo2.rs @@ -0,0 +1,14 @@ +use super::exp; + +/* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ +const K: i32 = 2043; + +/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ +#[inline] +pub(crate) fn k_expo2(x: f64) -> f64 { + let k_ln2 = f64::from_bits(0x40962066151add8b); + /* note that k is odd and scale*scale overflows */ + let scale = f64::from_bits(((((0x3ff + K / 2) as u32) << 20) as u64) << 32); + /* exp(x - k ln2) * 2**(k-1) */ + exp(x - k_ln2) * scale * scale +} diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 7fa4252077d7..352e1d37b6c5 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -19,6 +19,7 @@ mod ceil; mod ceilf; mod cos; mod cosf; +mod cosh; mod coshf; mod exp; mod exp2; @@ -77,6 +78,7 @@ pub use self::ceil::ceil; pub use self::ceilf::ceilf; pub use self::cos::cos; pub use self::cosf::cosf; +pub use self::cosh::cosh; pub use self::coshf::coshf; pub use self::exp::exp; pub use self::exp2::exp2; @@ -127,6 +129,7 @@ mod expo2; mod fenv; mod k_cos; mod k_cosf; +mod k_expo2; mod k_expo2f; mod k_sin; mod k_sinf; @@ -140,6 +143,7 @@ mod rem_pio2f; use self::expo2::expo2; use self::k_cos::k_cos; use self::k_cosf::k_cosf; +use self::k_expo2::k_expo2; use self::k_expo2f::k_expo2f; use self::k_sin::k_sin; use self::k_sinf::k_sinf; diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index b36321760bd4..7c48031c174f 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -703,7 +703,7 @@ f64_f64! { cbrt, ceil, cos, - // cosh, + cosh, exp, exp2, expm1,