Merge branch 'master' into regexident-i128
This commit is contained in:
commit
261efafe0b
|
@ -17,7 +17,7 @@ pub trait Zero: Sized + Add<Self, Output = Self> {
|
|||
/// 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
|
||||
// This cannot be an associated constant, because of bignums.
|
||||
fn zero() -> Self;
|
||||
|
||||
/// Returns `true` if `self` is equal to the additive identity.
|
||||
|
@ -81,7 +81,7 @@ pub trait One: Sized + Mul<Self, Output = Self> {
|
|||
/// 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
|
||||
// This cannot be an associated constant, because of bignums.
|
||||
fn one() -> Self;
|
||||
|
||||
/// Returns `true` if `self` is equal to the multiplicative identity.
|
||||
|
|
|
@ -34,8 +34,10 @@ pub use float::FloatConst;
|
|||
// pub use real::{FloatCore, Real}; // NOTE: Don't do this, it breaks `use num_traits::*;`.
|
||||
pub use identities::{Zero, One, zero, one};
|
||||
pub use ops::inv::Inv;
|
||||
pub use ops::checked::{CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, CheckedShl, CheckedShr};
|
||||
pub use ops::checked::{CheckedAdd, CheckedSub, CheckedMul, CheckedDiv,
|
||||
CheckedRem, CheckedNeg, CheckedShl, CheckedShr};
|
||||
pub use ops::wrapping::{WrappingAdd, WrappingMul, WrappingSub};
|
||||
pub use ops::mul_add::{MulAdd, MulAddAssign};
|
||||
pub use ops::saturating::Saturating;
|
||||
pub use sign::{Signed, Unsigned, abs, abs_sub, signum};
|
||||
pub use cast::{AsPrimitive, FromPrimitive, ToPrimitive, NumCast, cast};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use core::ops::{Add, Sub, Mul, Div, Shl, Shr};
|
||||
use core::ops::{Add, Sub, Mul, Div, Rem, Shl, Shr};
|
||||
|
||||
/// Performs addition that returns `None` instead of wrapping around on
|
||||
/// overflow.
|
||||
|
@ -106,6 +106,87 @@ checked_impl!(CheckedDiv, checked_div, isize);
|
|||
#[cfg(feature = "i128")]
|
||||
checked_impl!(CheckedDiv, checked_div, i128);
|
||||
|
||||
/// Performs an integral remainder that returns `None` instead of panicking on division by zero and
|
||||
/// instead of wrapping around on underflow and overflow.
|
||||
pub trait CheckedRem: Sized + Rem<Self, Output = Self> {
|
||||
/// Finds the remainder of dividing two numbers, checking for underflow, overflow and division
|
||||
/// by zero. If any of that happens, `None` is returned.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use num_traits::CheckedRem;
|
||||
/// use std::i32::MIN;
|
||||
///
|
||||
/// assert_eq!(CheckedRem::checked_rem(&10, &7), Some(3));
|
||||
/// assert_eq!(CheckedRem::checked_rem(&10, &-7), Some(3));
|
||||
/// assert_eq!(CheckedRem::checked_rem(&-10, &7), Some(-3));
|
||||
/// assert_eq!(CheckedRem::checked_rem(&-10, &-7), Some(-3));
|
||||
///
|
||||
/// assert_eq!(CheckedRem::checked_rem(&10, &0), None);
|
||||
///
|
||||
/// assert_eq!(CheckedRem::checked_rem(&MIN, &1), Some(0));
|
||||
/// assert_eq!(CheckedRem::checked_rem(&MIN, &-1), None);
|
||||
/// ```
|
||||
fn checked_rem(&self, v: &Self) -> Option<Self>;
|
||||
}
|
||||
|
||||
checked_impl!(CheckedRem, checked_rem, u8);
|
||||
checked_impl!(CheckedRem, checked_rem, u16);
|
||||
checked_impl!(CheckedRem, checked_rem, u32);
|
||||
checked_impl!(CheckedRem, checked_rem, u64);
|
||||
checked_impl!(CheckedRem, checked_rem, usize);
|
||||
|
||||
checked_impl!(CheckedRem, checked_rem, i8);
|
||||
checked_impl!(CheckedRem, checked_rem, i16);
|
||||
checked_impl!(CheckedRem, checked_rem, i32);
|
||||
checked_impl!(CheckedRem, checked_rem, i64);
|
||||
checked_impl!(CheckedRem, checked_rem, isize);
|
||||
|
||||
macro_rules! checked_impl_unary {
|
||||
($trait_name:ident, $method:ident, $t:ty) => {
|
||||
impl $trait_name for $t {
|
||||
#[inline]
|
||||
fn $method(&self) -> Option<$t> {
|
||||
<$t>::$method(*self)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Performs negation that returns `None` if the result can't be represented.
|
||||
pub trait CheckedNeg: Sized {
|
||||
/// Negates a number, returning `None` for results that can't be represented, like signed `MIN`
|
||||
/// values that can't be positive, or non-zero unsigned values that can't be negative.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use num_traits::CheckedNeg;
|
||||
/// use std::i32::MIN;
|
||||
///
|
||||
/// assert_eq!(CheckedNeg::checked_neg(&1_i32), Some(-1));
|
||||
/// assert_eq!(CheckedNeg::checked_neg(&-1_i32), Some(1));
|
||||
/// assert_eq!(CheckedNeg::checked_neg(&MIN), None);
|
||||
///
|
||||
/// assert_eq!(CheckedNeg::checked_neg(&0_u32), Some(0));
|
||||
/// assert_eq!(CheckedNeg::checked_neg(&1_u32), None);
|
||||
/// ```
|
||||
fn checked_neg(&self) -> Option<Self>;
|
||||
}
|
||||
|
||||
checked_impl_unary!(CheckedNeg, checked_neg, u8);
|
||||
checked_impl_unary!(CheckedNeg, checked_neg, u16);
|
||||
checked_impl_unary!(CheckedNeg, checked_neg, u32);
|
||||
checked_impl_unary!(CheckedNeg, checked_neg, u64);
|
||||
checked_impl_unary!(CheckedNeg, checked_neg, usize);
|
||||
|
||||
checked_impl_unary!(CheckedNeg, checked_neg, i8);
|
||||
checked_impl_unary!(CheckedNeg, checked_neg, i16);
|
||||
checked_impl_unary!(CheckedNeg, checked_neg, i32);
|
||||
checked_impl_unary!(CheckedNeg, checked_neg, i64);
|
||||
checked_impl_unary!(CheckedNeg, checked_neg, isize);
|
||||
|
||||
/// Performs a left shift that returns `None` on overflow.
|
||||
pub trait CheckedShl: Sized + Shl<u32, Output=Self> {
|
||||
/// Shifts a number to the left, checking for overflow. If overflow happens,
|
||||
|
|
|
@ -2,3 +2,4 @@ pub mod saturating;
|
|||
pub mod checked;
|
||||
pub mod wrapping;
|
||||
pub mod inv;
|
||||
pub mod mul_add;
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
/// The fused multiply-add operation.
|
||||
/// Computes (self * a) + b with only one rounding error.
|
||||
/// This produces a more accurate result with better performance
|
||||
/// than a separate multiplication operation followed by an add.
|
||||
///
|
||||
/// Note that `A` and `B` are `Self` by default, but this is not mandatory.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::f32;
|
||||
///
|
||||
/// let m = 10.0_f32;
|
||||
/// let x = 4.0_f32;
|
||||
/// let b = 60.0_f32;
|
||||
///
|
||||
/// // 100.0
|
||||
/// let abs_difference = (m.mul_add(x, b) - (m*x + b)).abs();
|
||||
///
|
||||
/// assert!(abs_difference <= f32::EPSILON);
|
||||
/// ```
|
||||
pub trait MulAdd<A = Self, B = Self> {
|
||||
/// The resulting type after applying the fused multiply-add.
|
||||
type Output;
|
||||
|
||||
/// Performs the fused multiply-add operation.
|
||||
fn mul_add(self, a: A, b: B) -> Self::Output;
|
||||
}
|
||||
|
||||
/// The fused multiply-add assignment operation.
|
||||
pub trait MulAddAssign<A = Self, B = Self> {
|
||||
/// Performs the fused multiply-add operation.
|
||||
fn mul_add_assign(&mut self, a: A, b: B);
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl MulAdd<f32, f32> for f32 {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn mul_add(self, a: Self, b: Self) -> Self::Output {
|
||||
f32::mul_add(self, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl MulAdd<f64, f64> for f64 {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn mul_add(self, a: Self, b: Self) -> Self::Output {
|
||||
f64::mul_add(self, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! mul_add_impl {
|
||||
($trait_name:ident for $($t:ty)*) => {$(
|
||||
impl $trait_name for $t {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn mul_add(self, a: Self, b: Self) -> Self::Output {
|
||||
(self * a) + b
|
||||
}
|
||||
}
|
||||
)*}
|
||||
}
|
||||
|
||||
mul_add_impl!(MulAdd for isize usize i8 u8 i16 u16 i32 u32 i64 u64);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl MulAddAssign<f32, f32> for f32 {
|
||||
#[inline]
|
||||
fn mul_add_assign(&mut self, a: Self, b: Self) {
|
||||
*self = f32::mul_add(*self, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl MulAddAssign<f64, f64> for f64 {
|
||||
#[inline]
|
||||
fn mul_add_assign(&mut self, a: Self, b: Self) {
|
||||
*self = f64::mul_add(*self, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! mul_add_assign_impl {
|
||||
($trait_name:ident for $($t:ty)*) => {$(
|
||||
impl $trait_name for $t {
|
||||
#[inline]
|
||||
fn mul_add_assign(&mut self, a: Self, b: Self) {
|
||||
*self = (*self * a) + b
|
||||
}
|
||||
}
|
||||
)*}
|
||||
}
|
||||
|
||||
mul_add_assign_impl!(MulAddAssign for isize usize i8 u8 i16 u16 i32 u32 i64 u64);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn mul_add_integer() {
|
||||
macro_rules! test_mul_add {
|
||||
($($t:ident)+) => {
|
||||
$(
|
||||
{
|
||||
let m: $t = 2;
|
||||
let x: $t = 3;
|
||||
let b: $t = 4;
|
||||
|
||||
assert_eq!(MulAdd::mul_add(m, x, b), (m*x + b));
|
||||
}
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
||||
test_mul_add!(usize u8 u16 u32 u64 isize i8 i16 i32 i64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "std")]
|
||||
fn mul_add_float() {
|
||||
macro_rules! test_mul_add {
|
||||
($($t:ident)+) => {
|
||||
$(
|
||||
{
|
||||
use core::$t;
|
||||
|
||||
let m: $t = 12.0;
|
||||
let x: $t = 3.4;
|
||||
let b: $t = 5.6;
|
||||
|
||||
let abs_difference = (MulAdd::mul_add(m, x, b) - (m*x + b)).abs();
|
||||
|
||||
assert!(abs_difference <= $t::EPSILON);
|
||||
}
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
||||
test_mul_add!(f32 f64);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue