Browse Source

Add numeric functions and `traits` module that provide numeric traits for generic
mathematcs.

Import numeric traits and functions that were removed from the standard library.
This also implements `AdditiveIterator` and `MultiplicativeIterator` for
`BigUint` and `BigInt`.

closes #28

gifnksm 10 years ago
parent
commit
2155e7d2ee
7 changed files with 699 additions and 28 deletions
  1. 1 4
      benches/shootout-pidigits.rs
  2. 66 11
      src/bigint.rs
  3. 23 4
      src/complex.rs
  4. 2 0
      src/integer.rs
  5. 68 0
      src/lib.rs
  6. 25 9
      src/rational.rs
  7. 514 0
      src/traits.rs

+ 1 - 4
benches/shootout-pidigits.rs

@@ -42,14 +42,11 @@ extern crate num;
 extern crate test;
 
 use std::from_str::FromStr;
-use std::num::One;
-use std::num::Zero;
 use std::num::FromPrimitive;
 
 use test::Bencher;
 
-use num::Integer;
-use num::bigint::BigInt;
+use num::{BigInt, Integer, One, Zero};
 
 struct Context {
     numer: BigInt,

+ 66 - 11
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.
@@ -62,13 +61,15 @@ 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::iter::{AdditiveIterator, MultiplicativeIterator};
+use std::num::{Int, ToPrimitive, FromPrimitive};
+use std::num::FromStrRadix;
 use std::str;
 use std::string::String;
 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 +740,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 +1099,6 @@ impl CheckedDiv for BigInt {
     }
 }
 
-
 impl Integer for BigInt {
     #[inline]
     fn div_rem(&self, other: &BigInt) -> (BigInt, BigInt) {
@@ -1374,6 +1388,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 +1444,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)]
@@ -1427,13 +1478,14 @@ mod biguint_tests {
     use std::cmp::{Less, Equal, Greater};
     use std::from_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 +2341,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 +2935,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> {

+ 68 - 0
src/lib.rs

@@ -64,8 +64,76 @@ pub use bigint::{BigInt, BigUint};
 pub use rational::{Rational, BigRational};
 pub use complex::Complex;
 pub use integer::Integer;
+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 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
+    }
+}

+ 25 - 9
src/rational.rs

@@ -15,10 +15,11 @@ use Integer;
 use std::cmp;
 use std::fmt;
 use std::from_str::FromStr;
-use std::num;
-use std::num::{Zero, One, FromStrRadix};
+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::num::{FromPrimitive, Float};
     use std::from_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)
+