// 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 //! //! ## Compatibility //! //! The `num-traits` crate is tested for rustc 1.31 and greater. #![doc(html_root_url = "https://docs.rs/num-traits/0.2")] #![deny(unconditional_recursion)] #![no_std] // Need to explicitly bring the crate in for inherent float methods #[cfg(feature = "std")] extern crate std; use core::fmt; use core::num::Wrapping; use core::ops::{Add, Div, Mul, Rem, Sub}; use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign}; pub use crate::bounds::Bounded; #[cfg(any(feature = "std", feature = "libm"))] pub use crate::float::Float; pub use crate::float::FloatConst; // pub use real::{FloatCore, Real}; // NOTE: Don't do this, it breaks `use num_traits::*;`. pub use crate::cast::{cast, AsPrimitive, FromPrimitive, NumCast, ToPrimitive}; pub use crate::identities::{one, zero, One, Zero}; pub use crate::int::PrimInt; pub use crate::ops::bytes::{FromBytes, ToBytes}; pub use crate::ops::checked::{ CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, CheckedShr, CheckedSub, }; pub use crate::ops::euclid::{CheckedEuclid, Euclid}; pub use crate::ops::inv::Inv; pub use crate::ops::mul_add::{MulAdd, MulAddAssign}; pub use crate::ops::saturating::{Saturating, SaturatingAdd, SaturatingMul, SaturatingSub}; pub use crate::ops::wrapping::{ WrappingAdd, WrappingMul, WrappingNeg, WrappingShl, WrappingShr, WrappingSub, }; pub use crate::pow::{checked_pow, pow, Pow}; pub use crate::sign::{abs, abs_sub, signum, Signed, Unsigned}; #[macro_use] mod macros; pub mod bounds; pub mod cast; pub mod float; pub mod identities; pub mod int; pub mod ops; pub mod pow; pub mod real; pub mod sign; /// The base trait for numeric types, covering `0` and `1` values, /// comparisons, basic numeric operations, and string conversion. pub trait Num: PartialEq + Zero + One + NumOps { type FromStrRadixErr; /// Convert from a string and radix (typically `2..=36`). /// /// # Examples /// /// ```rust /// use num_traits::Num; /// /// let result = ::from_str_radix("27", 10); /// assert_eq!(result, Ok(27)); /// /// let result = ::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; } /// Generic trait for types implementing basic numeric operations /// /// This is automatically implemented for types which implement the operators. pub trait NumOps: Add + Sub + Mul + Div + Rem { } impl NumOps for T where T: Add + Sub + Mul + Div + Rem { } /// 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. pub trait NumRef: Num + for<'r> NumOps<&'r Self> {} impl 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`. pub trait RefNum: NumOps + for<'r> NumOps<&'r Base, Base> {} impl RefNum for T where T: NumOps + 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. pub trait NumAssignOps: AddAssign + SubAssign + MulAssign + DivAssign + RemAssign { } impl NumAssignOps for T where T: AddAssign + SubAssign + MulAssign + DivAssign + RemAssign { } /// The trait for `Num` types which also implement assignment operators. /// /// This is automatically implemented for types which implement the operators. pub trait NumAssign: Num + NumAssignOps {} impl 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. pub trait NumAssignRef: NumAssign + for<'r> NumAssignOps<&'r Self> {} impl 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 { <$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 Num for Wrapping where Wrapping: NumOps, { type FromStrRadixErr = T::FromStrRadixErr; fn from_str_radix(str: &str, radix: u32) -> Result { T::from_str_radix(str, radix).map(Wrapping) } } #[derive(Debug)] pub enum 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)] pub struct ParseFloatError { pub kind: FloatErrorKind, } impl fmt::Display for ParseFloatError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let description = match self.kind { FloatErrorKind::Empty => "cannot parse float from empty string", FloatErrorKind::Invalid => "invalid float literal", }; description.fmt(f) } } 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; fn from_str_radix(src: &str, radix: u32) -> Result { use self::FloatErrorKind::*; use self::ParseFloatError as PFE; // 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 }, }); } // Special values if str_to_ascii_lower_eq_str(src, "inf") || str_to_ascii_lower_eq_str(src, "infinity") { return Ok(core::$t::INFINITY); } else if str_to_ascii_lower_eq_str(src, "-inf") || str_to_ascii_lower_eq_str(src, "-infinity") { return Ok(core::$t::NEG_INFINITY); } else if str_to_ascii_lower_eq_str(src, "nan") { return Ok(core::$t::NAN); } else if str_to_ascii_lower_eq_str(src, "-nan") { return Ok(-core::$t::NAN); } fn slice_shift_char(src: &str) -> Option<(char, &str)> { let mut chars = src.chars(); Some((chars.next()?, chars.as_str())) } let (is_positive, src) = match slice_shift_char(src) { None => return Err(PFE { kind: Empty }), Some(('-', "")) => return Err(PFE { kind: Empty }), Some(('-', src)) => (false, src), Some((_, _)) => (true, src), }; // The significand to accumulate let mut sig = if is_positive { 0.0 } else { -0.0 }; // Necessary to detect overflow let mut prev_sig = sig; let mut cs = src.chars().enumerate(); // Exponent prefix and exponent index offset let mut 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() { let mut 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::()), Some(('+', src)) => (true, src.parse::()), Some((_, _)) => (true, src.parse::()), 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 match (is_positive, exp) { (true, Ok(exp)) => pow(base, exp), (false, Ok(exp)) => 1.0 / pow(base, exp), (_, Err(_)) => return Err(PFE { kind: Invalid }), } }, None => 1.0, // no exponent }; Ok(sig * exp) } } )*) } float_trait_impl!(Num for f32 f64); /// 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] pub fn clamp(input: T, min: T, max: T) -> T { debug_assert!(min <= max, "min must be less than or equal to max"); if input < min { min } else if 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)] pub fn clamp_min(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)] pub fn clamp_max(input: T, max: T) -> T { debug_assert!(max == max, "max must not be NAN"); if input > max { max } else { input } } #[test] fn clamp_test() { // Int test assert_eq!(1, clamp(1, -1, 2)); assert_eq!(-1, clamp(-2, -1, 2)); assert_eq!(2, clamp(3, -1, 2)); assert_eq!(1, clamp_min(1, -1)); assert_eq!(-1, clamp_min(-2, -1)); assert_eq!(-1, clamp_max(1, -1)); assert_eq!(-2, clamp_max(-2, -1)); // Float test assert_eq!(1.0, clamp(1.0, -1.0, 2.0)); assert_eq!(-1.0, clamp(-2.0, -1.0, 2.0)); assert_eq!(2.0, clamp(3.0, -1.0, 2.0)); assert_eq!(1.0, clamp_min(1.0, -1.0)); assert_eq!(-1.0, clamp_min(-2.0, -1.0)); assert_eq!(-1.0, clamp_max(1.0, -1.0)); assert_eq!(-2.0, clamp_max(-2.0, -1.0)); assert!(clamp(::core::f32::NAN, -1.0, 1.0).is_nan()); assert!(clamp_min(::core::f32::NAN, 1.0).is_nan()); assert!(clamp_max(::core::f32::NAN, 1.0).is_nan()); } #[test] #[should_panic] #[cfg(debug_assertions)] fn clamp_nan_min() { clamp(0., ::core::f32::NAN, 1.); } #[test] #[should_panic] #[cfg(debug_assertions)] fn clamp_nan_max() { clamp(0., -1., ::core::f32::NAN); } #[test] #[should_panic] #[cfg(debug_assertions)] fn clamp_nan_min_max() { clamp(0., ::core::f32::NAN, ::core::f32::NAN); } #[test] #[should_panic] #[cfg(debug_assertions)] fn clamp_min_nan_min() { clamp_min(0., ::core::f32::NAN); } #[test] #[should_panic] #[cfg(debug_assertions)] fn clamp_max_nan_max() { clamp_max(0., ::core::f32::NAN); } #[test] fn from_str_radix_unwrap() { // The Result error must impl Debug to allow unwrap() let i: i32 = Num::from_str_radix("0", 10).unwrap(); assert_eq!(i, 0); let f: f32 = Num::from_str_radix("0.0", 10).unwrap(); assert_eq!(f, 0.0); } #[test] fn from_str_radix_multi_byte_fail() { // Ensure parsing doesn't panic, even on invalid sign characters assert!(f32::from_str_radix("™0.2", 10).is_err()); // Even when parsing the exponent sign assert!(f32::from_str_radix("0.2E™1", 10).is_err()); } #[test] fn from_str_radix_ignore_case() { assert_eq!( f32::from_str_radix("InF", 16).unwrap(), ::core::f32::INFINITY ); assert_eq!( f32::from_str_radix("InfinitY", 16).unwrap(), ::core::f32::INFINITY ); assert_eq!( f32::from_str_radix("-InF", 8).unwrap(), ::core::f32::NEG_INFINITY ); assert_eq!( f32::from_str_radix("-InfinitY", 8).unwrap(), ::core::f32::NEG_INFINITY ); assert!(f32::from_str_radix("nAn", 4).unwrap().is_nan()); assert!(f32::from_str_radix("-nAn", 4).unwrap().is_nan()); } #[test] fn wrapping_is_num() { fn require_num(_: &T) {} require_num(&Wrapping(42_u32)); require_num(&Wrapping(-42)); } #[test] fn wrapping_from_str_radix() { macro_rules! test_wrapping_from_str_radix { ($($t:ty)+) => { $( for &(s, r) in &[("42", 10), ("42", 2), ("-13.0", 10), ("foo", 10)] { let w = Wrapping::<$t>::from_str_radix(s, r).map(|w| w.0); assert_eq!(w, <$t as Num>::from_str_radix(s, r)); } )+ }; } test_wrapping_from_str_radix!(usize u8 u16 u32 u64 isize i8 i16 i32 i64); } #[test] fn check_num_ops() { fn compute(x: T, y: T) -> T { x * y / y % y + y - y } assert_eq!(compute(1, 2), 1) } #[test] fn check_numref_ops() { fn compute(x: T, y: &T) -> T { x * y / y % y + y - y } assert_eq!(compute(1, &2), 1) } #[test] fn check_refnum_ops() { fn compute(x: &T, y: T) -> T where for<'a> &'a T: RefNum, { &(&(&(&(x * y) / y) % y) + y) - y } assert_eq!(compute(&1, 2), 1) } #[test] fn check_refref_ops() { fn compute(x: &T, y: &T) -> T where for<'a> &'a T: RefNum, { &(&(&(&(x * y) / y) % y) + y) - y } assert_eq!(compute(&1, &2), 1) } #[test] fn check_numassign_ops() { fn compute(mut x: T, y: T) -> T { x *= y; x /= y; x %= y; x += y; x -= y; x } assert_eq!(compute(1, 2), 1) } #[test] fn check_numassignref_ops() { fn compute(mut x: T, y: &T) -> T { x *= y; x /= y; x %= y; x += y; x -= y; x } assert_eq!(compute(1, &2), 1) }