提交 06c5e7f3 编写于 作者: B Brendan Zabarauskas

Implement exp_m1 and ln_1p as methods for Float

Both expm1 and ln1p have been renamed to exp_m1 and ln_1p in order to be consistent with the underscore usage elsewhere.

The exp_m1 method is used for increased accuracy when doing floating point calculations, so this has been moved from the more general 'Exponential' trait into 'Float'.
上级 9b09dce3
......@@ -33,7 +33,8 @@ pub mod c_double_utils {
unsafe fn erf(n: c_double) -> c_double;
unsafe fn erfc(n: c_double) -> c_double;
unsafe fn exp(n: c_double) -> c_double;
unsafe fn expm1(n: c_double) -> c_double;
// rename: for consistency with underscore usage elsewhere
#[link_name="expm1"] unsafe fn exp_m1(n: c_double) -> c_double;
unsafe fn exp2(n: c_double) -> c_double;
#[link_name="fabs"] unsafe fn abs(n: c_double) -> c_double;
// rename: for clarity and consistency with add/sub/mul/div
......@@ -63,7 +64,7 @@ pub mod c_double_utils {
// renamed: "logb" /often/ is confused for log2 by beginners
#[link_name="logb"] unsafe fn log_radix(n: c_double) -> c_double;
// renamed: to be consitent with log as ln
#[link_name="log1p"] unsafe fn ln1p(n: c_double) -> c_double;
#[link_name="log1p"] unsafe fn ln_1p(n: c_double) -> c_double;
unsafe fn log10(n: c_double) -> c_double;
unsafe fn log2(n: c_double) -> c_double;
#[link_name="ilogb"] unsafe fn ilog_radix(n: c_double) -> c_int;
......@@ -117,7 +118,7 @@ pub mod c_float_utils {
#[link_name="erff"] unsafe fn erf(n: c_float) -> c_float;
#[link_name="erfcf"] unsafe fn erfc(n: c_float) -> c_float;
#[link_name="expf"] unsafe fn exp(n: c_float) -> c_float;
#[link_name="expm1f"]unsafe fn expm1(n: c_float) -> c_float;
#[link_name="expm1f"]unsafe fn exp_m1(n: c_float) -> c_float;
#[link_name="exp2f"] unsafe fn exp2(n: c_float) -> c_float;
#[link_name="fabsf"] unsafe fn abs(n: c_float) -> c_float;
#[link_name="fdimf"]
......@@ -148,7 +149,7 @@ pub mod c_float_utils {
#[link_name="logf"] unsafe fn ln(n: c_float) -> c_float;
#[link_name="logbf"] unsafe fn log_radix(n: c_float) -> c_float;
#[link_name="log1pf"] unsafe fn ln1p(n: c_float) -> c_float;
#[link_name="log1pf"] unsafe fn ln_1p(n: c_float) -> c_float;
#[link_name="log2f"] unsafe fn log2(n: c_float) -> c_float;
#[link_name="log10f"] unsafe fn log10(n: c_float) -> c_float;
#[link_name="ilogbf"] unsafe fn ilog_radix(n: c_float) -> c_int;
......
......@@ -82,7 +82,7 @@ fn copysign(x: c_float, y: c_float) -> c_float = c_float_utils::copysign,
fn cosh(n: c_float) -> c_float = c_float_utils::cosh,
fn erf(n: c_float) -> c_float = c_float_utils::erf,
fn erfc(n: c_float) -> c_float = c_float_utils::erfc,
fn expm1(n: c_float) -> c_float = c_float_utils::expm1,
fn exp_m1(n: c_float) -> c_float = c_float_utils::exp_m1,
fn abs_sub(a: c_float, b: c_float) -> c_float = c_float_utils::abs_sub,
fn fmax(a: c_float, b: c_float) -> c_float = c_float_utils::fmax,
fn fmin(a: c_float, b: c_float) -> c_float = c_float_utils::fmin,
......@@ -92,7 +92,7 @@ fn hypot(x: c_float, y: c_float) -> c_float = c_float_utils::hypot,
fn ldexp(x: c_float, n: c_int) -> c_float = c_float_utils::ldexp,
fn lgamma(n: c_float, sign: &mut c_int) -> c_float = c_float_utils::lgamma,
fn log_radix(n: c_float) -> c_float = c_float_utils::log_radix,
fn ln1p(n: c_float) -> c_float = c_float_utils::ln1p,
fn ln_1p(n: c_float) -> c_float = c_float_utils::ln_1p,
fn ilog_radix(n: c_float) -> c_int = c_float_utils::ilog_radix,
fn modf(n: c_float, iptr: &mut c_float) -> c_float = c_float_utils::modf,
fn round(n: c_float) -> c_float = c_float_utils::round,
......@@ -408,15 +408,14 @@ fn atan2(&self, other: f32) -> f32 { atan2(*self, other) }
}
impl Exponential for f32 {
/// Returns the exponential of the number
#[inline(always)]
fn exp(&self) -> f32 { exp(*self) }
/// Returns 2 raised to the power of the number
#[inline(always)]
fn exp2(&self) -> f32 { exp2(*self) }
#[inline(always)]
fn expm1(&self) -> f32 { expm1(*self) }
/// Returns the natural logarithm of the number
#[inline(always)]
fn ln(&self) -> f32 { ln(*self) }
......@@ -588,6 +587,20 @@ fn is_finite(&self) -> bool {
!(self.is_NaN() || self.is_infinite())
}
///
/// Returns the exponential of the number, minus `1`, in a way that is accurate
/// even if the number is close to zero
///
#[inline(always)]
fn exp_m1(&self) -> f32 { exp_m1(*self) }
///
/// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more accurately
/// than if the operations were performed separately
///
#[inline(always)]
fn ln_1p(&self) -> f32 { ln_1p(*self) }
///
/// Fused multiply-add. Computes `(self * a) + b` with only one rounding error. This
/// produces a more accurate result with better performance than a separate multiplication
......
......@@ -84,7 +84,7 @@ fn copysign(x: c_double, y: c_double) -> c_double = c_double_utils::copysign,
fn cosh(n: c_double) -> c_double = c_double_utils::cosh,
fn erf(n: c_double) -> c_double = c_double_utils::erf,
fn erfc(n: c_double) -> c_double = c_double_utils::erfc,
fn expm1(n: c_double) -> c_double = c_double_utils::expm1,
fn exp_m1(n: c_double) -> c_double = c_double_utils::exp_m1,
fn abs_sub(a: c_double, b: c_double) -> c_double = c_double_utils::abs_sub,
fn fmax(a: c_double, b: c_double) -> c_double = c_double_utils::fmax,
fn fmin(a: c_double, b: c_double) -> c_double = c_double_utils::fmin,
......@@ -94,7 +94,7 @@ fn hypot(x: c_double, y: c_double) -> c_double = c_double_utils::hypot,
fn ldexp(x: c_double, n: c_int) -> c_double = c_double_utils::ldexp,
fn lgamma(n: c_double, sign: &mut c_int) -> c_double = c_double_utils::lgamma,
fn log_radix(n: c_double) -> c_double = c_double_utils::log_radix,
fn ln1p(n: c_double) -> c_double = c_double_utils::ln1p,
fn ln_1p(n: c_double) -> c_double = c_double_utils::ln_1p,
fn ilog_radix(n: c_double) -> c_int = c_double_utils::ilog_radix,
fn modf(n: c_double, iptr: &mut c_double) -> c_double = c_double_utils::modf,
fn round(n: c_double) -> c_double = c_double_utils::round,
......@@ -421,15 +421,14 @@ fn atan2(&self, other: f64) -> f64 { atan2(*self, other) }
}
impl Exponential for f64 {
/// Returns the exponential of the number
#[inline(always)]
fn exp(&self) -> f64 { exp(*self) }
/// Returns 2 raised to the power of the number
#[inline(always)]
fn exp2(&self) -> f64 { exp2(*self) }
#[inline(always)]
fn expm1(&self) -> f64 { expm1(*self) }
/// Returns the natural logarithm of the number
#[inline(always)]
fn ln(&self) -> f64 { ln(*self) }
......@@ -631,6 +630,20 @@ fn min_10_exp() -> int { -307 }
#[inline(always)]
fn max_10_exp() -> int { 308 }
///
/// Returns the exponential of the number, minus `1`, in a way that is accurate
/// even if the number is close to zero
///
#[inline(always)]
fn exp_m1(&self) -> f64 { exp_m1(*self) }
///
/// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more accurately
/// than if the operations were performed separately
///
#[inline(always)]
fn ln_1p(&self) -> f64 { ln_1p(*self) }
///
/// Fused multiply-add. Computes `(self * a) + b` with only one rounding error. This
/// produces a more accurate result with better performance than a separate multiplication
......
......@@ -26,9 +26,9 @@
pub use f64::{add, sub, mul, div, rem, lt, le, eq, ne, ge, gt};
pub use f64::{acos, asin, atan2, cbrt, ceil, copysign, cosh, floor};
pub use f64::{erf, erfc, exp, expm1, exp2, abs_sub};
pub use f64::{erf, erfc, exp, exp_m1, exp2, abs_sub};
pub use f64::{mul_add, fmax, fmin, next_after, frexp, hypot, ldexp};
pub use f64::{lgamma, ln, log_radix, ln1p, log10, log2, ilog_radix};
pub use f64::{lgamma, ln, log_radix, ln_1p, log10, log2, ilog_radix};
pub use f64::{modf, pow, powi, round, sinh, tanh, tgamma, trunc};
pub use f64::{j0, j1, jn, y0, y1, yn};
......@@ -532,21 +532,18 @@ fn atan2(&self, other: float) -> float {
}
impl Exponential for float {
/// Returns the exponential of the number
#[inline(always)]
fn exp(&self) -> float {
(*self as f64).exp() as float
}
/// Returns 2 raised to the power of the number
#[inline(always)]
fn exp2(&self) -> float {
(*self as f64).exp2() as float
}
#[inline(always)]
fn expm1(&self) -> float {
(*self as f64).expm1() as float
}
/// Returns the natural logarithm of the number
#[inline(always)]
fn ln(&self) -> float {
......@@ -823,6 +820,24 @@ fn is_finite(&self) -> bool {
!(self.is_NaN() || self.is_infinite())
}
///
/// Returns the exponential of the number, minus `1`, in a way that is accurate
/// even if the number is close to zero
///
#[inline(always)]
fn exp_m1(&self) -> float {
(*self as f64).exp_m1() as float
}
///
/// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more accurately
/// than if the operations were performed separately
///
#[inline(always)]
fn ln_1p(&self) -> float {
(*self as f64).ln_1p() as float
}
///
/// Fused multiply-add. Computes `(self * a) + b` with only one rounding error. This
/// produces a more accurate result with better performance than a separate multiplication
......
......@@ -121,7 +121,6 @@ pub trait Trigonometric {
pub trait Exponential {
fn exp(&self) -> Self;
fn exp2(&self) -> Self;
fn expm1(&self) -> Self;
fn ln(&self) -> Self;
fn log(&self, base: Self) -> Self;
fn log2(&self) -> Self;
......@@ -261,6 +260,8 @@ pub trait Float: Real
fn min_10_exp() -> int;
fn max_10_exp() -> int;
fn exp_m1(&self) -> Self;
fn ln_1p(&self) -> Self;
fn mul_add(&self, a: Self, b: Self) -> Self;
fn next_after(&self, other: Self) -> Self;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册