Skip to content

Commit 4697d39

Browse files
Merge pull request #429 from okaneco/abs_diff
Add `abs_diff` function to `SimdInt` and `SimdUint` traits
2 parents 283acf4 + c992db6 commit 4697d39

File tree

3 files changed

+65
-3
lines changed

3 files changed

+65
-3
lines changed

Diff for: crates/core_simd/src/simd/num/int.rs

+25-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::sealed::Sealed;
22
use crate::simd::{
3-
cmp::SimdPartialOrd, num::SimdUint, LaneCount, Mask, Simd, SimdCast, SimdElement,
3+
cmp::SimdOrd, cmp::SimdPartialOrd, num::SimdUint, LaneCount, Mask, Simd, SimdCast, SimdElement,
44
SupportedLaneCount,
55
};
66

@@ -70,11 +70,27 @@ pub trait SimdInt: Copy + Sealed {
7070
/// # #[cfg(not(feature = "as_crate"))] use core::simd;
7171
/// # use simd::prelude::*;
7272
/// use core::i32::{MIN, MAX};
73-
/// let xs = Simd::from_array([MIN, MIN +1, -5, 0]);
73+
/// let xs = Simd::from_array([MIN, MIN + 1, -5, 0]);
7474
/// assert_eq!(xs.abs(), Simd::from_array([MIN, MAX, 5, 0]));
7575
/// ```
7676
fn abs(self) -> Self;
7777

78+
/// Lanewise absolute difference.
79+
/// Every element becomes the absolute difference of `self` and `second`.
80+
///
81+
/// # Examples
82+
/// ```
83+
/// # #![feature(portable_simd)]
84+
/// # #[cfg(feature = "as_crate")] use core_simd::simd;
85+
/// # #[cfg(not(feature = "as_crate"))] use core::simd;
86+
/// # use simd::prelude::*;
87+
/// use core::i32::{MIN, MAX};
88+
/// let a = Simd::from_array([MIN, MAX, 100, -100]);
89+
/// let b = Simd::from_array([MAX, MIN, -80, -120]);
90+
/// assert_eq!(a.abs_diff(b), Simd::from_array([u32::MAX, u32::MAX, 180, 20]));
91+
/// ```
92+
fn abs_diff(self, second: Self) -> Self::Unsigned;
93+
7894
/// Lanewise saturating absolute value, implemented in Rust.
7995
/// As abs(), except the MIN value becomes MAX instead of itself.
8096
///
@@ -259,6 +275,13 @@ macro_rules! impl_trait {
259275
(self^m) - m
260276
}
261277

278+
#[inline]
279+
fn abs_diff(self, second: Self) -> Self::Unsigned {
280+
let max = self.simd_max(second);
281+
let min = self.simd_min(second);
282+
(max - min).cast()
283+
}
284+
262285
#[inline]
263286
fn saturating_abs(self) -> Self {
264287
// arith shift for -1 or 0 mask based on sign bit, giving 2s complement

Diff for: crates/core_simd/src/simd/num/uint.rs

+24-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::sealed::Sealed;
2-
use crate::simd::{LaneCount, Simd, SimdCast, SimdElement, SupportedLaneCount};
2+
use crate::simd::{cmp::SimdOrd, LaneCount, Simd, SimdCast, SimdElement, SupportedLaneCount};
33

44
/// Operations on SIMD vectors of unsigned integers.
55
pub trait SimdUint: Copy + Sealed {
@@ -57,6 +57,22 @@ pub trait SimdUint: Copy + Sealed {
5757
/// assert_eq!(sat, Simd::splat(0));
5858
fn saturating_sub(self, second: Self) -> Self;
5959

60+
/// Lanewise absolute difference.
61+
/// Every element becomes the absolute difference of `self` and `second`.
62+
///
63+
/// # Examples
64+
/// ```
65+
/// # #![feature(portable_simd)]
66+
/// # #[cfg(feature = "as_crate")] use core_simd::simd;
67+
/// # #[cfg(not(feature = "as_crate"))] use core::simd;
68+
/// # use simd::prelude::*;
69+
/// use core::u32::MAX;
70+
/// let a = Simd::from_array([0, MAX, 100, 20]);
71+
/// let b = Simd::from_array([MAX, 0, 80, 200]);
72+
/// assert_eq!(a.abs_diff(b), Simd::from_array([MAX, MAX, 20, 180]));
73+
/// ```
74+
fn abs_diff(self, second: Self) -> Self;
75+
6076
/// Returns the sum of the elements of the vector, with wrapping addition.
6177
fn reduce_sum(self) -> Self::Scalar;
6278

@@ -138,6 +154,13 @@ macro_rules! impl_trait {
138154
unsafe { core::intrinsics::simd::simd_saturating_sub(self, second) }
139155
}
140156

157+
#[inline]
158+
fn abs_diff(self, second: Self) -> Self {
159+
let max = self.simd_max(second);
160+
let min = self.simd_min(second);
161+
max - min
162+
}
163+
141164
#[inline]
142165
fn reduce_sum(self) -> Self::Scalar {
143166
// Safety: `self` is an integer vector

Diff for: crates/core_simd/tests/ops_macros.rs

+16
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,14 @@ macro_rules! impl_signed_tests {
307307
assert_eq!(a % b, Vector::<LANES>::splat(0));
308308
}
309309

310+
fn abs_diff<const LANES: usize>() {
311+
test_helpers::test_binary_elementwise(
312+
&Vector::<LANES>::abs_diff,
313+
&Scalar::abs_diff,
314+
&|_, _| true,
315+
)
316+
}
317+
310318
fn simd_min<const LANES: usize>() {
311319
use core_simd::simd::cmp::SimdOrd;
312320
let a = Vector::<LANES>::splat(Scalar::MIN);
@@ -419,6 +427,14 @@ macro_rules! impl_unsigned_tests {
419427
&|_| true,
420428
);
421429
}
430+
431+
fn abs_diff<const LANES: usize>() {
432+
test_helpers::test_binary_elementwise(
433+
&Vector::<LANES>::abs_diff,
434+
&Scalar::abs_diff,
435+
&|_, _| true,
436+
)
437+
}
422438
}
423439

424440
impl_binary_op_test!(Scalar, Add::add, AddAssign::add_assign, Scalar::wrapping_add);

0 commit comments

Comments
 (0)