From b61b0046c0dbc98cca990131adee22cfc599c4ec Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sun, 15 Jul 2018 02:06:20 +0300 Subject: [PATCH 1/2] coshf tanhf and atan2f --- library/compiler-builtins/libm/src/lib.rs | 6 -- .../compiler-builtins/libm/src/math/atan2f.rs | 71 +++++++++++++++++++ .../compiler-builtins/libm/src/math/coshf.rs | 33 +++++++++ .../libm/src/math/k_expo2f.rs | 14 ++++ .../compiler-builtins/libm/src/math/mod.rs | 11 ++- .../compiler-builtins/libm/src/math/tanhf.rs | 39 ++++++++++ .../libm/test-generator/src/main.rs | 6 +- 7 files changed, 169 insertions(+), 11 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/atan2f.rs create mode 100644 library/compiler-builtins/libm/src/math/coshf.rs create mode 100644 library/compiler-builtins/libm/src/math/k_expo2f.rs create mode 100644 library/compiler-builtins/libm/src/math/tanhf.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index df7ee813fbaf..969e7c45b5e4 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -96,7 +96,6 @@ pub trait F32Ext: private::Sealed { fn atan(self) -> Self; - #[cfg(todo)] fn atan2(self, other: Self) -> Self; #[cfg(todo)] @@ -112,10 +111,8 @@ pub trait F32Ext: private::Sealed { #[cfg(todo)] fn sinh(self) -> Self; - #[cfg(todo)] fn cosh(self) -> Self; - #[cfg(todo)] fn tanh(self) -> Self; #[cfg(todo)] @@ -272,7 +269,6 @@ impl F32Ext for f32 { atanf(self) } - #[cfg(todo)] #[inline] fn atan2(self, other: Self) -> Self { atan2f(self, other) @@ -294,13 +290,11 @@ impl F32Ext for f32 { sinhf(self) } - #[cfg(todo)] #[inline] fn cosh(self) -> Self { coshf(self) } - #[cfg(todo)] #[inline] fn tanh(self) -> Self { tanhf(self) diff --git a/library/compiler-builtins/libm/src/math/atan2f.rs b/library/compiler-builtins/libm/src/math/atan2f.rs new file mode 100644 index 000000000000..a232ffdd61dc --- /dev/null +++ b/library/compiler-builtins/libm/src/math/atan2f.rs @@ -0,0 +1,71 @@ +use super::atanf; +use super::fabsf; + +const PI: f32 = 3.1415927410e+00; /* 0x40490fdb */ +const PI_LO: f32 = -8.7422776573e-08; /* 0xb3bbbd2e */ + +#[inline] +pub fn atan2f(y: f32, x: f32) -> f32 { + if x.is_nan() || y.is_nan() { + return x + y; + } + let mut ix = x.to_bits(); + let mut iy = y.to_bits(); + + if ix == 0x3f800000 { + /* x=1.0 */ + return atanf(y); + } + let m = ((iy >> 31) & 1) | ((ix >> 30) & 2); /* 2*sign(x)+sign(y) */ + ix &= 0x7fffffff; + iy &= 0x7fffffff; + + /* when y = 0 */ + if iy == 0 { + return match m { + 0 | 1 => y, /* atan(+-0,+anything)=+-0 */ + 2 => PI, /* atan(+0,-anything) = pi */ + 3 | _ => -PI, /* atan(-0,-anything) =-pi */ + }; + } + /* when x = 0 */ + if ix == 0 { + return if m & 1 != 0 { -PI / 2. } else { PI / 2. }; + } + /* when x is INF */ + if ix == 0x7f800000 { + return if iy == 0x7f800000 { + match m { + 0 => PI / 4., /* atan(+INF,+INF) */ + 1 => -PI / 4., /* atan(-INF,+INF) */ + 2 => 3. * PI / 4., /* atan(+INF,-INF)*/ + 3 | _ => -3. * PI / 4., /* atan(-INF,-INF)*/ + } + } else { + match m { + 0 => 0., /* atan(+...,+INF) */ + 1 => -0., /* atan(-...,+INF) */ + 2 => PI, /* atan(+...,-INF) */ + 3 | _ => -PI, /* atan(-...,-INF) */ + } + }; + } + /* |y/x| > 0x1p26 */ + if (ix + (26 << 23) < iy) || (iy == 0x7f800000) { + return if m & 1 != 0 { -PI / 2. } else { PI / 2. }; + } + + /* z = atan(|y/x|) with correct underflow */ + let z = if (m & 2 != 0) && (iy + (26 << 23) < ix) { + /*|y/x| < 0x1p-26, x < 0 */ + 0. + } else { + atanf(fabsf(y / x)) + }; + match m { + 0 => z, /* atan(+,+) */ + 1 => -z, /* atan(-,+) */ + 2 => PI - (z - PI_LO), /* atan(+,-) */ + _ => (z - PI_LO) - PI, /* case 3 */ /* atan(-,-) */ + } +} diff --git a/library/compiler-builtins/libm/src/math/coshf.rs b/library/compiler-builtins/libm/src/math/coshf.rs new file mode 100644 index 000000000000..bd468f5da712 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/coshf.rs @@ -0,0 +1,33 @@ +use super::expf; +use super::expm1f; +use super::k_expo2f; + +#[inline] +pub fn coshf(mut x: f32) -> f32 { + let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120 + + /* |x| */ + let mut ix = x.to_bits(); + ix &= 0x7fffffff; + x = f32::from_bits(ix); + let w = ix; + + /* |x| < log(2) */ + if w < 0x3f317217 { + if w < (0x3f800000 - (12 << 23)) { + force_eval!(x + x1p120); + return 1.; + } + let t = expm1f(x); + return 1. + t * t / (2. * (1. + t)); + } + + /* |x| < log(FLT_MAX) */ + if w < 0x42b17217 { + let t = expf(x); + return 0.5 * (t + 1. / t); + } + + /* |x| > log(FLT_MAX) or nan */ + k_expo2f(x) +} diff --git a/library/compiler-builtins/libm/src/math/k_expo2f.rs b/library/compiler-builtins/libm/src/math/k_expo2f.rs new file mode 100644 index 000000000000..031a0bdd0365 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/k_expo2f.rs @@ -0,0 +1,14 @@ +use super::expf; + +/* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ +const K: i32 = 235; +const K_LN2: f32 = 162.89; /* 0x1.45c778p+7f */ + +/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ +#[inline] +pub(crate) fn k_expo2f(x: f32) -> f32 { + /* note that k is odd and scale*scale overflows */ + let scale = f32::from_bits(((0x7f + K / 2) as u32) << 23); + /* exp(x - k ln2) * 2**(k-1) */ + expf(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 42c596857d7e..1ac5472576b2 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -10,12 +10,14 @@ mod acos; mod acosf; mod asin; mod asinf; +mod atan2f; mod atanf; mod cbrt; mod cbrtf; mod ceil; mod ceilf; mod cosf; +mod coshf; mod exp; mod exp2; mod exp2f; @@ -50,6 +52,7 @@ mod sinf; mod sqrt; mod sqrtf; mod tanf; +mod tanhf; mod trunc; mod truncf; @@ -58,12 +61,14 @@ pub use self::acos::acos; pub use self::acosf::acosf; pub use self::asin::asin; pub use self::asinf::asinf; +pub use self::atan2f::atan2f; pub use self::atanf::atanf; pub use self::cbrt::cbrt; pub use self::cbrtf::cbrtf; pub use self::ceil::ceil; pub use self::ceilf::ceilf; pub use self::cosf::cosf; +pub use self::coshf::coshf; pub use self::exp::exp; pub use self::exp2::exp2; pub use self::exp2f::exp2f; @@ -98,18 +103,20 @@ pub use self::sinf::sinf; pub use self::sqrt::sqrt; pub use self::sqrtf::sqrtf; pub use self::tanf::tanf; +pub use self::tanhf::tanhf; pub use self::trunc::trunc; pub use self::truncf::truncf; mod k_cosf; +mod k_expo2f; mod k_sinf; mod k_tanf; mod rem_pio2_large; mod rem_pio2f; use self::{ - k_cosf::k_cosf, k_sinf::k_sinf, k_tanf::k_tanf, rem_pio2_large::rem_pio2_large, - rem_pio2f::rem_pio2f, + k_cosf::k_cosf, k_expo2f::k_expo2f, k_sinf::k_sinf, k_tanf::k_tanf, + rem_pio2_large::rem_pio2_large, rem_pio2f::rem_pio2f, }; #[inline] diff --git a/library/compiler-builtins/libm/src/math/tanhf.rs b/library/compiler-builtins/libm/src/math/tanhf.rs new file mode 100644 index 000000000000..98a1b60c29be --- /dev/null +++ b/library/compiler-builtins/libm/src/math/tanhf.rs @@ -0,0 +1,39 @@ +use super::expm1f; + +#[inline] +pub fn tanhf(mut x: f32) -> f32 { + /* x = |x| */ + let mut ix = x.to_bits(); + let sign = (ix >> 31) != 0; + ix &= 0x7fffffff; + x = f32::from_bits(ix); + let w = ix; + + let tt = if w > 0x3f0c9f54 { + /* |x| > log(3)/2 ~= 0.5493 or nan */ + if w > 0x41200000 { + /* |x| > 10 */ + 1. + 0. / x + } else { + let t = expm1f(2. * x); + 1. - 2. / (t + 2.) + } + } else if w > 0x3e82c578 { + /* |x| > log(5/3)/2 ~= 0.2554 */ + let t = expm1f(2. * x); + t / (t + 2.) + } else if w >= 0x00800000 { + /* |x| >= 0x1p-126 */ + let t = expm1f(-2. * x); + -t / (t + 2.) + } else { + /* |x| is subnormal */ + force_eval!(x * x); + x + }; + if sign { + -tt + } else { + tt + } +} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index b639cf11b19a..1c261b2ebafe 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -659,7 +659,7 @@ f32_f32! { cbrtf, cosf, ceilf, - // coshf, + coshf, exp2f, expf, expm1f, @@ -671,14 +671,14 @@ f32_f32! { sinf, // sinhf, tanf, - // tanhf, + tanhf, fabsf, sqrtf, } // With signature `fn(f32, f32) -> f32` f32f32_f32! { - // atan2f, + atan2f, fdimf, hypotf, fmodf, From f8e937fa466f721925073225a1a2177eee8b8e81 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sun, 15 Jul 2018 07:01:26 +0300 Subject: [PATCH 2/2] sinf, fix constant in k_expo2f --- library/compiler-builtins/libm/src/lib.rs | 2 -- .../libm/src/math/k_expo2f.rs | 4 +-- .../compiler-builtins/libm/src/math/mod.rs | 2 ++ .../compiler-builtins/libm/src/math/sinhf.rs | 30 +++++++++++++++++++ .../libm/test-generator/src/main.rs | 2 +- 5 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/sinhf.rs diff --git a/library/compiler-builtins/libm/src/lib.rs b/library/compiler-builtins/libm/src/lib.rs index 1ed07873421e..45213a25f7ab 100644 --- a/library/compiler-builtins/libm/src/lib.rs +++ b/library/compiler-builtins/libm/src/lib.rs @@ -108,7 +108,6 @@ pub trait F32Ext: private::Sealed { fn ln_1p(self) -> Self; - #[cfg(todo)] fn sinh(self) -> Self; fn cosh(self) -> Self; @@ -284,7 +283,6 @@ impl F32Ext for f32 { log1pf(self) } - #[cfg(todo)] #[inline] fn sinh(self) -> Self { sinhf(self) diff --git a/library/compiler-builtins/libm/src/math/k_expo2f.rs b/library/compiler-builtins/libm/src/math/k_expo2f.rs index 031a0bdd0365..e2eaa4e6bb02 100644 --- a/library/compiler-builtins/libm/src/math/k_expo2f.rs +++ b/library/compiler-builtins/libm/src/math/k_expo2f.rs @@ -2,13 +2,13 @@ use super::expf; /* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ const K: i32 = 235; -const K_LN2: f32 = 162.89; /* 0x1.45c778p+7f */ /* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ #[inline] pub(crate) fn k_expo2f(x: f32) -> f32 { + let k_ln2 = f32::from_bits(0x4322e3bc); /* note that k is odd and scale*scale overflows */ let scale = f32::from_bits(((0x7f + K / 2) as u32) << 23); /* exp(x - k ln2) * 2**(k-1) */ - expf(x - K_LN2) * scale * scale + expf(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 a29f2fb0ab43..eda6b5b72931 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -53,6 +53,7 @@ mod scalbnf; mod sin; mod sinf; mod sinh; +mod sinhf; mod sqrt; mod sqrtf; mod tan; @@ -108,6 +109,7 @@ pub use self::scalbnf::scalbnf; pub use self::sin::sin; pub use self::sinf::sinf; pub use self::sinh::sinh; +pub use self::sinhf::sinhf; pub use self::sqrt::sqrt; pub use self::sqrtf::sqrtf; pub use self::tan::tan; diff --git a/library/compiler-builtins/libm/src/math/sinhf.rs b/library/compiler-builtins/libm/src/math/sinhf.rs new file mode 100644 index 000000000000..90c4b9312819 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/sinhf.rs @@ -0,0 +1,30 @@ +use super::expm1f; +use super::k_expo2f; + +#[inline] +pub fn sinhf(x: f32) -> f32 { + let mut h = 0.5f32; + let mut ix = x.to_bits(); + if (ix >> 31) != 0 { + h = -h; + } + /* |x| */ + ix &= 0x7fffffff; + let absx = f32::from_bits(ix); + let w = ix; + + /* |x| < log(FLT_MAX) */ + if w < 0x42b17217 { + let t = expm1f(absx); + if w < 0x3f800000 { + if w < (0x3f800000 - (12 << 23)) { + return x; + } + return h * (2. * t - t * t / (t + 1.)); + } + return h * (t + t / (t + 1.)); + } + + /* |x| > logf(FLT_MAX) or nan */ + 2. * h * k_expo2f(absx) +} diff --git a/library/compiler-builtins/libm/test-generator/src/main.rs b/library/compiler-builtins/libm/test-generator/src/main.rs index 6708891f3ed3..7caada4ef3e9 100644 --- a/library/compiler-builtins/libm/test-generator/src/main.rs +++ b/library/compiler-builtins/libm/test-generator/src/main.rs @@ -669,7 +669,7 @@ f32_f32! { logf, roundf, sinf, - // sinhf, + sinhf, tanf, tanhf, fabsf,