coshf tanhf and atan2f

This commit is contained in:
Andrey Zgarbul 2018-07-15 02:06:20 +03:00
parent 802f6a2b46
commit b61b0046c0
7 changed files with 169 additions and 11 deletions

View file

@ -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)

View file

@ -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(-,-) */
}
}

View file

@ -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)
}

View file

@ -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
}

View file

@ -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]

View file

@ -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
}
}

View file

@ -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,