Merge pull request #30 from gifnksm/master

Add numeric functions and traits that provide numeric traits for generic mathematics.
This commit is contained in:
Alex Crichton 2014-11-17 10:25:35 -06:00
commit c0df55e470
8 changed files with 1047 additions and 35 deletions

View File

@ -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,

View File

@ -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();

View File

@ -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() {

View File

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

341
src/iter.rs Normal file
View File

@ -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]);
}
}

View File

@ -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
}
}

View File

@ -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
src/traits.rs Normal file
View File

@ -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)