Skip to content

Commit b936f34

Browse files
committed
Add various special functions (recip, signum, copysign)
1 parent 96f0f5d commit b936f34

File tree

3 files changed

+104
-1
lines changed

3 files changed

+104
-1
lines changed

crates/core_simd/src/vector/float.rs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
/// `$lanes` of float `$type`, which uses `$bits_ty` as its binary
55
/// representation. Called from `define_float_vector!`.
66
macro_rules! impl_float_vector {
7-
{ $name:ident, $type:ty, $bits_ty:ident, $mask_ty:ident, $mask_impl_ty:ident } => {
7+
{ $name:ident, $type:ident, $bits_ty:ident, $mask_ty:ident, $mask_impl_ty:ident } => {
88
impl_vector! { $name, $type }
99
impl_float_reductions! { $name, $type }
1010

@@ -43,6 +43,25 @@ macro_rules! impl_float_vector {
4343
pub fn sqrt(self) -> Self {
4444
unsafe { crate::intrinsics::simd_fsqrt(self) }
4545
}
46+
47+
/// Takes the reciprocal (inverse) of each lane, `1/x`.
48+
#[inline]
49+
pub fn recip(self) -> Self {
50+
Self::splat(1.0) / self
51+
}
52+
53+
/// Converts each lane from radians to degrees.
54+
#[inline]
55+
pub fn to_degrees(self) -> Self {
56+
// to_degrees uses a special constant for better precision, so extract that constant
57+
self * Self::splat($type::to_degrees(1.))
58+
}
59+
60+
/// Converts each lane from degrees to radians.
61+
#[inline]
62+
pub fn to_radians(self) -> Self {
63+
self * Self::splat(core::$type::consts::PI / 180.)
64+
}
4665
}
4766

4867
impl<const LANES: usize> $name<LANES>
@@ -97,6 +116,26 @@ macro_rules! impl_float_vector {
97116
pub fn is_normal(self) -> crate::$mask_ty<LANES> {
98117
!(self.abs().lanes_eq(Self::splat(0.0)) | self.is_nan() | self.is_subnormal() | self.is_infinite())
99118
}
119+
120+
/// Replaces each lane with a number that represents its sign.
121+
///
122+
/// * `1.0` if the number is positive, `+0.0`, or `INFINITY`
123+
/// * `-1.0` if the number is negative, `-0.0`, or `NEG_INFINITY`
124+
/// * `NAN` if the number is `NAN`
125+
#[inline]
126+
pub fn signum(self) -> Self {
127+
self.is_nan().select(Self::splat($type::NAN), Self::splat(1.0).copysign(self))
128+
}
129+
130+
/// Returns each lane with the magnitude of `self` and the sign of `sign`.
131+
///
132+
/// If any lane is a `NAN`, then a `NAN` with the sign of `sign` is returned.
133+
#[inline]
134+
pub fn copysign(self, sign: Self) -> Self {
135+
let sign_bit = sign.to_bits() & Self::splat(-0.).to_bits();
136+
let magnitude = self.to_bits() & !Self::splat(-0.).to_bits();
137+
Self::from_bits(sign_bit | magnitude)
138+
}
100139
}
101140
};
102141
}

crates/core_simd/src/vector/int.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,28 @@ macro_rules! impl_integer_vector {
3333
crate::$mask_ty<LANES>: crate::Mask,
3434
{
3535
/// Returns true for each positive lane and false if it is zero or negative.
36+
#[inline]
3637
pub fn is_positive(self) -> crate::$mask_ty<LANES> {
3738
self.lanes_gt(Self::splat(0))
3839
}
3940

4041
/// Returns true for each negative lane and false if it is zero or positive.
42+
#[inline]
4143
pub fn is_negative(self) -> crate::$mask_ty<LANES> {
4244
self.lanes_lt(Self::splat(0))
4345
}
46+
47+
/// Returns numbers representing the sign of each lane.
48+
/// * `0` if the number is zero
49+
/// * `1` if the number is positive
50+
/// * `-1` if the number is negative
51+
#[inline]
52+
pub fn signum(self) -> Self {
53+
self.is_positive().select(
54+
Self::splat(1),
55+
self.is_negative().select(Self::splat(-1), Self::splat(0))
56+
)
57+
}
4458
}
4559
}
4660
}

crates/core_simd/tests/ops_macros.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,15 @@ macro_rules! impl_signed_tests {
247247
&|_| true,
248248
);
249249
}
250+
251+
fn signum<const LANES: usize>() {
252+
test_helpers::test_unary_elementwise(
253+
&Vector::<LANES>::signum,
254+
&Scalar::signum,
255+
&|_| true,
256+
)
257+
}
258+
250259
}
251260

252261
test_helpers::test_lanes_panic! {
@@ -433,6 +442,47 @@ macro_rules! impl_float_tests {
433442
&|_| true,
434443
)
435444
}
445+
446+
fn recip<const LANES: usize>() {
447+
test_helpers::test_unary_elementwise(
448+
&Vector::<LANES>::recip,
449+
&Scalar::recip,
450+
&|_| true,
451+
)
452+
}
453+
454+
fn to_degrees<const LANES: usize>() {
455+
test_helpers::test_unary_elementwise(
456+
&Vector::<LANES>::to_degrees,
457+
&Scalar::to_degrees,
458+
&|_| true,
459+
)
460+
}
461+
462+
fn to_radians<const LANES: usize>() {
463+
test_helpers::test_unary_elementwise(
464+
&Vector::<LANES>::to_radians,
465+
&Scalar::to_radians,
466+
&|_| true,
467+
)
468+
}
469+
470+
fn signum<const LANES: usize>() {
471+
test_helpers::test_unary_elementwise(
472+
&Vector::<LANES>::signum,
473+
&Scalar::signum,
474+
&|_| true,
475+
)
476+
}
477+
478+
fn copysign<const LANES: usize>() {
479+
test_helpers::test_binary_elementwise(
480+
&Vector::<LANES>::copysign,
481+
&Scalar::copysign,
482+
&|_, _| true,
483+
)
484+
}
485+
436486
fn horizontal_sum<const LANES: usize>() {
437487
test_helpers::test_1(&|x| {
438488
test_helpers::prop_assert_biteq! (

0 commit comments

Comments
 (0)