Merge pull request #429 from okaneco/abs_diff
Add `abs_diff` function to `SimdInt` and `SimdUint` traits
This commit is contained in:
commit
4697d39413
3 changed files with 65 additions and 3 deletions
|
|
@ -1,6 +1,6 @@
|
|||
use super::sealed::Sealed;
|
||||
use crate::simd::{
|
||||
cmp::SimdPartialOrd, num::SimdUint, LaneCount, Mask, Simd, SimdCast, SimdElement,
|
||||
cmp::SimdOrd, cmp::SimdPartialOrd, num::SimdUint, LaneCount, Mask, Simd, SimdCast, SimdElement,
|
||||
SupportedLaneCount,
|
||||
};
|
||||
|
||||
|
|
@ -70,11 +70,27 @@ pub trait SimdInt: Copy + Sealed {
|
|||
/// # #[cfg(not(feature = "as_crate"))] use core::simd;
|
||||
/// # use simd::prelude::*;
|
||||
/// use core::i32::{MIN, MAX};
|
||||
/// let xs = Simd::from_array([MIN, MIN +1, -5, 0]);
|
||||
/// let xs = Simd::from_array([MIN, MIN + 1, -5, 0]);
|
||||
/// assert_eq!(xs.abs(), Simd::from_array([MIN, MAX, 5, 0]));
|
||||
/// ```
|
||||
fn abs(self) -> Self;
|
||||
|
||||
/// Lanewise absolute difference.
|
||||
/// Every element becomes the absolute difference of `self` and `second`.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// # #![feature(portable_simd)]
|
||||
/// # #[cfg(feature = "as_crate")] use core_simd::simd;
|
||||
/// # #[cfg(not(feature = "as_crate"))] use core::simd;
|
||||
/// # use simd::prelude::*;
|
||||
/// use core::i32::{MIN, MAX};
|
||||
/// let a = Simd::from_array([MIN, MAX, 100, -100]);
|
||||
/// let b = Simd::from_array([MAX, MIN, -80, -120]);
|
||||
/// assert_eq!(a.abs_diff(b), Simd::from_array([u32::MAX, u32::MAX, 180, 20]));
|
||||
/// ```
|
||||
fn abs_diff(self, second: Self) -> Self::Unsigned;
|
||||
|
||||
/// Lanewise saturating absolute value, implemented in Rust.
|
||||
/// As abs(), except the MIN value becomes MAX instead of itself.
|
||||
///
|
||||
|
|
@ -259,6 +275,13 @@ macro_rules! impl_trait {
|
|||
(self^m) - m
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn abs_diff(self, second: Self) -> Self::Unsigned {
|
||||
let max = self.simd_max(second);
|
||||
let min = self.simd_min(second);
|
||||
(max - min).cast()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn saturating_abs(self) -> Self {
|
||||
// arith shift for -1 or 0 mask based on sign bit, giving 2s complement
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use super::sealed::Sealed;
|
||||
use crate::simd::{LaneCount, Simd, SimdCast, SimdElement, SupportedLaneCount};
|
||||
use crate::simd::{cmp::SimdOrd, LaneCount, Simd, SimdCast, SimdElement, SupportedLaneCount};
|
||||
|
||||
/// Operations on SIMD vectors of unsigned integers.
|
||||
pub trait SimdUint: Copy + Sealed {
|
||||
|
|
@ -57,6 +57,22 @@ pub trait SimdUint: Copy + Sealed {
|
|||
/// assert_eq!(sat, Simd::splat(0));
|
||||
fn saturating_sub(self, second: Self) -> Self;
|
||||
|
||||
/// Lanewise absolute difference.
|
||||
/// Every element becomes the absolute difference of `self` and `second`.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// # #![feature(portable_simd)]
|
||||
/// # #[cfg(feature = "as_crate")] use core_simd::simd;
|
||||
/// # #[cfg(not(feature = "as_crate"))] use core::simd;
|
||||
/// # use simd::prelude::*;
|
||||
/// use core::u32::MAX;
|
||||
/// let a = Simd::from_array([0, MAX, 100, 20]);
|
||||
/// let b = Simd::from_array([MAX, 0, 80, 200]);
|
||||
/// assert_eq!(a.abs_diff(b), Simd::from_array([MAX, MAX, 20, 180]));
|
||||
/// ```
|
||||
fn abs_diff(self, second: Self) -> Self;
|
||||
|
||||
/// Returns the sum of the elements of the vector, with wrapping addition.
|
||||
fn reduce_sum(self) -> Self::Scalar;
|
||||
|
||||
|
|
@ -138,6 +154,13 @@ macro_rules! impl_trait {
|
|||
unsafe { core::intrinsics::simd::simd_saturating_sub(self, second) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn abs_diff(self, second: Self) -> Self {
|
||||
let max = self.simd_max(second);
|
||||
let min = self.simd_min(second);
|
||||
max - min
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn reduce_sum(self) -> Self::Scalar {
|
||||
// Safety: `self` is an integer vector
|
||||
|
|
|
|||
|
|
@ -307,6 +307,14 @@ macro_rules! impl_signed_tests {
|
|||
assert_eq!(a % b, Vector::<LANES>::splat(0));
|
||||
}
|
||||
|
||||
fn abs_diff<const LANES: usize>() {
|
||||
test_helpers::test_binary_elementwise(
|
||||
&Vector::<LANES>::abs_diff,
|
||||
&Scalar::abs_diff,
|
||||
&|_, _| true,
|
||||
)
|
||||
}
|
||||
|
||||
fn simd_min<const LANES: usize>() {
|
||||
use core_simd::simd::cmp::SimdOrd;
|
||||
let a = Vector::<LANES>::splat(Scalar::MIN);
|
||||
|
|
@ -419,6 +427,14 @@ macro_rules! impl_unsigned_tests {
|
|||
&|_| true,
|
||||
);
|
||||
}
|
||||
|
||||
fn abs_diff<const LANES: usize>() {
|
||||
test_helpers::test_binary_elementwise(
|
||||
&Vector::<LANES>::abs_diff,
|
||||
&Scalar::abs_diff,
|
||||
&|_, _| true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl_binary_op_test!(Scalar, Add::add, AddAssign::add_assign, Scalar::wrapping_add);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue