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
This commit is contained in:
gifnksm 2014-11-15 12:30:48 +09:00
parent aec75185e5
commit 2155e7d2ee
7 changed files with 699 additions and 28 deletions

View File

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

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

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> {

View File

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

View File

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