Skip to content

Commit

Permalink
Add copysign operation and unit tests for it (#371)
Browse files Browse the repository at this point in the history
  • Loading branch information
atlv24 committed Dec 28, 2022
1 parent 7a78b18 commit 3b65de3
Show file tree
Hide file tree
Showing 20 changed files with 286 additions and 1 deletion.
26 changes: 26 additions & 0 deletions codegen/templates/vec.rs.tera
Original file line number Diff line number Diff line change
Expand Up @@ -829,6 +829,32 @@ impl {{ self_t }} {
{% endif %}
}

/// Returns a vector with signs of `rhs` and the magnitudes of `self`.
#[inline]
pub fn copysign(self, rhs: Self) -> Self {
{% if is_scalar and is_float %}
Self {
{% for c in components %}
{{ c }}: self.{{ c }}.copysign(rhs.{{ c }}),
{%- endfor %}
}
{% elif is_scalar %}
Self::select(rhs.cmpge(Self::ZERO), self, -self)
{% elif is_coresimd %}
Self(self.0.copysign(rhs.0))
{% elif is_sse2 %}
unsafe {
let mask = Self::splat(-0.0);
Self(_mm_or_ps(_mm_and_ps(rhs.0, mask.0), _mm_andnot_ps(mask.0, self.0)))
}
{% elif is_wasm32 %}
unsafe {
let mask = Self::splat(-0.0);
Self(v128_or(v128_and(rhs.0, mask.0), v128_andnot(self.0, mask.0)))
}
{% endif %}
}

/// Returns a bitmask with the lowest {{ dim }} bits set to the sign bits from the elements of `self`.
///
/// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes
Expand Down
6 changes: 6 additions & 0 deletions src/f32/coresimd/vec3a.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,12 @@ impl Vec3A {
Self(self.0.signum())
}

/// Returns a vector with signs of `rhs` and the magnitudes of `self`.
#[inline]
pub fn copysign(self, rhs: Self) -> Self {
Self(self.0.copysign(rhs.0))
}

/// Returns a bitmask with the lowest 3 bits set to the sign bits from the elements of `self`.
///
/// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes
Expand Down
6 changes: 6 additions & 0 deletions src/f32/coresimd/vec4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,12 @@ impl Vec4 {
Self(self.0.signum())
}

/// Returns a vector with signs of `rhs` and the magnitudes of `self`.
#[inline]
pub fn copysign(self, rhs: Self) -> Self {
Self(self.0.copysign(rhs.0))
}

/// Returns a bitmask with the lowest 4 bits set to the sign bits from the elements of `self`.
///
/// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes
Expand Down
10 changes: 10 additions & 0 deletions src/f32/scalar/vec3a.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,16 @@ impl Vec3A {
}
}

/// Returns a vector with signs of `rhs` and the magnitudes of `self`.
#[inline]
pub fn copysign(self, rhs: Self) -> Self {
Self {
x: self.x.copysign(rhs.x),
y: self.y.copysign(rhs.y),
z: self.z.copysign(rhs.z),
}
}

/// Returns a bitmask with the lowest 3 bits set to the sign bits from the elements of `self`.
///
/// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes
Expand Down
11 changes: 11 additions & 0 deletions src/f32/scalar/vec4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,17 @@ impl Vec4 {
}
}

/// Returns a vector with signs of `rhs` and the magnitudes of `self`.
#[inline]
pub fn copysign(self, rhs: Self) -> Self {
Self {
x: self.x.copysign(rhs.x),
y: self.y.copysign(rhs.y),
z: self.z.copysign(rhs.z),
w: self.w.copysign(rhs.w),
}
}

/// Returns a bitmask with the lowest 4 bits set to the sign bits from the elements of `self`.
///
/// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes
Expand Down
12 changes: 12 additions & 0 deletions src/f32/sse2/vec3a.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,18 @@ impl Vec3A {
}
}

/// Returns a vector with signs of `rhs` and the magnitudes of `self`.
#[inline]
pub fn copysign(self, rhs: Self) -> Self {
unsafe {
let mask = Self::splat(-0.0);
Self(_mm_or_ps(
_mm_and_ps(rhs.0, mask.0),
_mm_andnot_ps(mask.0, self.0),
))
}
}

/// Returns a bitmask with the lowest 3 bits set to the sign bits from the elements of `self`.
///
/// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes
Expand Down
12 changes: 12 additions & 0 deletions src/f32/sse2/vec4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,18 @@ impl Vec4 {
}
}

/// Returns a vector with signs of `rhs` and the magnitudes of `self`.
#[inline]
pub fn copysign(self, rhs: Self) -> Self {
unsafe {
let mask = Self::splat(-0.0);
Self(_mm_or_ps(
_mm_and_ps(rhs.0, mask.0),
_mm_andnot_ps(mask.0, self.0),
))
}
}

/// Returns a bitmask with the lowest 4 bits set to the sign bits from the elements of `self`.
///
/// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes
Expand Down
9 changes: 9 additions & 0 deletions src/f32/vec2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,15 @@ impl Vec2 {
}
}

/// Returns a vector with signs of `rhs` and the magnitudes of `self`.
#[inline]
pub fn copysign(self, rhs: Self) -> Self {
Self {
x: self.x.copysign(rhs.x),
y: self.y.copysign(rhs.y),
}
}

/// Returns a bitmask with the lowest 2 bits set to the sign bits from the elements of `self`.
///
/// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes
Expand Down
10 changes: 10 additions & 0 deletions src/f32/vec3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,16 @@ impl Vec3 {
}
}

/// Returns a vector with signs of `rhs` and the magnitudes of `self`.
#[inline]
pub fn copysign(self, rhs: Self) -> Self {
Self {
x: self.x.copysign(rhs.x),
y: self.y.copysign(rhs.y),
z: self.z.copysign(rhs.z),
}
}

/// Returns a bitmask with the lowest 3 bits set to the sign bits from the elements of `self`.
///
/// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes
Expand Down
12 changes: 12 additions & 0 deletions src/f32/wasm32/vec3a.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,18 @@ impl Vec3A {
}
}

/// Returns a vector with signs of `rhs` and the magnitudes of `self`.
#[inline]
pub fn copysign(self, rhs: Self) -> Self {
unsafe {
let mask = Self::splat(-0.0);
Self(v128_or(
v128_and(rhs.0, mask.0),
v128_andnot(self.0, mask.0),
))
}
}

/// Returns a bitmask with the lowest 3 bits set to the sign bits from the elements of `self`.
///
/// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes
Expand Down
12 changes: 12 additions & 0 deletions src/f32/wasm32/vec4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,18 @@ impl Vec4 {
}
}

/// Returns a vector with signs of `rhs` and the magnitudes of `self`.
#[inline]
pub fn copysign(self, rhs: Self) -> Self {
unsafe {
let mask = Self::splat(-0.0);
Self(v128_or(
v128_and(rhs.0, mask.0),
v128_andnot(self.0, mask.0),
))
}
}

/// Returns a bitmask with the lowest 4 bits set to the sign bits from the elements of `self`.
///
/// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes
Expand Down
9 changes: 9 additions & 0 deletions src/f64/dvec2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,15 @@ impl DVec2 {
}
}

/// Returns a vector with signs of `rhs` and the magnitudes of `self`.
#[inline]
pub fn copysign(self, rhs: Self) -> Self {
Self {
x: self.x.copysign(rhs.x),
y: self.y.copysign(rhs.y),
}
}

/// Returns a bitmask with the lowest 2 bits set to the sign bits from the elements of `self`.
///
/// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes
Expand Down
10 changes: 10 additions & 0 deletions src/f64/dvec3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,16 @@ impl DVec3 {
}
}

/// Returns a vector with signs of `rhs` and the magnitudes of `self`.
#[inline]
pub fn copysign(self, rhs: Self) -> Self {
Self {
x: self.x.copysign(rhs.x),
y: self.y.copysign(rhs.y),
z: self.z.copysign(rhs.z),
}
}

/// Returns a bitmask with the lowest 3 bits set to the sign bits from the elements of `self`.
///
/// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes
Expand Down
11 changes: 11 additions & 0 deletions src/f64/dvec4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,17 @@ impl DVec4 {
}
}

/// Returns a vector with signs of `rhs` and the magnitudes of `self`.
#[inline]
pub fn copysign(self, rhs: Self) -> Self {
Self {
x: self.x.copysign(rhs.x),
y: self.y.copysign(rhs.y),
z: self.z.copysign(rhs.z),
w: self.w.copysign(rhs.w),
}
}

/// Returns a bitmask with the lowest 4 bits set to the sign bits from the elements of `self`.
///
/// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes
Expand Down
6 changes: 6 additions & 0 deletions src/i32/ivec2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,12 @@ impl IVec2 {
}
}

/// Returns a vector with signs of `rhs` and the magnitudes of `self`.
#[inline]
pub fn copysign(self, rhs: Self) -> Self {
Self::select(rhs.cmpge(Self::ZERO), self, -self)
}

/// Returns a bitmask with the lowest 2 bits set to the sign bits from the elements of `self`.
///
/// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes
Expand Down
6 changes: 6 additions & 0 deletions src/i32/ivec3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,12 @@ impl IVec3 {
}
}

/// Returns a vector with signs of `rhs` and the magnitudes of `self`.
#[inline]
pub fn copysign(self, rhs: Self) -> Self {
Self::select(rhs.cmpge(Self::ZERO), self, -self)
}

/// Returns a bitmask with the lowest 3 bits set to the sign bits from the elements of `self`.
///
/// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes
Expand Down
6 changes: 6 additions & 0 deletions src/i32/ivec4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,12 @@ impl IVec4 {
}
}

/// Returns a vector with signs of `rhs` and the magnitudes of `self`.
#[inline]
pub fn copysign(self, rhs: Self) -> Self {
Self::select(rhs.cmpge(Self::ZERO), self, -self)
}

/// Returns a bitmask with the lowest 4 bits set to the sign bits from the elements of `self`.
///
/// A negative element results in a `1` bit and a positive element in a `0` bit. Element `x` goes
Expand Down
39 changes: 38 additions & 1 deletion tests/vec2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -593,7 +593,7 @@ macro_rules! impl_vec2_float_tests {
should_glam_assert!({ $vec2::ONE.reject_from_normalized($vec2::ONE) });
});

glam_test!(test_sign, {
glam_test!(test_signum, {
assert_eq!($vec2::ZERO.signum(), $vec2::ONE);
assert_eq!((-$vec2::ZERO).signum(), -$vec2::ONE);
assert_eq!($vec2::ONE.signum(), $vec2::ONE);
Expand All @@ -603,6 +603,43 @@ macro_rules! impl_vec2_float_tests {
assert!($vec2::splat(NAN).signum().is_nan_mask().all());
});

glam_test!(test_copysign, {
assert_eq!($vec2::ZERO.copysign(-$vec2::ZERO), -$vec2::ZERO);
assert_eq!((-$vec2::ZERO).copysign(-$vec2::ZERO), -$vec2::ZERO);
assert_eq!($vec2::ZERO.copysign($vec2::ZERO), $vec2::ZERO);
assert_eq!((-$vec2::ZERO).copysign($vec2::ZERO), $vec2::ZERO);
assert_eq!($vec2::ONE.copysign(-$vec2::ZERO), -$vec2::ONE);
assert_eq!((-$vec2::ONE).copysign(-$vec2::ZERO), -$vec2::ONE);
assert_eq!($vec2::ONE.copysign($vec2::ZERO), $vec2::ONE);
assert_eq!((-$vec2::ONE).copysign($vec2::ZERO), $vec2::ONE);
assert_eq!($vec2::ZERO.copysign(-$vec2::ONE), -$vec2::ZERO);
assert_eq!((-$vec2::ZERO).copysign(-$vec2::ONE), -$vec2::ZERO);
assert_eq!($vec2::ZERO.copysign($vec2::ONE), $vec2::ZERO);
assert_eq!((-$vec2::ZERO).copysign($vec2::ONE), $vec2::ZERO);
assert_eq!($vec2::ONE.copysign(-$vec2::ONE), -$vec2::ONE);
assert_eq!((-$vec2::ONE).copysign(-$vec2::ONE), -$vec2::ONE);
assert_eq!($vec2::ONE.copysign($vec2::ONE), $vec2::ONE);
assert_eq!((-$vec2::ONE).copysign($vec2::ONE), $vec2::ONE);
assert_eq!(
$vec2::splat(INFINITY).copysign($vec2::ONE),
$vec2::splat(INFINITY)
);
assert_eq!(
$vec2::splat(INFINITY).copysign(-$vec2::ONE),
$vec2::splat(NEG_INFINITY)
);
assert_eq!(
$vec2::splat(NEG_INFINITY).copysign($vec2::ONE),
$vec2::splat(INFINITY)
);
assert_eq!(
$vec2::splat(NEG_INFINITY).copysign(-$vec2::ONE),
$vec2::splat(NEG_INFINITY)
);
assert!($vec2::splat(NAN).copysign($vec2::ONE).is_nan_mask().all());
assert!($vec2::splat(NAN).copysign(-$vec2::ONE).is_nan_mask().all());
});

glam_test!(test_is_negative_bitmask, {
assert_eq!($vec2::ZERO.is_negative_bitmask(), 0b00);
assert_eq!((-$vec2::ZERO).is_negative_bitmask(), 0b11);
Expand Down
37 changes: 37 additions & 0 deletions tests/vec3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,43 @@ macro_rules! impl_vec3_float_tests {
assert!($vec3::splat(NAN).signum().is_nan_mask().all());
});

glam_test!(test_copysign, {
assert_eq!($vec3::ZERO.copysign(-$vec3::ZERO), -$vec3::ZERO);
assert_eq!((-$vec3::ZERO).copysign(-$vec3::ZERO), -$vec3::ZERO);
assert_eq!($vec3::ZERO.copysign($vec3::ZERO), $vec3::ZERO);
assert_eq!((-$vec3::ZERO).copysign($vec3::ZERO), $vec3::ZERO);
assert_eq!($vec3::ONE.copysign(-$vec3::ZERO), -$vec3::ONE);
assert_eq!((-$vec3::ONE).copysign(-$vec3::ZERO), -$vec3::ONE);
assert_eq!($vec3::ONE.copysign($vec3::ZERO), $vec3::ONE);
assert_eq!((-$vec3::ONE).copysign($vec3::ZERO), $vec3::ONE);
assert_eq!($vec3::ZERO.copysign(-$vec3::ONE), -$vec3::ZERO);
assert_eq!((-$vec3::ZERO).copysign(-$vec3::ONE), -$vec3::ZERO);
assert_eq!($vec3::ZERO.copysign($vec3::ONE), $vec3::ZERO);
assert_eq!((-$vec3::ZERO).copysign($vec3::ONE), $vec3::ZERO);
assert_eq!($vec3::ONE.copysign(-$vec3::ONE), -$vec3::ONE);
assert_eq!((-$vec3::ONE).copysign(-$vec3::ONE), -$vec3::ONE);
assert_eq!($vec3::ONE.copysign($vec3::ONE), $vec3::ONE);
assert_eq!((-$vec3::ONE).copysign($vec3::ONE), $vec3::ONE);
assert_eq!(
$vec3::splat(INFINITY).copysign($vec3::ONE),
$vec3::splat(INFINITY)
);
assert_eq!(
$vec3::splat(INFINITY).copysign(-$vec3::ONE),
$vec3::splat(NEG_INFINITY)
);
assert_eq!(
$vec3::splat(NEG_INFINITY).copysign($vec3::ONE),
$vec3::splat(INFINITY)
);
assert_eq!(
$vec3::splat(NEG_INFINITY).copysign(-$vec3::ONE),
$vec3::splat(NEG_INFINITY)
);
assert!($vec3::splat(NAN).copysign($vec3::ONE).is_nan_mask().all());
assert!($vec3::splat(NAN).copysign(-$vec3::ONE).is_nan_mask().all());
});

glam_test!(test_is_negative_bitmask, {
assert_eq!($vec3::ZERO.is_negative_bitmask(), 0b000);
assert_eq!((-$vec3::ZERO).is_negative_bitmask(), 0b111);
Expand Down

0 comments on commit 3b65de3

Please sign in to comment.