Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

coshf tanhf and atan2f #108

Merged
merged 4 commits into from
Jul 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ pub trait F32Ext: private::Sealed {

fn atan(self) -> Self;

#[cfg(todo)]
fn atan2(self, other: Self) -> Self;

#[cfg(todo)]
Expand All @@ -109,13 +108,10 @@ pub trait F32Ext: private::Sealed {

fn ln_1p(self) -> Self;

#[cfg(todo)]
fn sinh(self) -> Self;

#[cfg(todo)]
fn cosh(self) -> Self;

#[cfg(todo)]
fn tanh(self) -> Self;

#[cfg(todo)]
Expand Down Expand Up @@ -272,7 +268,6 @@ impl F32Ext for f32 {
atanf(self)
}

#[cfg(todo)]
#[inline]
fn atan2(self, other: Self) -> Self {
atan2f(self, other)
Expand All @@ -288,19 +283,16 @@ impl F32Ext for f32 {
log1pf(self)
}

#[cfg(todo)]
#[inline]
fn sinh(self) -> Self {
sinhf(self)
}

#[cfg(todo)]
#[inline]
fn cosh(self) -> Self {
coshf(self)
}

#[cfg(todo)]
#[inline]
fn tanh(self) -> Self {
tanhf(self)
Expand Down
71 changes: 71 additions & 0 deletions src/math/atan2f.rs
Original file line number Diff line number Diff line change
@@ -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(-,-) */
}
}
33 changes: 33 additions & 0 deletions src/math/coshf.rs
Original file line number Diff line number Diff line change
@@ -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)
}
14 changes: 14 additions & 0 deletions src/math/k_expo2f.rs
Original file line number Diff line number Diff line change
@@ -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;

/* 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
}
10 changes: 10 additions & 0 deletions src/math/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ mod acos;
mod acosf;
mod asin;
mod asinf;
mod atan2f;
mod atanf;
mod cbrt;
mod cbrtf;
mod ceil;
mod ceilf;
mod cos;
mod cosf;
mod coshf;
mod exp;
mod exp2;
mod exp2f;
Expand Down Expand Up @@ -51,10 +53,12 @@ mod scalbnf;
mod sin;
mod sinf;
mod sinh;
mod sinhf;
mod sqrt;
mod sqrtf;
mod tan;
mod tanf;
mod tanhf;
mod trunc;
mod truncf;

Expand All @@ -63,13 +67,15 @@ 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::cos::cos;
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;
Expand Down Expand Up @@ -103,17 +109,20 @@ 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;
pub use self::tanf::tanf;
pub use self::tanhf::tanhf;
pub use self::trunc::trunc;
pub use self::truncf::truncf;

// Private modules
mod expo2;
mod k_cos;
mod k_cosf;
mod k_expo2f;
mod k_sin;
mod k_sinf;
mod k_tan;
Expand All @@ -126,6 +135,7 @@ mod rem_pio2f;
use self::expo2::expo2;
use self::k_cos::k_cos;
use self::k_cosf::k_cosf;
use self::k_expo2f::k_expo2f;
use self::k_sin::k_sin;
use self::k_sinf::k_sinf;
use self::k_tan::k_tan;
Expand Down
30 changes: 30 additions & 0 deletions src/math/sinhf.rs
Original file line number Diff line number Diff line change
@@ -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)
}
39 changes: 39 additions & 0 deletions src/math/tanhf.rs
Original file line number Diff line number Diff line change
@@ -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
}
}
8 changes: 4 additions & 4 deletions test-generator/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,7 @@ f32_f32! {
cbrtf,
cosf,
ceilf,
// coshf,
coshf,
exp2f,
expf,
expm1f,
Expand All @@ -669,16 +669,16 @@ f32_f32! {
logf,
roundf,
sinf,
// sinhf,
sinhf,
tanf,
// tanhf,
tanhf,
fabsf,
sqrtf,
}

// With signature `fn(f32, f32) -> f32`
f32f32_f32! {
// atan2f,
atan2f,
fdimf,
hypotf,
fmodf,
Expand Down