// 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 //! //! ## Compatibility //! //! The `num-traits` crate is tested for rustc 1.60 and greater.
// Need to explicitly bring the crate in for inherent float methods #[cfg(feature = "std")] externcrate std;
use core::fmt; use core::num::Wrapping; use core::ops::{Add, Div, Mul, Rem, Sub}; use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign};
/// The base trait for numeric types, covering `0` and `1` values, /// comparisons, basic numeric operations, and string conversion. pubtrait Num: PartialEq + Zero + One + NumOps { type FromStrRadixErr;
/// Convert from a string and radix (typically `2..=36`). /// /// # Examples /// /// ```rust /// use num_traits::Num; /// /// let result = <i32 as Num>::from_str_radix("27", 10); /// assert_eq!(result, Ok(27)); /// /// let result = <i32 as Num>::from_str_radix("foo", 10); /// assert!(result.is_err()); /// ``` /// /// # Supported radices /// /// The exact range of supported radices is at the discretion of each type implementation. For /// primitive integers, this is implemented by the inherent `from_str_radix` methods in the /// standard library, which **panic** if the radix is not in the range from 2 to 36. The /// implementation in this crate for primitive floats is similar. /// /// For third-party types, it is suggested that implementations should follow suit and at least /// accept `2..=36` without panicking, but an `Err` may be returned for any unsupported radix. /// It's possible that a type might not even support the common radix 10, nor any, if string /// parsing doesn't make sense for that type. fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr>;
}
/// Generic trait for types implementing basic numeric operations /// /// This is automatically implemented for types which implement the operators. pubtrait NumOps<Rhs = Self, Output = Self>:
Add<Rhs, Output = Output>
+ Sub<Rhs, Output = Output>
+ Mul<Rhs, Output = Output>
+ Div<Rhs, Output = Output>
+ Rem<Rhs, Output = Output>
{
}
/// The trait for `Num` types which also implement numeric operations taking /// the second operand by reference. /// /// This is automatically implemented for types which implement the operators. pubtrait NumRef: Num + for<'r> NumOps<&'r Self> {} impl<T> NumRef for T where T: Num + for<'r> NumOps<&'r T> {}
/// The trait for `Num` references which implement numeric operations, taking the /// second operand either by value or by reference. /// /// This is automatically implemented for all types which implement the operators. It covers /// every type implementing the operations though, regardless of it being a reference or /// related to `Num`. pubtrait RefNum<Base>: NumOps<Base, Base> + for<'r> NumOps<&'r Base, Base> {} impl<T, Base> RefNum<Base> for T where T: NumOps<Base, Base> + for<'r> NumOps<&'r Base, Base> {}
/// Generic trait for types implementing numeric assignment operators (like `+=`). /// /// This is automatically implemented for types which implement the operators. pubtrait NumAssignOps<Rhs = Self>:
AddAssign<Rhs> + SubAssign<Rhs> + MulAssign<Rhs> + DivAssign<Rhs> + RemAssign<Rhs>
{
}
impl<T, Rhs> NumAssignOps<Rhs> for T where
T: AddAssign<Rhs> + SubAssign<Rhs> + MulAssign<Rhs> + DivAssign<Rhs> + RemAssign<Rhs>
{
}
/// The trait for `Num` types which also implement assignment operators. /// /// This is automatically implemented for types which implement the operators. pubtrait NumAssign: Num + NumAssignOps {} impl<T> NumAssign for T where T: Num + NumAssignOps {}
/// The trait for `NumAssign` types which also implement assignment operations /// taking the second operand by reference. /// /// This is automatically implemented for types which implement the operators. pubtrait NumAssignRef: NumAssign + for<'r> NumAssignOps<&'r Self> {} impl<T> NumAssignRef for T where T: NumAssign + for<'r> NumAssignOps<&'r T> {}
macro_rules! int_trait_impl {
($name:ident for $($t:ty)*) => ($( impl $name for $t { type FromStrRadixErr = ::core::num::ParseIntError; #[inline] fn from_str_radix(s: &str, radix: u32)
-> Result<Self, ::core::num::ParseIntError>
{
<$t>::from_str_radix(s, radix)
}
}
)*)
}
int_trait_impl!(Num for usize u8 u16 u32 u64 u128);
int_trait_impl!(Num for isize i8 i16 i32 i64 i128);
impl<T: Num> Num for Wrapping<T> where
Wrapping<T>: NumOps,
{ type FromStrRadixErr = T::FromStrRadixErr; fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
T::from_str_radix(str, radix).map(Wrapping)
}
}
#[derive(Debug)] pubenum FloatErrorKind {
Empty,
Invalid,
} // FIXME: core::num::ParseFloatError is stable in 1.0, but opaque to us, // so there's not really any way for us to reuse it. #[derive(Debug)] pubstruct ParseFloatError { pub kind: FloatErrorKind,
}
fn str_to_ascii_lower_eq_str(a: &str, b: &str) -> bool {
a.len() == b.len()
&& a.bytes().zip(b.bytes()).all(|(a, b)| { let a_to_ascii_lower = a | (((b'A' <= a && a <= b'Z') as u8) << 5);
a_to_ascii_lower == b
})
}
// FIXME: The standard library from_str_radix on floats was deprecated, so we're stuck // with this implementation ourselves until we want to make a breaking change. // (would have to drop it from `Num` though)
macro_rules! float_trait_impl {
($name:ident for $($t:ident)*) => ($( impl $name for $t { type FromStrRadixErr = ParseFloatError;
// Special case radix 10 to use more accurate standard library implementation if radix == 10 { return src.parse().map_err(|_| PFE {
kind: if src.is_empty() { Empty } else { Invalid },
});
}
// The significand to accumulate letmut sig = if is_positive { 0.0 } else { -0.0 }; // Necessary to detect overflow letmut prev_sig = sig; letmut cs = src.chars().enumerate(); // Exponent prefix and exponent index offset letmut exp_info = None::<(char, usize)>;
// Parse the integer part of the significand for (i, c) in cs.by_ref() { match c.to_digit(radix) {
Some(digit) => { // shift significand one digit left
sig *= radix as $t;
// add/subtract current digit depending on sign if is_positive {
sig += (digit as isize) as $t;
} else {
sig -= (digit as isize) as $t;
}
// Detect overflow by comparing to last value, except // if we've not seen any non-zero digits. if prev_sig != 0.0 { if is_positive && sig <= prev_sig
{ return Ok(core::$t::INFINITY); } if !is_positive && sig >= prev_sig
{ return Ok(core::$t::NEG_INFINITY); }
// Detect overflow by reversing the shift-and-add process if is_positive && (prev_sig != (sig - digit as $t) / radix as $t)
{ return Ok(core::$t::INFINITY); } if !is_positive && (prev_sig != (sig + digit as $t) / radix as $t)
{ return Ok(core::$t::NEG_INFINITY); }
}
prev_sig = sig;
},
None => match c { 'e' | 'E' | 'p' | 'P' => {
exp_info = Some((c, i + 1)); break; // start of exponent
}, '.' => { break; // start of fractional part
},
_ => { return Err(PFE { kind: Invalid });
},
},
}
}
// If we are not yet at the exponent parse the fractional // part of the significand if exp_info.is_none() { letmut power = 1.0; for (i, c) in cs.by_ref() { match c.to_digit(radix) {
Some(digit) => { // Decrease power one order of magnitude
power /= radix as $t; // add/subtract current digit depending on sign
sig = if is_positive {
sig + (digit as $t) * power
} else {
sig - (digit as $t) * power
}; // Detect overflow by comparing to last value if is_positive && sig < prev_sig
{ return Ok(core::$t::INFINITY); } if !is_positive && sig > prev_sig
{ return Ok(core::$t::NEG_INFINITY); }
prev_sig = sig;
},
None => match c { 'e' | 'E' | 'p' | 'P' => {
exp_info = Some((c, i + 1)); break; // start of exponent
},
_ => { return Err(PFE { kind: Invalid });
},
},
}
}
}
// Parse and calculate the exponent let exp = match exp_info {
Some((c, offset)) => { let base = match c { 'E' | 'e'if radix == 10 => 10.0, 'P' | 'p'if radix == 16 => 2.0,
_ => return Err(PFE { kind: Invalid }),
};
// Parse the exponent as decimal integer let src = &src[offset..]; let (is_positive, exp) = match slice_shift_char(src) {
Some(('-', src)) => (false, src.parse::<usize>()),
Some(('+', src)) => (true, src.parse::<usize>()),
Some((_, _)) => (true, src.parse::<usize>()),
None => return Err(PFE { kind: Invalid }),
};
#[cfg(feature = "std")] fn pow(base: $t, exp: usize) -> $t {
Float::powi(base, exp as i32)
} // otherwise uses the generic `pow` from the root
/// A value bounded by a minimum and a maximum /// /// If input is less than min then this returns min. /// If input is greater than max then this returns max. /// Otherwise this returns input. /// /// **Panics** in debug mode if `!(min <= max)`. #[inline] pubfn clamp<T: PartialOrd>(input: T, min: T, max: T) -> T {
debug_assert!(min <= max, "min must be less than or equal to max"); if input < min {
min
} elseif input > max {
max
} else {
input
}
}
/// A value bounded by a minimum value /// /// If input is less than min then this returns min. /// Otherwise this returns input. /// `clamp_min(std::f32::NAN, 1.0)` preserves `NAN` different from `f32::min(std::f32::NAN, 1.0)`. /// /// **Panics** in debug mode if `!(min == min)`. (This occurs if `min` is `NAN`.) #[inline] #[allow(clippy::eq_op)] pubfn clamp_min<T: PartialOrd>(input: T, min: T) -> T {
debug_assert!(min == min, "min must not be NAN"); if input < min {
min
} else {
input
}
}
/// A value bounded by a maximum value /// /// If input is greater than max then this returns max. /// Otherwise this returns input. /// `clamp_max(std::f32::NAN, 1.0)` preserves `NAN` different from `f32::max(std::f32::NAN, 1.0)`. /// /// **Panics** in debug mode if `!(max == max)`. (This occurs if `max` is `NAN`.) #[inline] #[allow(clippy::eq_op)] pubfn clamp_max<T: PartialOrd>(input: T, max: T) -> T {
debug_assert!(max == max, "max must not be NAN"); if input > max {
max
} else {
input
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.