Move functions remaining in num to num-traits

Fixes #102.
This commit is contained in:
Vinzent Steinberg 2016-05-09 17:02:21 +02:00
parent 4bbc34b083
commit 3e4595eac6
5 changed files with 123 additions and 116 deletions

View File

@ -78,10 +78,10 @@ pub use num_complex::Complex;
pub use num_integer::Integer;
pub use num_iter::{range, range_inclusive, range_step, range_step_inclusive};
pub use num_traits::{Num, Zero, One, Signed, Unsigned, Bounded,
one, zero, abs, abs_sub, signum,
Saturating, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv,
PrimInt, Float, ToPrimitive, FromPrimitive, NumCast, cast};
use std::ops::{Mul};
PrimInt, Float, ToPrimitive, FromPrimitive, NumCast, cast,
pow, checked_pow};
#[cfg(feature = "num-bigint")]
pub mod bigint {
@ -109,114 +109,3 @@ pub mod traits {
pub mod rational {
pub use num_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(2i8, 4), 16);
/// assert_eq!(num::pow(6u8, 3), 216);
/// ```
#[inline]
pub fn pow<T: Clone + One + Mul<T, Output = T>>(mut base: T, mut exp: usize) -> T {
if exp == 0 { return T::one() }
while exp & 1 == 0 {
base = base.clone() * base;
exp >>= 1;
}
if exp == 1 { return base }
let mut acc = base.clone();
while exp > 1 {
exp >>= 1;
base = base.clone() * base;
if exp & 1 == 1 {
acc = acc * base.clone();
}
}
acc
}
/// Raises a value to the power of exp, returning `None` if an overflow occurred.
///
/// Otherwise same as the `pow` function.
///
/// # Example
///
/// ```rust
/// use num;
///
/// assert_eq!(num::checked_pow(2i8, 4), Some(16));
/// assert_eq!(num::checked_pow(7i8, 8), None);
/// assert_eq!(num::checked_pow(7u32, 8), Some(5_764_801));
/// ```
#[inline]
pub fn checked_pow<T: Clone + One + CheckedMul>(mut base: T, mut exp: usize) -> Option<T> {
if exp == 0 { return Some(T::one()) }
macro_rules! optry {
( $ expr : expr ) => {
if let Some(val) = $expr { val } else { return None }
}
}
while exp & 1 == 0 {
base = optry!(base.checked_mul(&base));
exp >>= 1;
}
if exp == 1 { return Some(base) }
let mut acc = base.clone();
while exp > 1 {
exp >>= 1;
base = optry!(base.checked_mul(&base));
if exp & 1 == 1 {
acc = optry!(acc.checked_mul(&base));
}
}
Some(acc)
}

View File

@ -93,3 +93,12 @@ one_impl!(i64, 1i64);
one_impl!(f32, 1.0f32);
one_impl!(f64, 1.0f64);
// Some helper functions provided for backwards compatibility.
/// 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() }

View File

@ -14,12 +14,13 @@ use std::ops::{Add, Sub, Mul, Div, Rem};
pub use bounds::Bounded;
pub use float::Float;
pub use identities::{Zero, One};
pub use identities::{Zero, One, zero, one};
pub use ops::checked::*;
pub use ops::saturating::Saturating;
pub use sign::{Signed, Unsigned};
pub use sign::{Signed, Unsigned, abs, abs_sub, signum};
pub use cast::*;
pub use int::PrimInt;
pub use pow::{pow, checked_pow};
pub mod identities;
pub mod sign;
@ -28,6 +29,7 @@ pub mod bounds;
pub mod float;
pub mod cast;
pub mod int;
pub mod pow;
/// The base trait for numeric types
pub trait Num: PartialEq + Zero + One

73
traits/src/pow.rs Normal file
View File

@ -0,0 +1,73 @@
use std::ops::Mul;
use {One, CheckedMul};
/// Raises a value to the power of exp, using exponentiation by squaring.
///
/// # Example
///
/// ```rust
/// use num_traits::pow;
///
/// assert_eq!(pow(2i8, 4), 16);
/// assert_eq!(pow(6u8, 3), 216);
/// ```
#[inline]
pub fn pow<T: Clone + One + Mul<T, Output = T>>(mut base: T, mut exp: usize) -> T {
if exp == 0 { return T::one() }
while exp & 1 == 0 {
base = base.clone() * base;
exp >>= 1;
}
if exp == 1 { return base }
let mut acc = base.clone();
while exp > 1 {
exp >>= 1;
base = base.clone() * base;
if exp & 1 == 1 {
acc = acc * base.clone();
}
}
acc
}
/// Raises a value to the power of exp, returning `None` if an overflow occurred.
///
/// Otherwise same as the `pow` function.
///
/// # Example
///
/// ```rust
/// use num_traits::checked_pow;
///
/// assert_eq!(checked_pow(2i8, 4), Some(16));
/// assert_eq!(checked_pow(7i8, 8), None);
/// assert_eq!(checked_pow(7u32, 8), Some(5_764_801));
/// ```
#[inline]
pub fn checked_pow<T: Clone + One + CheckedMul>(mut base: T, mut exp: usize) -> Option<T> {
if exp == 0 { return Some(T::one()) }
macro_rules! optry {
( $ expr : expr ) => {
if let Some(val) = $expr { val } else { return None }
}
}
while exp & 1 == 0 {
base = optry!(base.checked_mul(&base));
exp >>= 1;
}
if exp == 1 { return Some(base) }
let mut acc = base.clone();
while exp > 1 {
exp >>= 1;
base = optry!(base.checked_mul(&base));
if exp & 1 == 1 {
acc = optry!(acc.checked_mul(&base));
}
}
Some(acc)
}

View File

@ -114,6 +114,40 @@ macro_rules! signed_float_impl {
signed_float_impl!(f32, f32::NAN, f32::INFINITY, f32::NEG_INFINITY);
signed_float_impl!(f64, f64::NAN, f64::INFINITY, f64::NEG_INFINITY);
/// 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() }
/// A trait for values which cannot be negative
pub trait Unsigned: Num {}