Skip to content

Commit

Permalink
Clarified that vectors must be finite to be normalized.
Browse files Browse the repository at this point in the history
Added is_finite_mask method which has simd implementations.
  • Loading branch information
bitshifter committed Jun 16, 2024
1 parent 3692d07 commit b3721e8
Show file tree
Hide file tree
Showing 16 changed files with 195 additions and 65 deletions.
37 changes: 27 additions & 10 deletions codegen/templates/vec.rs.tera
Original file line number Diff line number Diff line change
Expand Up @@ -1334,16 +1334,33 @@ impl {{ self_t }} {
#[inline]
#[must_use]
pub fn is_finite(self) -> bool {
{% if is_coresimd %}
{% if dim == 3 %}
f32x4::is_finite(self.0).bitor(mask32x4::from_array([false, false, false, true])).all()
{% elif dim == 4 %}
f32x4::is_finite(self.0).all()
{% endif %}
{% else %}
{% if is_scalar %}
{% for c in components %}
self.{{ c }}.is_finite() {% if not loop.last %} && {% endif %}
{%- endfor %}
{% else %}
self.is_finite_mask().all()
{% endif %}
}

/// Performs `is_finite` on each element of self, returning a vector mask of the results.
///
/// In other words, this computes `[x.is_finite(), y.is_finite(), ...]`.
pub fn is_finite_mask(self) -> {{ mask_t }} {
{% if is_scalar %}
{{ mask_t }}::new(
{% for c in components %}
self.{{ c }}.is_finite(),
{%- endfor %}
)
{% elif is_sse2 %}
{{ mask_t }}(unsafe { _mm_cmplt_ps(crate::sse2::m128_abs(self.0), Self::INFINITY.0) })
{% elif is_wasm32 %}
{{ mask_t }}(f32x4_lt(f32x4_abs(self.0), Self::INFINITY.0))
{% elif is_coresimd %}
{{ mask_t }}(f32x4::is_finite(self.0))
{% elif is_neon %}
{{ mask_t }}(unsafe { vcltq_f32(vabsq_f32(self.0), Self::INFINITY.0) })
{% endif %}
}

Expand All @@ -1362,7 +1379,7 @@ impl {{ self_t }} {

/// Performs `is_nan` on each element of self, returning a vector mask of the results.
///
/// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`.
/// In other words, this computes `[x.is_nan(), y.is_nan(), ...]`.
#[inline]
#[must_use]
pub fn is_nan_mask(self) -> {{ mask_t }} {
Expand Down Expand Up @@ -1502,13 +1519,13 @@ impl {{ self_t }} {
{% if is_float %}
/// Returns `self` normalized to length 1.0.
///
/// For valid results, `self` must _not_ be of length zero, nor very close to zero.
/// For valid results, `self` must be finite and _not_ of length zero, nor very close to zero.
///
/// See also [`Self::try_normalize()`] and [`Self::normalize_or_zero()`].
///
/// Panics
///
/// Will panic if `self` is zero length when `glam_assert` is enabled.
/// Will panic if the resulting normalized vector is not finite when `glam_assert` is enabled.
#[inline]
#[must_use]
pub fn normalize(self) -> Self {
Expand Down
17 changes: 11 additions & 6 deletions src/f32/coresimd/vec3a.rs
Original file line number Diff line number Diff line change
Expand Up @@ -394,9 +394,14 @@ impl Vec3A {
#[inline]
#[must_use]
pub fn is_finite(self) -> bool {
f32x4::is_finite(self.0)
.bitor(mask32x4::from_array([false, false, false, true]))
.all()
self.is_finite_mask().all()
}

/// Performs `is_finite` on each element of self, returning a vector mask of the results.
///
/// In other words, this computes `[x.is_finite(), y.is_finite(), ...]`.
pub fn is_finite_mask(self) -> BVec3A {
BVec3A(f32x4::is_finite(self.0))
}

/// Returns `true` if any elements are `NaN`.
Expand All @@ -408,7 +413,7 @@ impl Vec3A {

/// Performs `is_nan` on each element of self, returning a vector mask of the results.
///
/// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`.
/// In other words, this computes `[x.is_nan(), y.is_nan(), ...]`.
#[inline]
#[must_use]
pub fn is_nan_mask(self) -> BVec3A {
Expand Down Expand Up @@ -484,13 +489,13 @@ impl Vec3A {

/// Returns `self` normalized to length 1.0.
///
/// For valid results, `self` must _not_ be of length zero, nor very close to zero.
/// For valid results, `self` must be finite and _not_ of length zero, nor very close to zero.
///
/// See also [`Self::try_normalize()`] and [`Self::normalize_or_zero()`].
///
/// Panics
///
/// Will panic if `self` is zero length when `glam_assert` is enabled.
/// Will panic if the resulting normalized vector is not finite when `glam_assert` is enabled.
#[inline]
#[must_use]
pub fn normalize(self) -> Self {
Expand Down
15 changes: 11 additions & 4 deletions src/f32/coresimd/vec4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,14 @@ impl Vec4 {
#[inline]
#[must_use]
pub fn is_finite(self) -> bool {
f32x4::is_finite(self.0).all()
self.is_finite_mask().all()
}

/// Performs `is_finite` on each element of self, returning a vector mask of the results.
///
/// In other words, this computes `[x.is_finite(), y.is_finite(), ...]`.
pub fn is_finite_mask(self) -> BVec4A {
BVec4A(f32x4::is_finite(self.0))
}

/// Returns `true` if any elements are `NaN`.
Expand All @@ -385,7 +392,7 @@ impl Vec4 {

/// Performs `is_nan` on each element of self, returning a vector mask of the results.
///
/// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`.
/// In other words, this computes `[x.is_nan(), y.is_nan(), ...]`.
#[inline]
#[must_use]
pub fn is_nan_mask(self) -> BVec4A {
Expand Down Expand Up @@ -463,13 +470,13 @@ impl Vec4 {

/// Returns `self` normalized to length 1.0.
///
/// For valid results, `self` must _not_ be of length zero, nor very close to zero.
/// For valid results, `self` must be finite and _not_ of length zero, nor very close to zero.
///
/// See also [`Self::try_normalize()`] and [`Self::normalize_or_zero()`].
///
/// Panics
///
/// Will panic if `self` is zero length when `glam_assert` is enabled.
/// Will panic if the resulting normalized vector is not finite when `glam_assert` is enabled.
#[inline]
#[must_use]
pub fn normalize(self) -> Self {
Expand Down
15 changes: 11 additions & 4 deletions src/f32/neon/vec3a.rs
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,14 @@ impl Vec3A {
#[inline]
#[must_use]
pub fn is_finite(self) -> bool {
self.x.is_finite() && self.y.is_finite() && self.z.is_finite()
self.is_finite_mask().all()
}

/// Performs `is_finite` on each element of self, returning a vector mask of the results.
///
/// In other words, this computes `[x.is_finite(), y.is_finite(), ...]`.
pub fn is_finite_mask(self) -> BVec3A {
BVec3A(unsafe { vcltq_f32(vabsq_f32(self.0), Self::INFINITY.0) })
}

/// Returns `true` if any elements are `NaN`.
Expand All @@ -453,7 +460,7 @@ impl Vec3A {

/// Performs `is_nan` on each element of self, returning a vector mask of the results.
///
/// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`.
/// In other words, this computes `[x.is_nan(), y.is_nan(), ...]`.
#[inline]
#[must_use]
pub fn is_nan_mask(self) -> BVec3A {
Expand Down Expand Up @@ -527,13 +534,13 @@ impl Vec3A {

/// Returns `self` normalized to length 1.0.
///
/// For valid results, `self` must _not_ be of length zero, nor very close to zero.
/// For valid results, `self` must be finite and _not_ of length zero, nor very close to zero.
///
/// See also [`Self::try_normalize()`] and [`Self::normalize_or_zero()`].
///
/// Panics
///
/// Will panic if `self` is zero length when `glam_assert` is enabled.
/// Will panic if the resulting normalized vector is not finite when `glam_assert` is enabled.
#[inline]
#[must_use]
pub fn normalize(self) -> Self {
Expand Down
15 changes: 11 additions & 4 deletions src/f32/neon/vec4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,14 @@ impl Vec4 {
#[inline]
#[must_use]
pub fn is_finite(self) -> bool {
self.x.is_finite() && self.y.is_finite() && self.z.is_finite() && self.w.is_finite()
self.is_finite_mask().all()
}

/// Performs `is_finite` on each element of self, returning a vector mask of the results.
///
/// In other words, this computes `[x.is_finite(), y.is_finite(), ...]`.
pub fn is_finite_mask(self) -> BVec4A {
BVec4A(unsafe { vcltq_f32(vabsq_f32(self.0), Self::INFINITY.0) })
}

/// Returns `true` if any elements are `NaN`.
Expand All @@ -422,7 +429,7 @@ impl Vec4 {

/// Performs `is_nan` on each element of self, returning a vector mask of the results.
///
/// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`.
/// In other words, this computes `[x.is_nan(), y.is_nan(), ...]`.
#[inline]
#[must_use]
pub fn is_nan_mask(self) -> BVec4A {
Expand Down Expand Up @@ -498,13 +505,13 @@ impl Vec4 {

/// Returns `self` normalized to length 1.0.
///
/// For valid results, `self` must _not_ be of length zero, nor very close to zero.
/// For valid results, `self` must be finite and _not_ of length zero, nor very close to zero.
///
/// See also [`Self::try_normalize()`] and [`Self::normalize_or_zero()`].
///
/// Panics
///
/// Will panic if `self` is zero length when `glam_assert` is enabled.
/// Will panic if the resulting normalized vector is not finite when `glam_assert` is enabled.
#[inline]
#[must_use]
pub fn normalize(self) -> Self {
Expand Down
13 changes: 10 additions & 3 deletions src/f32/scalar/vec3a.rs
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,13 @@ impl Vec3A {
self.x.is_finite() && self.y.is_finite() && self.z.is_finite()
}

/// Performs `is_finite` on each element of self, returning a vector mask of the results.
///
/// In other words, this computes `[x.is_finite(), y.is_finite(), ...]`.
pub fn is_finite_mask(self) -> BVec3A {
BVec3A::new(self.x.is_finite(), self.y.is_finite(), self.z.is_finite())
}

/// Returns `true` if any elements are `NaN`.
#[inline]
#[must_use]
Expand All @@ -432,7 +439,7 @@ impl Vec3A {

/// Performs `is_nan` on each element of self, returning a vector mask of the results.
///
/// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`.
/// In other words, this computes `[x.is_nan(), y.is_nan(), ...]`.
#[inline]
#[must_use]
pub fn is_nan_mask(self) -> BVec3A {
Expand Down Expand Up @@ -506,13 +513,13 @@ impl Vec3A {

/// Returns `self` normalized to length 1.0.
///
/// For valid results, `self` must _not_ be of length zero, nor very close to zero.
/// For valid results, `self` must be finite and _not_ of length zero, nor very close to zero.
///
/// See also [`Self::try_normalize()`] and [`Self::normalize_or_zero()`].
///
/// Panics
///
/// Will panic if `self` is zero length when `glam_assert` is enabled.
/// Will panic if the resulting normalized vector is not finite when `glam_assert` is enabled.
#[inline]
#[must_use]
pub fn normalize(self) -> Self {
Expand Down
18 changes: 15 additions & 3 deletions src/f32/scalar/vec4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,18 @@ impl Vec4 {
self.x.is_finite() && self.y.is_finite() && self.z.is_finite() && self.w.is_finite()
}

/// Performs `is_finite` on each element of self, returning a vector mask of the results.
///
/// In other words, this computes `[x.is_finite(), y.is_finite(), ...]`.
pub fn is_finite_mask(self) -> BVec4A {
BVec4A::new(
self.x.is_finite(),
self.y.is_finite(),
self.z.is_finite(),
self.w.is_finite(),
)
}

/// Returns `true` if any elements are `NaN`.
#[inline]
#[must_use]
Expand All @@ -467,7 +479,7 @@ impl Vec4 {

/// Performs `is_nan` on each element of self, returning a vector mask of the results.
///
/// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`.
/// In other words, this computes `[x.is_nan(), y.is_nan(), ...]`.
#[inline]
#[must_use]
pub fn is_nan_mask(self) -> BVec4A {
Expand Down Expand Up @@ -548,13 +560,13 @@ impl Vec4 {

/// Returns `self` normalized to length 1.0.
///
/// For valid results, `self` must _not_ be of length zero, nor very close to zero.
/// For valid results, `self` must be finite and _not_ of length zero, nor very close to zero.
///
/// See also [`Self::try_normalize()`] and [`Self::normalize_or_zero()`].
///
/// Panics
///
/// Will panic if `self` is zero length when `glam_assert` is enabled.
/// Will panic if the resulting normalized vector is not finite when `glam_assert` is enabled.
#[inline]
#[must_use]
pub fn normalize(self) -> Self {
Expand Down
15 changes: 11 additions & 4 deletions src/f32/sse2/vec3a.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,14 @@ impl Vec3A {
#[inline]
#[must_use]
pub fn is_finite(self) -> bool {
self.x.is_finite() && self.y.is_finite() && self.z.is_finite()
self.is_finite_mask().all()
}

/// Performs `is_finite` on each element of self, returning a vector mask of the results.
///
/// In other words, this computes `[x.is_finite(), y.is_finite(), ...]`.
pub fn is_finite_mask(self) -> BVec3A {
BVec3A(unsafe { _mm_cmplt_ps(crate::sse2::m128_abs(self.0), Self::INFINITY.0) })
}

/// Returns `true` if any elements are `NaN`.
Expand All @@ -443,7 +450,7 @@ impl Vec3A {

/// Performs `is_nan` on each element of self, returning a vector mask of the results.
///
/// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`.
/// In other words, this computes `[x.is_nan(), y.is_nan(), ...]`.
#[inline]
#[must_use]
pub fn is_nan_mask(self) -> BVec3A {
Expand Down Expand Up @@ -523,13 +530,13 @@ impl Vec3A {

/// Returns `self` normalized to length 1.0.
///
/// For valid results, `self` must _not_ be of length zero, nor very close to zero.
/// For valid results, `self` must be finite and _not_ of length zero, nor very close to zero.
///
/// See also [`Self::try_normalize()`] and [`Self::normalize_or_zero()`].
///
/// Panics
///
/// Will panic if `self` is zero length when `glam_assert` is enabled.
/// Will panic if the resulting normalized vector is not finite when `glam_assert` is enabled.
#[inline]
#[must_use]
pub fn normalize(self) -> Self {
Expand Down
15 changes: 11 additions & 4 deletions src/f32/sse2/vec4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,14 @@ impl Vec4 {
#[inline]
#[must_use]
pub fn is_finite(self) -> bool {
self.x.is_finite() && self.y.is_finite() && self.z.is_finite() && self.w.is_finite()
self.is_finite_mask().all()
}

/// Performs `is_finite` on each element of self, returning a vector mask of the results.
///
/// In other words, this computes `[x.is_finite(), y.is_finite(), ...]`.
pub fn is_finite_mask(self) -> BVec4A {
BVec4A(unsafe { _mm_cmplt_ps(crate::sse2::m128_abs(self.0), Self::INFINITY.0) })
}

/// Returns `true` if any elements are `NaN`.
Expand All @@ -421,7 +428,7 @@ impl Vec4 {

/// Performs `is_nan` on each element of self, returning a vector mask of the results.
///
/// In other words, this computes `[x.is_nan(), y.is_nan(), z.is_nan(), w.is_nan()]`.
/// In other words, this computes `[x.is_nan(), y.is_nan(), ...]`.
#[inline]
#[must_use]
pub fn is_nan_mask(self) -> BVec4A {
Expand Down Expand Up @@ -503,13 +510,13 @@ impl Vec4 {

/// Returns `self` normalized to length 1.0.
///
/// For valid results, `self` must _not_ be of length zero, nor very close to zero.
/// For valid results, `self` must be finite and _not_ of length zero, nor very close to zero.
///
/// See also [`Self::try_normalize()`] and [`Self::normalize_or_zero()`].
///
/// Panics
///
/// Will panic if `self` is zero length when `glam_assert` is enabled.
/// Will panic if the resulting normalized vector is not finite when `glam_assert` is enabled.
#[inline]
#[must_use]
pub fn normalize(self) -> Self {
Expand Down
Loading

0 comments on commit b3721e8

Please sign in to comment.