From 06c5e7f383405094ab95229da7854aa61bb9df7f Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Tue, 7 May 2013 04:47:46 +1000 Subject: [PATCH] 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'. --- src/libcore/num/cmath.rs | 9 +++++---- src/libcore/num/f32.rs | 23 ++++++++++++++++++----- src/libcore/num/f64.rs | 23 ++++++++++++++++++----- src/libcore/num/float.rs | 29 ++++++++++++++++++++++------- src/libcore/num/num.rs | 3 ++- 5 files changed, 65 insertions(+), 22 deletions(-) diff --git a/src/libcore/num/cmath.rs b/src/libcore/num/cmath.rs index 8a0a88235d20..a80703fafa3d 100644 --- a/src/libcore/num/cmath.rs +++ b/src/libcore/num/cmath.rs @@ -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; diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 8a0b6567898e..58dc6f4f45b5 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -82,7 +82,7 @@ delegate!( 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 @@ delegate!( 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 @@ impl Trigonometric for f32 { } 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 @@ impl Float for f32 { !(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 diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 6d2fd3d1b81b..41fc9cca66e5 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -84,7 +84,7 @@ delegate!( 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 @@ delegate!( 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 @@ impl Trigonometric for f64 { } 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 @@ impl Float for f64 { #[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 diff --git a/src/libcore/num/float.rs b/src/libcore/num/float.rs index 18c512b485fb..512d3afc2b62 100644 --- a/src/libcore/num/float.rs +++ b/src/libcore/num/float.rs @@ -26,9 +26,9 @@ use prelude::*; 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 @@ impl Trigonometric for 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 @@ impl Float for float { !(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 diff --git a/src/libcore/num/num.rs b/src/libcore/num/num.rs index 7fcd16c199a7..2496ba497dcc 100644 --- a/src/libcore/num/num.rs +++ b/src/libcore/num/num.rs @@ -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; }