Skip to content

Commit

Permalink
auto merge of #6041 : bjz/rust/numeric-traits, r=brson
Browse files Browse the repository at this point in the history
As part of the numeric trait reform (see issue #4819), I have added the following traits to `core::num` and implemented them for the appropriate types:

~~~rust
pub trait Signed: Num
                + Neg<Self> {
    fn abs(&self) -> Self;
    fn signum(&self) -> Self;
    fn is_positive(&self) -> bool;
    fn is_negative(&self) -> bool;
}

pub trait Unsigned: Num {}

pub trait Natural: Num
                 + Ord
                 + Quot<Self,Self>
                 + Rem<Self,Self> {
    fn div(&self, other: Self) -> Self;
    fn modulo(&self, other: Self) -> Self;
    fn div_mod(&self, other: Self) -> (Self,Self);
    fn quot_rem(&self, other: Self) -> (Self,Self);

    fn gcd(&self, other: Self) -> Self;
    fn lcm(&self, other: Self) -> Self;
    fn divisible_by(&self, other: Self) -> bool;
    fn is_even(&self) -> bool;
    fn is_odd(&self) -> bool;
}
~~~

I have not implemented `Natural` for `BigInt` and `BigUInt` because they're a little over my head. Help with this would be most appreciated.
  • Loading branch information
bors committed Apr 24, 2013
2 parents 706096b + ab8068c commit c8ac057
Show file tree
Hide file tree
Showing 15 changed files with 671 additions and 188 deletions.
2 changes: 1 addition & 1 deletion src/libcore/core.rc
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ pub use iter::{BaseIter, ExtendedIter, EqIter, CopyableIter};
pub use iter::{CopyableOrderedIter, CopyableNonstrictIter, Times};
pub use iter::{ExtendedMutableIter};

pub use num::{Num, NumCast};
pub use num::{Num, Signed, Unsigned, Natural, NumCast};
pub use ptr::Ptr;
pub use to_str::ToStr;
pub use clone::Clone;
Expand Down
114 changes: 74 additions & 40 deletions src/libcore/num/f32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//! Operations and constants for `f32`

use num::strconv;
use num::Signed;
use num;
use option::Option;
use from_str;
Expand Down Expand Up @@ -163,38 +164,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 positive number, including +0.0f320 and +Infinity
#[inline(always)]
pub fn is_positive(x: f32) -> bool {
x > 0.0f32 || (1.0f32/x) == infinity
}

/// Returns true if `x` is a negative number, including -0.0f320 and -Infinity
#[inline(always)]
pub fn is_negative(x: f32) -> bool {
x < 0.0f32 || (1.0f32/x) == neg_infinity
}

/**
* Returns true if `x` is a negative number, including -0.0f320 and -Infinity
*
* This is the same as `f32::is_negative`.
*/
#[inline(always)]
pub fn is_nonpositive(x: f32) -> bool {
return x < 0.0f32 || (1.0f32/x) == neg_infinity;
}

/**
* Returns true if `x` is a positive number, including +0.0f320 and +Infinity
*
* This is the same as `f32::is_positive`.)
*/
#[inline(always)]
pub fn is_nonnegative(x: f32) -> bool {
return x > 0.0f32 || (1.0f32/x) == infinity;
}

/// Returns true if `x` is a zero number (positive or negative zero)
#[inline(always)]
pub fn is_zero(x: f32) -> bool {
Expand Down Expand Up @@ -259,11 +228,6 @@ pub mod consts {
pub static ln_10: f32 = 2.30258509299404568401799145468436421_f32;
}

#[inline(always)]
pub fn signbit(x: f32) -> int {
if is_negative(x) { return 1; } else { return 0; }
}

#[inline(always)]
pub fn logarithm(n: f32, b: f32) -> f32 {
return log2(n) / log2(b);
Expand Down Expand Up @@ -351,15 +315,41 @@ impl Neg<f32> for f32 {
fn neg(&self) -> f32 { -*self }
}

impl Signed for f32 {
/// Computes the absolute value. Returns `NaN` if the number is `NaN`.
#[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`
*/
#[inline(always)]
fn signum(&self) -> f32 {
if is_NaN(*self) { NaN } else { copysign(1.0, *self) }
}

/// Returns `true` if the number is positive, including `+0.0` and `infinity`
#[inline(always)]
fn is_positive(&self) -> bool { *self > 0.0 || (1.0 / *self) == infinity }

/// Returns `true` if the number is negative, including `-0.0` and `neg_infinity`
#[inline(always)]
fn is_negative(&self) -> bool { *self < 0.0 || (1.0 / *self) == neg_infinity }
}

impl num::Round for f32 {
#[inline(always)]
fn round(&self, mode: num::RoundMode) -> f32 {
match mode {
num::RoundDown => floor(*self),
num::RoundUp => ceil(*self),
num::RoundToZero if is_negative(*self) => ceil(*self),
num::RoundToZero if self.is_negative() => ceil(*self),
num::RoundToZero => floor(*self),
num::RoundFromZero if is_negative(*self) => floor(*self),
num::RoundFromZero if self.is_negative() => floor(*self),
num::RoundFromZero => ceil(*self)
}
}
Expand All @@ -370,7 +360,7 @@ impl num::Round for f32 {
fn ceil(&self) -> f32 { ceil(*self) }
#[inline(always)]
fn fract(&self) -> f32 {
if is_negative(*self) {
if self.is_negative() {
(*self) - ceil(*self)
} else {
(*self) - floor(*self)
Expand Down Expand Up @@ -595,6 +585,50 @@ impl num::FromStrRadix for f32 {
}
}

#[cfg(test)]
mod tests {
use f32::*;

#[test]
pub fn test_signed() {
assert_eq!(infinity.abs(), infinity);
assert_eq!(1f32.abs(), 1f32);
assert_eq!(0f32.abs(), 0f32);
assert_eq!((-0f32).abs(), 0f32);
assert_eq!((-1f32).abs(), 1f32);
assert_eq!(neg_infinity.abs(), infinity);
assert_eq!((1f32/neg_infinity).abs(), 0f32);
assert!(is_NaN(NaN.abs()));

assert_eq!(infinity.signum(), 1f32);
assert_eq!(1f32.signum(), 1f32);
assert_eq!(0f32.signum(), 1f32);
assert_eq!((-0f32).signum(), -1f32);
assert_eq!((-1f32).signum(), -1f32);
assert_eq!(neg_infinity.signum(), -1f32);
assert_eq!((1f32/neg_infinity).signum(), -1f32);
assert!(is_NaN(NaN.signum()));

assert!(infinity.is_positive());
assert!(1f32.is_positive());
assert!(0f32.is_positive());
assert!(!(-0f32).is_positive());
assert!(!(-1f32).is_positive());
assert!(!neg_infinity.is_positive());
assert!(!(1f32/neg_infinity).is_positive());
assert!(!NaN.is_positive());

assert!(!infinity.is_negative());
assert!(!1f32.is_negative());
assert!(!0f32.is_negative());
assert!((-0f32).is_negative());
assert!((-1f32).is_negative());
assert!(neg_infinity.is_negative());
assert!((1f32/neg_infinity).is_negative());
assert!(!NaN.is_negative());
}
}

//
// Local Variables:
// mode: rust
Expand Down
112 changes: 74 additions & 38 deletions src/libcore/num/f64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//! Operations and constants for `f64`

use num::strconv;
use num::Signed;
use num;
use option::Option;
use to_str;
Expand Down Expand Up @@ -183,36 +184,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 positive number, including +0.0f640 and +Infinity
#[inline(always)]
pub fn is_positive(x: f64) -> bool
{ return x > 0.0f64 || (1.0f64/x) == infinity; }

/// Returns true if `x` is a negative number, including -0.0f640 and -Infinity
#[inline(always)]
pub fn is_negative(x: f64) -> bool
{ return x < 0.0f64 || (1.0f64/x) == neg_infinity; }

/**
* Returns true if `x` is a negative number, including -0.0f640 and -Infinity
*
* This is the same as `f64::is_negative`.
*/
#[inline(always)]
pub fn is_nonpositive(x: f64) -> bool {
return x < 0.0f64 || (1.0f64/x) == neg_infinity;
}

/**
* Returns true if `x` is a positive number, including +0.0f640 and +Infinity
*
* This is the same as `f64::positive`.
*/
#[inline(always)]
pub fn is_nonnegative(x: f64) -> bool {
return x > 0.0f64 || (1.0f64/x) == infinity;
}

/// Returns true if `x` is a zero number (positive or negative zero)
#[inline(always)]
pub fn is_zero(x: f64) -> bool {
Expand Down Expand Up @@ -278,11 +249,6 @@ pub mod consts {
pub static ln_10: f64 = 2.30258509299404568401799145468436421_f64;
}

#[inline(always)]
pub fn signbit(x: f64) -> int {
if is_negative(x) { return 1; } else { return 0; }
}

#[inline(always)]
pub fn logarithm(n: f64, b: f64) -> f64 {
return log2(n) / log2(b);
Expand Down Expand Up @@ -357,15 +323,41 @@ impl Neg<f64> for f64 {
fn neg(&self) -> f64 { -*self }
}

impl Signed for f64 {
/// Computes the absolute value. Returns `NaN` if the number is `NaN`.
#[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`
*/
#[inline(always)]
fn signum(&self) -> f64 {
if is_NaN(*self) { NaN } else { copysign(1.0, *self) }
}

/// Returns `true` if the number is positive, including `+0.0` and `infinity`
#[inline(always)]
fn is_positive(&self) -> bool { *self > 0.0 || (1.0 / *self) == infinity }

/// Returns `true` if the number is negative, including `-0.0` and `neg_infinity`
#[inline(always)]
fn is_negative(&self) -> bool { *self < 0.0 || (1.0 / *self) == neg_infinity }
}

impl num::Round for f64 {
#[inline(always)]
fn round(&self, mode: num::RoundMode) -> f64 {
match mode {
num::RoundDown => floor(*self),
num::RoundUp => ceil(*self),
num::RoundToZero if is_negative(*self) => ceil(*self),
num::RoundToZero if self.is_negative() => ceil(*self),
num::RoundToZero => floor(*self),
num::RoundFromZero if is_negative(*self) => floor(*self),
num::RoundFromZero if self.is_negative() => floor(*self),
num::RoundFromZero => ceil(*self)
}
}
Expand All @@ -376,7 +368,7 @@ impl num::Round for f64 {
fn ceil(&self) -> f64 { ceil(*self) }
#[inline(always)]
fn fract(&self) -> f64 {
if is_negative(*self) {
if self.is_negative() {
(*self) - ceil(*self)
} else {
(*self) - floor(*self)
Expand Down Expand Up @@ -601,6 +593,50 @@ impl num::FromStrRadix for f64 {
}
}

#[cfg(test)]
mod tests {
use f64::*;

#[test]
pub fn test_signed() {
assert_eq!(infinity.abs(), infinity);
assert_eq!(1f64.abs(), 1f64);
assert_eq!(0f64.abs(), 0f64);
assert_eq!((-0f64).abs(), 0f64);
assert_eq!((-1f64).abs(), 1f64);
assert_eq!(neg_infinity.abs(), infinity);
assert_eq!((1f64/neg_infinity).abs(), 0f64);
assert!(is_NaN(NaN.abs()));

assert_eq!(infinity.signum(), 1f64);
assert_eq!(1f64.signum(), 1f64);
assert_eq!(0f64.signum(), 1f64);
assert_eq!((-0f64).signum(), -1f64);
assert_eq!((-1f64).signum(), -1f64);
assert_eq!(neg_infinity.signum(), -1f64);
assert_eq!((1f64/neg_infinity).signum(), -1f64);
assert!(is_NaN(NaN.signum()));

assert!(infinity.is_positive());
assert!(1f64.is_positive());
assert!(0f64.is_positive());
assert!(!(-0f64).is_positive());
assert!(!(-1f64).is_positive());
assert!(!neg_infinity.is_positive());
assert!(!(1f64/neg_infinity).is_positive());
assert!(!NaN.is_positive());

assert!(!infinity.is_negative());
assert!(!1f64.is_negative());
assert!(!0f64.is_negative());
assert!((-0f64).is_negative());
assert!((-1f64).is_negative());
assert!(neg_infinity.is_negative());
assert!((1f64/neg_infinity).is_negative());
assert!(!NaN.is_negative());
}
}

//
// Local Variables:
// mode: rust
Expand Down
Loading

0 comments on commit c8ac057

Please sign in to comment.