diff --git a/src/libcore/core.rc b/src/libcore/core.rc index 71bbaf557ce..158da9a12fc 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -104,8 +104,11 @@ pub use iter::{CopyableOrderedIter, CopyableNonstrictIter, Times}; pub use iter::{ExtendedMutableIter}; pub use num::{Num, NumCast}; -pub use num::{Signed, Unsigned, Integer}; +pub use num::{Orderable, Signed, Unsigned, Integer}; pub use num::{Round, Fractional, Real, RealExt}; +pub use num::{Bitwise, BitCount, Bounded}; +pub use num::{Primitive, Int, Float}; + pub use ptr::Ptr; pub use to_str::ToStr; pub use clone::Clone; diff --git a/src/libcore/num/cmath.rs b/src/libcore/num/cmath.rs index 378ebfa53a0..30b0c54dc2d 100644 --- a/src/libcore/num/cmath.rs +++ b/src/libcore/num/cmath.rs @@ -47,7 +47,8 @@ pub mod c_double_utils { unsafe fn fmax(a: c_double, b: c_double) -> c_double; #[link_name="fmin"] unsafe fn fmin(a: c_double, b: c_double) -> c_double; - unsafe fn nextafter(x: c_double, y: c_double) -> c_double; + #[link_name="nextafter"] + unsafe fn next_after(x: c_double, y: c_double) -> c_double; unsafe fn frexp(n: c_double, value: &mut c_int) -> c_double; unsafe fn hypot(x: c_double, y: c_double) -> c_double; unsafe fn ldexp(x: c_double, n: c_int) -> c_double; @@ -131,7 +132,7 @@ pub mod c_float_utils { #[link_name="fminf"] unsafe fn fmin(a: c_float, b: c_float) -> c_float; #[link_name="nextafterf"] - unsafe fn nextafter(x: c_float, y: c_float) -> c_float; + unsafe fn next_after(x: c_float, y: c_float) -> c_float; #[link_name="hypotf"] unsafe fn hypot(x: c_float, y: c_float) -> c_float; #[link_name="ldexpf"] diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 7d5807ba546..ada47fb597e 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -12,7 +12,7 @@ use from_str; use libc::c_int; -use num::strconv; +use num::{Zero, One, strconv}; use prelude::*; pub use cmath::c_float_targ_consts::*; @@ -88,7 +88,7 @@ delegate!( 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, - fn nextafter(x: c_float, y: c_float) -> c_float = c_float_utils::nextafter, + fn next_after(x: c_float, y: c_float) -> c_float = c_float_utils::next_after, fn frexp(n: c_float, value: &mut c_int) -> c_float = c_float_utils::frexp, 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, @@ -114,9 +114,6 @@ pub static infinity: f32 = 1.0_f32/0.0_f32; pub static neg_infinity: f32 = -1.0_f32/0.0_f32; -#[inline(always)] -pub fn is_NaN(f: f32) -> bool { f != f } - #[inline(always)] pub fn add(x: f32, y: f32) -> f32 { return x + y; } @@ -154,24 +151,6 @@ pub fn gt(x: f32, y: f32) -> bool { return x > y; } // FIXME (#1999): replace the predicates below with llvm intrinsics or // calls to the libmath macros in the rust runtime for performance. -/// Returns true if `x` is a zero number (positive or negative zero) -#[inline(always)] -pub fn is_zero(x: f32) -> bool { - return x == 0.0f32 || x == -0.0f32; -} - -/// Returns true if `x`is an infinite number -#[inline(always)] -pub fn is_infinite(x: f32) -> bool { - return x == infinity || x == neg_infinity; -} - -/// Returns true if `x`is a finite number -#[inline(always)] -pub fn is_finite(x: f32) -> bool { - return !(is_NaN(x) || is_infinite(x)); -} - // FIXME (#1999): add is_normal, is_subnormal, and fpclassify. /* Module: consts */ @@ -245,12 +224,40 @@ impl Ord for f32 { fn gt(&self, other: &f32) -> bool { (*self) > (*other) } } -impl num::Zero for f32 { +impl Orderable for f32 { + /// Returns `NaN` if either of the numbers are `NaN`. #[inline(always)] - fn zero() -> f32 { 0.0 } + fn min(&self, other: &f32) -> f32 { + if self.is_NaN() || other.is_NaN() { Float::NaN() } else { fmin(*self, *other) } + } + + /// Returns `NaN` if either of the numbers are `NaN`. + #[inline(always)] + fn max(&self, other: &f32) -> f32 { + if self.is_NaN() || other.is_NaN() { Float::NaN() } else { fmax(*self, *other) } + } + + /// Returns the number constrained within the range `mn <= self <= mx`. + /// If any of the numbers are `NaN` then `NaN` is returned. + #[inline(always)] + fn clamp(&self, mn: &f32, mx: &f32) -> f32 { + if self.is_NaN() { *self } + else if !(*self <= *mx) { *mx } + else if !(*self >= *mn) { *mn } + else { *self } + } } -impl num::One for f32 { +impl Zero for f32 { + #[inline(always)] + fn zero() -> f32 { 0.0 } + + /// Returns true if the number is equal to either `0.0` or `-0.0` + #[inline(always)] + fn is_zero(&self) -> bool { *self == 0.0 || *self == -0.0 } +} + +impl One for f32 { #[inline(always)] fn one() -> f32 { 1.0 } } @@ -306,16 +313,16 @@ impl Signed for f32 { #[inline(always)] fn abs(&self) -> f32 { abs(*self) } - /** - * # Returns - * - * - `1.0` if the number is positive, `+0.0` or `infinity` - * - `-1.0` if the number is negative, `-0.0` or `neg_infinity` - * - `NaN` if the number is `NaN` - */ + /// + /// # Returns + /// + /// - `1.0` if the number is positive, `+0.0` or `infinity` + /// - `-1.0` if the number is negative, `-0.0` or `neg_infinity` + /// - `NaN` if the number is NaN + /// #[inline(always)] fn signum(&self) -> f32 { - if is_NaN(*self) { NaN } else { copysign(1.0, *self) } + if self.is_NaN() { NaN } else { copysign(1.0, *self) } } /// Returns `true` if the number is positive, including `+0.0` and `infinity` @@ -511,17 +518,99 @@ impl Real for f32 { fn tanh(&self) -> f32 { tanh(*self) } } -/** - * Section: String Conversions - */ +impl Bounded for f32 { + #[inline(always)] + fn min_value() -> f32 { 1.17549435e-38 } -/** - * Converts a float to a string - * - * # Arguments - * - * * num - The float value - */ + #[inline(always)] + fn max_value() -> f32 { 3.40282347e+38 } +} + +impl Primitive for f32 { + #[inline(always)] + fn bits() -> uint { 32 } + + #[inline(always)] + fn bytes() -> uint { Primitive::bits::() / 8 } +} + +impl Float for f32 { + #[inline(always)] + fn NaN() -> f32 { 0.0 / 0.0 } + + #[inline(always)] + fn infinity() -> f32 { 1.0 / 0.0 } + + #[inline(always)] + fn neg_infinity() -> f32 { -1.0 / 0.0 } + + #[inline(always)] + fn neg_zero() -> f32 { -0.0 } + + #[inline(always)] + fn is_NaN(&self) -> bool { *self != *self } + + #[inline(always)] + fn mantissa_digits() -> uint { 24 } + + #[inline(always)] + fn digits() -> uint { 6 } + + #[inline(always)] + fn epsilon() -> f32 { 1.19209290e-07 } + + #[inline(always)] + fn min_exp() -> int { -125 } + + #[inline(always)] + fn max_exp() -> int { 128 } + + #[inline(always)] + fn min_10_exp() -> int { -37 } + + #[inline(always)] + fn max_10_exp() -> int { 38 } + + /// 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 finite + #[inline(always)] + fn is_finite(&self) -> bool { + !(self.is_NaN() || self.is_infinite()) + } + + /// + /// 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 + /// operation followed by an add. + /// + #[inline(always)] + fn mul_add(&self, a: f32, b: f32) -> f32 { + mul_add(*self, a, b) + } + + /// Returns the next representable floating-point value in the direction of `other` + #[inline(always)] + fn next_after(&self, other: f32) -> f32 { + next_after(*self, other) + } +} + +// +// Section: String Conversions +// + +/// +/// Converts a float to a string +/// +/// # Arguments +/// +/// * num - The float value +/// #[inline(always)] pub fn to_str(num: f32) -> ~str { let (r, _) = strconv::to_str_common( @@ -529,13 +618,13 @@ pub fn to_str(num: f32) -> ~str { r } -/** - * Converts a float to a string in hexadecimal format - * - * # Arguments - * - * * num - The float value - */ +/// +/// Converts a float to a string in hexadecimal format +/// +/// # Arguments +/// +/// * num - The float value +/// #[inline(always)] pub fn to_str_hex(num: f32) -> ~str { let (r, _) = strconv::to_str_common( @@ -543,20 +632,20 @@ pub fn to_str_hex(num: f32) -> ~str { r } -/** - * Converts a float to a string in a given radix - * - * # Arguments - * - * * num - The float value - * * radix - The base to use - * - * # Failure - * - * Fails if called on a special value like `inf`, `-inf` or `NaN` due to - * possible misinterpretation of the result at higher bases. If those values - * are expected, use `to_str_radix_special()` instead. - */ +/// +/// Converts a float to a string in a given radix +/// +/// # Arguments +/// +/// * num - The float value +/// * radix - The base to use +/// +/// # Failure +/// +/// Fails if called on a special value like `inf`, `-inf` or `NaN` due to +/// possible misinterpretation of the result at higher bases. If those values +/// are expected, use `to_str_radix_special()` instead. +/// #[inline(always)] pub fn to_str_radix(num: f32, rdx: uint) -> ~str { let (r, special) = strconv::to_str_common( @@ -566,30 +655,30 @@ pub fn to_str_radix(num: f32, rdx: uint) -> ~str { r } -/** - * Converts a float to a string in a given radix, and a flag indicating - * whether it's a special value - * - * # Arguments - * - * * num - The float value - * * radix - The base to use - */ +/// +/// Converts a float to a string in a given radix, and a flag indicating +/// whether it's a special value +/// +/// # Arguments +/// +/// * num - The float value +/// * radix - The base to use +/// #[inline(always)] pub fn to_str_radix_special(num: f32, rdx: uint) -> (~str, bool) { strconv::to_str_common(&num, rdx, true, strconv::SignNeg, strconv::DigAll) } -/** - * Converts a float to a string with exactly the number of - * provided significant digits - * - * # Arguments - * - * * num - The float value - * * digits - The number of significant digits - */ +/// +/// Converts a float to a string with exactly the number of +/// provided significant digits +/// +/// # Arguments +/// +/// * num - The float value +/// * digits - The number of significant digits +/// #[inline(always)] pub fn to_str_exact(num: f32, dig: uint) -> ~str { let (r, _) = strconv::to_str_common( @@ -597,15 +686,15 @@ pub fn to_str_exact(num: f32, dig: uint) -> ~str { r } -/** - * Converts a float to a string with a maximum number of - * significant digits - * - * # Arguments - * - * * num - The float value - * * digits - The number of significant digits - */ +/// +/// Converts a float to a string with a maximum number of +/// significant digits +/// +/// # Arguments +/// +/// * num - The float value +/// * digits - The number of significant digits +/// #[inline(always)] pub fn to_str_digits(num: f32, dig: uint) -> ~str { let (r, _) = strconv::to_str_common( @@ -625,91 +714,91 @@ impl num::ToStrRadix for f32 { } } -/** - * Convert a string in base 10 to a float. - * Accepts a optional decimal exponent. - * - * This function accepts strings such as - * - * * '3.14' - * * '+3.14', equivalent to '3.14' - * * '-3.14' - * * '2.5E10', or equivalently, '2.5e10' - * * '2.5E-10' - * * '.' (understood as 0) - * * '5.' - * * '.5', or, equivalently, '0.5' - * * '+inf', 'inf', '-inf', 'NaN' - * - * Leading and trailing whitespace represent an error. - * - * # Arguments - * - * * num - A string - * - * # Return value - * - * `none` if the string did not represent a valid number. Otherwise, - * `Some(n)` where `n` is the floating-point number represented by `num`. - */ +/// +/// Convert a string in base 10 to a float. +/// Accepts a optional decimal exponent. +/// +/// This function accepts strings such as +/// +/// * '3.14' +/// * '+3.14', equivalent to '3.14' +/// * '-3.14' +/// * '2.5E10', or equivalently, '2.5e10' +/// * '2.5E-10' +/// * '.' (understood as 0) +/// * '5.' +/// * '.5', or, equivalently, '0.5' +/// * '+inf', 'inf', '-inf', 'NaN' +/// +/// Leading and trailing whitespace represent an error. +/// +/// # Arguments +/// +/// * num - A string +/// +/// # Return value +/// +/// `none` if the string did not represent a valid number. Otherwise, +/// `Some(n)` where `n` is the floating-point number represented by `num`. +/// #[inline(always)] pub fn from_str(num: &str) -> Option { strconv::from_str_common(num, 10u, true, true, true, strconv::ExpDec, false, false) } -/** - * Convert a string in base 16 to a float. - * Accepts a optional binary exponent. - * - * This function accepts strings such as - * - * * 'a4.fe' - * * '+a4.fe', equivalent to 'a4.fe' - * * '-a4.fe' - * * '2b.aP128', or equivalently, '2b.ap128' - * * '2b.aP-128' - * * '.' (understood as 0) - * * 'c.' - * * '.c', or, equivalently, '0.c' - * * '+inf', 'inf', '-inf', 'NaN' - * - * Leading and trailing whitespace represent an error. - * - * # Arguments - * - * * num - A string - * - * # Return value - * - * `none` if the string did not represent a valid number. Otherwise, - * `Some(n)` where `n` is the floating-point number represented by `[num]`. - */ +/// +/// Convert a string in base 16 to a float. +/// Accepts a optional binary exponent. +/// +/// This function accepts strings such as +/// +/// * 'a4.fe' +/// * '+a4.fe', equivalent to 'a4.fe' +/// * '-a4.fe' +/// * '2b.aP128', or equivalently, '2b.ap128' +/// * '2b.aP-128' +/// * '.' (understood as 0) +/// * 'c.' +/// * '.c', or, equivalently, '0.c' +/// * '+inf', 'inf', '-inf', 'NaN' +/// +/// Leading and trailing whitespace represent an error. +/// +/// # Arguments +/// +/// * num - A string +/// +/// # Return value +/// +/// `none` if the string did not represent a valid number. Otherwise, +/// `Some(n)` where `n` is the floating-point number represented by `[num]`. +/// #[inline(always)] pub fn from_str_hex(num: &str) -> Option { strconv::from_str_common(num, 16u, true, true, true, strconv::ExpBin, false, false) } -/** - * Convert a string in an given base to a float. - * - * Due to possible conflicts, this function does **not** accept - * the special values `inf`, `-inf`, `+inf` and `NaN`, **nor** - * does it recognize exponents of any kind. - * - * Leading and trailing whitespace represent an error. - * - * # Arguments - * - * * num - A string - * * radix - The base to use. Must lie in the range [2 .. 36] - * - * # Return value - * - * `none` if the string did not represent a valid number. Otherwise, - * `Some(n)` where `n` is the floating-point number represented by `num`. - */ +/// +/// Convert a string in an given base to a float. +/// +/// Due to possible conflicts, this function does **not** accept +/// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor** +/// does it recognize exponents of any kind. +/// +/// Leading and trailing whitespace represent an error. +/// +/// # Arguments +/// +/// * num - A string +/// * radix - The base to use. Must lie in the range [2 .. 36] +/// +/// # Return value +/// +/// `none` if the string did not represent a valid number. Otherwise, +/// `Some(n)` where `n` is the floating-point number represented by `num`. +/// #[inline(always)] pub fn from_str_radix(num: &str, rdx: uint) -> Option { strconv::from_str_common(num, rdx, true, true, false, @@ -748,6 +837,28 @@ mod tests { num::test_num(10f32, 2f32); } + #[test] + fn test_min() { + assert_eq!(1f32.min(&2f32), 1f32); + assert_eq!(2f32.min(&1f32), 1f32); + } + + #[test] + fn test_max() { + assert_eq!(1f32.max(&2f32), 2f32); + assert_eq!(2f32.max(&1f32), 2f32); + } + + #[test] + fn test_clamp() { + assert_eq!(1f32.clamp(&2f32, &4f32), 2f32); + assert_eq!(8f32.clamp(&2f32, &4f32), 4f32); + assert_eq!(3f32.clamp(&2f32, &4f32), 3f32); + assert!(3f32.clamp(&Float::NaN::(), &4f32).is_NaN()); + assert!(3f32.clamp(&2f32, &Float::NaN::()).is_NaN()); + assert!(Float::NaN::().clamp(&2f32, &4f32).is_NaN()); + } + #[test] fn test_floor() { assert_fuzzy_eq!(1.0f32.floor(), 1.0f32); @@ -846,7 +957,7 @@ mod tests { assert_eq!((-1f32).abs(), 1f32); assert_eq!(neg_infinity.abs(), infinity); assert_eq!((1f32/neg_infinity).abs(), 0f32); - assert!(is_NaN(NaN.abs())); + assert!(NaN.abs().is_NaN()); assert_eq!(infinity.signum(), 1f32); assert_eq!(1f32.signum(), 1f32); @@ -855,7 +966,7 @@ mod tests { assert_eq!((-1f32).signum(), -1f32); assert_eq!(neg_infinity.signum(), -1f32); assert_eq!((1f32/neg_infinity).signum(), -1f32); - assert!(is_NaN(NaN.signum())); + assert!(NaN.signum().is_NaN()); assert!(infinity.is_positive()); assert!(1f32.is_positive()); @@ -875,6 +986,12 @@ mod tests { assert!((1f32/neg_infinity).is_negative()); assert!(!NaN.is_negative()); } + + #[test] + fn test_primitive() { + assert_eq!(Primitive::bits::(), sys::size_of::() * 8); + assert_eq!(Primitive::bytes::(), sys::size_of::()); + } } // diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 3b6198bfc47..07a29652e94 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -12,7 +12,7 @@ use from_str; use libc::c_int; -use num::strconv; +use num::{Zero, One, strconv}; use prelude::*; pub use cmath::c_double_targ_consts::*; @@ -89,7 +89,7 @@ delegate!( 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, - fn nextafter(x: c_double, y: c_double) -> c_double = c_double_utils::nextafter, + fn next_after(x: c_double, y: c_double) -> c_double = c_double_utils::next_after, fn frexp(n: c_double, value: &mut c_int) -> c_double = c_double_utils::frexp, 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, @@ -138,9 +138,6 @@ pub static infinity: f64 = 1.0_f64/0.0_f64; pub static neg_infinity: f64 = -1.0_f64/0.0_f64; -#[inline(always)] -pub fn is_NaN(f: f64) -> bool { f != f } - #[inline(always)] pub fn add(x: f64, y: f64) -> f64 { return x + y; } @@ -174,24 +171,6 @@ pub fn ge(x: f64, y: f64) -> bool { return x >= y; } #[inline(always)] pub fn gt(x: f64, y: f64) -> bool { return x > y; } -/// Returns true if `x` is a zero number (positive or negative zero) -#[inline(always)] -pub fn is_zero(x: f64) -> bool { - return x == 0.0f64 || x == -0.0f64; -} - -/// Returns true if `x`is an infinite number -#[inline(always)] -pub fn is_infinite(x: f64) -> bool { - return x == infinity || x == neg_infinity; -} - -/// Returns true if `x` is a finite number -#[inline(always)] -pub fn is_finite(x: f64) -> bool { - return !(is_NaN(x) || is_infinite(x)); -} - // FIXME (#1999): add is_normal, is_subnormal, and fpclassify @@ -266,12 +245,40 @@ impl Ord for f64 { fn gt(&self, other: &f64) -> bool { (*self) > (*other) } } -impl num::Zero for f64 { +impl Orderable for f64 { + /// Returns `NaN` if either of the numbers are `NaN`. #[inline(always)] - fn zero() -> f64 { 0.0 } + fn min(&self, other: &f64) -> f64 { + if self.is_NaN() || other.is_NaN() { Float::NaN() } else { fmin(*self, *other) } + } + + /// Returns `NaN` if either of the numbers are `NaN`. + #[inline(always)] + fn max(&self, other: &f64) -> f64 { + if self.is_NaN() || other.is_NaN() { Float::NaN() } else { fmax(*self, *other) } + } + + /// Returns the number constrained within the range `mn <= self <= mx`. + /// If any of the numbers are `NaN` then `NaN` is returned. + #[inline(always)] + fn clamp(&self, mn: &f64, mx: &f64) -> f64 { + if self.is_NaN() { *self } + else if !(*self <= *mx) { *mx } + else if !(*self >= *mn) { *mn } + else { *self } + } } -impl num::One for f64 { +impl Zero for f64 { + #[inline(always)] + fn zero() -> f64 { 0.0 } + + /// Returns true if the number is equal to either `0.0` or `-0.0` + #[inline(always)] + fn is_zero(&self) -> bool { *self == 0.0 || *self == -0.0 } +} + +impl One for f64 { #[inline(always)] fn one() -> f64 { 1.0 } } @@ -316,16 +323,16 @@ impl Signed for f64 { #[inline(always)] fn abs(&self) -> f64 { abs(*self) } - /** - * # Returns - * - * - `1.0` if the number is positive, `+0.0` or `infinity` - * - `-1.0` if the number is negative, `-0.0` or `neg_infinity` - * - `NaN` if the number is `NaN` - */ + /// + /// # Returns + /// + /// - `1.0` if the number is positive, `+0.0` or `infinity` + /// - `-1.0` if the number is negative, `-0.0` or `neg_infinity` + /// - `NaN` if the number is NaN + /// #[inline(always)] fn signum(&self) -> f64 { - if is_NaN(*self) { NaN } else { copysign(1.0, *self) } + if self.is_NaN() { NaN } else { copysign(1.0, *self) } } /// Returns `true` if the number is positive, including `+0.0` and `infinity` @@ -551,17 +558,99 @@ impl RealExt for f64 { fn yn(&self, n: int) -> f64 { yn(n as c_int, *self) } } -/** - * Section: String Conversions - */ +impl Bounded for f64 { + #[inline(always)] + fn min_value() -> f64 { 2.2250738585072014e-308 } -/** - * Converts a float to a string - * - * # Arguments - * - * * num - The float value - */ + #[inline(always)] + fn max_value() -> f64 { 1.7976931348623157e+308 } +} + +impl Primitive for f64 { + #[inline(always)] + fn bits() -> uint { 64 } + + #[inline(always)] + fn bytes() -> uint { Primitive::bits::() / 8 } +} + +impl Float for f64 { + #[inline(always)] + fn NaN() -> f64 { 0.0 / 0.0 } + + #[inline(always)] + fn infinity() -> f64 { 1.0 / 0.0 } + + #[inline(always)] + fn neg_infinity() -> f64 { -1.0 / 0.0 } + + #[inline(always)] + fn neg_zero() -> f64 { -0.0 } + + #[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 finite + #[inline(always)] + fn is_finite(&self) -> bool { + !(self.is_NaN() || self.is_infinite()) + } + + #[inline(always)] + fn mantissa_digits() -> uint { 53 } + + #[inline(always)] + fn digits() -> uint { 15 } + + #[inline(always)] + fn epsilon() -> f64 { 2.2204460492503131e-16 } + + #[inline(always)] + fn min_exp() -> int { -1021 } + + #[inline(always)] + fn max_exp() -> int { 1024 } + + #[inline(always)] + fn min_10_exp() -> int { -307 } + + #[inline(always)] + fn max_10_exp() -> int { 308 } + + /// + /// 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 + /// operation followed by an add. + /// + #[inline(always)] + fn mul_add(&self, a: f64, b: f64) -> f64 { + mul_add(*self, a, b) + } + + /// Returns the next representable floating-point value in the direction of `other` + #[inline(always)] + fn next_after(&self, other: f64) -> f64 { + next_after(*self, other) + } +} + +// +// Section: String Conversions +// + +/// +/// Converts a float to a string +/// +/// # Arguments +/// +/// * num - The float value +/// #[inline(always)] pub fn to_str(num: f64) -> ~str { let (r, _) = strconv::to_str_common( @@ -569,13 +658,13 @@ pub fn to_str(num: f64) -> ~str { r } -/** - * Converts a float to a string in hexadecimal format - * - * # Arguments - * - * * num - The float value - */ +/// +/// Converts a float to a string in hexadecimal format +/// +/// # Arguments +/// +/// * num - The float value +/// #[inline(always)] pub fn to_str_hex(num: f64) -> ~str { let (r, _) = strconv::to_str_common( @@ -583,20 +672,20 @@ pub fn to_str_hex(num: f64) -> ~str { r } -/** - * Converts a float to a string in a given radix - * - * # Arguments - * - * * num - The float value - * * radix - The base to use - * - * # Failure - * - * Fails if called on a special value like `inf`, `-inf` or `NaN` due to - * possible misinterpretation of the result at higher bases. If those values - * are expected, use `to_str_radix_special()` instead. - */ +/// +/// Converts a float to a string in a given radix +/// +/// # Arguments +/// +/// * num - The float value +/// * radix - The base to use +/// +/// # Failure +/// +/// Fails if called on a special value like `inf`, `-inf` or `NaN` due to +/// possible misinterpretation of the result at higher bases. If those values +/// are expected, use `to_str_radix_special()` instead. +/// #[inline(always)] pub fn to_str_radix(num: f64, rdx: uint) -> ~str { let (r, special) = strconv::to_str_common( @@ -606,30 +695,30 @@ pub fn to_str_radix(num: f64, rdx: uint) -> ~str { r } -/** - * Converts a float to a string in a given radix, and a flag indicating - * whether it's a special value - * - * # Arguments - * - * * num - The float value - * * radix - The base to use - */ +/// +/// Converts a float to a string in a given radix, and a flag indicating +/// whether it's a special value +/// +/// # Arguments +/// +/// * num - The float value +/// * radix - The base to use +/// #[inline(always)] pub fn to_str_radix_special(num: f64, rdx: uint) -> (~str, bool) { strconv::to_str_common(&num, rdx, true, strconv::SignNeg, strconv::DigAll) } -/** - * Converts a float to a string with exactly the number of - * provided significant digits - * - * # Arguments - * - * * num - The float value - * * digits - The number of significant digits - */ +/// +/// Converts a float to a string with exactly the number of +/// provided significant digits +/// +/// # Arguments +/// +/// * num - The float value +/// * digits - The number of significant digits +/// #[inline(always)] pub fn to_str_exact(num: f64, dig: uint) -> ~str { let (r, _) = strconv::to_str_common( @@ -637,15 +726,15 @@ pub fn to_str_exact(num: f64, dig: uint) -> ~str { r } -/** - * Converts a float to a string with a maximum number of - * significant digits - * - * # Arguments - * - * * num - The float value - * * digits - The number of significant digits - */ +/// +/// Converts a float to a string with a maximum number of +/// significant digits +/// +/// # Arguments +/// +/// * num - The float value +/// * digits - The number of significant digits +/// #[inline(always)] pub fn to_str_digits(num: f64, dig: uint) -> ~str { let (r, _) = strconv::to_str_common( @@ -665,91 +754,91 @@ impl num::ToStrRadix for f64 { } } -/** - * Convert a string in base 10 to a float. - * Accepts a optional decimal exponent. - * - * This function accepts strings such as - * - * * '3.14' - * * '+3.14', equivalent to '3.14' - * * '-3.14' - * * '2.5E10', or equivalently, '2.5e10' - * * '2.5E-10' - * * '.' (understood as 0) - * * '5.' - * * '.5', or, equivalently, '0.5' - * * '+inf', 'inf', '-inf', 'NaN' - * - * Leading and trailing whitespace represent an error. - * - * # Arguments - * - * * num - A string - * - * # Return value - * - * `none` if the string did not represent a valid number. Otherwise, - * `Some(n)` where `n` is the floating-point number represented by `num`. - */ +/// +/// Convert a string in base 10 to a float. +/// Accepts a optional decimal exponent. +/// +/// This function accepts strings such as +/// +/// * '3.14' +/// * '+3.14', equivalent to '3.14' +/// * '-3.14' +/// * '2.5E10', or equivalently, '2.5e10' +/// * '2.5E-10' +/// * '.' (understood as 0) +/// * '5.' +/// * '.5', or, equivalently, '0.5' +/// * '+inf', 'inf', '-inf', 'NaN' +/// +/// Leading and trailing whitespace represent an error. +/// +/// # Arguments +/// +/// * num - A string +/// +/// # Return value +/// +/// `none` if the string did not represent a valid number. Otherwise, +/// `Some(n)` where `n` is the floating-point number represented by `num`. +/// #[inline(always)] pub fn from_str(num: &str) -> Option { strconv::from_str_common(num, 10u, true, true, true, strconv::ExpDec, false, false) } -/** - * Convert a string in base 16 to a float. - * Accepts a optional binary exponent. - * - * This function accepts strings such as - * - * * 'a4.fe' - * * '+a4.fe', equivalent to 'a4.fe' - * * '-a4.fe' - * * '2b.aP128', or equivalently, '2b.ap128' - * * '2b.aP-128' - * * '.' (understood as 0) - * * 'c.' - * * '.c', or, equivalently, '0.c' - * * '+inf', 'inf', '-inf', 'NaN' - * - * Leading and trailing whitespace represent an error. - * - * # Arguments - * - * * num - A string - * - * # Return value - * - * `none` if the string did not represent a valid number. Otherwise, - * `Some(n)` where `n` is the floating-point number represented by `[num]`. - */ +/// +/// Convert a string in base 16 to a float. +/// Accepts a optional binary exponent. +/// +/// This function accepts strings such as +/// +/// * 'a4.fe' +/// * '+a4.fe', equivalent to 'a4.fe' +/// * '-a4.fe' +/// * '2b.aP128', or equivalently, '2b.ap128' +/// * '2b.aP-128' +/// * '.' (understood as 0) +/// * 'c.' +/// * '.c', or, equivalently, '0.c' +/// * '+inf', 'inf', '-inf', 'NaN' +/// +/// Leading and trailing whitespace represent an error. +/// +/// # Arguments +/// +/// * num - A string +/// +/// # Return value +/// +/// `none` if the string did not represent a valid number. Otherwise, +/// `Some(n)` where `n` is the floating-point number represented by `[num]`. +/// #[inline(always)] pub fn from_str_hex(num: &str) -> Option { strconv::from_str_common(num, 16u, true, true, true, strconv::ExpBin, false, false) } -/** - * Convert a string in an given base to a float. - * - * Due to possible conflicts, this function does **not** accept - * the special values `inf`, `-inf`, `+inf` and `NaN`, **nor** - * does it recognize exponents of any kind. - * - * Leading and trailing whitespace represent an error. - * - * # Arguments - * - * * num - A string - * * radix - The base to use. Must lie in the range [2 .. 36] - * - * # Return value - * - * `none` if the string did not represent a valid number. Otherwise, - * `Some(n)` where `n` is the floating-point number represented by `num`. - */ +/// +/// Convert a string in an given base to a float. +/// +/// Due to possible conflicts, this function does **not** accept +/// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor** +/// does it recognize exponents of any kind. +/// +/// Leading and trailing whitespace represent an error. +/// +/// # Arguments +/// +/// * num - A string +/// * radix - The base to use. Must lie in the range [2 .. 36] +/// +/// # Return value +/// +/// `none` if the string did not represent a valid number. Otherwise, +/// `Some(n)` where `n` is the floating-point number represented by `num`. +/// #[inline(always)] pub fn from_str_radix(num: &str, rdx: uint) -> Option { strconv::from_str_common(num, rdx, true, true, false, @@ -789,6 +878,32 @@ mod tests { num::test_num(10f64, 2f64); } + #[test] + fn test_min() { + assert_eq!(1f64.min(&2f64), 1f64); + assert_eq!(2f64.min(&1f64), 1f64); + assert!(1f64.min(&Float::NaN::()).is_NaN()); + assert!(Float::NaN::().min(&1f64).is_NaN()); + } + + #[test] + fn test_max() { + assert_eq!(1f64.max(&2f64), 2f64); + assert_eq!(2f64.max(&1f64), 2f64); + assert!(1f64.max(&Float::NaN::()).is_NaN()); + assert!(Float::NaN::().max(&1f64).is_NaN()); + } + + #[test] + fn test_clamp() { + assert_eq!(1f64.clamp(&2f64, &4f64), 2f64); + assert_eq!(8f64.clamp(&2f64, &4f64), 4f64); + assert_eq!(3f64.clamp(&2f64, &4f64), 3f64); + assert!(3f64.clamp(&Float::NaN::(), &4f64).is_NaN()); + assert!(3f64.clamp(&2f64, &Float::NaN::()).is_NaN()); + assert!(Float::NaN::().clamp(&2f64, &4f64).is_NaN()); + } + #[test] fn test_floor() { assert_fuzzy_eq!(1.0f64.floor(), 1.0f64); @@ -887,7 +1002,7 @@ mod tests { assert_eq!((-1f64).abs(), 1f64); assert_eq!(neg_infinity.abs(), infinity); assert_eq!((1f64/neg_infinity).abs(), 0f64); - assert!(is_NaN(NaN.abs())); + assert!(NaN.abs().is_NaN()); assert_eq!(infinity.signum(), 1f64); assert_eq!(1f64.signum(), 1f64); @@ -896,7 +1011,7 @@ mod tests { assert_eq!((-1f64).signum(), -1f64); assert_eq!(neg_infinity.signum(), -1f64); assert_eq!((1f64/neg_infinity).signum(), -1f64); - assert!(is_NaN(NaN.signum())); + assert!(NaN.signum().is_NaN()); assert!(infinity.is_positive()); assert!(1f64.is_positive()); @@ -916,6 +1031,12 @@ mod tests { assert!((1f64/neg_infinity).is_negative()); assert!(!NaN.is_negative()); } + + #[test] + fn test_primitive() { + assert_eq!(Primitive::bits::(), sys::size_of::() * 8); + assert_eq!(Primitive::bytes::(), sys::size_of::()); + } } // diff --git a/src/libcore/num/float.rs b/src/libcore/num/float.rs index 9c0412b422f..ef0adee884b 100644 --- a/src/libcore/num/float.rs +++ b/src/libcore/num/float.rs @@ -22,14 +22,14 @@ use from_str; use libc::c_int; -use num::strconv; +use num::{Zero, One, strconv}; use prelude::*; pub use f64::{add, sub, mul, quot, 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::{mul_add, fmax, fmin, nextafter, frexp, hypot, ldexp}; +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::{modf, pow, powi, round, sinh, tanh, tgamma, trunc}; pub use f64::{j0, j1, jn, y0, y1, yn}; @@ -84,17 +84,17 @@ pub mod consts { pub static ln_10: float = 2.30258509299404568401799145468436421; } -/* - * Section: String Conversions - */ +// +// Section: String Conversions +// -/** - * Converts a float to a string - * - * # Arguments - * - * * num - The float value - */ +/// +/// Converts a float to a string +/// +/// # Arguments +/// +/// * num - The float value +/// #[inline(always)] pub fn to_str(num: float) -> ~str { let (r, _) = strconv::to_str_common( @@ -102,13 +102,13 @@ pub fn to_str(num: float) -> ~str { r } -/** - * Converts a float to a string in hexadecimal format - * - * # Arguments - * - * * num - The float value - */ +/// +/// Converts a float to a string in hexadecimal format +/// +/// # Arguments +/// +/// * num - The float value +/// #[inline(always)] pub fn to_str_hex(num: float) -> ~str { let (r, _) = strconv::to_str_common( @@ -116,20 +116,20 @@ pub fn to_str_hex(num: float) -> ~str { r } -/** - * Converts a float to a string in a given radix - * - * # Arguments - * - * * num - The float value - * * radix - The base to use - * - * # Failure - * - * Fails if called on a special value like `inf`, `-inf` or `NaN` due to - * possible misinterpretation of the result at higher bases. If those values - * are expected, use `to_str_radix_special()` instead. - */ +/// +/// Converts a float to a string in a given radix +/// +/// # Arguments +/// +/// * num - The float value +/// * radix - The base to use +/// +/// # Failure +/// +/// Fails if called on a special value like `inf`, `-inf` or `NaN` due to +/// possible misinterpretation of the result at higher bases. If those values +/// are expected, use `to_str_radix_special()` instead. +/// #[inline(always)] pub fn to_str_radix(num: float, radix: uint) -> ~str { let (r, special) = strconv::to_str_common( @@ -139,30 +139,30 @@ pub fn to_str_radix(num: float, radix: uint) -> ~str { r } -/** - * Converts a float to a string in a given radix, and a flag indicating - * whether it's a special value - * - * # Arguments - * - * * num - The float value - * * radix - The base to use - */ +/// +/// Converts a float to a string in a given radix, and a flag indicating +/// whether it's a special value +/// +/// # Arguments +/// +/// * num - The float value +/// * radix - The base to use +/// #[inline(always)] pub fn to_str_radix_special(num: float, radix: uint) -> (~str, bool) { strconv::to_str_common(&num, radix, true, strconv::SignNeg, strconv::DigAll) } -/** - * Converts a float to a string with exactly the number of - * provided significant digits - * - * # Arguments - * - * * num - The float value - * * digits - The number of significant digits - */ +/// +/// Converts a float to a string with exactly the number of +/// provided significant digits +/// +/// # Arguments +/// +/// * num - The float value +/// * digits - The number of significant digits +/// #[inline(always)] pub fn to_str_exact(num: float, digits: uint) -> ~str { let (r, _) = strconv::to_str_common( @@ -170,15 +170,15 @@ pub fn to_str_exact(num: float, digits: uint) -> ~str { r } -/** - * Converts a float to a string with a maximum number of - * significant digits - * - * # Arguments - * - * * num - The float value - * * digits - The number of significant digits - */ +/// +/// Converts a float to a string with a maximum number of +/// significant digits +/// +/// # Arguments +/// +/// * num - The float value +/// * digits - The number of significant digits +/// #[inline(always)] pub fn to_str_digits(num: float, digits: uint) -> ~str { let (r, _) = strconv::to_str_common( @@ -198,91 +198,91 @@ impl num::ToStrRadix for float { } } -/** - * Convert a string in base 10 to a float. - * Accepts a optional decimal exponent. - * - * This function accepts strings such as - * - * * '3.14' - * * '+3.14', equivalent to '3.14' - * * '-3.14' - * * '2.5E10', or equivalently, '2.5e10' - * * '2.5E-10' - * * '.' (understood as 0) - * * '5.' - * * '.5', or, equivalently, '0.5' - * * '+inf', 'inf', '-inf', 'NaN' - * - * Leading and trailing whitespace represent an error. - * - * # Arguments - * - * * num - A string - * - * # Return value - * - * `none` if the string did not represent a valid number. Otherwise, - * `Some(n)` where `n` is the floating-point number represented by `num`. - */ +/// +/// Convert a string in base 10 to a float. +/// Accepts a optional decimal exponent. +/// +/// This function accepts strings such as +/// +/// * '3.14' +/// * '+3.14', equivalent to '3.14' +/// * '-3.14' +/// * '2.5E10', or equivalently, '2.5e10' +/// * '2.5E-10' +/// * '.' (understood as 0) +/// * '5.' +/// * '.5', or, equivalently, '0.5' +/// * '+inf', 'inf', '-inf', 'NaN' +/// +/// Leading and trailing whitespace represent an error. +/// +/// # Arguments +/// +/// * num - A string +/// +/// # Return value +/// +/// `none` if the string did not represent a valid number. Otherwise, +/// `Some(n)` where `n` is the floating-point number represented by `num`. +/// #[inline(always)] pub fn from_str(num: &str) -> Option { strconv::from_str_common(num, 10u, true, true, true, strconv::ExpDec, false, false) } -/** - * Convert a string in base 16 to a float. - * Accepts a optional binary exponent. - * - * This function accepts strings such as - * - * * 'a4.fe' - * * '+a4.fe', equivalent to 'a4.fe' - * * '-a4.fe' - * * '2b.aP128', or equivalently, '2b.ap128' - * * '2b.aP-128' - * * '.' (understood as 0) - * * 'c.' - * * '.c', or, equivalently, '0.c' - * * '+inf', 'inf', '-inf', 'NaN' - * - * Leading and trailing whitespace represent an error. - * - * # Arguments - * - * * num - A string - * - * # Return value - * - * `none` if the string did not represent a valid number. Otherwise, - * `Some(n)` where `n` is the floating-point number represented by `[num]`. - */ +/// +/// Convert a string in base 16 to a float. +/// Accepts a optional binary exponent. +/// +/// This function accepts strings such as +/// +/// * 'a4.fe' +/// * '+a4.fe', equivalent to 'a4.fe' +/// * '-a4.fe' +/// * '2b.aP128', or equivalently, '2b.ap128' +/// * '2b.aP-128' +/// * '.' (understood as 0) +/// * 'c.' +/// * '.c', or, equivalently, '0.c' +/// * '+inf', 'inf', '-inf', 'NaN' +/// +/// Leading and trailing whitespace represent an error. +/// +/// # Arguments +/// +/// * num - A string +/// +/// # Return value +/// +/// `none` if the string did not represent a valid number. Otherwise, +/// `Some(n)` where `n` is the floating-point number represented by `[num]`. +/// #[inline(always)] pub fn from_str_hex(num: &str) -> Option { strconv::from_str_common(num, 16u, true, true, true, strconv::ExpBin, false, false) } -/** - * Convert a string in an given base to a float. - * - * Due to possible conflicts, this function does **not** accept - * the special values `inf`, `-inf`, `+inf` and `NaN`, **nor** - * does it recognize exponents of any kind. - * - * Leading and trailing whitespace represent an error. - * - * # Arguments - * - * * num - A string - * * radix - The base to use. Must lie in the range [2 .. 36] - * - * # Return value - * - * `none` if the string did not represent a valid number. Otherwise, - * `Some(n)` where `n` is the floating-point number represented by `num`. - */ +/// +/// Convert a string in an given base to a float. +/// +/// Due to possible conflicts, this function does **not** accept +/// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor** +/// does it recognize exponents of any kind. +/// +/// Leading and trailing whitespace represent an error. +/// +/// # Arguments +/// +/// * num - A string +/// * radix - The base to use. Must lie in the range [2 .. 36] +/// +/// # Return value +/// +/// `none` if the string did not represent a valid number. Otherwise, +/// `Some(n)` where `n` is the floating-point number represented by `num`. +/// #[inline(always)] pub fn from_str_radix(num: &str, radix: uint) -> Option { strconv::from_str_common(num, radix, true, true, false, @@ -301,22 +301,22 @@ impl num::FromStrRadix for float { } } -/** - * Section: Arithmetics - */ +// +// Section: Arithmetics +// -/** - * Compute the exponentiation of an integer by another integer as a float - * - * # Arguments - * - * * x - The base - * * pow - The exponent - * - * # Return value - * - * `NaN` if both `x` and `pow` are `0u`, otherwise `x^pow` - */ +/// +/// Compute the exponentiation of an integer by another integer as a float +/// +/// # Arguments +/// +/// * x - The base +/// * pow - The exponent +/// +/// # Return value +/// +/// `NaN` if both `x` and `pow` are `0u`, otherwise `x^pow` +/// pub fn pow_with_uint(base: uint, pow: uint) -> float { if base == 0u { if pow == 0u { @@ -337,15 +337,6 @@ pub fn pow_with_uint(base: uint, pow: uint) -> float { return total; } -#[inline(always)] -pub fn is_zero(x: float) -> bool { f64::is_zero(x as f64) } -#[inline(always)] -pub fn is_infinite(x: float) -> bool { f64::is_infinite(x as f64) } -#[inline(always)] -pub fn is_finite(x: float) -> bool { f64::is_finite(x as f64) } -#[inline(always)] -pub fn is_NaN(x: float) -> bool { f64::is_NaN(x as f64) } - #[inline(always)] pub fn abs(x: float) -> float { f64::abs(x as f64) as float @@ -393,12 +384,37 @@ impl Ord for float { fn gt(&self, other: &float) -> bool { (*self) > (*other) } } -impl num::Zero for float { +impl Orderable for float { + /// Returns `NaN` if either of the numbers are `NaN`. #[inline(always)] - fn zero() -> float { 0.0 } + fn min(&self, other: &float) -> float { + (*self as f64).min(&(*other as f64)) as float + } + + /// Returns `NaN` if either of the numbers are `NaN`. + #[inline(always)] + fn max(&self, other: &float) -> float { + (*self as f64).max(&(*other as f64)) as float + } + + /// Returns the number constrained within the range `mn <= self <= mx`. + /// If any of the numbers are `NaN` then `NaN` is returned. + #[inline(always)] + fn clamp(&self, mn: &float, mx: &float) -> float { + (*self as f64).clamp(&(*mn as f64), &(*mx as f64)) as float + } } -impl num::One for float { +impl Zero for float { + #[inline(always)] + fn zero() -> float { 0.0 } + + /// Returns true if the number is equal to either `0.0` or `-0.0` + #[inline(always)] + fn is_zero(&self) -> bool { *self == 0.0 || *self == -0.0 } +} + +impl One for float { #[inline(always)] fn one() -> float { 1.0 } } @@ -666,16 +682,16 @@ impl Signed for float { #[inline(always)] fn abs(&self) -> float { abs(*self) } - /** - * # Returns - * - * - `1.0` if the number is positive, `+0.0` or `infinity` - * - `-1.0` if the number is negative, `-0.0` or `neg_infinity` - * - `NaN` if the number is NaN - */ + /// + /// # Returns + /// + /// - `1.0` if the number is positive, `+0.0` or `infinity` + /// - `-1.0` if the number is negative, `-0.0` or `neg_infinity` + /// - `NaN` if the number is NaN + /// #[inline(always)] fn signum(&self) -> float { - if is_NaN(*self) { NaN } else { f64::copysign(1.0, *self as f64) as float } + if self.is_NaN() { NaN } else { f64::copysign(1.0, *self as f64) as float } } /// Returns `true` if the number is positive, including `+0.0` and `infinity` @@ -687,6 +703,88 @@ impl Signed for float { fn is_negative(&self) -> bool { *self < 0.0 || (1.0 / *self) == neg_infinity } } +impl Bounded for float { + #[inline(always)] + fn min_value() -> float { Bounded::min_value::() as float } + + #[inline(always)] + fn max_value() -> float { Bounded::max_value::() as float } +} + +impl Primitive for float { + #[inline(always)] + fn bits() -> uint { Primitive::bits::() } + + #[inline(always)] + fn bytes() -> uint { Primitive::bytes::() } +} + +impl Float for float { + #[inline(always)] + fn NaN() -> float { 0.0 / 0.0 } + + #[inline(always)] + fn infinity() -> float { 1.0 / 0.0 } + + #[inline(always)] + fn neg_infinity() -> float { -1.0 / 0.0 } + + #[inline(always)] + fn neg_zero() -> float { -0.0 } + + #[inline(always)] + fn is_NaN(&self) -> bool { *self != *self } + + #[inline(always)] + fn mantissa_digits() -> uint { Float::mantissa_digits::() } + + #[inline(always)] + fn digits() -> uint { Float::digits::() } + + #[inline(always)] + fn epsilon() -> float { Float::epsilon::() as float } + + #[inline(always)] + fn min_exp() -> int { Float::min_exp::() } + + #[inline(always)] + fn max_exp() -> int { Float::max_exp::() } + + #[inline(always)] + fn min_10_exp() -> int { Float::min_10_exp::() } + + #[inline(always)] + fn max_10_exp() -> int { Float::max_10_exp::() } + + /// 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 finite + #[inline(always)] + fn is_finite(&self) -> bool { + !(self.is_NaN() || self.is_infinite()) + } + + /// + /// 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 + /// operation followed by an add. + /// + #[inline(always)] + fn mul_add(&self, a: float, b: float) -> float { + mul_add(*self as f64, a as f64, b as f64) as float + } + + /// Returns the next representable floating-point value in the direction of `other` + #[inline(always)] + fn next_after(&self, other: float) -> float { + next_after(*self as f64, other as f64) as float + } +} + #[cfg(test)] mod tests { use super::*; @@ -706,6 +804,28 @@ mod tests { num::test_num(10f, 2f); } + #[test] + fn test_min() { + assert_eq!(1f.min(&2f), 1f); + assert_eq!(2f.min(&1f), 1f); + } + + #[test] + fn test_max() { + assert_eq!(1f.max(&2f), 2f); + assert_eq!(2f.max(&1f), 2f); + } + + #[test] + fn test_clamp() { + assert_eq!(1f.clamp(&2f, &4f), 2f); + assert_eq!(8f.clamp(&2f, &4f), 4f); + assert_eq!(3f.clamp(&2f, &4f), 3f); + assert!(3f.clamp(&Float::NaN::(), &4f).is_NaN()); + assert!(3f.clamp(&2f, &Float::NaN::()).is_NaN()); + assert!(Float::NaN::().clamp(&2f, &4f).is_NaN()); + } + #[test] fn test_floor() { assert_fuzzy_eq!(1.0f.floor(), 1.0f); @@ -796,7 +916,7 @@ mod tests { } #[test] - pub fn test_signed() { + fn test_signed() { assert_eq!(infinity.abs(), infinity); assert_eq!(1f.abs(), 1f); assert_eq!(0f.abs(), 0f); @@ -804,7 +924,7 @@ mod tests { assert_eq!((-1f).abs(), 1f); assert_eq!(neg_infinity.abs(), infinity); assert_eq!((1f/neg_infinity).abs(), 0f); - assert!(is_NaN(NaN.abs())); + assert!(NaN.abs().is_NaN()); assert_eq!(infinity.signum(), 1f); assert_eq!(1f.signum(), 1f); @@ -813,7 +933,7 @@ mod tests { assert_eq!((-1f).signum(), -1f); assert_eq!(neg_infinity.signum(), -1f); assert_eq!((1f/neg_infinity).signum(), -1f); - assert!(is_NaN(NaN.signum())); + assert!(NaN.signum().is_NaN()); assert!(infinity.is_positive()); assert!(1f.is_positive()); @@ -834,6 +954,12 @@ mod tests { assert!(!NaN.is_negative()); } + #[test] + fn test_primitive() { + assert_eq!(Primitive::bits::(), sys::size_of::() * 8); + assert_eq!(Primitive::bytes::(), sys::size_of::()); + } + #[test] pub fn test_to_str_exact_do_decimal() { let s = to_str_exact(5.0, 4u); @@ -862,16 +988,16 @@ mod tests { assert_eq!(from_str(~"-inf"), Some(neg_infinity)); // note: NaN != NaN, hence this slightly complex test match from_str(~"NaN") { - Some(f) => assert!(is_NaN(f)), + Some(f) => assert!(f.is_NaN()), None => fail!() } // note: -0 == 0, hence these slightly more complex tests match from_str(~"-0") { - Some(v) if is_zero(v) => assert!(v.is_negative()), + Some(v) if v.is_zero() => assert!(v.is_negative()), _ => fail!() } match from_str(~"0") { - Some(v) if is_zero(v) => assert!(v.is_positive()), + Some(v) if v.is_zero() => assert!(v.is_positive()), _ => fail!() } @@ -909,16 +1035,16 @@ mod tests { assert_eq!(from_str_hex(~"-inf"), Some(neg_infinity)); // note: NaN != NaN, hence this slightly complex test match from_str_hex(~"NaN") { - Some(f) => assert!(is_NaN(f)), + Some(f) => assert!(f.is_NaN()), None => fail!() } // note: -0 == 0, hence these slightly more complex tests match from_str_hex(~"-0") { - Some(v) if is_zero(v) => assert!(v.is_negative()), + Some(v) if v.is_zero() => assert!(v.is_negative()), _ => fail!() } match from_str_hex(~"0") { - Some(v) if is_zero(v) => assert!(v.is_positive()), + Some(v) if v.is_zero() => assert!(v.is_positive()), _ => fail!() } assert_eq!(from_str_hex(~"e"), Some(14.)); diff --git a/src/libcore/num/int-template.rs b/src/libcore/num/int-template.rs index f9edf1cefc8..08df820a73d 100644 --- a/src/libcore/num/int-template.rs +++ b/src/libcore/num/int-template.rs @@ -12,7 +12,7 @@ use T = self::inst::T; use from_str::FromStr; use num::{ToStrRadix, FromStrRadix}; -use num::strconv; +use num::{Zero, One, strconv}; use prelude::*; pub use cmp::{min, max}; @@ -32,26 +32,26 @@ pub fn mul(x: T, y: T) -> T { x * y } #[inline(always)] pub fn quot(x: T, y: T) -> T { x / y } -/** - * Returns the remainder of y / x. - * - * # Examples - * ~~~ - * assert!(int::rem(5 / 2) == 1); - * ~~~ - * - * When faced with negative numbers, the result copies the sign of the - * dividend. - * - * ~~~ - * assert!(int::rem(2 / -3) == 2); - * ~~~ - * - * ~~~ - * assert!(int::rem(-2 / 3) == -2); - * ~~~ - * - */ +/// +/// Returns the remainder of y / x. +/// +/// # Examples +/// ~~~ +/// assert!(int::rem(5 / 2) == 1); +/// ~~~ +/// +/// When faced with negative numbers, the result copies the sign of the +/// dividend. +/// +/// ~~~ +/// assert!(int::rem(2 / -3) == 2); +/// ~~~ +/// +/// ~~~ +/// assert!(int::rem(-2 / 3) == -2); +/// ~~~ +/// +/// #[inline(always)] pub fn rem(x: T, y: T) -> T { x % y } @@ -68,23 +68,23 @@ pub fn ge(x: T, y: T) -> bool { x >= y } #[inline(always)] pub fn gt(x: T, y: T) -> bool { x > y } -/** - * Iterate over the range [`lo`..`hi`) - * - * # Arguments - * - * * `lo` - lower bound, inclusive - * * `hi` - higher bound, exclusive - * - * # Examples - * ~~~ - * let mut sum = 0; - * for int::range(1, 5) |i| { - * sum += i; - * } - * assert!(sum == 10); - * ~~~ - */ +/// +/// Iterate over the range [`lo`..`hi`) +/// +/// # Arguments +/// +/// * `lo` - lower bound, inclusive +/// * `hi` - higher bound, exclusive +/// +/// # Examples +/// ~~~ +/// let mut sum = 0; +/// for int::range(1, 5) |i| { +/// sum += i; +/// } +/// assert!(sum == 10); +/// ~~~ +/// #[inline(always)] /// Iterate over the range [`start`,`start`+`step`..`stop`) pub fn range_step(start: T, stop: T, step: T, it: &fn(T) -> bool) { @@ -152,12 +152,33 @@ impl Eq for T { fn ne(&self, other: &T) -> bool { return (*self) != (*other); } } -impl num::Zero for T { +impl Orderable for T { #[inline(always)] - fn zero() -> T { 0 } + fn min(&self, other: &T) -> T { + if *self < *other { *self } else { *other } + } + + #[inline(always)] + fn max(&self, other: &T) -> T { + if *self > *other { *self } else { *other } + } + + #[inline(always)] + fn clamp(&self, mn: &T, mx: &T) -> T { + if *self > *mx { *mx } else + if *self < *mn { *mn } else { *self } + } } -impl num::One for T { +impl Zero for T { + #[inline(always)] + fn zero() -> T { 0 } + + #[inline(always)] + fn is_zero(&self) -> bool { *self == 0 } +} + +impl One for T { #[inline(always)] fn one() -> T { 1 } } @@ -187,24 +208,24 @@ impl Div for T { } #[cfg(not(stage0),notest)] impl Quot for T { - /** - * Returns the integer quotient, truncated towards 0. As this behaviour reflects - * the underlying machine implementation it is more efficient than `Natural::div`. - * - * # Examples - * - * ~~~ - * assert!( 8 / 3 == 2); - * assert!( 8 / -3 == -2); - * assert!(-8 / 3 == -2); - * assert!(-8 / -3 == 2); + /// + /// Returns the integer quotient, truncated towards 0. As this behaviour reflects + /// the underlying machine implementation it is more efficient than `Natural::div`. + /// + /// # Examples + /// + /// ~~~ + /// assert!( 8 / 3 == 2); + /// assert!( 8 / -3 == -2); + /// assert!(-8 / 3 == -2); + /// assert!(-8 / -3 == 2); - * assert!( 1 / 2 == 0); - * assert!( 1 / -2 == 0); - * assert!(-1 / 2 == 0); - * assert!(-1 / -2 == 0); - * ~~~ - */ + /// assert!( 1 / 2 == 0); + /// assert!( 1 / -2 == 0); + /// assert!(-1 / 2 == 0); + /// assert!(-1 / -2 == 0); + /// ~~~ + /// #[inline(always)] fn quot(&self, other: &T) -> T { *self / *other } } @@ -216,27 +237,27 @@ impl Modulo for T { } #[cfg(not(stage0),notest)] impl Rem for T { - /** - * Returns the integer remainder after division, satisfying: - * - * ~~~ - * assert!((n / d) * d + (n % d) == n) - * ~~~ - * - * # Examples - * - * ~~~ - * assert!( 8 % 3 == 2); - * assert!( 8 % -3 == 2); - * assert!(-8 % 3 == -2); - * assert!(-8 % -3 == -2); + /// + /// Returns the integer remainder after division, satisfying: + /// + /// ~~~ + /// assert!((n / d) * d + (n % d) == n) + /// ~~~ + /// + /// # Examples + /// + /// ~~~ + /// assert!( 8 % 3 == 2); + /// assert!( 8 % -3 == 2); + /// assert!(-8 % 3 == -2); + /// assert!(-8 % -3 == -2); - * assert!( 1 % 2 == 1); - * assert!( 1 % -2 == 1); - * assert!(-1 % 2 == -1); - * assert!(-1 % -2 == -1); - * ~~~ - */ + /// assert!( 1 % 2 == 1); + /// assert!( 1 % -2 == 1); + /// assert!(-1 % 2 == -1); + /// assert!(-1 % -2 == -1); + /// ~~~ + /// #[inline(always)] fn rem(&self, other: &T) -> T { *self % *other } } @@ -254,13 +275,13 @@ impl Signed for T { if self.is_negative() { -*self } else { *self } } - /** - * # Returns - * - * - `0` if the number is zero - * - `1` if the number is positive - * - `-1` if the number is negative - */ + /// + /// # Returns + /// + /// - `0` if the number is zero + /// - `1` if the number is positive + /// - `-1` if the number is negative + /// #[inline(always)] fn signum(&self) -> T { match *self { @@ -280,23 +301,23 @@ impl Signed for T { } impl Integer for T { - /** - * Floored integer division - * - * # Examples - * - * ~~~ - * assert!(( 8).div( 3) == 2); - * assert!(( 8).div(-3) == -3); - * assert!((-8).div( 3) == -3); - * assert!((-8).div(-3) == 2); - * - * assert!(( 1).div( 2) == 0); - * assert!(( 1).div(-2) == -1); - * assert!((-1).div( 2) == -1); - * assert!((-1).div(-2) == 0); - * ~~~ - */ + /// + /// Floored integer division + /// + /// # Examples + /// + /// ~~~ + /// assert!(( 8).div( 3) == 2); + /// assert!(( 8).div(-3) == -3); + /// assert!((-8).div( 3) == -3); + /// assert!((-8).div(-3) == 2); + /// + /// assert!(( 1).div( 2) == 0); + /// assert!(( 1).div(-2) == -1); + /// assert!((-1).div( 2) == -1); + /// assert!((-1).div(-2) == 0); + /// ~~~ + /// #[inline(always)] fn div(&self, other: &T) -> T { // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, @@ -308,27 +329,27 @@ impl Integer for T { } } - /** - * Integer modulo, satisfying: - * - * ~~~ - * assert!(n.div(d) * d + n.modulo(d) == n) - * ~~~ - * - * # Examples - * - * ~~~ - * assert!(( 8).modulo( 3) == 2); - * assert!(( 8).modulo(-3) == -1); - * assert!((-8).modulo( 3) == 1); - * assert!((-8).modulo(-3) == -2); - * - * assert!(( 1).modulo( 2) == 1); - * assert!(( 1).modulo(-2) == -1); - * assert!((-1).modulo( 2) == 1); - * assert!((-1).modulo(-2) == -1); - * ~~~ - */ + /// + /// Integer modulo, satisfying: + /// + /// ~~~ + /// assert!(n.div(d) * d + n.modulo(d) == n) + /// ~~~ + /// + /// # Examples + /// + /// ~~~ + /// assert!(( 8).modulo( 3) == 2); + /// assert!(( 8).modulo(-3) == -1); + /// assert!((-8).modulo( 3) == 1); + /// assert!((-8).modulo(-3) == -2); + /// + /// assert!(( 1).modulo( 2) == 1); + /// assert!(( 1).modulo(-2) == -1); + /// assert!((-1).modulo( 2) == 1); + /// assert!((-1).modulo(-2) == -1); + /// ~~~ + /// #[inline(always)] fn modulo(&self, other: &T) -> T { // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, @@ -358,11 +379,11 @@ impl Integer for T { (*self / *other, *self % *other) } - /** - * Calculates the Greatest Common Divisor (GCD) of the number and `other` - * - * The result is always positive - */ + /// + /// Calculates the Greatest Common Divisor (GCD) of the number and `other` + /// + /// The result is always positive + /// #[inline(always)] fn gcd(&self, other: &T) -> T { // Use Euclid's algorithm @@ -375,9 +396,9 @@ impl Integer for T { n.abs() } - /** - * Calculates the Lowest Common Multiple (LCM) of the number and `other` - */ + /// + /// Calculates the Lowest Common Multiple (LCM) of the number and `other` + /// #[inline(always)] fn lcm(&self, other: &T) -> T { ((*self * *other) / self.gcd(other)).abs() // should not have to recaluculate abs @@ -396,6 +417,8 @@ impl Integer for T { fn is_odd(&self) -> bool { !self.is_even() } } +impl Bitwise for T {} + #[cfg(notest)] impl BitOr for T { #[inline(always)] @@ -432,6 +455,16 @@ impl Not for T { fn not(&self) -> T { !*self } } +impl Bounded for T { + #[inline(always)] + fn min_value() -> T { min_value } + + #[inline(always)] + fn max_value() -> T { max_value } +} + +impl Int for T {} + // String conversion functions and impl str -> num /// Parse a string as a number in base 10. @@ -520,6 +553,17 @@ mod tests { num::test_num(10 as T, 2 as T); } + #[test] + fn test_orderable() { + assert_eq!((1 as T).min(&(2 as T)), 1 as T); + assert_eq!((2 as T).min(&(1 as T)), 1 as T); + assert_eq!((1 as T).max(&(2 as T)), 2 as T); + assert_eq!((2 as T).max(&(1 as T)), 2 as T); + assert_eq!((1 as T).clamp(&(2 as T), &(4 as T)), 2 as T); + assert_eq!((8 as T).clamp(&(2 as T), &(4 as T)), 4 as T); + assert_eq!((3 as T).clamp(&(2 as T), &(4 as T)), 3 as T); + } + #[test] pub fn test_signed() { assert_eq!((1 as T).abs(), 1 as T); @@ -542,18 +586,15 @@ mod tests { assert!((-1 as T).is_negative()); } - /** - * Checks that the division rule holds for: - * - * - `n`: numerator (dividend) - * - `d`: denominator (divisor) - * - `qr`: quotient and remainder - */ + /// + /// Checks that the division rule holds for: + /// + /// - `n`: numerator (dividend) + /// - `d`: denominator (divisor) + /// - `qr`: quotient and remainder + /// #[cfg(test)] - fn test_division_rule(nd: (T,T), qr: (T,T)) { - let (n,d) = nd, - (q,r) = qr; - + fn test_division_rule((n,d): (T,T), (q,r): (T,T)) { assert_eq!(d * q + r, n); } @@ -632,7 +673,7 @@ mod tests { } #[test] - fn test_bitwise_ops() { + fn test_bitwise() { assert_eq!(0b1110 as T, (0b1100 as T).bitor(&(0b1010 as T))); assert_eq!(0b1000 as T, (0b1100 as T).bitand(&(0b1010 as T))); assert_eq!(0b0110 as T, (0b1100 as T).bitxor(&(0b1010 as T))); @@ -641,6 +682,17 @@ mod tests { assert_eq!(-(0b11 as T) - (1 as T), (0b11 as T).not()); } + #[test] + fn test_bitcount() { + assert_eq!((0b010101 as T).population_count(), 3); + } + + #[test] + fn test_primitive() { + assert_eq!(Primitive::bits::(), sys::size_of::() * 8); + assert_eq!(Primitive::bytes::(), sys::size_of::()); + } + #[test] fn test_from_str() { assert_eq!(from_str(~"0"), Some(0 as T)); diff --git a/src/libcore/num/int-template/i16.rs b/src/libcore/num/int-template/i16.rs index 34dcd508397..28263378555 100644 --- a/src/libcore/num/int-template/i16.rs +++ b/src/libcore/num/int-template/i16.rs @@ -11,6 +11,31 @@ //! Operations and constants for `i16` mod inst { + use num::{Primitive, BitCount}; + use unstable::intrinsics; + pub type T = i16; pub static bits: uint = ::u16::bits; + + impl Primitive for i16 { + #[inline(always)] + fn bits() -> uint { 16 } + + #[inline(always)] + fn bytes() -> uint { Primitive::bits::() / 8 } + } + + impl BitCount for i16 { + /// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic. + #[inline(always)] + fn population_count(&self) -> i16 { unsafe { intrinsics::ctpop16(*self) } } + + /// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic. + #[inline(always)] + fn leading_zeros(&self) -> i16 { unsafe { intrinsics::ctlz16(*self) } } + + /// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic. + #[inline(always)] + fn trailing_zeros(&self) -> i16 { unsafe { intrinsics::cttz16(*self) } } + } } diff --git a/src/libcore/num/int-template/i32.rs b/src/libcore/num/int-template/i32.rs index 91eea0e8d47..959cf8f7d77 100644 --- a/src/libcore/num/int-template/i32.rs +++ b/src/libcore/num/int-template/i32.rs @@ -11,6 +11,31 @@ //! Operations and constants for `i32` mod inst { + use num::{Primitive, BitCount}; + use unstable::intrinsics; + pub type T = i32; pub static bits: uint = ::u32::bits; + + impl Primitive for i32 { + #[inline(always)] + fn bits() -> uint { 32 } + + #[inline(always)] + fn bytes() -> uint { Primitive::bits::() / 8 } + } + + impl BitCount for i32 { + /// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic. + #[inline(always)] + fn population_count(&self) -> i32 { unsafe { intrinsics::ctpop32(*self) } } + + /// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic. + #[inline(always)] + fn leading_zeros(&self) -> i32 { unsafe { intrinsics::ctlz32(*self) } } + + /// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic. + #[inline(always)] + fn trailing_zeros(&self) -> i32 { unsafe { intrinsics::cttz32(*self) } } + } } diff --git a/src/libcore/num/int-template/i64.rs b/src/libcore/num/int-template/i64.rs index 3834a1e2a03..3b51c70be12 100644 --- a/src/libcore/num/int-template/i64.rs +++ b/src/libcore/num/int-template/i64.rs @@ -11,6 +11,31 @@ //! Operations and constants for `i64` mod inst { + use num::{Primitive, BitCount}; + use unstable::intrinsics; + pub type T = i64; pub static bits: uint = ::u64::bits; + + impl Primitive for i64 { + #[inline(always)] + fn bits() -> uint { 64 } + + #[inline(always)] + fn bytes() -> uint { Primitive::bits::() / 8 } + } + + impl BitCount for i64 { + /// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic. + #[inline(always)] + fn population_count(&self) -> i64 { unsafe { intrinsics::ctpop64(*self) } } + + /// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic. + #[inline(always)] + fn leading_zeros(&self) -> i64 { unsafe { intrinsics::ctlz64(*self) } } + + /// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic. + #[inline(always)] + fn trailing_zeros(&self) -> i64 { unsafe { intrinsics::cttz64(*self) } } + } } diff --git a/src/libcore/num/int-template/i8.rs b/src/libcore/num/int-template/i8.rs index 9486ed748d7..896fb4dbf50 100644 --- a/src/libcore/num/int-template/i8.rs +++ b/src/libcore/num/int-template/i8.rs @@ -11,6 +11,31 @@ //! Operations and constants for `i8` mod inst { + use num::{Primitive, BitCount}; + use unstable::intrinsics; + pub type T = i8; pub static bits: uint = ::u8::bits; + + impl Primitive for i8 { + #[inline(always)] + fn bits() -> uint { 8 } + + #[inline(always)] + fn bytes() -> uint { Primitive::bits::() / 8 } + } + + impl BitCount for i8 { + /// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic. + #[inline(always)] + fn population_count(&self) -> i8 { unsafe { intrinsics::ctpop8(*self) } } + + /// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic. + #[inline(always)] + fn leading_zeros(&self) -> i8 { unsafe { intrinsics::ctlz8(*self) } } + + /// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic. + #[inline(always)] + fn trailing_zeros(&self) -> i8 { unsafe { intrinsics::cttz8(*self) } } + } } diff --git a/src/libcore/num/int-template/int.rs b/src/libcore/num/int-template/int.rs index 6649b364015..7a44bfdf160 100644 --- a/src/libcore/num/int-template/int.rs +++ b/src/libcore/num/int-template/int.rs @@ -13,9 +13,56 @@ pub use self::inst::pow; mod inst { + use num::{Primitive, BitCount}; + pub type T = int; pub static bits: uint = ::uint::bits; + impl Primitive for int { + #[cfg(target_word_size = "32")] + #[inline(always)] + fn bits() -> uint { 32 } + + #[cfg(target_word_size = "64")] + #[inline(always)] + fn bits() -> uint { 64 } + + #[inline(always)] + fn bytes() -> uint { Primitive::bits::() / 8 } + } + + #[cfg(target_word_size = "32")] + #[inline(always)] + impl BitCount for int { + /// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic. + #[inline(always)] + fn population_count(&self) -> int { (*self as i32).population_count() as int } + + /// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic. + #[inline(always)] + fn leading_zeros(&self) -> int { (*self as i32).leading_zeros() as int } + + /// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic. + #[inline(always)] + fn trailing_zeros(&self) -> int { (*self as i32).trailing_zeros() as int } + } + + #[cfg(target_word_size = "64")] + #[inline(always)] + impl BitCount for int { + /// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic. + #[inline(always)] + fn population_count(&self) -> int { (*self as i64).population_count() as int } + + /// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic. + #[inline(always)] + fn leading_zeros(&self) -> int { (*self as i64).leading_zeros() as int } + + /// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic. + #[inline(always)] + fn trailing_zeros(&self) -> int { (*self as i64).trailing_zeros() as int } + } + /// Returns `base` raised to the power of `exponent` pub fn pow(base: int, exponent: uint) -> int { if exponent == 0u { diff --git a/src/libcore/num/num.rs b/src/libcore/num/num.rs index e19afdc69c3..0e2669a26b6 100644 --- a/src/libcore/num/num.rs +++ b/src/libcore/num/num.rs @@ -18,11 +18,15 @@ use Quot = ops::Div; use Rem = ops::Modulo; #[cfg(not(stage0))] use ops::{Add, Sub, Mul, Quot, Rem, Neg}; +use ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr}; use option::Option; use kinds::Copy; pub mod strconv; +/// +/// The base trait for numeric types +/// pub trait Num: Eq + Zero + One + Neg + Add @@ -36,14 +40,23 @@ pub trait IntConvertible { fn from_int(n: int) -> Self; } +pub trait Orderable: Ord { + // These should be methods on `Ord`, with overridable default implementations. We don't want + // to encumber all implementors of Ord by requiring them to implement these functions, but at + // the same time we want to be able to take advantage of the speed of the specific numeric + // functions (like the `fmin` and `fmax` intrinsics). + fn min(&self, other: &Self) -> Self; + fn max(&self, other: &Self) -> Self; + fn clamp(&self, mn: &Self, mx: &Self) -> Self; +} + pub trait Zero { - // FIXME (#5527): These should be associated constants - fn zero() -> Self; + fn zero() -> Self; // FIXME (#5527): This should be an associated constant + fn is_zero(&self) -> bool; } pub trait One { - // FIXME (#5527): These should be associated constants - fn one() -> Self; + fn one() -> Self; // FIXME (#5527): This should be an associated constant } pub trait Signed: Num @@ -62,7 +75,7 @@ pub fn abs>(v: T) -> T { } pub trait Integer: Num - + Ord + + Orderable + Quot + Rem { fn div(&self, other: &Self) -> Self; @@ -86,12 +99,15 @@ pub trait Round { } pub trait Fractional: Num - + Ord + + Orderable + Round + Quot { fn recip(&self) -> Self; } +/// +/// Defines constants and methods common to real numbers +/// pub trait Real: Signed + Fractional { // FIXME (#5527): usages of `int` should be replaced with an associated @@ -154,7 +170,9 @@ pub trait Real: Signed fn tanh(&self) -> Self; } +/// /// Methods that are harder to implement and not commonly used. +/// pub trait RealExt: Real { // FIXME (#5527): usages of `int` should be replaced with an associated // integer type once these are implemented @@ -172,24 +190,101 @@ pub trait RealExt: Real { fn yn(&self, n: int) -> Self; } -/** - * Cast from one machine scalar to another - * - * # Example - * - * ~~~ - * let twenty: f32 = num::cast(0x14); - * assert_eq!(twenty, 20f32); - * ~~~ - */ +/// +/// Collects the bitwise operators under one trait. +/// +pub trait Bitwise: Not + + BitAnd + + BitOr + + BitXor + + Shl + + Shr {} + +pub trait BitCount { + fn population_count(&self) -> Self; + fn leading_zeros(&self) -> Self; + fn trailing_zeros(&self) -> Self; +} + +pub trait Bounded { + // FIXME (#5527): These should be associated constants + fn min_value() -> Self; + fn max_value() -> Self; +} + +/// +/// Specifies the available operations common to all of Rust's core numeric primitives. +/// These may not always make sense from a purely mathematical point of view, but +/// may be useful for systems programming. +/// +pub trait Primitive: Num + + NumCast + + Bounded + + Neg + + Add + + Sub + + Mul + + Quot + + Rem { + // FIXME (#5527): These should be associated constants + fn bits() -> uint; + fn bytes() -> uint; +} + +/// +/// A collection of traits relevant to primitive signed and unsigned integers +/// +pub trait Int: Integer + + Primitive + + Bitwise + + BitCount {} + +/// +/// Primitive floating point numbers +/// +pub trait Float: Real + + Signed + + Primitive { + // FIXME (#5527): These should be associated constants + fn NaN() -> Self; + fn infinity() -> Self; + fn neg_infinity() -> Self; + fn neg_zero() -> Self; + + fn is_NaN(&self) -> bool; + fn is_infinite(&self) -> bool; + fn is_finite(&self) -> bool; + + fn mantissa_digits() -> uint; + fn digits() -> uint; + fn epsilon() -> Self; + fn min_exp() -> int; + fn max_exp() -> int; + fn min_10_exp() -> int; + fn max_10_exp() -> int; + + fn mul_add(&self, a: Self, b: Self) -> Self; + fn next_after(&self, other: Self) -> Self; +} + +/// +/// Cast from one machine scalar to another +/// +/// # Example +/// +/// ~~~ +/// let twenty: f32 = num::cast(0x14); +/// assert_eq!(twenty, 20f32); +/// ~~~ +/// #[inline(always)] pub fn cast(n: T) -> U { NumCast::from(n) } -/** - * An interface for casting between machine scalars - */ +/// +/// An interface for casting between machine scalars +/// pub trait NumCast { fn from(n: T) -> Self; @@ -261,21 +356,19 @@ pub trait FromStrRadix { pub fn from_str_radix(str: &str, radix: uint) -> Option; } -// Generic math functions: - -/** - * Calculates a power to a given radix, optimized for uint `pow` and `radix`. - * - * Returns `radix^pow` as `T`. - * - * Note: - * Also returns `1` for `0^0`, despite that technically being an - * undefined number. The reason for this is twofold: - * - If code written to use this function cares about that special case, it's - * probably going to catch it before making the call. - * - If code written to use this function doesn't care about it, it's - * probably assuming that `x^0` always equals `1`. - */ +/// +/// Calculates a power to a given radix, optimized for uint `pow` and `radix`. +/// +/// Returns `radix^pow` as `T`. +/// +/// Note: +/// Also returns `1` for `0^0`, despite that technically being an +/// undefined number. The reason for this is twofold: +/// - If code written to use this function cares about that special case, it's +/// probably going to catch it before making the call. +/// - If code written to use this function doesn't care about it, it's +/// probably assuming that `x^0` always equals `1`. +/// pub fn pow_with_uint+Mul>( radix: uint, pow: uint) -> T { let _0: T = Zero::zero(); diff --git a/src/libcore/num/uint-template.rs b/src/libcore/num/uint-template.rs index 96019ddd564..af64660ad0c 100644 --- a/src/libcore/num/uint-template.rs +++ b/src/libcore/num/uint-template.rs @@ -13,7 +13,7 @@ use T_SIGNED = self::inst::T_SIGNED; use from_str::FromStr; use num::{ToStrRadix, FromStrRadix}; -use num::strconv; +use num::{Zero, One, strconv}; use prelude::*; pub use cmp::{min, max}; @@ -49,10 +49,9 @@ pub fn ge(x: T, y: T) -> bool { x >= y } pub fn gt(x: T, y: T) -> bool { x > y } #[inline(always)] -/** - * Iterate over the range [`start`,`start`+`step`..`stop`) - * - */ +/// +/// Iterate over the range [`start`,`start`+`step`..`stop`) +/// pub fn range_step(start: T, stop: T, step: T_SIGNED, @@ -118,12 +117,33 @@ impl Eq for T { fn ne(&self, other: &T) -> bool { return (*self) != (*other); } } -impl num::Zero for T { +impl Orderable for T { #[inline(always)] - fn zero() -> T { 0 } + fn min(&self, other: &T) -> T { + if *self < *other { *self } else { *other } + } + + #[inline(always)] + fn max(&self, other: &T) -> T { + if *self > *other { *self } else { *other } + } + + #[inline(always)] + fn clamp(&self, mn: &T, mx: &T) -> T { + if *self > *mx { *mx } else + if *self < *mn { *mn } else { *self } + } } -impl num::One for T { +impl Zero for T { + #[inline(always)] + fn zero() -> T { 0 } + + #[inline(always)] + fn is_zero(&self) -> bool { *self == 0 } +} + +impl One for T { #[inline(always)] fn one() -> T { 1 } } @@ -229,6 +249,8 @@ impl Integer for T { fn is_odd(&self) -> bool { !self.is_even() } } +impl Bitwise for T {} + #[cfg(notest)] impl BitOr for T { #[inline(always)] @@ -265,6 +287,16 @@ impl Not for T { fn not(&self) -> T { !*self } } +impl Bounded for T { + #[inline(always)] + fn min_value() -> T { min_value } + + #[inline(always)] + fn max_value() -> T { max_value } +} + +impl Int for T {} + // String conversion functions and impl str -> num /// Parse a string as a number in base 10. @@ -353,6 +385,17 @@ mod tests { num::test_num(10 as T, 2 as T); } + #[test] + fn test_orderable() { + assert_eq!((1 as T).min(&(2 as T)), 1 as T); + assert_eq!((2 as T).min(&(1 as T)), 1 as T); + assert_eq!((1 as T).max(&(2 as T)), 2 as T); + assert_eq!((2 as T).max(&(1 as T)), 2 as T); + assert_eq!((1 as T).clamp(&(2 as T), &(4 as T)), 2 as T); + assert_eq!((8 as T).clamp(&(2 as T), &(4 as T)), 4 as T); + assert_eq!((3 as T).clamp(&(2 as T), &(4 as T)), 3 as T); + } + #[test] fn test_gcd() { assert_eq!((10 as T).gcd(&2), 2 as T); @@ -373,7 +416,7 @@ mod tests { } #[test] - fn test_bitwise_ops() { + fn test_bitwise() { assert_eq!(0b1110 as T, (0b1100 as T).bitor(&(0b1010 as T))); assert_eq!(0b1000 as T, (0b1100 as T).bitand(&(0b1010 as T))); assert_eq!(0b0110 as T, (0b1100 as T).bitxor(&(0b1010 as T))); @@ -382,6 +425,17 @@ mod tests { assert_eq!(max_value - (0b1011 as T), (0b1011 as T).not()); } + #[test] + fn test_bitcount() { + assert_eq!((0b010101 as T).population_count(), 3); + } + + #[test] + fn test_primitive() { + assert_eq!(Primitive::bits::(), sys::size_of::() * 8); + assert_eq!(Primitive::bytes::(), sys::size_of::()); + } + #[test] pub fn test_to_str() { assert_eq!(to_str_radix(0 as T, 10u), ~"0"); diff --git a/src/libcore/num/uint-template/u16.rs b/src/libcore/num/uint-template/u16.rs index 63144162fc5..cc262f6b4de 100644 --- a/src/libcore/num/uint-template/u16.rs +++ b/src/libcore/num/uint-template/u16.rs @@ -11,8 +11,33 @@ //! Operations and constants for `u16` mod inst { + use num::{Primitive, BitCount}; + use unstable::intrinsics; + pub type T = u16; #[allow(non_camel_case_types)] pub type T_SIGNED = i16; pub static bits: uint = 16; + + impl Primitive for u16 { + #[inline(always)] + fn bits() -> uint { 16 } + + #[inline(always)] + fn bytes() -> uint { Primitive::bits::() / 8 } + } + + impl BitCount for u16 { + /// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic. + #[inline(always)] + fn population_count(&self) -> u16 { unsafe { intrinsics::ctpop16(*self as i16) as u16 } } + + /// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic. + #[inline(always)] + fn leading_zeros(&self) -> u16 { unsafe { intrinsics::ctlz16(*self as i16) as u16 } } + + /// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic. + #[inline(always)] + fn trailing_zeros(&self) -> u16 { unsafe { intrinsics::cttz16(*self as i16) as u16 } } + } } diff --git a/src/libcore/num/uint-template/u32.rs b/src/libcore/num/uint-template/u32.rs index 4d9958fe38a..7d7c8e3be30 100644 --- a/src/libcore/num/uint-template/u32.rs +++ b/src/libcore/num/uint-template/u32.rs @@ -11,8 +11,33 @@ //! Operations and constants for `u32` mod inst { + use num::{Primitive, BitCount}; + use unstable::intrinsics; + pub type T = u32; #[allow(non_camel_case_types)] pub type T_SIGNED = i32; pub static bits: uint = 32; + + impl Primitive for u32 { + #[inline(always)] + fn bits() -> uint { 32 } + + #[inline(always)] + fn bytes() -> uint { Primitive::bits::() / 8 } + } + + impl BitCount for u32 { + /// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic. + #[inline(always)] + fn population_count(&self) -> u32 { unsafe { intrinsics::ctpop32(*self as i32) as u32 } } + + /// Counts the number of leading zeros. Wraps LLVM's `ctlp` intrinsic. + #[inline(always)] + fn leading_zeros(&self) -> u32 { unsafe { intrinsics::ctlz32(*self as i32) as u32 } } + + /// Counts the number of trailing zeros. Wraps LLVM's `cttp` intrinsic. + #[inline(always)] + fn trailing_zeros(&self) -> u32 { unsafe { intrinsics::cttz32(*self as i32) as u32 } } + } } diff --git a/src/libcore/num/uint-template/u64.rs b/src/libcore/num/uint-template/u64.rs index af198dd6942..756c29950c3 100644 --- a/src/libcore/num/uint-template/u64.rs +++ b/src/libcore/num/uint-template/u64.rs @@ -11,8 +11,33 @@ //! Operations and constants for `u64` mod inst { + use num::{Primitive, BitCount}; + use unstable::intrinsics; + pub type T = u64; #[allow(non_camel_case_types)] pub type T_SIGNED = i64; pub static bits: uint = 64; + + impl Primitive for u64 { + #[inline(always)] + fn bits() -> uint { 64 } + + #[inline(always)] + fn bytes() -> uint { Primitive::bits::() / 8 } + } + + impl BitCount for u64 { + /// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic. + #[inline(always)] + fn population_count(&self) -> u64 { unsafe { intrinsics::ctpop64(*self as i64) as u64 } } + + /// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic. + #[inline(always)] + fn leading_zeros(&self) -> u64 { unsafe { intrinsics::ctlz64(*self as i64) as u64 } } + + /// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic. + #[inline(always)] + fn trailing_zeros(&self) -> u64 { unsafe { intrinsics::cttz64(*self as i64) as u64 } } + } } diff --git a/src/libcore/num/uint-template/u8.rs b/src/libcore/num/uint-template/u8.rs index 5c548d72093..5ac860c0359 100644 --- a/src/libcore/num/uint-template/u8.rs +++ b/src/libcore/num/uint-template/u8.rs @@ -11,8 +11,33 @@ //! Operations and constants for `u8` mod inst { + use num::{Primitive, BitCount}; + use unstable::intrinsics; + pub type T = u8; #[allow(non_camel_case_types)] pub type T_SIGNED = i8; pub static bits: uint = 8; + + impl Primitive for u8 { + #[inline(always)] + fn bits() -> uint { 8 } + + #[inline(always)] + fn bytes() -> uint { Primitive::bits::() / 8 } + } + + impl BitCount for u8 { + /// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic. + #[inline(always)] + fn population_count(&self) -> u8 { unsafe { intrinsics::ctpop8(*self as i8) as u8 } } + + /// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic. + #[inline(always)] + fn leading_zeros(&self) -> u8 { unsafe { intrinsics::ctlz8(*self as i8) as u8 } } + + /// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic. + #[inline(always)] + fn trailing_zeros(&self) -> u8 { unsafe { intrinsics::cttz8(*self as i8) as u8 } } + } } diff --git a/src/libcore/num/uint-template/uint.rs b/src/libcore/num/uint-template/uint.rs index efcf68aba31..6a8567451e6 100644 --- a/src/libcore/num/uint-template/uint.rs +++ b/src/libcore/num/uint-template/uint.rs @@ -18,6 +18,7 @@ pub use self::inst::{ pub mod inst { use sys; use iter; + use num::{Primitive, BitCount}; pub type T = uint; #[allow(non_camel_case_types)] @@ -31,74 +32,119 @@ pub mod inst { #[cfg(target_arch = "x86_64")] pub static bits: uint = 64; - /** - * Divide two numbers, return the result, rounded up. - * - * # Arguments - * - * * x - an integer - * * y - an integer distinct from 0u - * - * # Return value - * - * The smallest integer `q` such that `x/y <= q`. - */ + impl Primitive for uint { + #[cfg(target_word_size = "32")] + #[inline(always)] + fn bits() -> uint { 32 } + + #[cfg(target_word_size = "64")] + #[inline(always)] + fn bits() -> uint { 64 } + + #[inline(always)] + fn bytes() -> uint { Primitive::bits::() / 8 } + } + + #[cfg(target_word_size = "32")] + #[inline(always)] + impl BitCount for uint { + /// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic. + #[inline(always)] + fn population_count(&self) -> uint { (*self as i32).population_count() as uint } + + /// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic. + #[inline(always)] + fn leading_zeros(&self) -> uint { (*self as i32).leading_zeros() as uint } + + /// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic. + #[inline(always)] + fn trailing_zeros(&self) -> uint { (*self as i32).trailing_zeros() as uint } + } + + #[cfg(target_word_size = "64")] + #[inline(always)] + impl BitCount for uint { + /// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic. + #[inline(always)] + fn population_count(&self) -> uint { (*self as i64).population_count() as uint } + + /// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic. + #[inline(always)] + fn leading_zeros(&self) -> uint { (*self as i64).leading_zeros() as uint } + + /// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic. + #[inline(always)] + fn trailing_zeros(&self) -> uint { (*self as i64).trailing_zeros() as uint } + } + + /// + /// Divide two numbers, return the result, rounded up. + /// + /// # Arguments + /// + /// * x - an integer + /// * y - an integer distinct from 0u + /// + /// # Return value + /// + /// The smallest integer `q` such that `x/y <= q`. + /// pub fn div_ceil(x: uint, y: uint) -> uint { let div = x / y; if x % y == 0u { div } else { div + 1u } } - /** - * Divide two numbers, return the result, rounded to the closest integer. - * - * # Arguments - * - * * x - an integer - * * y - an integer distinct from 0u - * - * # Return value - * - * The integer `q` closest to `x/y`. - */ + /// + /// Divide two numbers, return the result, rounded to the closest integer. + /// + /// # Arguments + /// + /// * x - an integer + /// * y - an integer distinct from 0u + /// + /// # Return value + /// + /// The integer `q` closest to `x/y`. + /// pub fn div_round(x: uint, y: uint) -> uint { let div = x / y; if x % y * 2u < y { div } else { div + 1u } } - /** - * Divide two numbers, return the result, rounded down. - * - * Note: This is the same function as `div`. - * - * # Arguments - * - * * x - an integer - * * y - an integer distinct from 0u - * - * # Return value - * - * The smallest integer `q` such that `x/y <= q`. This - * is either `x/y` or `x/y + 1`. - */ + /// + /// Divide two numbers, return the result, rounded down. + /// + /// Note: This is the same function as `div`. + /// + /// # Arguments + /// + /// * x - an integer + /// * y - an integer distinct from 0u + /// + /// # Return value + /// + /// The smallest integer `q` such that `x/y <= q`. This + /// is either `x/y` or `x/y + 1`. + /// pub fn div_floor(x: uint, y: uint) -> uint { return x / y; } - /** - * Iterate over the range [`lo`..`hi`), or stop when requested - * - * # Arguments - * - * * lo - The integer at which to start the loop (included) - * * hi - The integer at which to stop the loop (excluded) - * * it - A block to execute with each consecutive integer of the range. - * Return `true` to continue, `false` to stop. - * - * # Return value - * - * `true` If execution proceeded correctly, `false` if it was interrupted, - * that is if `it` returned `false` at any point. - */ + /// + /// Iterate over the range [`lo`..`hi`), or stop when requested + /// + /// # Arguments + /// + /// * lo - The integer at which to start the loop (included) + /// * hi - The integer at which to stop the loop (excluded) + /// * it - A block to execute with each consecutive integer of the range. + /// Return `true` to continue, `false` to stop. + /// + /// # Return value + /// + /// `true` If execution proceeded correctly, `false` if it was interrupted, + /// that is if `it` returned `false` at any point. + /// pub fn iterate(lo: uint, hi: uint, it: &fn(uint) -> bool) -> bool { let mut i = lo; while i < hi { @@ -110,16 +156,16 @@ pub mod inst { impl iter::Times for uint { #[inline(always)] - /** - * A convenience form for basic iteration. Given a uint `x`, - * `for x.times { ... }` executes the given block x times. - * - * Equivalent to `for uint::range(0, x) |_| { ... }`. - * - * Not defined on all integer types to permit unambiguous - * use with integer literals of inferred integer-type as - * the self-value (eg. `for 100.times { ... }`). - */ + /// + /// A convenience form for basic iteration. Given a uint `x`, + /// `for x.times { ... }` executes the given block x times. + /// + /// Equivalent to `for uint::range(0, x) |_| { ... }`. + /// + /// Not defined on all integer types to permit unambiguous + /// use with integer literals of inferred integer-type as + /// the self-value (eg. `for 100.times { ... }`). + /// fn times(&self, it: &fn() -> bool) { let mut i = *self; while i > 0 { diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs index 553bb826810..7e41f1b5b34 100644 --- a/src/libcore/prelude.rs +++ b/src/libcore/prelude.rs @@ -38,8 +38,10 @@ pub use iter::{BaseIter, ReverseIter, MutableIter, ExtendedIter, EqIter}; pub use iter::{CopyableIter, CopyableOrderedIter, CopyableNonstrictIter}; pub use iter::{Times, ExtendedMutableIter}; pub use num::{Num, NumCast}; -pub use num::{Signed, Unsigned, Integer}; +pub use num::{Orderable, Signed, Unsigned, Integer}; pub use num::{Round, Fractional, Real, RealExt}; +pub use num::{Bitwise, BitCount, Bounded}; +pub use num::{Primitive, Int, Float}; pub use path::GenericPath; pub use path::Path; pub use path::PosixPath; diff --git a/src/libstd/num/bigint.rs b/src/libstd/num/bigint.rs index 5f0fd76640a..214bb0be0ed 100644 --- a/src/libstd/num/bigint.rs +++ b/src/libstd/num/bigint.rs @@ -148,10 +148,12 @@ impl Shr for BigUint { impl Zero for BigUint { fn zero() -> BigUint { BigUint::new(~[]) } + + fn is_zero(&self) -> bool { self.data.is_empty() } } impl One for BigUint { - pub fn one() -> BigUint { BigUint::new(~[1]) } + fn one() -> BigUint { BigUint::new(~[1]) } } impl Unsigned for BigUint {} @@ -310,7 +312,7 @@ impl ToStrRadix for BigUint { result += [m0.to_uint() as BigDigit]; m = d; } - if m.is_not_zero() { + if !m.is_zero() { result += [m.to_uint() as BigDigit]; } return result; @@ -470,10 +472,6 @@ pub impl BigUint { self.div_mod(other) } - fn is_zero(&self) -> bool { self.data.is_empty() } - - fn is_not_zero(&self) -> bool { !self.data.is_empty() } - fn to_uint(&self) -> uint { match self.data.len() { 0 => 0, @@ -684,6 +682,8 @@ impl Zero for BigInt { pub fn zero() -> BigInt { BigInt::from_biguint(Zero, Zero::zero()) } + + fn is_zero(&self) -> bool { self.sign == Zero } } impl One for BigInt { @@ -909,8 +909,6 @@ pub impl BigInt { fn is_zero(&self) -> bool { self.sign == Zero } - fn is_not_zero(&self) -> bool { self.sign != Zero } - fn to_uint(&self) -> uint { match self.sign { Plus => self.data.to_uint(), @@ -1212,10 +1210,10 @@ mod biguint_tests { let b = BigUint::from_slice(bVec); let c = BigUint::from_slice(cVec); - if a.is_not_zero() { + if !a.is_zero() { assert!(c.quot_rem(&a) == (b, Zero::zero())); } - if b.is_not_zero() { + if !b.is_zero() { assert!(c.quot_rem(&b) == (a, Zero::zero())); } } @@ -1227,7 +1225,7 @@ mod biguint_tests { let c = BigUint::from_slice(cVec); let d = BigUint::from_slice(dVec); - if b.is_not_zero() { assert!(a.quot_rem(&b) == (c, d)); } + if !b.is_zero() { assert!(a.quot_rem(&b) == (c, d)); } } } @@ -1577,7 +1575,7 @@ mod bigint_tests { fn test_div_mod() { fn check_sub(a: &BigInt, b: &BigInt, ans_d: &BigInt, ans_m: &BigInt) { let (d, m) = a.div_mod(b); - if m.is_not_zero() { + if !m.is_zero() { assert!(m.sign == b.sign); } assert!(m.abs() <= b.abs()); @@ -1606,8 +1604,8 @@ mod bigint_tests { let b = BigInt::from_slice(Plus, bVec); let c = BigInt::from_slice(Plus, cVec); - if a.is_not_zero() { check(&c, &a, &b, &Zero::zero()); } - if b.is_not_zero() { check(&c, &b, &a, &Zero::zero()); } + if !a.is_zero() { check(&c, &a, &b, &Zero::zero()); } + if !b.is_zero() { check(&c, &b, &a, &Zero::zero()); } } for quot_rem_quadruples.each |elm| { @@ -1617,7 +1615,7 @@ mod bigint_tests { let c = BigInt::from_slice(Plus, cVec); let d = BigInt::from_slice(Plus, dVec); - if b.is_not_zero() { + if !b.is_zero() { check(&a, &b, &c, &d); } } @@ -1628,7 +1626,7 @@ mod bigint_tests { fn test_quot_rem() { fn check_sub(a: &BigInt, b: &BigInt, ans_q: &BigInt, ans_r: &BigInt) { let (q, r) = a.quot_rem(b); - if r.is_not_zero() { + if !r.is_zero() { assert!(r.sign == a.sign); } assert!(r.abs() <= b.abs()); @@ -1649,8 +1647,8 @@ mod bigint_tests { let b = BigInt::from_slice(Plus, bVec); let c = BigInt::from_slice(Plus, cVec); - if a.is_not_zero() { check(&c, &a, &b, &Zero::zero()); } - if b.is_not_zero() { check(&c, &b, &a, &Zero::zero()); } + if !a.is_zero() { check(&c, &a, &b, &Zero::zero()); } + if !b.is_zero() { check(&c, &b, &a, &Zero::zero()); } } for quot_rem_quadruples.each |elm| { @@ -1660,7 +1658,7 @@ mod bigint_tests { let c = BigInt::from_slice(Plus, cVec); let d = BigInt::from_slice(Plus, dVec); - if b.is_not_zero() { + if !b.is_zero() { check(&a, &b, &c, &d); } } diff --git a/src/libstd/num/complex.rs b/src/libstd/num/complex.rs index ef7fa397d7f..fc17cbc678e 100644 --- a/src/libstd/num/complex.rs +++ b/src/libstd/num/complex.rs @@ -125,6 +125,11 @@ impl Zero for Cmplx { fn zero() -> Cmplx { Cmplx::new(Zero::zero(), Zero::zero()) } + + #[inline] + fn is_zero(&self) -> bool { + *self == Zero::zero() + } } impl One for Cmplx { diff --git a/src/libstd/num/rational.rs b/src/libstd/num/rational.rs index 8af1d99fa47..93b63593a5e 100644 --- a/src/libstd/num/rational.rs +++ b/src/libstd/num/rational.rs @@ -191,6 +191,11 @@ impl fn zero() -> Ratio { Ratio::new_raw(Zero::zero(), One::one()) } + + #[inline] + fn is_zero(&self) -> bool { + *self == Zero::zero() + } } impl diff --git a/src/test/run-pass/float-nan.rs b/src/test/run-pass/float-nan.rs index 918d45ad492..08523de3ccd 100644 --- a/src/test/run-pass/float-nan.rs +++ b/src/test/run-pass/float-nan.rs @@ -10,82 +10,86 @@ extern mod std; +use core::num::Float::{ + NaN, infinity, neg_infinity +}; + pub fn main() { - let nan = float::NaN; - assert!((float::is_NaN(nan))); + let nan = NaN::(); + assert!((nan).is_NaN()); - let inf = float::infinity; - assert!((-inf == float::neg_infinity)); + let inf = infinity::(); + assert!(-inf == neg_infinity::()); - assert!(( nan != nan)); - assert!(( nan != -nan)); - assert!((-nan != -nan)); - assert!((-nan != nan)); + assert!( nan != nan); + assert!( nan != -nan); + assert!(-nan != -nan); + assert!(-nan != nan); - assert!(( nan != 1.)); - assert!(( nan != 0.)); - assert!(( nan != inf)); - assert!(( nan != -inf)); + assert!( nan != 1.); + assert!( nan != 0.); + assert!( nan != inf); + assert!( nan != -inf); - assert!(( 1. != nan)); - assert!(( 0. != nan)); - assert!(( inf != nan)); - assert!((-inf != nan)); + assert!( 1. != nan); + assert!( 0. != nan); + assert!( inf != nan); + assert!(-inf != nan); - assert!((!( nan == nan))); - assert!((!( nan == -nan))); - assert!((!( nan == 1.))); - assert!((!( nan == 0.))); - assert!((!( nan == inf))); - assert!((!( nan == -inf))); - assert!((!( 1. == nan))); - assert!((!( 0. == nan))); - assert!((!( inf == nan))); - assert!((!(-inf == nan))); - assert!((!(-nan == nan))); - assert!((!(-nan == -nan))); + assert!(!( nan == nan)); + assert!(!( nan == -nan)); + assert!(!( nan == 1.)); + assert!(!( nan == 0.)); + assert!(!( nan == inf)); + assert!(!( nan == -inf)); + assert!(!( 1. == nan)); + assert!(!( 0. == nan)); + assert!(!( inf == nan)); + assert!(!(-inf == nan)); + assert!(!(-nan == nan)); + assert!(!(-nan == -nan)); - assert!((!( nan > nan))); - assert!((!( nan > -nan))); - assert!((!( nan > 0.))); - assert!((!( nan > inf))); - assert!((!( nan > -inf))); - assert!((!( 0. > nan))); - assert!((!( inf > nan))); - assert!((!(-inf > nan))); - assert!((!(-nan > nan))); + assert!(!( nan > nan)); + assert!(!( nan > -nan)); + assert!(!( nan > 0.)); + assert!(!( nan > inf)); + assert!(!( nan > -inf)); + assert!(!( 0. > nan)); + assert!(!( inf > nan)); + assert!(!(-inf > nan)); + assert!(!(-nan > nan)); - assert!((!(nan < 0.))); - assert!((!(nan < 1.))); - assert!((!(nan < -1.))); - assert!((!(nan < inf))); - assert!((!(nan < -inf))); - assert!((!(nan < nan))); - assert!((!(nan < -nan))); + assert!(!(nan < 0.)); + assert!(!(nan < 1.)); + assert!(!(nan < -1.)); + assert!(!(nan < inf)); + assert!(!(nan < -inf)); + assert!(!(nan < nan)); + assert!(!(nan < -nan)); - assert!((!( 0. < nan))); - assert!((!( 1. < nan))); - assert!((!( -1. < nan))); - assert!((!( inf < nan))); - assert!((!(-inf < nan))); - assert!((!(-nan < nan))); + assert!(!( 0. < nan)); + assert!(!( 1. < nan)); + assert!(!( -1. < nan)); + assert!(!( inf < nan)); + assert!(!(-inf < nan)); + assert!(!(-nan < nan)); - assert!((float::is_NaN(nan + inf))); - assert!((float::is_NaN(nan + -inf))); - assert!((float::is_NaN(nan + 0.))); - assert!((float::is_NaN(nan + 1.))); - assert!((float::is_NaN(nan * 1.))); - assert!((float::is_NaN(nan / 1.))); - assert!((float::is_NaN(nan / 0.))); - assert!((float::is_NaN(0. / 0.))); - assert!((float::is_NaN(-inf + inf))); - assert!((float::is_NaN(inf - inf))); + assert!((nan + inf).is_NaN()); + assert!((nan + -inf).is_NaN()); + assert!((nan + 0.).is_NaN()); + assert!((nan + 1.).is_NaN()); + assert!((nan * 1.).is_NaN()); + assert!((nan / 1.).is_NaN()); + assert!((nan / 0.).is_NaN()); + assert!((0f/0f).is_NaN()); + assert!((-inf + inf).is_NaN()); + assert!((inf - inf).is_NaN()); - assert!((!float::is_NaN(-1.))); - assert!((!float::is_NaN(0.))); - assert!((!float::is_NaN(0.1))); - assert!((!float::is_NaN(1.))); - assert!((!float::is_NaN(inf))); - assert!((!float::is_NaN(-inf))); - assert!((!float::is_NaN(1./-inf))); + assert!(!(-1f).is_NaN()); + assert!(!(0f).is_NaN()); + assert!(!(0.1f).is_NaN()); + assert!(!(1f).is_NaN()); + assert!(!(inf).is_NaN()); + assert!(!(-inf).is_NaN()); + assert!(!(1./-inf).is_NaN()); }