Browse Source

Merge pull request #30 from gifnksm/master

Add numeric functions and traits that provide numeric traits for generic mathematics.
Alex Crichton 10 years ago
parent
commit
c0df55e470
8 changed files with 1047 additions and 35 deletions
  1. 2 5
      benches/shootout-pidigits.rs
  2. 68 15
      src/bigint.rs
  3. 23 4
      src/complex.rs
  4. 2 0
      src/integer.rs
  5. 341 0
      src/iter.rs
  6. 70 0
      src/lib.rs
  7. 27 11
      src/rational.rs
  8. 514 0
      src/traits.rs

+ 2 - 5
benches/shootout-pidigits.rs

@@ -41,15 +41,12 @@
 extern crate num;
 extern crate test;
 
-use std::from_str::FromStr;
-use std::num::One;
-use std::num::Zero;
+use std::str::FromStr;
 use std::num::FromPrimitive;
 
 use test::Bencher;
 
-use num::Integer;
-use num::bigint::BigInt;
+use num::{BigInt, Integer, One, Zero};
 
 struct Context {
     numer: BigInt,

+ 68 - 15
src/bigint.rs

@@ -19,8 +19,7 @@
 //! ## Example
 //!
 //! ```rust
-//! use num::bigint::BigUint;
-//! use std::num::{Zero, One};
+//! use num::{BigUint, Zero, One};
 //! use std::mem::replace;
 //!
 //! // Calculate large fibonacci numbers.
@@ -61,14 +60,14 @@ use rand::Rng;
 
 use std::{cmp, fmt, hash};
 use std::default::Default;
-use std::from_str::FromStr;
-use std::num::CheckedDiv;
-use std::num::{ToPrimitive, FromPrimitive};
-use std::num::{Zero, One, FromStrRadix};
-use std::str;
-use std::string::String;
+use std::iter::{AdditiveIterator, MultiplicativeIterator};
+use std::num::{Int, ToPrimitive, FromPrimitive};
+use std::num::FromStrRadix;
+use std::str::{mod, FromStr};
 use std::{i64, u64};
 
+use {Num, Unsigned, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, Signed, Zero, One};
+
 /// A `BigDigit` is a `BigUint`'s composing element.
 pub type BigDigit = u32;
 
@@ -739,6 +738,20 @@ impl FromStrRadix for BigUint {
     }
 }
 
+impl<T: Iterator<BigUint>> AdditiveIterator<BigUint> for T {
+    fn sum(&mut self) -> BigUint {
+        let init: BigUint = Zero::zero();
+        self.fold(init, |acc, x| acc + x)
+    }
+}
+
+impl<T: Iterator<BigUint>> MultiplicativeIterator<BigUint> for T {
+    fn product(&mut self) -> BigUint {
+        let init: BigUint = One::one();
+        self.fold(init, |acc, x| acc * x)
+    }
+}
+
 impl BigUint {
     /// Creates and initializes a `BigUint`.
     ///
@@ -1084,7 +1097,6 @@ impl CheckedDiv for BigInt {
     }
 }
 
-
 impl Integer for BigInt {
     #[inline]
     fn div_rem(&self, other: &BigInt) -> (BigInt, BigInt) {
@@ -1374,6 +1386,20 @@ impl<R: Rng> RandBigInt for R {
     }
 }
 
+impl<T: Iterator<BigInt>> AdditiveIterator<BigInt> for T {
+    fn sum(&mut self) -> BigInt {
+        let init: BigInt = Zero::zero();
+        self.fold(init, |acc, x| acc + x)
+    }
+}
+
+impl<T: Iterator<BigInt>> MultiplicativeIterator<BigInt> for T {
+    fn product(&mut self) -> BigInt {
+        let init: BigInt = One::one();
+        self.fold(init, |acc, x| acc * x)
+    }
+}
+
 impl BigInt {
     /// Creates and initializes a BigInt.
     ///
@@ -1416,6 +1442,29 @@ impl BigInt {
             Minus => None
         }
     }
+
+    #[inline]
+    pub fn checked_add(&self, v: &BigInt) -> Option<BigInt> {
+        return Some(self.add(v));
+    }
+
+    #[inline]
+    pub fn checked_sub(&self, v: &BigInt) -> Option<BigInt> {
+        return Some(self.sub(v));
+    }
+
+    #[inline]
+    pub fn checked_mul(&self, v: &BigInt) -> Option<BigInt> {
+        return Some(self.mul(v));
+    }
+
+    #[inline]
+    pub fn checked_div(&self, v: &BigInt) -> Option<BigInt> {
+        if v.is_zero() {
+            return None;
+        }
+        return Some(self.div(v));
+    }
 }
 
 #[cfg(test)]
@@ -1425,15 +1474,16 @@ mod biguint_tests {
     use super::{Plus, BigInt, RandBigInt, ToBigInt};
 
     use std::cmp::{Less, Equal, Greater};
-    use std::from_str::FromStr;
+    use std::str::FromStr;
     use std::i64;
-    use std::num::{Zero, One, FromStrRadix};
+    use std::num::FromStrRadix;
     use std::num::{ToPrimitive, FromPrimitive};
-    use std::num::CheckedDiv;
     use std::rand::task_rng;
     use std::u64;
     use std::hash::hash;
 
+    use {Zero, One, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv};
+
     #[test]
     fn test_from_slice() {
         fn check(slice: &[BigDigit], data: &[BigDigit]) {
@@ -2289,13 +2339,14 @@ mod bigint_tests {
 
     use std::cmp::{Less, Equal, Greater};
     use std::i64;
-    use std::num::CheckedDiv;
-    use std::num::{Zero, One, FromStrRadix};
+    use std::num::FromStrRadix;
     use std::num::{ToPrimitive, FromPrimitive};
     use std::rand::task_rng;
     use std::u64;
     use std::hash::hash;
 
+    use {Zero, One, Signed};
+
     #[test]
     fn test_from_biguint() {
         fn check(inp_s: Sign, inp_n: uint, ans_s: Sign, ans_n: uint) {
@@ -2882,7 +2933,9 @@ mod bench {
     use super::BigUint;
     use std::iter;
     use std::mem::replace;
-    use std::num::{FromPrimitive, Zero, One};
+    use std::num::FromPrimitive;
+
+    use {Zero, One};
 
     fn factorial(n: uint) -> BigUint {
         let mut f: BigUint = One::one();

+ 23 - 4
src/complex.rs

@@ -12,7 +12,10 @@
 //! Complex numbers.
 
 use std::fmt;
-use std::num::{Zero, One};
+use std::num::FloatMath;
+use std::iter::{AdditiveIterator, MultiplicativeIterator};
+
+use {Zero, One, Num};
 
 // FIXME #1284: handle complex NaN & infinity etc. This
 // probably doesn't map to C's _Complex correctly.
@@ -80,7 +83,7 @@ impl<T: Clone + FloatMath> Complex<T> {
     }
 }
 
-impl<T: Clone + FloatMath> Complex<T> {
+impl<T: Clone + FloatMath + Num> Complex<T> {
     /// Calculate the principal Arg of self.
     #[inline]
     pub fn arg(&self) -> T {
@@ -172,14 +175,30 @@ impl<T: fmt::Show + Num + PartialOrd> fmt::Show for Complex<T> {
     }
 }
 
+impl<A: Clone + Num, T: Iterator<Complex<A>>> AdditiveIterator<Complex<A>> for T {
+    fn sum(&mut self) -> Complex<A> {
+        let init: Complex<A> = Zero::zero();
+        self.fold(init, |acc, x| acc + x)
+    }
+}
+
+impl<A: Clone + Num, T: Iterator<Complex<A>>> MultiplicativeIterator<Complex<A>> for T {
+    fn product(&mut self) -> Complex<A> {
+        let init: Complex<A> = One::one();
+        self.fold(init, |acc, x| acc * x)
+    }
+}
+
 #[cfg(test)]
 mod test {
     #![allow(non_upper_case_globals)]
 
     use super::{Complex64, Complex};
-    use std::num::{Zero, One, Float};
+    use std::num::Float;
     use std::hash::hash;
 
+    use {Zero, One};
+
     pub const _0_0i : Complex64 = Complex { re: 0.0, im: 0.0 };
     pub const _1_0i : Complex64 = Complex { re: 1.0, im: 0.0 };
     pub const _1_1i : Complex64 = Complex { re: 1.0, im: 1.0 };
@@ -280,7 +299,7 @@ mod test {
 
     mod arith {
         use super::{_0_0i, _1_0i, _1_1i, _0_1i, _neg1_1i, _05_05i, all_consts};
-        use std::num::Zero;
+        use Zero;
 
         #[test]
         fn test_add() {

+ 2 - 0
src/integer.rs

@@ -10,6 +10,8 @@
 
 //! Integer trait and functions.
 
+use {Num, Signed};
+
 pub trait Integer: Num + PartialOrd
                  + Div<Self, Self>
                  + Rem<Self, Self> {

+ 341 - 0
src/iter.rs

@@ -0,0 +1,341 @@
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! External iterators for generic mathematics
+
+use {Integer, Zero, One, CheckedAdd};
+use std::num::Int;
+
+/// An iterator over the range [start, stop)
+#[deriving(Clone)]
+pub struct Range<A> {
+    state: A,
+    stop: A,
+    one: A
+}
+
+/// Returns an iterator over the given range [start, stop) (that is, starting
+/// at start (inclusive), and ending at stop (exclusive)).
+///
+/// # Example
+///
+/// ```rust
+/// let array = [0, 1, 2, 3, 4];
+///
+/// for i in range(0, 5u) {
+///     println!("{}", i);
+///     assert_eq!(i,  array[i]);
+/// }
+/// ```
+#[inline]
+pub fn range<A: Add<A, A> + PartialOrd + Clone + One>(start: A, stop: A) -> Range<A> {
+    Range{state: start, stop: stop, one: One::one()}
+}
+
+// FIXME: rust-lang/rust#10414: Unfortunate type bound
+impl<A: Add<A, A> + PartialOrd + Clone + ToPrimitive> Iterator<A> for Range<A> {
+    #[inline]
+    fn next(&mut self) -> Option<A> {
+        if self.state < self.stop {
+            let result = self.state.clone();
+            self.state = self.state + self.one;
+            Some(result)
+        } else {
+            None
+        }
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (uint, Option<uint>) {
+        // This first checks if the elements are representable as i64. If they aren't, try u64 (to
+        // handle cases like range(huge, huger)). We don't use uint/int because the difference of
+        // the i64/u64 might lie within their range.
+        let bound = match self.state.to_i64() {
+            Some(a) => {
+                let sz = self.stop.to_i64().map(|b| b.checked_sub(a));
+                match sz {
+                    Some(Some(bound)) => bound.to_uint(),
+                    _ => None,
+                }
+            },
+            None => match self.state.to_u64() {
+                Some(a) => {
+                    let sz = self.stop.to_u64().map(|b| b.checked_sub(a));
+                    match sz {
+                        Some(Some(bound)) => bound.to_uint(),
+                        _ => None
+                    }
+                },
+                None => None
+            }
+        };
+
+        match bound {
+            Some(b) => (b, Some(b)),
+            // Standard fallback for unbounded/unrepresentable bounds
+            None => (0, None)
+        }
+    }
+}
+
+/// `Integer` is required to ensure the range will be the same regardless of
+/// the direction it is consumed.
+impl<A: Integer + PartialOrd + Clone + ToPrimitive> DoubleEndedIterator<A> for Range<A> {
+    #[inline]
+    fn next_back(&mut self) -> Option<A> {
+        if self.stop > self.state {
+            self.stop = self.stop - self.one;
+            Some(self.stop.clone())
+        } else {
+            None
+        }
+    }
+}
+
+/// An iterator over the range [start, stop]
+#[deriving(Clone)]
+pub struct RangeInclusive<A> {
+    range: Range<A>,
+    done: bool,
+}
+
+/// Return an iterator over the range [start, stop]
+#[inline]
+pub fn range_inclusive<A: Add<A, A> + PartialOrd + Clone + One>(start: A, stop: A)
+    -> RangeInclusive<A> {
+    RangeInclusive{range: range(start, stop), done: false}
+}
+
+impl<A: Add<A, A> + PartialOrd + Clone + ToPrimitive> Iterator<A> for RangeInclusive<A> {
+    #[inline]
+    fn next(&mut self) -> Option<A> {
+        match self.range.next() {
+            Some(x) => Some(x),
+            None => {
+                if !self.done && self.range.state == self.range.stop {
+                    self.done = true;
+                    Some(self.range.stop.clone())
+                } else {
+                    None
+                }
+            }
+        }
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (uint, Option<uint>) {
+        let (lo, hi) = self.range.size_hint();
+        if self.done {
+            (lo, hi)
+        } else {
+            let lo = lo.saturating_add(1);
+            let hi = match hi {
+                Some(x) => x.checked_add(1),
+                None => None
+            };
+            (lo, hi)
+        }
+    }
+}
+
+impl<A: Sub<A, A> + Integer + PartialOrd + Clone + ToPrimitive> DoubleEndedIterator<A>
+    for RangeInclusive<A> {
+    #[inline]
+    fn next_back(&mut self) -> Option<A> {
+        if self.range.stop > self.range.state {
+            let result = self.range.stop.clone();
+            self.range.stop = self.range.stop - self.range.one;
+            Some(result)
+        } else if !self.done && self.range.state == self.range.stop {
+            self.done = true;
+            Some(self.range.stop.clone())
+        } else {
+            None
+        }
+    }
+}
+
+/// An iterator over the range [start, stop) by `step`. It handles overflow by stopping.
+#[deriving(Clone)]
+pub struct RangeStep<A> {
+    state: A,
+    stop: A,
+    step: A,
+    rev: bool,
+}
+
+/// Return an iterator over the range [start, stop) by `step`. It handles overflow by stopping.
+#[inline]
+pub fn range_step<A: CheckedAdd + PartialOrd +
+                  Clone + Zero>(start: A, stop: A, step: A) -> RangeStep<A> {
+    let rev = step < Zero::zero();
+    RangeStep{state: start, stop: stop, step: step, rev: rev}
+}
+
+impl<A: CheckedAdd + PartialOrd + Clone> Iterator<A> for RangeStep<A> {
+    #[inline]
+    fn next(&mut self) -> Option<A> {
+        if (self.rev && self.state > self.stop) || (!self.rev && self.state < self.stop) {
+            let result = self.state.clone();
+            match self.state.checked_add(&self.step) {
+                Some(x) => self.state = x,
+                None => self.state = self.stop.clone()
+            }
+            Some(result)
+        } else {
+            None
+        }
+    }
+}
+
+/// An iterator over the range [start, stop] by `step`. It handles overflow by stopping.
+#[deriving(Clone)]
+pub struct RangeStepInclusive<A> {
+    state: A,
+    stop: A,
+    step: A,
+    rev: bool,
+    done: bool,
+}
+
+/// Return an iterator over the range [start, stop] by `step`. It handles overflow by stopping.
+#[inline]
+pub fn range_step_inclusive<A: CheckedAdd + PartialOrd + Clone + Zero>(start: A, stop: A,
+                                                                step: A) -> RangeStepInclusive<A> {
+    let rev = step < Zero::zero();
+    RangeStepInclusive{state: start, stop: stop, step: step, rev: rev, done: false}
+}
+
+impl<A: CheckedAdd + PartialOrd + Clone + PartialEq> Iterator<A> for RangeStepInclusive<A> {
+    #[inline]
+    fn next(&mut self) -> Option<A> {
+        if !self.done && ((self.rev && self.state >= self.stop) ||
+                          (!self.rev && self.state <= self.stop)) {
+            let result = self.state.clone();
+            match self.state.checked_add(&self.step) {
+                Some(x) => self.state = x,
+                None => self.done = true
+            }
+            Some(result)
+        } else {
+            None
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::uint;
+    use One;
+
+    #[test]
+    fn test_range() {
+        /// A mock type to check Range when ToPrimitive returns None
+        struct Foo;
+
+        impl ToPrimitive for Foo {
+            fn to_i64(&self) -> Option<i64> { None }
+            fn to_u64(&self) -> Option<u64> { None }
+        }
+
+        impl Add<Foo, Foo> for Foo {
+            fn add(&self, _: &Foo) -> Foo {
+                Foo
+            }
+        }
+
+        impl PartialEq for Foo {
+            fn eq(&self, _: &Foo) -> bool {
+                true
+            }
+        }
+
+        impl PartialOrd for Foo {
+            fn partial_cmp(&self, _: &Foo) -> Option<Ordering> {
+                None
+            }
+        }
+
+        impl Clone for Foo {
+            fn clone(&self) -> Foo {
+                Foo
+            }
+        }
+
+        impl Mul<Foo, Foo> for Foo {
+            fn mul(&self, _: &Foo) -> Foo {
+                Foo
+            }
+        }
+
+        impl One for Foo {
+            fn one() -> Foo {
+                Foo
+            }
+        }
+
+        assert!(super::range(0i, 5).collect::<Vec<int>>() == vec![0i, 1, 2, 3, 4]);
+        assert!(super::range(-10i, -1).collect::<Vec<int>>() ==
+                vec![-10, -9, -8, -7, -6, -5, -4, -3, -2]);
+        assert!(super::range(0i, 5).rev().collect::<Vec<int>>() == vec![4, 3, 2, 1, 0]);
+        assert_eq!(super::range(200i, -5).count(), 0);
+        assert_eq!(super::range(200i, -5).rev().count(), 0);
+        assert_eq!(super::range(200i, 200).count(), 0);
+        assert_eq!(super::range(200i, 200).rev().count(), 0);
+
+        assert_eq!(super::range(0i, 100).size_hint(), (100, Some(100)));
+        // this test is only meaningful when sizeof uint < sizeof u64
+        assert_eq!(super::range(uint::MAX - 1, uint::MAX).size_hint(), (1, Some(1)));
+        assert_eq!(super::range(-10i, -1).size_hint(), (9, Some(9)));
+        assert_eq!(super::range(Foo, Foo).size_hint(), (0, None));
+    }
+
+    #[test]
+    fn test_range_inclusive() {
+        assert!(super::range_inclusive(0i, 5).collect::<Vec<int>>() ==
+                vec![0i, 1, 2, 3, 4, 5]);
+        assert!(super::range_inclusive(0i, 5).rev().collect::<Vec<int>>() ==
+                vec![5i, 4, 3, 2, 1, 0]);
+        assert_eq!(super::range_inclusive(200i, -5).count(), 0);
+        assert_eq!(super::range_inclusive(200i, -5).rev().count(), 0);
+        assert!(super::range_inclusive(200i, 200).collect::<Vec<int>>() == vec![200]);
+        assert!(super::range_inclusive(200i, 200).rev().collect::<Vec<int>>() == vec![200]);
+    }
+
+    #[test]
+    fn test_range_step() {
+        assert!(super::range_step(0i, 20, 5).collect::<Vec<int>>() ==
+                vec![0, 5, 10, 15]);
+        assert!(super::range_step(20i, 0, -5).collect::<Vec<int>>() ==
+                vec![20, 15, 10, 5]);
+        assert!(super::range_step(20i, 0, -6).collect::<Vec<int>>() ==
+                vec![20, 14, 8, 2]);
+        assert!(super::range_step(200u8, 255, 50).collect::<Vec<u8>>() ==
+                vec![200u8, 250]);
+        assert!(super::range_step(200i, -5, 1).collect::<Vec<int>>() == vec![]);
+        assert!(super::range_step(200i, 200, 1).collect::<Vec<int>>() == vec![]);
+    }
+
+    #[test]
+    fn test_range_step_inclusive() {
+        assert!(super::range_step_inclusive(0i, 20, 5).collect::<Vec<int>>() ==
+                vec![0, 5, 10, 15, 20]);
+        assert!(super::range_step_inclusive(20i, 0, -5).collect::<Vec<int>>() ==
+                vec![20, 15, 10, 5, 0]);
+        assert!(super::range_step_inclusive(20i, 0, -6).collect::<Vec<int>>() ==
+                vec![20, 14, 8, 2]);
+        assert!(super::range_step_inclusive(200u8, 255, 50).collect::<Vec<u8>>() ==
+                vec![200u8, 250]);
+        assert!(super::range_step_inclusive(200i, -5, 1).collect::<Vec<int>>() ==
+                vec![]);
+        assert!(super::range_step_inclusive(200i, 200, 1).collect::<Vec<int>>() ==
+                vec![200]);
+    }
+}

+ 70 - 0
src/lib.rs

@@ -64,8 +64,78 @@ pub use bigint::{BigInt, BigUint};
 pub use rational::{Rational, BigRational};
 pub use complex::Complex;
 pub use integer::Integer;
+pub use iter::{range, range_inclusive, range_step, range_step_inclusive};
+pub use traits::{Num, Zero, One, Signed, Unsigned, Bounded,
+                 Saturating, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv};
 
 pub mod bigint;
 pub mod complex;
 pub mod integer;
+pub mod iter;
+pub mod traits;
 pub mod rational;
+
+/// Returns the additive identity, `0`.
+#[inline(always)] pub fn zero<T: Zero>() -> T { Zero::zero() }
+
+/// Returns the multiplicative identity, `1`.
+#[inline(always)] pub fn one<T: One>() -> T { One::one() }
+
+/// Computes the absolute value.
+///
+/// For `f32` and `f64`, `NaN` will be returned if the number is `NaN`
+///
+/// For signed integers, `::MIN` will be returned if the number is `::MIN`.
+#[inline(always)]
+pub fn abs<T: Signed>(value: T) -> T {
+    value.abs()
+}
+
+/// The positive difference of two numbers.
+///
+/// Returns zero if `x` is less than or equal to `y`, otherwise the difference
+/// between `x` and `y` is returned.
+#[inline(always)]
+pub fn abs_sub<T: Signed>(x: T, y: T) -> T {
+    x.abs_sub(&y)
+}
+
+/// Returns the sign of the number.
+///
+/// For `f32` and `f64`:
+///
+/// * `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`
+///
+/// For signed integers:
+///
+/// * `0` if the number is zero
+/// * `1` if the number is positive
+/// * `-1` if the number is negative
+#[inline(always)] pub fn signum<T: Signed>(value: T) -> T { value.signum() }
+
+/// Raises a value to the power of exp, using exponentiation by squaring.
+///
+/// # Example
+///
+/// ```rust
+/// use num;
+///
+/// assert_eq!(num::pow(2i, 4), 16);
+/// ```
+#[inline]
+pub fn pow<T: One + Mul<T, T>>(mut base: T, mut exp: uint) -> T {
+    if exp == 1 { base }
+    else {
+        let mut acc = one::<T>();
+        while exp > 0 {
+            if (exp & 1) == 1 {
+                acc = acc * base;
+            }
+            base = base * base;
+            exp = exp >> 1;
+        }
+        acc
+    }
+}

+ 27 - 11
src/rational.rs

@@ -14,11 +14,12 @@ use Integer;
 
 use std::cmp;
 use std::fmt;
-use std::from_str::FromStr;
-use std::num;
-use std::num::{Zero, One, FromStrRadix};
+use std::str::FromStr;
+use std::num::{FromStrRadix, Float};
+use std::iter::{AdditiveIterator, MultiplicativeIterator};
 
 use bigint::{BigInt, BigUint, Sign, Plus, Minus};
+use {Num, Signed, Zero, One};
 
 /// Represents the ratio between 2 numbers.
 #[deriving(Clone, Hash, Encodable, Decodable)]
@@ -303,7 +304,7 @@ impl<T: Clone + Integer + PartialOrd>
     Num for Ratio<T> {}
 
 impl<T: Clone + Integer + PartialOrd>
-    num::Signed for Ratio<T> {
+    Signed for Ratio<T> {
     #[inline]
     fn abs(&self) -> Ratio<T> {
         if self.is_negative() { -self.clone() } else { self.clone() }
@@ -317,11 +318,11 @@ impl<T: Clone + Integer + PartialOrd>
     #[inline]
     fn signum(&self) -> Ratio<T> {
         if *self > Zero::zero() {
-            num::one()
+            One::one()
         } else if self.is_zero() {
-            num::zero()
+            Zero::zero()
         } else {
-            - num::one::<Ratio<T>>()
+            - ::one::<Ratio<T>>()
         }
     }
 
@@ -382,15 +383,30 @@ impl<T: FromStrRadix + Clone + Integer + PartialOrd>
     }
 }
 
+impl<A: Clone + Integer + PartialOrd, T: Iterator<Ratio<A>>> AdditiveIterator<Ratio<A>> for T {
+    fn sum(&mut self) -> Ratio<A> {
+        let init: Ratio<A> = Zero::zero();
+        self.fold(init, |acc, x| acc + x)
+    }
+}
+
+impl<A: Clone + Integer + PartialOrd, T: Iterator<Ratio<A>>> MultiplicativeIterator<Ratio<A>> for T {
+    fn product(&mut self) -> Ratio<A> {
+        let init: Ratio<A> = One::one();
+        self.fold(init, |acc, x| acc * x)
+    }
+}
+
+
 #[cfg(test)]
 mod test {
 
     use super::{Ratio, Rational, BigRational};
-    use std::num::{Zero, One, FromPrimitive};
-    use std::from_str::FromStr;
+    use std::num::{FromPrimitive, Float};
+    use std::str::FromStr;
     use std::hash::hash;
-    use std::num;
     use std::i32;
+    use {Zero, One, Signed};
 
     pub const _0 : Rational = Ratio { numer: 0, denom: 1};
     pub const _1 : Rational = Ratio { numer: 1, denom: 1};
@@ -735,7 +751,7 @@ mod test {
         assert_eq!(_3_2.abs_sub(&_1_2), _1);
         assert_eq!(_1_2.abs_sub(&_3_2), Zero::zero());
         assert_eq!(_1_2.signum(), One::one());
-        assert_eq!(_NEG1_2.signum(), - num::one::<Ratio<int>>());
+        assert_eq!(_NEG1_2.signum(), - ::one::<Ratio<int>>());
         assert!(_NEG1_2.is_negative());
         assert!(! _NEG1_2.is_positive());
         assert!(! _1_2.is_negative());

+ 514 - 0
src/traits.rs

@@ -0,0 +1,514 @@
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Numeric traits for generic mathematics
+
+use std::intrinsics;
+use std::{uint, u8, u16, u32, u64};
+use std::{int, i8, i16, i32, i64};
+use std::{f32, f64};
+
+/// The base trait for numeric types
+pub trait Num: PartialEq + Zero + One
+             + Neg<Self>
+             + Add<Self,Self>
+             + Sub<Self,Self>
+             + Mul<Self,Self>
+             + Div<Self,Self>
+             + Rem<Self,Self> {}
+
+macro_rules! trait_impl(
+    ($name:ident for $($t:ty)*) => ($(
+        impl $name for $t {}
+    )*)
+)
+
+trait_impl!(Num for uint u8 u16 u32 u64 int i8 i16 i32 i64 f32 f64)
+
+/// Defines an additive identity element for `Self`.
+///
+/// # Deriving
+///
+/// This trait can be automatically be derived using `#[deriving(Zero)]`
+/// attribute. If you choose to use this, make sure that the laws outlined in
+/// the documentation for `Zero::zero` still hold.
+pub trait Zero: Add<Self, Self> {
+    /// Returns the additive identity element of `Self`, `0`.
+    ///
+    /// # Laws
+    ///
+    /// ```{.text}
+    /// a + 0 = a       ∀ a ∈ Self
+    /// 0 + a = a       ∀ a ∈ Self
+    /// ```
+    ///
+    /// # Purity
+    ///
+    /// This function should return the same result at all times regardless of
+    /// external mutable state, for example values stored in TLS or in
+    /// `static mut`s.
+    // FIXME (#5527): This should be an associated constant
+    fn zero() -> Self;
+
+    /// Returns `true` if `self` is equal to the additive identity.
+    #[inline]
+    fn is_zero(&self) -> bool;
+}
+
+macro_rules! zero_impl(
+    ($t:ty, $v:expr) => {
+        impl Zero for $t {
+            #[inline]
+            fn zero() -> $t { $v }
+            #[inline]
+            fn is_zero(&self) -> bool { *self == $v }
+        }
+    }
+)
+
+zero_impl!(uint, 0u)
+zero_impl!(u8,   0u8)
+zero_impl!(u16,  0u16)
+zero_impl!(u32,  0u32)
+zero_impl!(u64,  0u64)
+
+zero_impl!(int, 0i)
+zero_impl!(i8,  0i8)
+zero_impl!(i16, 0i16)
+zero_impl!(i32, 0i32)
+zero_impl!(i64, 0i64)
+
+zero_impl!(f32, 0.0f32)
+zero_impl!(f64, 0.0f64)
+
+/// Defines a multiplicative identity element for `Self`.
+pub trait One: Mul<Self, Self> {
+    /// Returns the multiplicative identity element of `Self`, `1`.
+    ///
+    /// # Laws
+    ///
+    /// ```{.text}
+    /// a * 1 = a       ∀ a ∈ Self
+    /// 1 * a = a       ∀ a ∈ Self
+    /// ```
+    ///
+    /// # Purity
+    ///
+    /// This function should return the same result at all times regardless of
+    /// external mutable state, for example values stored in TLS or in
+    /// `static mut`s.
+    // FIXME (#5527): This should be an associated constant
+    fn one() -> Self;
+}
+
+macro_rules! one_impl(
+    ($t:ty, $v:expr) => {
+        impl One for $t {
+            #[inline]
+            fn one() -> $t { $v }
+        }
+    }
+)
+
+one_impl!(uint, 1u)
+one_impl!(u8,  1u8)
+one_impl!(u16, 1u16)
+one_impl!(u32, 1u32)
+one_impl!(u64, 1u64)
+
+one_impl!(int, 1i)
+one_impl!(i8,  1i8)
+one_impl!(i16, 1i16)
+one_impl!(i32, 1i32)
+one_impl!(i64, 1i64)
+
+one_impl!(f32, 1.0f32)
+one_impl!(f64, 1.0f64)
+
+/// Useful functions for signed numbers (i.e. numbers that can be negative).
+pub trait Signed: Num + Neg<Self> {
+    /// Computes the absolute value.
+    ///
+    /// For `f32` and `f64`, `NaN` will be returned if the number is `NaN`.
+    ///
+    /// For signed integers, `::MIN` will be returned if the number is `::MIN`.
+    fn abs(&self) -> Self;
+
+    /// The positive difference of two numbers.
+    ///
+    /// Returns `zero` if the number is less than or equal to `other`, otherwise the difference
+    /// between `self` and `other` is returned.
+    fn abs_sub(&self, other: &Self) -> Self;
+
+    /// Returns the sign of the number.
+    ///
+    /// For `f32` and `f64`:
+    ///
+    /// * `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`
+    ///
+    /// For signed integers:
+    ///
+    /// * `0` if the number is zero
+    /// * `1` if the number is positive
+    /// * `-1` if the number is negative
+    fn signum(&self) -> Self;
+
+    /// Returns true if the number is positive and false if the number is zero or negative.
+    fn is_positive(&self) -> bool;
+
+    /// Returns true if the number is negative and false if the number is zero or positive.
+    fn is_negative(&self) -> bool;
+}
+
+macro_rules! signed_impl(
+    ($($t:ty)*) => ($(
+        impl Signed for $t {
+            #[inline]
+            fn abs(&self) -> $t {
+                if self.is_negative() { -*self } else { *self }
+            }
+
+            #[inline]
+            fn abs_sub(&self, other: &$t) -> $t {
+                if *self <= *other { 0 } else { *self - *other }
+            }
+
+            #[inline]
+            fn signum(&self) -> $t {
+                match *self {
+                    n if n > 0 => 1,
+                    0 => 0,
+                    _ => -1,
+                }
+            }
+
+            #[inline]
+            fn is_positive(&self) -> bool { *self > 0 }
+
+            #[inline]
+            fn is_negative(&self) -> bool { *self < 0 }
+        }
+    )*)
+)
+
+signed_impl!(int i8 i16 i32 i64)
+
+macro_rules! signed_float_impl(
+    ($t:ty, $nan:expr, $inf:expr, $neg_inf:expr, $fabs:path, $fcopysign:path, $fdim:ident) => {
+        impl Signed for $t {
+            /// Computes the absolute value. Returns `NAN` if the number is `NAN`.
+            #[inline]
+            fn abs(&self) -> $t {
+                unsafe { $fabs(*self) }
+            }
+
+            /// The positive difference of two numbers. Returns `0.0` if the number is
+            /// less than or equal to `other`, otherwise the difference between`self`
+            /// and `other` is returned.
+            #[inline]
+            fn abs_sub(&self, other: &$t) -> $t {
+                extern { fn $fdim(a: $t, b: $t) -> $t; }
+                unsafe { $fdim(*self, *other) }
+            }
+
+            /// # 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]
+            fn signum(&self) -> $t {
+                if self != self { $nan } else {
+                    unsafe { $fcopysign(1.0, *self) }
+                }
+            }
+
+            /// Returns `true` if the number is positive, including `+0.0` and `INFINITY`
+            #[inline]
+            fn is_positive(&self) -> bool { *self > 0.0 || (1.0 / *self) == $inf }
+
+            /// Returns `true` if the number is negative, including `-0.0` and `NEG_INFINITY`
+            #[inline]
+            fn is_negative(&self) -> bool { *self < 0.0 || (1.0 / *self) == $neg_inf }
+        }
+    }
+)
+
+signed_float_impl!(f32, f32::NAN, f32::INFINITY, f32::NEG_INFINITY,
+                   intrinsics::fabsf32, intrinsics::copysignf32, fdimf)
+signed_float_impl!(f64, f64::NAN, f64::INFINITY, f64::NEG_INFINITY,
+                   intrinsics::fabsf64, intrinsics::copysignf64, fdim)
+
+/// A trait for values which cannot be negative
+pub trait Unsigned: Num {}
+
+trait_impl!(Unsigned for uint u8 u16 u32 u64)
+
+/// Numbers which have upper and lower bounds
+pub trait Bounded {
+    // FIXME (#5527): These should be associated constants
+    /// returns the smallest finite number this type can represent
+    fn min_value() -> Self;
+    /// returns the largest finite number this type can represent
+    fn max_value() -> Self;
+}
+
+macro_rules! bounded_impl(
+    ($t:ty, $min:expr, $max:expr) => {
+        impl Bounded for $t {
+            #[inline]
+            fn min_value() -> $t { $min }
+
+            #[inline]
+            fn max_value() -> $t { $max }
+        }
+    }
+)
+
+bounded_impl!(uint, uint::MIN, uint::MAX)
+bounded_impl!(u8, u8::MIN, u8::MAX)
+bounded_impl!(u16, u16::MIN, u16::MAX)
+bounded_impl!(u32, u32::MIN, u32::MAX)
+bounded_impl!(u64, u64::MIN, u64::MAX)
+
+bounded_impl!(int, int::MIN, int::MAX)
+bounded_impl!(i8, i8::MIN, i8::MAX)
+bounded_impl!(i16, i16::MIN, i16::MAX)
+bounded_impl!(i32, i32::MIN, i32::MAX)
+bounded_impl!(i64, i64::MIN, i64::MAX)
+
+bounded_impl!(f32, f32::MIN_VALUE, f32::MAX_VALUE)
+bounded_impl!(f64, f64::MIN_VALUE, f64::MAX_VALUE)
+
+/// Saturating math operations
+pub trait Saturating {
+    /// Saturating addition operator.
+    /// Returns a+b, saturating at the numeric bounds instead of overflowing.
+    fn saturating_add(self, v: Self) -> Self;
+
+    /// Saturating subtraction operator.
+    /// Returns a-b, saturating at the numeric bounds instead of overflowing.
+    fn saturating_sub(self, v: Self) -> Self;
+}
+
+impl<T: CheckedAdd + CheckedSub + Zero + PartialOrd + Bounded> Saturating for T {
+    #[inline]
+    fn saturating_add(self, v: T) -> T {
+        match self.checked_add(&v) {
+            Some(x) => x,
+            None => if v >= Zero::zero() {
+                Bounded::max_value()
+            } else {
+                Bounded::min_value()
+            }
+        }
+    }
+
+    #[inline]
+    fn saturating_sub(self, v: T) -> T {
+        match self.checked_sub(&v) {
+            Some(x) => x,
+            None => if v >= Zero::zero() {
+                Bounded::min_value()
+            } else {
+                Bounded::max_value()
+            }
+        }
+    }
+}
+
+/// Performs addition that returns `None` instead of wrapping around on overflow.
+pub trait CheckedAdd: Add<Self, Self> {
+    /// Adds two numbers, checking for overflow. If overflow happens, `None` is returned.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// use num::CheckedAdd;
+    /// assert_eq!(5u16.checked_add(&65530), Some(65535));
+    /// assert_eq!(6u16.checked_add(&65530), None);
+    /// ```
+    fn checked_add(&self, v: &Self) -> Option<Self>;
+}
+
+macro_rules! checked_impl(
+    ($trait_name:ident, $method:ident, $t:ty, $op:path) => {
+        impl $trait_name for $t {
+            #[inline]
+            fn $method(&self, v: &$t) -> Option<$t> {
+                unsafe {
+                    let (x, y) = $op(*self, *v);
+                    if y { None } else { Some(x) }
+                }
+            }
+        }
+    }
+)
+macro_rules! checked_cast_impl(
+    ($trait_name:ident, $method:ident, $t:ty, $cast:ty, $op:path) => {
+        impl $trait_name for $t {
+            #[inline]
+            fn $method(&self, v: &$t) -> Option<$t> {
+                unsafe {
+                    let (x, y) = $op(*self as $cast, *v as $cast);
+                    if y { None } else { Some(x as $t) }
+                }
+            }
+        }
+    }
+)
+
+#[cfg(target_word_size = "32")]
+checked_cast_impl!(CheckedAdd, checked_add, uint, u32, intrinsics::u32_add_with_overflow)
+#[cfg(target_word_size = "64")]
+checked_cast_impl!(CheckedAdd, checked_add, uint, u64, intrinsics::u64_add_with_overflow)
+
+checked_impl!(CheckedAdd, checked_add, u8,  intrinsics::u8_add_with_overflow)
+checked_impl!(CheckedAdd, checked_add, u16, intrinsics::u16_add_with_overflow)
+checked_impl!(CheckedAdd, checked_add, u32, intrinsics::u32_add_with_overflow)
+checked_impl!(CheckedAdd, checked_add, u64, intrinsics::u64_add_with_overflow)
+
+#[cfg(target_word_size = "32")]
+checked_cast_impl!(CheckedAdd, checked_add, int, i32, intrinsics::i32_add_with_overflow)
+#[cfg(target_word_size = "64")]
+checked_cast_impl!(CheckedAdd, checked_add, int, i64, intrinsics::i64_add_with_overflow)
+
+checked_impl!(CheckedAdd, checked_add, i8,  intrinsics::i8_add_with_overflow)
+checked_impl!(CheckedAdd, checked_add, i16, intrinsics::i16_add_with_overflow)
+checked_impl!(CheckedAdd, checked_add, i32, intrinsics::i32_add_with_overflow)
+checked_impl!(CheckedAdd, checked_add, i64, intrinsics::i64_add_with_overflow)
+
+/// Performs subtraction that returns `None` instead of wrapping around on underflow.
+pub trait CheckedSub: Sub<Self, Self> {
+    /// Subtracts two numbers, checking for underflow. If underflow happens, `None` is returned.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// use num::CheckedSub;
+    /// assert_eq!((-127i8).checked_sub(&1), Some(-128));
+    /// assert_eq!((-128i8).checked_sub(&1), None);
+    /// ```
+    fn checked_sub(&self, v: &Self) -> Option<Self>;
+}
+
+#[cfg(target_word_size = "32")]
+checked_cast_impl!(CheckedSub, checked_sub, uint, u32, intrinsics::u32_sub_with_overflow)
+#[cfg(target_word_size = "64")]
+checked_cast_impl!(CheckedSub, checked_sub, uint, u64, intrinsics::u64_sub_with_overflow)
+
+checked_impl!(CheckedSub, checked_sub, u8,  intrinsics::u8_sub_with_overflow)
+checked_impl!(CheckedSub, checked_sub, u16, intrinsics::u16_sub_with_overflow)
+checked_impl!(CheckedSub, checked_sub, u32, intrinsics::u32_sub_with_overflow)
+checked_impl!(CheckedSub, checked_sub, u64, intrinsics::u64_sub_with_overflow)
+
+#[cfg(target_word_size = "32")]
+checked_cast_impl!(CheckedSub, checked_sub, int, i32, intrinsics::i32_sub_with_overflow)
+#[cfg(target_word_size = "64")]
+checked_cast_impl!(CheckedSub, checked_sub, int, i64, intrinsics::i64_sub_with_overflow)
+
+checked_impl!(CheckedSub, checked_sub, i8,  intrinsics::i8_sub_with_overflow)
+checked_impl!(CheckedSub, checked_sub, i16, intrinsics::i16_sub_with_overflow)
+checked_impl!(CheckedSub, checked_sub, i32, intrinsics::i32_sub_with_overflow)
+checked_impl!(CheckedSub, checked_sub, i64, intrinsics::i64_sub_with_overflow)
+
+/// Performs multiplication that returns `None` instead of wrapping around on underflow or
+/// overflow.
+pub trait CheckedMul: Mul<Self, Self> {
+    /// Multiplies two numbers, checking for underflow or overflow. If underflow or overflow
+    /// happens, `None` is returned.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// use num::CheckedMul;
+    /// assert_eq!(5u8.checked_mul(&51), Some(255));
+    /// assert_eq!(5u8.checked_mul(&52), None);
+    /// ```
+    fn checked_mul(&self, v: &Self) -> Option<Self>;
+}
+
+#[cfg(target_word_size = "32")]
+checked_cast_impl!(CheckedMul, checked_mul, uint, u32, intrinsics::u32_mul_with_overflow)
+#[cfg(target_word_size = "64")]
+checked_cast_impl!(CheckedMul, checked_mul, uint, u64, intrinsics::u64_mul_with_overflow)
+
+checked_impl!(CheckedMul, checked_mul, u8,  intrinsics::u8_mul_with_overflow)
+checked_impl!(CheckedMul, checked_mul, u16, intrinsics::u16_mul_with_overflow)
+checked_impl!(CheckedMul, checked_mul, u32, intrinsics::u32_mul_with_overflow)
+checked_impl!(CheckedMul, checked_mul, u64, intrinsics::u64_mul_with_overflow)
+
+#[cfg(target_word_size = "32")]
+checked_cast_impl!(CheckedMul, checked_mul, int, i32, intrinsics::i32_mul_with_overflow)
+#[cfg(target_word_size = "64")]
+checked_cast_impl!(CheckedMul, checked_mul, int, i64, intrinsics::i64_mul_with_overflow)
+
+checked_impl!(CheckedMul, checked_mul, i8,  intrinsics::i8_mul_with_overflow)
+checked_impl!(CheckedMul, checked_mul, i16, intrinsics::i16_mul_with_overflow)
+checked_impl!(CheckedMul, checked_mul, i32, intrinsics::i32_mul_with_overflow)
+checked_impl!(CheckedMul, checked_mul, i64, intrinsics::i64_mul_with_overflow)
+
+/// Performs division that returns `None` instead of panicking on division by zero and instead of
+/// wrapping around on underflow and overflow.
+pub trait CheckedDiv: Div<Self, Self> {
+    /// Divides two numbers, checking for underflow, overflow and division by zero. If any of that
+    /// happens, `None` is returned.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// use num::CheckedDiv;
+    /// assert_eq!((-127i8).checked_div(&-1), Some(127));
+    /// assert_eq!((-128i8).checked_div(&-1), None);
+    /// assert_eq!((1i8).checked_div(&0), None);
+    /// ```
+    fn checked_div(&self, v: &Self) -> Option<Self>;
+}
+
+macro_rules! checkeddiv_int_impl(
+    ($t:ty, $min:expr) => {
+        impl CheckedDiv for $t {
+            #[inline]
+            fn checked_div(&self, v: &$t) -> Option<$t> {
+                if *v == 0 || (*self == $min && *v == -1) {
+                    None
+                } else {
+                    Some(*self / *v)
+                }
+            }
+        }
+    }
+)
+
+checkeddiv_int_impl!(int, int::MIN)
+checkeddiv_int_impl!(i8, i8::MIN)
+checkeddiv_int_impl!(i16, i16::MIN)
+checkeddiv_int_impl!(i32, i32::MIN)
+checkeddiv_int_impl!(i64, i64::MIN)
+
+macro_rules! checkeddiv_uint_impl(
+    ($($t:ty)*) => ($(
+        impl CheckedDiv for $t {
+            #[inline]
+            fn checked_div(&self, v: &$t) -> Option<$t> {
+                if *v == 0 {
+                    None
+                } else {
+                    Some(*self / *v)
+                }
+            }
+        }
+    )*)
+)
+
+checkeddiv_uint_impl!(uint u8 u16 u32 u64)
+