From 2155e7d2eef98f913aa9efbaa1f0dcee719e6887 Mon Sep 17 00:00:00 2001 From: gifnksm Date: Sat, 15 Nov 2014 12:30:48 +0900 Subject: [PATCH] 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 --- benches/shootout-pidigits.rs | 5 +- src/bigint.rs | 77 +++++- src/complex.rs | 27 +- src/integer.rs | 2 + src/lib.rs | 68 +++++ src/rational.rs | 34 ++- src/traits.rs | 514 +++++++++++++++++++++++++++++++++++ 7 files changed, 699 insertions(+), 28 deletions(-) create mode 100644 src/traits.rs diff --git a/benches/shootout-pidigits.rs b/benches/shootout-pidigits.rs index 7089421..dad9590 100644 --- a/benches/shootout-pidigits.rs +++ b/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, diff --git a/src/bigint.rs b/src/bigint.rs index 3ba6ce7..4eb9370 100644 --- a/src/bigint.rs +++ b/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> AdditiveIterator for T { + fn sum(&mut self) -> BigUint { + let init: BigUint = Zero::zero(); + self.fold(init, |acc, x| acc + x) + } +} + +impl> MultiplicativeIterator 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 RandBigInt for R { } } +impl> AdditiveIterator for T { + fn sum(&mut self) -> BigInt { + let init: BigInt = Zero::zero(); + self.fold(init, |acc, x| acc + x) + } +} + +impl> MultiplicativeIterator 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 { + return Some(self.add(v)); + } + + #[inline] + pub fn checked_sub(&self, v: &BigInt) -> Option { + return Some(self.sub(v)); + } + + #[inline] + pub fn checked_mul(&self, v: &BigInt) -> Option { + return Some(self.mul(v)); + } + + #[inline] + pub fn checked_div(&self, v: &BigInt) -> Option { + 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(); diff --git a/src/complex.rs b/src/complex.rs index 0d40b5f..7a63c0b 100644 --- a/src/complex.rs +++ b/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 Complex { } } -impl Complex { +impl Complex { /// Calculate the principal Arg of self. #[inline] pub fn arg(&self) -> T { @@ -172,14 +175,30 @@ impl fmt::Show for Complex { } } +impl>> AdditiveIterator> for T { + fn sum(&mut self) -> Complex { + let init: Complex = Zero::zero(); + self.fold(init, |acc, x| acc + x) + } +} + +impl>> MultiplicativeIterator> for T { + fn product(&mut self) -> Complex { + let init: Complex = 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() { diff --git a/src/integer.rs b/src/integer.rs index 4aca00f..90c2302 100644 --- a/src/integer.rs +++ b/src/integer.rs @@ -10,6 +10,8 @@ //! Integer trait and functions. +use {Num, Signed}; + pub trait Integer: Num + PartialOrd + Div + Rem { diff --git a/src/lib.rs b/src/lib.rs index f386d4b..ee4ae8c 100644 --- a/src/lib.rs +++ b/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::zero() } + +/// Returns the multiplicative identity, `1`. +#[inline(always)] pub fn 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(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(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(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>(mut base: T, mut exp: uint) -> T { + if exp == 1 { base } + else { + let mut acc = one::(); + while exp > 0 { + if (exp & 1) == 1 { + acc = acc * base; + } + base = base * base; + exp = exp >> 1; + } + acc + } +} diff --git a/src/rational.rs b/src/rational.rs index 2c3fbc3..73fa0a9 100644 --- a/src/rational.rs +++ b/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 Num for Ratio {} impl - num::Signed for Ratio { + Signed for Ratio { #[inline] fn abs(&self) -> Ratio { if self.is_negative() { -self.clone() } else { self.clone() } @@ -317,11 +318,11 @@ impl #[inline] fn signum(&self) -> Ratio { if *self > Zero::zero() { - num::one() + One::one() } else if self.is_zero() { - num::zero() + Zero::zero() } else { - - num::one::>() + - ::one::>() } } @@ -382,15 +383,30 @@ impl } } +impl>> AdditiveIterator> for T { + fn sum(&mut self) -> Ratio { + let init: Ratio = Zero::zero(); + self.fold(init, |acc, x| acc + x) + } +} + +impl>> MultiplicativeIterator> for T { + fn product(&mut self) -> Ratio { + let init: Ratio = 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::>()); + assert_eq!(_NEG1_2.signum(), - ::one::>()); assert!(_NEG1_2.is_negative()); assert!(! _NEG1_2.is_positive()); assert!(! _1_2.is_negative()); diff --git a/src/traits.rs b/src/traits.rs new file mode 100644 index 0000000..06557a3 --- /dev/null +++ b/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 or the MIT license +// , 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 + + Add + + Sub + + Mul + + Div + + Rem {} + +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 { + /// 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 { + /// 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 { + /// 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 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 { + /// 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; +} + +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 { + /// 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; +} + +#[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 { + /// 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; +} + +#[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 { + /// 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; +} + +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) +