41: Various improvements to FloatCore r=vks a=cuviper

- New macros simplify forwarding method implementations.
  - `Float` and `Real` use this to compact their implementations.
  - `FloatCore` now forwards `std` implementations when possible.
- `FloatCore` now requires `NumCast`, like `Float does.
- New additions to `FloatCore`:
  - Constants like `min_value()` -> `f64::MIN`
  - Rounding methods `floor`, `ceil`, `round`, `trunc`, `fract`
  - `integer_decode` matching `Float`'s
- Fix NAN sign handling in `FloatCore` (rust-num/num#312, rust-lang/rust#42425)
- Fix overflow in `FloatCore::powi` exponent negation.
- Add doctests to all `FloatCore` methods.
This commit is contained in:
bors[bot] 2018-03-01 20:57:29 +00:00
commit 5f906234bc
6 changed files with 848 additions and 485 deletions

View File

@ -1,4 +1,3 @@
use core::f64;
use core::mem::size_of; use core::mem::size_of;
use core::num::Wrapping; use core::num::Wrapping;

File diff suppressed because it is too large Load Diff

View File

@ -42,6 +42,9 @@ pub use cast::{AsPrimitive, FromPrimitive, ToPrimitive, NumCast, cast};
pub use int::PrimInt; pub use int::PrimInt;
pub use pow::{Pow, pow, checked_pow}; pub use pow::{Pow, pow, checked_pow};
#[macro_use]
mod macros;
pub mod identities; pub mod identities;
pub mod sign; pub mod sign;
pub mod ops; pub mod ops;

37
src/macros.rs Normal file
View File

@ -0,0 +1,37 @@
// not all are used in all features configurations
#![allow(unused)]
/// Forward a method to an inherent method or a base trait method.
macro_rules! forward {
($( Self :: $method:ident ( self $( , $arg:ident : $ty:ty )* ) -> $ret:ty ; )*)
=> {$(
#[inline]
fn $method(self $( , $arg : $ty )* ) -> $ret {
Self::$method(self $( , $arg )* )
}
)*};
($( $base:ident :: $method:ident ( self $( , $arg:ident : $ty:ty )* ) -> $ret:ty ; )*)
=> {$(
#[inline]
fn $method(self $( , $arg : $ty )* ) -> $ret {
<Self as $base>::$method(self $( , $arg )* )
}
)*};
($( $base:ident :: $method:ident ( $( $arg:ident : $ty:ty ),* ) -> $ret:ty ; )*)
=> {$(
#[inline]
fn $method( $( $arg : $ty ),* ) -> $ret {
<Self as $base>::$method( $( $arg ),* )
}
)*}
}
macro_rules! constant {
($( $method:ident () -> $ret:expr ; )*)
=> {$(
#[inline]
fn $method() -> Self {
$ret
}
)*};
}

View File

@ -782,145 +782,55 @@ pub trait Real
} }
impl<T: Float> Real for T { impl<T: Float> Real for T {
fn min_value() -> Self { forward! {
Self::min_value() Float::min_value() -> Self;
Float::min_positive_value() -> Self;
Float::epsilon() -> Self;
Float::max_value() -> Self;
} }
fn min_positive_value() -> Self { forward! {
Self::min_positive_value() Float::floor(self) -> Self;
} Float::ceil(self) -> Self;
fn epsilon() -> Self { Float::round(self) -> Self;
Self::epsilon() Float::trunc(self) -> Self;
} Float::fract(self) -> Self;
fn max_value() -> Self { Float::abs(self) -> Self;
Self::max_value() Float::signum(self) -> Self;
} Float::is_sign_positive(self) -> bool;
fn floor(self) -> Self { Float::is_sign_negative(self) -> bool;
self.floor() Float::mul_add(self, a: Self, b: Self) -> Self;
} Float::recip(self) -> Self;
fn ceil(self) -> Self { Float::powi(self, n: i32) -> Self;
self.ceil() Float::powf(self, n: Self) -> Self;
} Float::sqrt(self) -> Self;
fn round(self) -> Self { Float::exp(self) -> Self;
self.round() Float::exp2(self) -> Self;
} Float::ln(self) -> Self;
fn trunc(self) -> Self { Float::log(self, base: Self) -> Self;
self.trunc() Float::log2(self) -> Self;
} Float::log10(self) -> Self;
fn fract(self) -> Self { Float::to_degrees(self) -> Self;
self.fract() Float::to_radians(self) -> Self;
} Float::max(self, other: Self) -> Self;
fn abs(self) -> Self { Float::min(self, other: Self) -> Self;
self.abs() Float::abs_sub(self, other: Self) -> Self;
} Float::cbrt(self) -> Self;
fn signum(self) -> Self { Float::hypot(self, other: Self) -> Self;
self.signum() Float::sin(self) -> Self;
} Float::cos(self) -> Self;
fn is_sign_positive(self) -> bool { Float::tan(self) -> Self;
self.is_sign_positive() Float::asin(self) -> Self;
} Float::acos(self) -> Self;
fn is_sign_negative(self) -> bool { Float::atan(self) -> Self;
self.is_sign_negative() Float::atan2(self, other: Self) -> Self;
} Float::sin_cos(self) -> (Self, Self);
fn mul_add(self, a: Self, b: Self) -> Self { Float::exp_m1(self) -> Self;
self.mul_add(a, b) Float::ln_1p(self) -> Self;
} Float::sinh(self) -> Self;
fn recip(self) -> Self { Float::cosh(self) -> Self;
self.recip() Float::tanh(self) -> Self;
} Float::asinh(self) -> Self;
fn powi(self, n: i32) -> Self { Float::acosh(self) -> Self;
self.powi(n) Float::atanh(self) -> Self;
}
fn powf(self, n: Self) -> Self {
self.powf(n)
}
fn sqrt(self) -> Self {
self.sqrt()
}
fn exp(self) -> Self {
self.exp()
}
fn exp2(self) -> Self {
self.exp2()
}
fn ln(self) -> Self {
self.ln()
}
fn log(self, base: Self) -> Self {
self.log(base)
}
fn log2(self) -> Self {
self.log2()
}
fn log10(self) -> Self {
self.log10()
}
fn to_degrees(self) -> Self {
self.to_degrees()
}
fn to_radians(self) -> Self {
self.to_radians()
}
fn max(self, other: Self) -> Self {
self.max(other)
}
fn min(self, other: Self) -> Self {
self.min(other)
}
fn abs_sub(self, other: Self) -> Self {
self.abs_sub(other)
}
fn cbrt(self) -> Self {
self.cbrt()
}
fn hypot(self, other: Self) -> Self {
self.hypot(other)
}
fn sin(self) -> Self {
self.sin()
}
fn cos(self) -> Self {
self.cos()
}
fn tan(self) -> Self {
self.tan()
}
fn asin(self) -> Self {
self.asin()
}
fn acos(self) -> Self {
self.acos()
}
fn atan(self) -> Self {
self.atan()
}
fn atan2(self, other: Self) -> Self {
self.atan2(other)
}
fn sin_cos(self) -> (Self, Self) {
self.sin_cos()
}
fn exp_m1(self) -> Self {
self.exp_m1()
}
fn ln_1p(self) -> Self {
self.ln_1p()
}
fn sinh(self) -> Self {
self.sinh()
}
fn cosh(self) -> Self {
self.cosh()
}
fn tanh(self) -> Self {
self.tanh()
}
fn asinh(self) -> Self {
self.asinh()
}
fn acosh(self) -> Self {
self.acosh()
}
fn atanh(self) -> Self {
self.atanh()
} }
} }

View File

@ -1,9 +1,7 @@
use core::ops::Neg; use core::ops::Neg;
use core::{f32, f64};
use core::num::Wrapping; use core::num::Wrapping;
use Num; use Num;
#[cfg(not(feature = "std"))]
use float::FloatCore; use float::FloatCore;
/// Useful functions for signed numbers (i.e. numbers that can be negative). /// Useful functions for signed numbers (i.e. numbers that can be negative).
@ -101,12 +99,12 @@ impl<T: Signed> Signed for Wrapping<T> where Wrapping<T>: Num + Neg<Output=Wrapp
} }
macro_rules! signed_float_impl { macro_rules! signed_float_impl {
($t:ty, $nan:expr, $inf:expr, $neg_inf:expr) => { ($t:ty) => {
impl Signed for $t { impl Signed for $t {
/// Computes the absolute value. Returns `NAN` if the number is `NAN`. /// Computes the absolute value. Returns `NAN` if the number is `NAN`.
#[inline] #[inline]
fn abs(&self) -> $t { fn abs(&self) -> $t {
(*self).abs() FloatCore::abs(*self)
} }
/// The positive difference of two numbers. Returns `0.0` if the number is /// The positive difference of two numbers. Returns `0.0` if the number is
@ -124,23 +122,22 @@ macro_rules! signed_float_impl {
/// - `NAN` if the number is NaN /// - `NAN` if the number is NaN
#[inline] #[inline]
fn signum(&self) -> $t { fn signum(&self) -> $t {
use float::FloatCore;
FloatCore::signum(*self) FloatCore::signum(*self)
} }
/// Returns `true` if the number is positive, including `+0.0` and `INFINITY` /// Returns `true` if the number is positive, including `+0.0` and `INFINITY`
#[inline] #[inline]
fn is_positive(&self) -> bool { *self > 0.0 || (1.0 / *self) == $inf } fn is_positive(&self) -> bool { FloatCore::is_sign_positive(*self) }
/// Returns `true` if the number is negative, including `-0.0` and `NEG_INFINITY` /// Returns `true` if the number is negative, including `-0.0` and `NEG_INFINITY`
#[inline] #[inline]
fn is_negative(&self) -> bool { *self < 0.0 || (1.0 / *self) == $neg_inf } fn is_negative(&self) -> bool { FloatCore::is_sign_negative(*self) }
} }
} }
} }
signed_float_impl!(f32, f32::NAN, f32::INFINITY, f32::NEG_INFINITY); signed_float_impl!(f32);
signed_float_impl!(f64, f64::NAN, f64::INFINITY, f64::NEG_INFINITY); signed_float_impl!(f64);
/// Computes the absolute value. /// Computes the absolute value.
/// ///