auto merge of #6301 : bjz/rust/numeric-traits, r=pcwalton
This is part of the redesign of the numeric traits tracked in issue #4819. Renamed: - `Exponential::expm1` -> `Float::exp_m1` - for consistency with underscore usage elsewhere - `Exponential::log` -> `Exponential::ln` - a less ambiguous name for the natural logarithm - `{float, f64, f32}::logarithm` -> `Exponential::log` - for arbitrary base logarithms - `Real::log_2` -> `Real::ln_2` - for consistency with `ln` - `Real::log_10` -> `Real::ln_10` - for consistency with `ln` Added: - `Signed::abs_sub` - wraps libm's `fdim` function - `Float::is_normal` - returns `true` if the number is neither zero, infinite, subnormal or NaN - `Float::classify` - returns the floating point category of the number - `Float::ln_1p` - returns the natural logarithm of the number plus one
This commit is contained in:
commit
847552f48b
7 changed files with 422 additions and 76 deletions
|
@ -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;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
//! Operations and constants for `f32`
|
||||
|
||||
use num::{Zero, One, strconv};
|
||||
use num::{FPCategory, FPNaN, FPInfinite , FPZero, FPSubnormal, FPNormal};
|
||||
use prelude::*;
|
||||
|
||||
pub use cmath::c_float_targ_consts::*;
|
||||
|
@ -82,7 +83,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 +93,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,
|
||||
|
@ -195,11 +196,6 @@ pub mod consts {
|
|||
pub static ln_10: f32 = 2.30258509299404568401799145468436421_f32;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn logarithm(n: f32, b: f32) -> f32 {
|
||||
return log2(n) / log2(b);
|
||||
}
|
||||
|
||||
impl Num for f32 {}
|
||||
|
||||
#[cfg(notest)]
|
||||
|
@ -317,6 +313,13 @@ impl Signed for f32 {
|
|||
#[inline(always)]
|
||||
fn abs(&self) -> f32 { abs(*self) }
|
||||
|
||||
///
|
||||
/// The positive difference of two numbers. Returns `0.0` if the number is less than or
|
||||
/// equal to `other`, otherwise the difference between`self` and `other` is returned.
|
||||
///
|
||||
#[inline(always)]
|
||||
fn abs_sub(&self, other: &f32) -> f32 { abs_sub(*self, *other) }
|
||||
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
|
@ -413,21 +416,27 @@ 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) }
|
||||
|
||||
/// Returns the natural logarithm of the number
|
||||
#[inline(always)]
|
||||
fn expm1(&self) -> f32 { expm1(*self) }
|
||||
fn ln(&self) -> f32 { ln(*self) }
|
||||
|
||||
/// Returns the logarithm of the number with respect to an arbitrary base
|
||||
#[inline(always)]
|
||||
fn log(&self) -> f32 { ln(*self) }
|
||||
fn log(&self, base: f32) -> f32 { self.ln() / base.ln() }
|
||||
|
||||
/// Returns the base 2 logarithm of the number
|
||||
#[inline(always)]
|
||||
fn log2(&self) -> f32 { log2(*self) }
|
||||
|
||||
/// Returns the base 10 logarithm of the number
|
||||
#[inline(always)]
|
||||
fn log10(&self) -> f32 { log10(*self) }
|
||||
}
|
||||
|
@ -504,13 +513,13 @@ impl Real for f32 {
|
|||
#[inline(always)]
|
||||
fn log10_e() -> f32 { 0.434294481903251827651128918916605082 }
|
||||
|
||||
/// log(2.0)
|
||||
/// ln(2.0)
|
||||
#[inline(always)]
|
||||
fn log_2() -> f32 { 0.693147180559945309417232121458176568 }
|
||||
fn ln_2() -> f32 { 0.693147180559945309417232121458176568 }
|
||||
|
||||
/// log(10.0)
|
||||
/// ln(10.0)
|
||||
#[inline(always)]
|
||||
fn log_10() -> f32 { 2.30258509299404568401799145468436421 }
|
||||
fn ln_10() -> f32 { 2.30258509299404568401799145468436421 }
|
||||
|
||||
/// Converts to degrees, assuming the number is in radians
|
||||
#[inline(always)]
|
||||
|
@ -550,9 +559,49 @@ impl Float for f32 {
|
|||
#[inline(always)]
|
||||
fn neg_zero() -> f32 { -0.0 }
|
||||
|
||||
/// Returns `true` if the number is NaN
|
||||
#[inline(always)]
|
||||
fn is_NaN(&self) -> bool { *self != *self }
|
||||
|
||||
/// Returns `true` if the number is infinite
|
||||
#[inline(always)]
|
||||
fn is_infinite(&self) -> bool {
|
||||
*self == Float::infinity() || *self == Float::neg_infinity()
|
||||
}
|
||||
|
||||
/// Returns `true` if the number is neither infinite or NaN
|
||||
#[inline(always)]
|
||||
fn is_finite(&self) -> bool {
|
||||
!(self.is_NaN() || self.is_infinite())
|
||||
}
|
||||
|
||||
/// Returns `true` if the number is neither zero, infinite, subnormal or NaN
|
||||
#[inline(always)]
|
||||
fn is_normal(&self) -> bool {
|
||||
match self.classify() {
|
||||
FPNormal => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the floating point category of the number. If only one property is going to
|
||||
/// be tested, it is generally faster to use the specific predicate instead.
|
||||
fn classify(&self) -> FPCategory {
|
||||
static EXP_MASK: u32 = 0x7f800000;
|
||||
static MAN_MASK: u32 = 0x007fffff;
|
||||
|
||||
match (
|
||||
unsafe { ::cast::transmute::<f32,u32>(*self) } & EXP_MASK,
|
||||
unsafe { ::cast::transmute::<f32,u32>(*self) } & MAN_MASK
|
||||
) {
|
||||
(EXP_MASK, 0) => FPInfinite,
|
||||
(EXP_MASK, _) => FPNaN,
|
||||
(exp, _) if exp != 0 => FPNormal,
|
||||
_ if self.is_zero() => FPZero,
|
||||
_ => FPSubnormal,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn mantissa_digits() -> uint { 24 }
|
||||
|
||||
|
@ -574,17 +623,19 @@ impl Float for f32 {
|
|||
#[inline(always)]
|
||||
fn max_10_exp() -> int { 38 }
|
||||
|
||||
/// Returns `true` if the number 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 is_infinite(&self) -> bool {
|
||||
*self == Float::infinity() || *self == Float::neg_infinity()
|
||||
}
|
||||
fn exp_m1(&self) -> f32 { exp_m1(*self) }
|
||||
|
||||
/// Returns `true` if the number is finite
|
||||
///
|
||||
/// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more accurately
|
||||
/// than if the operations were performed separately
|
||||
///
|
||||
#[inline(always)]
|
||||
fn is_finite(&self) -> bool {
|
||||
!(self.is_NaN() || self.is_infinite())
|
||||
}
|
||||
fn ln_1p(&self) -> f32 { ln_1p(*self) }
|
||||
|
||||
///
|
||||
/// Fused multiply-add. Computes `(self * a) + b` with only one rounding error. This
|
||||
|
@ -823,6 +874,7 @@ impl num::FromStrRadix for f32 {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use f32::*;
|
||||
use num::*;
|
||||
use super::*;
|
||||
use prelude::*;
|
||||
|
||||
|
@ -938,12 +990,12 @@ mod tests {
|
|||
assert_approx_eq!(Real::frac_1_sqrt2::<f32>(), 1f32 / 2f32.sqrt());
|
||||
assert_approx_eq!(Real::log2_e::<f32>(), Real::e::<f32>().log2());
|
||||
assert_approx_eq!(Real::log10_e::<f32>(), Real::e::<f32>().log10());
|
||||
assert_approx_eq!(Real::log_2::<f32>(), 2f32.log());
|
||||
assert_approx_eq!(Real::log_10::<f32>(), 10f32.log());
|
||||
assert_approx_eq!(Real::ln_2::<f32>(), 2f32.ln());
|
||||
assert_approx_eq!(Real::ln_10::<f32>(), 10f32.ln());
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_signed() {
|
||||
pub fn test_abs() {
|
||||
assert_eq!(infinity.abs(), infinity);
|
||||
assert_eq!(1f32.abs(), 1f32);
|
||||
assert_eq!(0f32.abs(), 0f32);
|
||||
|
@ -952,7 +1004,24 @@ mod tests {
|
|||
assert_eq!(neg_infinity.abs(), infinity);
|
||||
assert_eq!((1f32/neg_infinity).abs(), 0f32);
|
||||
assert!(NaN.abs().is_NaN());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_abs_sub() {
|
||||
assert_eq!((-1f32).abs_sub(&1f32), 0f32);
|
||||
assert_eq!(1f32.abs_sub(&1f32), 0f32);
|
||||
assert_eq!(1f32.abs_sub(&0f32), 1f32);
|
||||
assert_eq!(1f32.abs_sub(&-1f32), 2f32);
|
||||
assert_eq!(neg_infinity.abs_sub(&0f32), 0f32);
|
||||
assert_eq!(infinity.abs_sub(&1f32), infinity);
|
||||
assert_eq!(0f32.abs_sub(&neg_infinity), infinity);
|
||||
assert_eq!(0f32.abs_sub(&infinity), 0f32);
|
||||
assert!(NaN.abs_sub(&-1f32).is_NaN());
|
||||
assert!(1f32.abs_sub(&NaN).is_NaN());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_signum() {
|
||||
assert_eq!(infinity.signum(), 1f32);
|
||||
assert_eq!(1f32.signum(), 1f32);
|
||||
assert_eq!(0f32.signum(), 1f32);
|
||||
|
@ -961,7 +1030,10 @@ mod tests {
|
|||
assert_eq!(neg_infinity.signum(), -1f32);
|
||||
assert_eq!((1f32/neg_infinity).signum(), -1f32);
|
||||
assert!(NaN.signum().is_NaN());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_positive() {
|
||||
assert!(infinity.is_positive());
|
||||
assert!(1f32.is_positive());
|
||||
assert!(0f32.is_positive());
|
||||
|
@ -970,7 +1042,10 @@ mod tests {
|
|||
assert!(!neg_infinity.is_positive());
|
||||
assert!(!(1f32/neg_infinity).is_positive());
|
||||
assert!(!NaN.is_positive());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_negative() {
|
||||
assert!(!infinity.is_negative());
|
||||
assert!(!1f32.is_negative());
|
||||
assert!(!0f32.is_negative());
|
||||
|
@ -995,4 +1070,28 @@ mod tests {
|
|||
assert_eq!(Primitive::bits::<f32>(), sys::size_of::<f32>() * 8);
|
||||
assert_eq!(Primitive::bytes::<f32>(), sys::size_of::<f32>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_normal() {
|
||||
assert!(!Float::NaN::<f32>().is_normal());
|
||||
assert!(!Float::infinity::<f32>().is_normal());
|
||||
assert!(!Float::neg_infinity::<f32>().is_normal());
|
||||
assert!(!Zero::zero::<f32>().is_normal());
|
||||
assert!(!Float::neg_zero::<f32>().is_normal());
|
||||
assert!(1f32.is_normal());
|
||||
assert!(1e-37f32.is_normal());
|
||||
assert!(!1e-38f32.is_normal());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_classify() {
|
||||
assert_eq!(Float::NaN::<f32>().classify(), FPNaN);
|
||||
assert_eq!(Float::infinity::<f32>().classify(), FPInfinite);
|
||||
assert_eq!(Float::neg_infinity::<f32>().classify(), FPInfinite);
|
||||
assert_eq!(Zero::zero::<f32>().classify(), FPZero);
|
||||
assert_eq!(Float::neg_zero::<f32>().classify(), FPZero);
|
||||
assert_eq!(1f32.classify(), FPNormal);
|
||||
assert_eq!(1e-37f32.classify(), FPNormal);
|
||||
assert_eq!(1e-38f32.classify(), FPSubnormal);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
use libc::c_int;
|
||||
use num::{Zero, One, strconv};
|
||||
use num::{FPCategory, FPNaN, FPInfinite , FPZero, FPSubnormal, FPNormal};
|
||||
use prelude::*;
|
||||
|
||||
pub use cmath::c_double_targ_consts::*;
|
||||
|
@ -84,7 +85,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 +95,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,
|
||||
|
@ -218,11 +219,6 @@ pub mod consts {
|
|||
pub static ln_10: f64 = 2.30258509299404568401799145468436421_f64;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn logarithm(n: f64, b: f64) -> f64 {
|
||||
return log2(n) / log2(b);
|
||||
}
|
||||
|
||||
impl Num for f64 {}
|
||||
|
||||
#[cfg(notest)]
|
||||
|
@ -330,6 +326,13 @@ impl Signed for f64 {
|
|||
#[inline(always)]
|
||||
fn abs(&self) -> f64 { abs(*self) }
|
||||
|
||||
///
|
||||
/// The positive difference of two numbers. Returns `0.0` if the number is less than or
|
||||
/// equal to `other`, otherwise the difference between`self` and `other` is returned.
|
||||
///
|
||||
#[inline(always)]
|
||||
fn abs_sub(&self, other: &f64) -> f64 { abs_sub(*self, *other) }
|
||||
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
|
@ -426,21 +429,27 @@ 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) }
|
||||
|
||||
/// Returns the natural logarithm of the number
|
||||
#[inline(always)]
|
||||
fn expm1(&self) -> f64 { expm1(*self) }
|
||||
fn ln(&self) -> f64 { ln(*self) }
|
||||
|
||||
/// Returns the logarithm of the number with respect to an arbitrary base
|
||||
#[inline(always)]
|
||||
fn log(&self) -> f64 { ln(*self) }
|
||||
fn log(&self, base: f64) -> f64 { self.ln() / base.ln() }
|
||||
|
||||
/// Returns the base 2 logarithm of the number
|
||||
#[inline(always)]
|
||||
fn log2(&self) -> f64 { log2(*self) }
|
||||
|
||||
/// Returns the base 10 logarithm of the number
|
||||
#[inline(always)]
|
||||
fn log10(&self) -> f64 { log10(*self) }
|
||||
}
|
||||
|
@ -517,13 +526,13 @@ impl Real for f64 {
|
|||
#[inline(always)]
|
||||
fn log10_e() -> f64 { 0.434294481903251827651128918916605082 }
|
||||
|
||||
/// log(2.0)
|
||||
/// ln(2.0)
|
||||
#[inline(always)]
|
||||
fn log_2() -> f64 { 0.693147180559945309417232121458176568 }
|
||||
fn ln_2() -> f64 { 0.693147180559945309417232121458176568 }
|
||||
|
||||
/// log(10.0)
|
||||
/// ln(10.0)
|
||||
#[inline(always)]
|
||||
fn log_10() -> f64 { 2.30258509299404568401799145468436421 }
|
||||
fn ln_10() -> f64 { 2.30258509299404568401799145468436421 }
|
||||
|
||||
/// Converts to degrees, assuming the number is in radians
|
||||
#[inline(always)]
|
||||
|
@ -593,6 +602,7 @@ impl Float for f64 {
|
|||
#[inline(always)]
|
||||
fn neg_zero() -> f64 { -0.0 }
|
||||
|
||||
/// Returns `true` if the number is NaN
|
||||
#[inline(always)]
|
||||
fn is_NaN(&self) -> bool { *self != *self }
|
||||
|
||||
|
@ -602,12 +612,39 @@ impl Float for f64 {
|
|||
*self == Float::infinity() || *self == Float::neg_infinity()
|
||||
}
|
||||
|
||||
/// Returns `true` if the number is finite
|
||||
/// Returns `true` if the number is neither infinite or NaN
|
||||
#[inline(always)]
|
||||
fn is_finite(&self) -> bool {
|
||||
!(self.is_NaN() || self.is_infinite())
|
||||
}
|
||||
|
||||
/// Returns `true` if the number is neither zero, infinite, subnormal or NaN
|
||||
#[inline(always)]
|
||||
fn is_normal(&self) -> bool {
|
||||
match self.classify() {
|
||||
FPNormal => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the floating point category of the number. If only one property is going to
|
||||
/// be tested, it is generally faster to use the specific predicate instead.
|
||||
fn classify(&self) -> FPCategory {
|
||||
static EXP_MASK: u64 = 0x7ff0000000000000;
|
||||
static MAN_MASK: u64 = 0x000fffffffffffff;
|
||||
|
||||
match (
|
||||
unsafe { ::cast::transmute::<f64,u64>(*self) } & EXP_MASK,
|
||||
unsafe { ::cast::transmute::<f64,u64>(*self) } & MAN_MASK
|
||||
) {
|
||||
(EXP_MASK, 0) => FPInfinite,
|
||||
(EXP_MASK, _) => FPNaN,
|
||||
(exp, _) if exp != 0 => FPNormal,
|
||||
_ if self.is_zero() => FPZero,
|
||||
_ => FPSubnormal,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn mantissa_digits() -> uint { 53 }
|
||||
|
||||
|
@ -629,6 +666,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
|
||||
|
@ -866,6 +917,7 @@ impl num::FromStrRadix for f64 {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use f64::*;
|
||||
use num::*;
|
||||
use super::*;
|
||||
use prelude::*;
|
||||
|
||||
|
@ -985,12 +1037,12 @@ mod tests {
|
|||
assert_approx_eq!(Real::frac_1_sqrt2::<f64>(), 1f64 / 2f64.sqrt());
|
||||
assert_approx_eq!(Real::log2_e::<f64>(), Real::e::<f64>().log2());
|
||||
assert_approx_eq!(Real::log10_e::<f64>(), Real::e::<f64>().log10());
|
||||
assert_approx_eq!(Real::log_2::<f64>(), 2f64.log());
|
||||
assert_approx_eq!(Real::log_10::<f64>(), 10f64.log());
|
||||
assert_approx_eq!(Real::ln_2::<f64>(), 2f64.ln());
|
||||
assert_approx_eq!(Real::ln_10::<f64>(), 10f64.ln());
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_signed() {
|
||||
pub fn test_abs() {
|
||||
assert_eq!(infinity.abs(), infinity);
|
||||
assert_eq!(1f64.abs(), 1f64);
|
||||
assert_eq!(0f64.abs(), 0f64);
|
||||
|
@ -999,7 +1051,24 @@ mod tests {
|
|||
assert_eq!(neg_infinity.abs(), infinity);
|
||||
assert_eq!((1f64/neg_infinity).abs(), 0f64);
|
||||
assert!(NaN.abs().is_NaN());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_abs_sub() {
|
||||
assert_eq!((-1f64).abs_sub(&1f64), 0f64);
|
||||
assert_eq!(1f64.abs_sub(&1f64), 0f64);
|
||||
assert_eq!(1f64.abs_sub(&0f64), 1f64);
|
||||
assert_eq!(1f64.abs_sub(&-1f64), 2f64);
|
||||
assert_eq!(neg_infinity.abs_sub(&0f64), 0f64);
|
||||
assert_eq!(infinity.abs_sub(&1f64), infinity);
|
||||
assert_eq!(0f64.abs_sub(&neg_infinity), infinity);
|
||||
assert_eq!(0f64.abs_sub(&infinity), 0f64);
|
||||
assert!(NaN.abs_sub(&-1f64).is_NaN());
|
||||
assert!(1f64.abs_sub(&NaN).is_NaN());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_signum() {
|
||||
assert_eq!(infinity.signum(), 1f64);
|
||||
assert_eq!(1f64.signum(), 1f64);
|
||||
assert_eq!(0f64.signum(), 1f64);
|
||||
|
@ -1008,7 +1077,10 @@ mod tests {
|
|||
assert_eq!(neg_infinity.signum(), -1f64);
|
||||
assert_eq!((1f64/neg_infinity).signum(), -1f64);
|
||||
assert!(NaN.signum().is_NaN());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_positive() {
|
||||
assert!(infinity.is_positive());
|
||||
assert!(1f64.is_positive());
|
||||
assert!(0f64.is_positive());
|
||||
|
@ -1017,7 +1089,10 @@ mod tests {
|
|||
assert!(!neg_infinity.is_positive());
|
||||
assert!(!(1f64/neg_infinity).is_positive());
|
||||
assert!(!NaN.is_positive());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_negative() {
|
||||
assert!(!infinity.is_negative());
|
||||
assert!(!1f64.is_negative());
|
||||
assert!(!0f64.is_negative());
|
||||
|
@ -1042,4 +1117,27 @@ mod tests {
|
|||
assert_eq!(Primitive::bits::<f64>(), sys::size_of::<f64>() * 8);
|
||||
assert_eq!(Primitive::bytes::<f64>(), sys::size_of::<f64>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_normal() {
|
||||
assert!(!Float::NaN::<f64>().is_normal());
|
||||
assert!(!Float::infinity::<f64>().is_normal());
|
||||
assert!(!Float::neg_infinity::<f64>().is_normal());
|
||||
assert!(!Zero::zero::<f64>().is_normal());
|
||||
assert!(!Float::neg_zero::<f64>().is_normal());
|
||||
assert!(1f64.is_normal());
|
||||
assert!(1e-307f64.is_normal());
|
||||
assert!(!1e-308f64.is_normal());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_classify() {
|
||||
assert_eq!(Float::NaN::<f64>().classify(), FPNaN);
|
||||
assert_eq!(Float::infinity::<f64>().classify(), FPInfinite);
|
||||
assert_eq!(Float::neg_infinity::<f64>().classify(), FPInfinite);
|
||||
assert_eq!(Zero::zero::<f64>().classify(), FPZero);
|
||||
assert_eq!(Float::neg_zero::<f64>().classify(), FPZero);
|
||||
assert_eq!(1e-307f64.classify(), FPNormal);
|
||||
assert_eq!(1e-308f64.classify(), FPSubnormal);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,14 +22,14 @@
|
|||
|
||||
use libc::c_int;
|
||||
use num::{Zero, One, strconv};
|
||||
use num::FPCategory;
|
||||
use prelude::*;
|
||||
|
||||
pub use f64::{add, sub, mul, div, rem, lt, le, eq, ne, ge, gt};
|
||||
pub use f64::logarithm;
|
||||
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};
|
||||
|
||||
|
@ -533,31 +533,37 @@ 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
|
||||
}
|
||||
|
||||
/// Returns the natural logarithm of the number
|
||||
#[inline(always)]
|
||||
fn expm1(&self) -> float {
|
||||
(*self as f64).expm1() as float
|
||||
fn ln(&self) -> float {
|
||||
(*self as f64).ln() as float
|
||||
}
|
||||
|
||||
/// Returns the logarithm of the number with respect to an arbitrary base
|
||||
#[inline(always)]
|
||||
fn log(&self) -> float {
|
||||
(*self as f64).log() as float
|
||||
fn log(&self, base: float) -> float {
|
||||
(*self as f64).log(base as f64) as float
|
||||
}
|
||||
|
||||
/// Returns the base 2 logarithm of the number
|
||||
#[inline(always)]
|
||||
fn log2(&self) -> float {
|
||||
(*self as f64).log2() as float
|
||||
}
|
||||
|
||||
/// Returns the base 10 logarithm of the number
|
||||
#[inline(always)]
|
||||
fn log10(&self) -> float {
|
||||
(*self as f64).log10() as float
|
||||
|
@ -642,13 +648,13 @@ impl Real for float {
|
|||
#[inline(always)]
|
||||
fn log10_e() -> float { 0.434294481903251827651128918916605082 }
|
||||
|
||||
/// log(2.0)
|
||||
/// ln(2.0)
|
||||
#[inline(always)]
|
||||
fn log_2() -> float { 0.693147180559945309417232121458176568 }
|
||||
fn ln_2() -> float { 0.693147180559945309417232121458176568 }
|
||||
|
||||
/// log(10.0)
|
||||
/// ln(10.0)
|
||||
#[inline(always)]
|
||||
fn log_10() -> float { 2.30258509299404568401799145468436421 }
|
||||
fn ln_10() -> float { 2.30258509299404568401799145468436421 }
|
||||
|
||||
/// Converts to degrees, assuming the number is in radians
|
||||
#[inline(always)]
|
||||
|
@ -729,6 +735,15 @@ impl Signed for float {
|
|||
#[inline(always)]
|
||||
fn abs(&self) -> float { abs(*self) }
|
||||
|
||||
///
|
||||
/// The positive difference of two numbers. Returns `0.0` if the number is less than or
|
||||
/// equal to `other`, otherwise the difference between`self` and `other` is returned.
|
||||
///
|
||||
#[inline(always)]
|
||||
fn abs_sub(&self, other: &float) -> float {
|
||||
(*self as f64).abs_sub(&(*other as f64)) as float
|
||||
}
|
||||
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
|
@ -768,19 +783,37 @@ impl Primitive for float {
|
|||
|
||||
impl Float for float {
|
||||
#[inline(always)]
|
||||
fn NaN() -> float { 0.0 / 0.0 }
|
||||
fn NaN() -> float { Float::NaN::<f64>() as float }
|
||||
|
||||
#[inline(always)]
|
||||
fn infinity() -> float { 1.0 / 0.0 }
|
||||
fn infinity() -> float { Float::infinity::<f64>() as float }
|
||||
|
||||
#[inline(always)]
|
||||
fn neg_infinity() -> float { -1.0 / 0.0 }
|
||||
fn neg_infinity() -> float { Float::neg_infinity::<f64>() as float }
|
||||
|
||||
#[inline(always)]
|
||||
fn neg_zero() -> float { -0.0 }
|
||||
fn neg_zero() -> float { Float::neg_zero::<f64>() as float }
|
||||
|
||||
/// Returns `true` if the number is NaN
|
||||
#[inline(always)]
|
||||
fn is_NaN(&self) -> bool { *self != *self }
|
||||
fn is_NaN(&self) -> bool { (*self as f64).is_NaN() }
|
||||
|
||||
/// Returns `true` if the number is infinite
|
||||
#[inline(always)]
|
||||
fn is_infinite(&self) -> bool { (*self as f64).is_infinite() }
|
||||
|
||||
/// Returns `true` if the number is neither infinite or NaN
|
||||
#[inline(always)]
|
||||
fn is_finite(&self) -> bool { (*self as f64).is_finite() }
|
||||
|
||||
/// Returns `true` if the number is neither zero, infinite, subnormal or NaN
|
||||
#[inline(always)]
|
||||
fn is_normal(&self) -> bool { (*self as f64).is_normal() }
|
||||
|
||||
/// Returns the floating point category of the number. If only one property is going to
|
||||
/// be tested, it is generally faster to use the specific predicate instead.
|
||||
#[inline(always)]
|
||||
fn classify(&self) -> FPCategory { (*self as f64).classify() }
|
||||
|
||||
#[inline(always)]
|
||||
fn mantissa_digits() -> uint { Float::mantissa_digits::<f64>() }
|
||||
|
@ -803,17 +836,21 @@ impl Float for float {
|
|||
#[inline(always)]
|
||||
fn max_10_exp() -> int { Float::max_10_exp::<f64>() }
|
||||
|
||||
/// Returns `true` if the number 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 is_infinite(&self) -> bool {
|
||||
*self == Float::infinity() || *self == Float::neg_infinity()
|
||||
fn exp_m1(&self) -> float {
|
||||
(*self as f64).exp_m1() as float
|
||||
}
|
||||
|
||||
/// Returns `true` if the number is finite
|
||||
///
|
||||
/// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more accurately
|
||||
/// than if the operations were performed separately
|
||||
///
|
||||
#[inline(always)]
|
||||
fn is_finite(&self) -> bool {
|
||||
!(self.is_NaN() || self.is_infinite())
|
||||
}
|
||||
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
|
||||
|
@ -834,6 +871,7 @@ impl Float for float {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use num::*;
|
||||
use super::*;
|
||||
use prelude::*;
|
||||
|
||||
|
@ -949,12 +987,12 @@ mod tests {
|
|||
assert_approx_eq!(Real::frac_1_sqrt2::<float>(), 1f / 2f.sqrt());
|
||||
assert_approx_eq!(Real::log2_e::<float>(), Real::e::<float>().log2());
|
||||
assert_approx_eq!(Real::log10_e::<float>(), Real::e::<float>().log10());
|
||||
assert_approx_eq!(Real::log_2::<float>(), 2f.log());
|
||||
assert_approx_eq!(Real::log_10::<float>(), 10f.log());
|
||||
assert_approx_eq!(Real::ln_2::<float>(), 2f.ln());
|
||||
assert_approx_eq!(Real::ln_10::<float>(), 10f.ln());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_signed() {
|
||||
fn test_abs() {
|
||||
assert_eq!(infinity.abs(), infinity);
|
||||
assert_eq!(1f.abs(), 1f);
|
||||
assert_eq!(0f.abs(), 0f);
|
||||
|
@ -963,7 +1001,24 @@ mod tests {
|
|||
assert_eq!(neg_infinity.abs(), infinity);
|
||||
assert_eq!((1f/neg_infinity).abs(), 0f);
|
||||
assert!(NaN.abs().is_NaN());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_abs_sub() {
|
||||
assert_eq!((-1f).abs_sub(&1f), 0f);
|
||||
assert_eq!(1f.abs_sub(&1f), 0f);
|
||||
assert_eq!(1f.abs_sub(&0f), 1f);
|
||||
assert_eq!(1f.abs_sub(&-1f), 2f);
|
||||
assert_eq!(neg_infinity.abs_sub(&0f), 0f);
|
||||
assert_eq!(infinity.abs_sub(&1f), infinity);
|
||||
assert_eq!(0f.abs_sub(&neg_infinity), infinity);
|
||||
assert_eq!(0f.abs_sub(&infinity), 0f);
|
||||
assert!(NaN.abs_sub(&-1f).is_NaN());
|
||||
assert!(1f.abs_sub(&NaN).is_NaN());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_signum() {
|
||||
assert_eq!(infinity.signum(), 1f);
|
||||
assert_eq!(1f.signum(), 1f);
|
||||
assert_eq!(0f.signum(), 1f);
|
||||
|
@ -972,7 +1027,10 @@ mod tests {
|
|||
assert_eq!(neg_infinity.signum(), -1f);
|
||||
assert_eq!((1f/neg_infinity).signum(), -1f);
|
||||
assert!(NaN.signum().is_NaN());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_positive() {
|
||||
assert!(infinity.is_positive());
|
||||
assert!(1f.is_positive());
|
||||
assert!(0f.is_positive());
|
||||
|
@ -981,7 +1039,10 @@ mod tests {
|
|||
assert!(!neg_infinity.is_positive());
|
||||
assert!(!(1f/neg_infinity).is_positive());
|
||||
assert!(!NaN.is_positive());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_negative() {
|
||||
assert!(!infinity.is_negative());
|
||||
assert!(!1f.is_negative());
|
||||
assert!(!0f.is_negative());
|
||||
|
@ -1007,6 +1068,30 @@ mod tests {
|
|||
assert_eq!(Primitive::bytes::<float>(), sys::size_of::<float>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_normal() {
|
||||
assert!(!Float::NaN::<float>().is_normal());
|
||||
assert!(!Float::infinity::<float>().is_normal());
|
||||
assert!(!Float::neg_infinity::<float>().is_normal());
|
||||
assert!(!Zero::zero::<float>().is_normal());
|
||||
assert!(!Float::neg_zero::<float>().is_normal());
|
||||
assert!(1f.is_normal());
|
||||
assert!(1e-307f.is_normal());
|
||||
assert!(!1e-308f.is_normal());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_classify() {
|
||||
assert_eq!(Float::NaN::<float>().classify(), FPNaN);
|
||||
assert_eq!(Float::infinity::<float>().classify(), FPInfinite);
|
||||
assert_eq!(Float::neg_infinity::<float>().classify(), FPInfinite);
|
||||
assert_eq!(Zero::zero::<float>().classify(), FPZero);
|
||||
assert_eq!(Float::neg_zero::<float>().classify(), FPZero);
|
||||
assert_eq!(1f.classify(), FPNormal);
|
||||
assert_eq!(1e-307f.classify(), FPNormal);
|
||||
assert_eq!(1e-308f.classify(), FPSubnormal);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_to_str_exact_do_decimal() {
|
||||
let s = to_str_exact(5.0, 4u);
|
||||
|
|
|
@ -264,6 +264,15 @@ impl Signed for T {
|
|||
if self.is_negative() { -*self } else { *self }
|
||||
}
|
||||
|
||||
///
|
||||
/// The positive difference of two numbers. Returns `0` if the number is less than or
|
||||
/// equal to `other`, otherwise the difference between`self` and `other` is returned.
|
||||
///
|
||||
#[inline(always)]
|
||||
fn abs_sub(&self, other: &T) -> T {
|
||||
if *self <= *other { 0 } else { *self - *other }
|
||||
}
|
||||
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
|
@ -554,21 +563,38 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_signed() {
|
||||
pub fn test_abs() {
|
||||
assert_eq!((1 as T).abs(), 1 as T);
|
||||
assert_eq!((0 as T).abs(), 0 as T);
|
||||
assert_eq!((-1 as T).abs(), 1 as T);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_abs_sub() {
|
||||
assert_eq!((-1 as T).abs_sub(&(1 as T)), 0 as T);
|
||||
assert_eq!((1 as T).abs_sub(&(1 as T)), 0 as T);
|
||||
assert_eq!((1 as T).abs_sub(&(0 as T)), 1 as T);
|
||||
assert_eq!((1 as T).abs_sub(&(-1 as T)), 2 as T);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_signum() {
|
||||
assert_eq!((1 as T).signum(), 1 as T);
|
||||
assert_eq!((0 as T).signum(), 0 as T);
|
||||
assert_eq!((-0 as T).signum(), 0 as T);
|
||||
assert_eq!((-1 as T).signum(), -1 as T);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_positive() {
|
||||
assert!((1 as T).is_positive());
|
||||
assert!(!(0 as T).is_positive());
|
||||
assert!(!(-0 as T).is_positive());
|
||||
assert!(!(-1 as T).is_positive());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_negative() {
|
||||
assert!(!(1 as T).is_negative());
|
||||
assert!(!(0 as T).is_negative());
|
||||
assert!(!(-0 as T).is_negative());
|
||||
|
|
|
@ -55,7 +55,9 @@ pub trait One {
|
|||
pub trait Signed: Num
|
||||
+ Neg<Self> {
|
||||
fn abs(&self) -> Self;
|
||||
fn abs_sub(&self, other: &Self) -> Self;
|
||||
fn signum(&self) -> Self;
|
||||
|
||||
fn is_positive(&self) -> bool;
|
||||
fn is_negative(&self) -> bool;
|
||||
}
|
||||
|
@ -121,8 +123,8 @@ pub trait Trigonometric {
|
|||
pub trait Exponential {
|
||||
fn exp(&self) -> Self;
|
||||
fn exp2(&self) -> Self;
|
||||
fn expm1(&self) -> Self;
|
||||
fn log(&self) -> Self;
|
||||
fn ln(&self) -> Self;
|
||||
fn log(&self, base: Self) -> Self;
|
||||
fn log2(&self) -> Self;
|
||||
fn log10(&self) -> Self;
|
||||
}
|
||||
|
@ -158,8 +160,8 @@ pub trait Real: Signed
|
|||
fn e() -> Self;
|
||||
fn log2_e() -> Self;
|
||||
fn log10_e() -> Self;
|
||||
fn log_2() -> Self;
|
||||
fn log_10() -> Self;
|
||||
fn ln_2() -> Self;
|
||||
fn ln_10() -> Self;
|
||||
|
||||
// Angular conversions
|
||||
fn to_degrees(&self) -> Self;
|
||||
|
@ -235,6 +237,23 @@ pub trait Int: Integer
|
|||
+ Bitwise
|
||||
+ BitCount {}
|
||||
|
||||
///
|
||||
/// Used for representing the classification of floating point numbers
|
||||
///
|
||||
#[deriving(Eq)]
|
||||
pub enum FPCategory {
|
||||
/// "Not a Number", often obtained by dividing by zero
|
||||
FPNaN,
|
||||
/// Positive or negative infinity
|
||||
FPInfinite ,
|
||||
/// Positive or negative zero
|
||||
FPZero,
|
||||
/// De-normalized floating point representation (less precise than `FPNormal`)
|
||||
FPSubnormal,
|
||||
/// A regular floating point number
|
||||
FPNormal,
|
||||
}
|
||||
|
||||
///
|
||||
/// Primitive floating point numbers
|
||||
///
|
||||
|
@ -251,6 +270,8 @@ pub trait Float: Real
|
|||
fn is_NaN(&self) -> bool;
|
||||
fn is_infinite(&self) -> bool;
|
||||
fn is_finite(&self) -> bool;
|
||||
fn is_normal(&self) -> bool;
|
||||
fn classify(&self) -> FPCategory;
|
||||
|
||||
fn mantissa_digits() -> uint;
|
||||
fn digits() -> uint;
|
||||
|
@ -260,6 +281,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;
|
||||
}
|
||||
|
|
|
@ -831,6 +831,11 @@ impl Signed for BigInt {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn abs_sub(&self, other: &BigInt) -> BigInt {
|
||||
if *self <= *other { Zero::zero() } else { *self - *other }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn signum(&self) -> BigInt {
|
||||
match self.sign {
|
||||
|
@ -1920,6 +1925,15 @@ mod bigint_tests {
|
|||
check(11, 5, 55);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_abs_sub() {
|
||||
assert_eq!((-One::one::<BigInt>()).abs_sub(&One::one()), Zero::zero());
|
||||
assert_eq!(One::one::<BigInt>().abs_sub(&One::one()), Zero::zero());
|
||||
assert_eq!(One::one::<BigInt>().abs_sub(&Zero::zero()), One::one());
|
||||
assert_eq!(One::one::<BigInt>().abs_sub(&-One::one::<BigInt>()),
|
||||
IntConvertible::from_int(2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_str_radix() {
|
||||
fn check(n: int, ans: &str) {
|
||||
|
|
Loading…
Reference in a new issue