Repository: bitshifter/glam-rs
Pull request #419 (2023-07-27 22:51:13)

Implement div_euclid, rem_euclid
Fixes #417.

I didn't find a way to vectorize this any any of the used instruction sets, but perhaps I'm just not clever enough (for floats, euclidean div is essentially a normal div followed by rounding away from the divisor).


Patch:
diff --git a/codegen/templates/vec.rs.tera b/codegen/templates/vec.rs.tera
index 7a43064..694fae5 100644
--- a/codegen/templates/vec.rs.tera
+++ b/codegen/templates/vec.rs.tera
@@ -1074,6 +1074,46 @@ impl {{ self_t }} {
     pub fn distance_squared(self, rhs: Self) -> {{ scalar_t }} {
         (self - rhs).length_squared()
     }
+
+    /// Returns the element-wise quotient of [Euclidean division] of `self` by `rhs`.
+    {%- if not is_float%}
+    ///
+    /// # Panics
+    /// This function will panic if any `rhs` element is 0 or the division results in overflow.
+    {%- endif %}
+    #[inline]
+    pub fn div_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            {% for c in components %}
+                {% if is_float %}
+                math::div_euclid(self.{{ c }}, rhs.{{ c }}),
+                {% else %}
+                self.{{ c }}.div_euclid(rhs.{{ c }}),
+                {% endif %}
+            {%- endfor %}
+        )
+    }
+
+    /// Returns the element-wise remainder of [Euclidean division] of `self` by `rhs`.
+    {%- if not is_float %}
+    ///
+    /// # Panics
+    /// This function will panic if any `rhs` element is 0 or the division results in overflow.
+    {%- endif %}
+    ///
+    /// [Euclidean division]: {{scalar_t}}::rem_euclid
+    #[inline]
+    pub fn rem_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            {% for c in components %}
+                {% if is_float %}
+                math::rem_euclid(self.{{ c }}, rhs.{{ c }}),
+                {% else %}
+                self.{{ c }}.rem_euclid(rhs.{{ c }}),
+                {% endif %}
+            {%- endfor %}
+        )
+    }
 {% endif %}
 
 {% if is_float %}
diff --git a/src/f32/coresimd/vec3a.rs b/src/f32/coresimd/vec3a.rs
index 8ba4966..8cbfc4e 100644
--- a/src/f32/coresimd/vec3a.rs
+++ b/src/f32/coresimd/vec3a.rs
@@ -379,6 +379,28 @@ impl Vec3A {
         (self - rhs).length_squared()
     }
 
+    /// Returns the element-wise quotient of [Euclidean division] of `self` by `rhs`.
+    #[inline]
+    pub fn div_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            math::div_euclid(self.x, rhs.x),
+            math::div_euclid(self.y, rhs.y),
+            math::div_euclid(self.z, rhs.z),
+        )
+    }
+
+    /// Returns the element-wise remainder of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// [Euclidean division]: f32::rem_euclid
+    #[inline]
+    pub fn rem_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            math::rem_euclid(self.x, rhs.x),
+            math::rem_euclid(self.y, rhs.y),
+            math::rem_euclid(self.z, rhs.z),
+        )
+    }
+
     /// Returns `self` normalized to length 1.0.
     ///
     /// For valid results, `self` must _not_ be of length zero, nor very close to zero.
diff --git a/src/f32/coresimd/vec4.rs b/src/f32/coresimd/vec4.rs
index 8d0c4c6..ae819d0 100644
--- a/src/f32/coresimd/vec4.rs
+++ b/src/f32/coresimd/vec4.rs
@@ -352,6 +352,30 @@ impl Vec4 {
         (self - rhs).length_squared()
     }
 
+    /// Returns the element-wise quotient of [Euclidean division] of `self` by `rhs`.
+    #[inline]
+    pub fn div_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            math::div_euclid(self.x, rhs.x),
+            math::div_euclid(self.y, rhs.y),
+            math::div_euclid(self.z, rhs.z),
+            math::div_euclid(self.w, rhs.w),
+        )
+    }
+
+    /// Returns the element-wise remainder of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// [Euclidean division]: f32::rem_euclid
+    #[inline]
+    pub fn rem_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            math::rem_euclid(self.x, rhs.x),
+            math::rem_euclid(self.y, rhs.y),
+            math::rem_euclid(self.z, rhs.z),
+            math::rem_euclid(self.w, rhs.w),
+        )
+    }
+
     /// Returns `self` normalized to length 1.0.
     ///
     /// For valid results, `self` must _not_ be of length zero, nor very close to zero.
diff --git a/src/f32/math.rs b/src/f32/math.rs
index 5ddf4f4..b6d5f1f 100644
--- a/src/f32/math.rs
+++ b/src/f32/math.rs
@@ -123,6 +123,26 @@ mod libm_math {
     pub(crate) fn mul_add(a: f32, b: f32, c: f32) -> f32 {
         libm::fmaf(a, b, c)
     }
+
+    #[inline]
+    pub fn div_euclid(a: f32, b: f32) -> f32 {
+        // Based on https://doc.rust-lang.org/src/std/f32.rs.html#293
+        let q = libm::truncf(a / b);
+        if a % b < 0.0 {
+            return if b > 0.0 { q - 1.0 } else { q + 1.0 };
+        }
+        q
+    }
+
+    #[inline]
+    pub fn rem_euclid(a: f32, b: f32) -> f32 {
+        let r = a % b;
+        if r < 0.0 {
+            r + abs(b)
+        } else {
+            r
+        }
+    }
 }
 
 #[cfg(not(feature = "libm"))]
@@ -212,6 +232,16 @@ mod std_math {
     pub(crate) fn mul_add(a: f32, b: f32, c: f32) -> f32 {
         f32::mul_add(a, b, c)
     }
+
+    #[inline]
+    pub fn div_euclid(a: f32, b: f32) -> f32 {
+        f32::div_euclid(a, b)
+    }
+
+    #[inline]
+    pub fn rem_euclid(a: f32, b: f32) -> f32 {
+        f32::rem_euclid(a, b)
+    }
 }
 
 #[cfg(feature = "libm")]
diff --git a/src/f32/scalar/vec3a.rs b/src/f32/scalar/vec3a.rs
index 7797a86..f8c9665 100644
--- a/src/f32/scalar/vec3a.rs
+++ b/src/f32/scalar/vec3a.rs
@@ -401,6 +401,28 @@ impl Vec3A {
         (self - rhs).length_squared()
     }
 
+    /// Returns the element-wise quotient of [Euclidean division] of `self` by `rhs`.
+    #[inline]
+    pub fn div_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            math::div_euclid(self.x, rhs.x),
+            math::div_euclid(self.y, rhs.y),
+            math::div_euclid(self.z, rhs.z),
+        )
+    }
+
+    /// Returns the element-wise remainder of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// [Euclidean division]: f32::rem_euclid
+    #[inline]
+    pub fn rem_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            math::rem_euclid(self.x, rhs.x),
+            math::rem_euclid(self.y, rhs.y),
+            math::rem_euclid(self.z, rhs.z),
+        )
+    }
+
     /// Returns `self` normalized to length 1.0.
     ///
     /// For valid results, `self` must _not_ be of length zero, nor very close to zero.
diff --git a/src/f32/scalar/vec4.rs b/src/f32/scalar/vec4.rs
index 2859832..77b482a 100644
--- a/src/f32/scalar/vec4.rs
+++ b/src/f32/scalar/vec4.rs
@@ -432,6 +432,30 @@ impl Vec4 {
         (self - rhs).length_squared()
     }
 
+    /// Returns the element-wise quotient of [Euclidean division] of `self` by `rhs`.
+    #[inline]
+    pub fn div_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            math::div_euclid(self.x, rhs.x),
+            math::div_euclid(self.y, rhs.y),
+            math::div_euclid(self.z, rhs.z),
+            math::div_euclid(self.w, rhs.w),
+        )
+    }
+
+    /// Returns the element-wise remainder of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// [Euclidean division]: f32::rem_euclid
+    #[inline]
+    pub fn rem_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            math::rem_euclid(self.x, rhs.x),
+            math::rem_euclid(self.y, rhs.y),
+            math::rem_euclid(self.z, rhs.z),
+            math::rem_euclid(self.w, rhs.w),
+        )
+    }
+
     /// Returns `self` normalized to length 1.0.
     ///
     /// For valid results, `self` must _not_ be of length zero, nor very close to zero.
diff --git a/src/f32/sse2/vec3a.rs b/src/f32/sse2/vec3a.rs
index fc7db8d..87915fc 100644
--- a/src/f32/sse2/vec3a.rs
+++ b/src/f32/sse2/vec3a.rs
@@ -415,6 +415,28 @@ impl Vec3A {
         (self - rhs).length_squared()
     }
 
+    /// Returns the element-wise quotient of [Euclidean division] of `self` by `rhs`.
+    #[inline]
+    pub fn div_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            math::div_euclid(self.x, rhs.x),
+            math::div_euclid(self.y, rhs.y),
+            math::div_euclid(self.z, rhs.z),
+        )
+    }
+
+    /// Returns the element-wise remainder of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// [Euclidean division]: f32::rem_euclid
+    #[inline]
+    pub fn rem_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            math::rem_euclid(self.x, rhs.x),
+            math::rem_euclid(self.y, rhs.y),
+            math::rem_euclid(self.z, rhs.z),
+        )
+    }
+
     /// Returns `self` normalized to length 1.0.
     ///
     /// For valid results, `self` must _not_ be of length zero, nor very close to zero.
diff --git a/src/f32/sse2/vec4.rs b/src/f32/sse2/vec4.rs
index cfbdebe..f388098 100644
--- a/src/f32/sse2/vec4.rs
+++ b/src/f32/sse2/vec4.rs
@@ -389,6 +389,30 @@ impl Vec4 {
         (self - rhs).length_squared()
     }
 
+    /// Returns the element-wise quotient of [Euclidean division] of `self` by `rhs`.
+    #[inline]
+    pub fn div_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            math::div_euclid(self.x, rhs.x),
+            math::div_euclid(self.y, rhs.y),
+            math::div_euclid(self.z, rhs.z),
+            math::div_euclid(self.w, rhs.w),
+        )
+    }
+
+    /// Returns the element-wise remainder of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// [Euclidean division]: f32::rem_euclid
+    #[inline]
+    pub fn rem_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            math::rem_euclid(self.x, rhs.x),
+            math::rem_euclid(self.y, rhs.y),
+            math::rem_euclid(self.z, rhs.z),
+            math::rem_euclid(self.w, rhs.w),
+        )
+    }
+
     /// Returns `self` normalized to length 1.0.
     ///
     /// For valid results, `self` must _not_ be of length zero, nor very close to zero.
diff --git a/src/f32/vec2.rs b/src/f32/vec2.rs
index d6ff498..7512f38 100644
--- a/src/f32/vec2.rs
+++ b/src/f32/vec2.rs
@@ -347,6 +347,26 @@ impl Vec2 {
         (self - rhs).length_squared()
     }
 
+    /// Returns the element-wise quotient of [Euclidean division] of `self` by `rhs`.
+    #[inline]
+    pub fn div_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            math::div_euclid(self.x, rhs.x),
+            math::div_euclid(self.y, rhs.y),
+        )
+    }
+
+    /// Returns the element-wise remainder of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// [Euclidean division]: f32::rem_euclid
+    #[inline]
+    pub fn rem_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            math::rem_euclid(self.x, rhs.x),
+            math::rem_euclid(self.y, rhs.y),
+        )
+    }
+
     /// Returns `self` normalized to length 1.0.
     ///
     /// For valid results, `self` must _not_ be of length zero, nor very close to zero.
diff --git a/src/f32/vec3.rs b/src/f32/vec3.rs
index ace8db1..5b31d06 100644
--- a/src/f32/vec3.rs
+++ b/src/f32/vec3.rs
@@ -392,6 +392,28 @@ impl Vec3 {
         (self - rhs).length_squared()
     }
 
+    /// Returns the element-wise quotient of [Euclidean division] of `self` by `rhs`.
+    #[inline]
+    pub fn div_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            math::div_euclid(self.x, rhs.x),
+            math::div_euclid(self.y, rhs.y),
+            math::div_euclid(self.z, rhs.z),
+        )
+    }
+
+    /// Returns the element-wise remainder of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// [Euclidean division]: f32::rem_euclid
+    #[inline]
+    pub fn rem_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            math::rem_euclid(self.x, rhs.x),
+            math::rem_euclid(self.y, rhs.y),
+            math::rem_euclid(self.z, rhs.z),
+        )
+    }
+
     /// Returns `self` normalized to length 1.0.
     ///
     /// For valid results, `self` must _not_ be of length zero, nor very close to zero.
diff --git a/src/f32/wasm32/vec3a.rs b/src/f32/wasm32/vec3a.rs
index 4be767a..a2d9cbc 100644
--- a/src/f32/wasm32/vec3a.rs
+++ b/src/f32/wasm32/vec3a.rs
@@ -392,6 +392,28 @@ impl Vec3A {
         (self - rhs).length_squared()
     }
 
+    /// Returns the element-wise quotient of [Euclidean division] of `self` by `rhs`.
+    #[inline]
+    pub fn div_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            math::div_euclid(self.x, rhs.x),
+            math::div_euclid(self.y, rhs.y),
+            math::div_euclid(self.z, rhs.z),
+        )
+    }
+
+    /// Returns the element-wise remainder of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// [Euclidean division]: f32::rem_euclid
+    #[inline]
+    pub fn rem_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            math::rem_euclid(self.x, rhs.x),
+            math::rem_euclid(self.y, rhs.y),
+            math::rem_euclid(self.z, rhs.z),
+        )
+    }
+
     /// Returns `self` normalized to length 1.0.
     ///
     /// For valid results, `self` must _not_ be of length zero, nor very close to zero.
diff --git a/src/f32/wasm32/vec4.rs b/src/f32/wasm32/vec4.rs
index eff0fc0..7f3e0dd 100644
--- a/src/f32/wasm32/vec4.rs
+++ b/src/f32/wasm32/vec4.rs
@@ -373,6 +373,30 @@ impl Vec4 {
         (self - rhs).length_squared()
     }
 
+    /// Returns the element-wise quotient of [Euclidean division] of `self` by `rhs`.
+    #[inline]
+    pub fn div_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            math::div_euclid(self.x, rhs.x),
+            math::div_euclid(self.y, rhs.y),
+            math::div_euclid(self.z, rhs.z),
+            math::div_euclid(self.w, rhs.w),
+        )
+    }
+
+    /// Returns the element-wise remainder of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// [Euclidean division]: f32::rem_euclid
+    #[inline]
+    pub fn rem_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            math::rem_euclid(self.x, rhs.x),
+            math::rem_euclid(self.y, rhs.y),
+            math::rem_euclid(self.z, rhs.z),
+            math::rem_euclid(self.w, rhs.w),
+        )
+    }
+
     /// Returns `self` normalized to length 1.0.
     ///
     /// For valid results, `self` must _not_ be of length zero, nor very close to zero.
diff --git a/src/f64/dvec2.rs b/src/f64/dvec2.rs
index a8f8ae3..7356627 100644
--- a/src/f64/dvec2.rs
+++ b/src/f64/dvec2.rs
@@ -347,6 +347,26 @@ impl DVec2 {
         (self - rhs).length_squared()
     }
 
+    /// Returns the element-wise quotient of [Euclidean division] of `self` by `rhs`.
+    #[inline]
+    pub fn div_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            math::div_euclid(self.x, rhs.x),
+            math::div_euclid(self.y, rhs.y),
+        )
+    }
+
+    /// Returns the element-wise remainder of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// [Euclidean division]: f64::rem_euclid
+    #[inline]
+    pub fn rem_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            math::rem_euclid(self.x, rhs.x),
+            math::rem_euclid(self.y, rhs.y),
+        )
+    }
+
     /// Returns `self` normalized to length 1.0.
     ///
     /// For valid results, `self` must _not_ be of length zero, nor very close to zero.
diff --git a/src/f64/dvec3.rs b/src/f64/dvec3.rs
index 6b88877..7d1349a 100644
--- a/src/f64/dvec3.rs
+++ b/src/f64/dvec3.rs
@@ -392,6 +392,28 @@ impl DVec3 {
         (self - rhs).length_squared()
     }
 
+    /// Returns the element-wise quotient of [Euclidean division] of `self` by `rhs`.
+    #[inline]
+    pub fn div_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            math::div_euclid(self.x, rhs.x),
+            math::div_euclid(self.y, rhs.y),
+            math::div_euclid(self.z, rhs.z),
+        )
+    }
+
+    /// Returns the element-wise remainder of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// [Euclidean division]: f64::rem_euclid
+    #[inline]
+    pub fn rem_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            math::rem_euclid(self.x, rhs.x),
+            math::rem_euclid(self.y, rhs.y),
+            math::rem_euclid(self.z, rhs.z),
+        )
+    }
+
     /// Returns `self` normalized to length 1.0.
     ///
     /// For valid results, `self` must _not_ be of length zero, nor very close to zero.
diff --git a/src/f64/dvec4.rs b/src/f64/dvec4.rs
index ecff505..03bb390 100644
--- a/src/f64/dvec4.rs
+++ b/src/f64/dvec4.rs
@@ -424,6 +424,30 @@ impl DVec4 {
         (self - rhs).length_squared()
     }
 
+    /// Returns the element-wise quotient of [Euclidean division] of `self` by `rhs`.
+    #[inline]
+    pub fn div_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            math::div_euclid(self.x, rhs.x),
+            math::div_euclid(self.y, rhs.y),
+            math::div_euclid(self.z, rhs.z),
+            math::div_euclid(self.w, rhs.w),
+        )
+    }
+
+    /// Returns the element-wise remainder of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// [Euclidean division]: f64::rem_euclid
+    #[inline]
+    pub fn rem_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            math::rem_euclid(self.x, rhs.x),
+            math::rem_euclid(self.y, rhs.y),
+            math::rem_euclid(self.z, rhs.z),
+            math::rem_euclid(self.w, rhs.w),
+        )
+    }
+
     /// Returns `self` normalized to length 1.0.
     ///
     /// For valid results, `self` must _not_ be of length zero, nor very close to zero.
diff --git a/src/f64/math.rs b/src/f64/math.rs
index 90f0064..d851ef4 100644
--- a/src/f64/math.rs
+++ b/src/f64/math.rs
@@ -88,6 +88,26 @@ mod libm_math {
     pub(crate) fn mul_add(a: f64, b: f64, c: f64) -> f64 {
         libm::fma(a, b, c)
     }
+
+    #[inline]
+    pub fn div_euclid(a: f64, b: f64) -> f64 {
+        // Based on https://doc.rust-lang.org/src/std/f64.rs.html#293
+        let q = libm::trunc(a / b);
+        if a % b < 0.0 {
+            return if b > 0.0 { q - 1.0 } else { q + 1.0 };
+        }
+        q
+    }
+
+    #[inline]
+    pub fn rem_euclid(a: f64, b: f64) -> f64 {
+        let r = a % b;
+        if r < 0.0 {
+            r + abs(b)
+        } else {
+            r
+        }
+    }
 }
 
 #[cfg(not(feature = "libm"))]
@@ -176,6 +196,16 @@ mod std_math {
     pub(crate) fn mul_add(a: f64, b: f64, c: f64) -> f64 {
         f64::mul_add(a, b, c)
     }
+
+    #[inline]
+    pub fn div_euclid(a: f64, b: f64) -> f64 {
+        f64::div_euclid(a, b)
+    }
+
+    #[inline]
+    pub fn rem_euclid(a: f64, b: f64) -> f64 {
+        f64::rem_euclid(a, b)
+    }
 }
 
 #[cfg(feature = "libm")]
diff --git a/src/i32/ivec2.rs b/src/i32/ivec2.rs
index 724b5fa..fb736da 100644
--- a/src/i32/ivec2.rs
+++ b/src/i32/ivec2.rs
@@ -286,6 +286,26 @@ impl IVec2 {
         (self - rhs).length_squared()
     }
 
+    /// Returns the element-wise quotient of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// # Panics
+    /// This function will panic if any `rhs` element is 0 or the division results in overflow.
+    #[inline]
+    pub fn div_euclid(self, rhs: Self) -> Self {
+        Self::new(self.x.div_euclid(rhs.x), self.y.div_euclid(rhs.y))
+    }
+
+    /// Returns the element-wise remainder of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// # Panics
+    /// This function will panic if any `rhs` element is 0 or the division results in overflow.
+    ///
+    /// [Euclidean division]: i32::rem_euclid
+    #[inline]
+    pub fn rem_euclid(self, rhs: Self) -> Self {
+        Self::new(self.x.rem_euclid(rhs.x), self.y.rem_euclid(rhs.y))
+    }
+
     /// Returns a vector that is equal to `self` rotated by 90 degrees.
     #[inline]
     pub fn perp(self) -> Self {
diff --git a/src/i32/ivec3.rs b/src/i32/ivec3.rs
index 533426d..9ebb6a1 100644
--- a/src/i32/ivec3.rs
+++ b/src/i32/ivec3.rs
@@ -330,6 +330,34 @@ impl IVec3 {
         (self - rhs).length_squared()
     }
 
+    /// Returns the element-wise quotient of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// # Panics
+    /// This function will panic if any `rhs` element is 0 or the division results in overflow.
+    #[inline]
+    pub fn div_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            self.x.div_euclid(rhs.x),
+            self.y.div_euclid(rhs.y),
+            self.z.div_euclid(rhs.z),
+        )
+    }
+
+    /// Returns the element-wise remainder of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// # Panics
+    /// This function will panic if any `rhs` element is 0 or the division results in overflow.
+    ///
+    /// [Euclidean division]: i32::rem_euclid
+    #[inline]
+    pub fn rem_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            self.x.rem_euclid(rhs.x),
+            self.y.rem_euclid(rhs.y),
+            self.z.rem_euclid(rhs.z),
+        )
+    }
+
     /// Casts all elements of `self` to `f32`.
     #[inline]
     pub fn as_vec3(&self) -> crate::Vec3 {
diff --git a/src/i32/ivec4.rs b/src/i32/ivec4.rs
index 9c3fca1..15dede6 100644
--- a/src/i32/ivec4.rs
+++ b/src/i32/ivec4.rs
@@ -356,6 +356,36 @@ impl IVec4 {
         (self - rhs).length_squared()
     }
 
+    /// Returns the element-wise quotient of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// # Panics
+    /// This function will panic if any `rhs` element is 0 or the division results in overflow.
+    #[inline]
+    pub fn div_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            self.x.div_euclid(rhs.x),
+            self.y.div_euclid(rhs.y),
+            self.z.div_euclid(rhs.z),
+            self.w.div_euclid(rhs.w),
+        )
+    }
+
+    /// Returns the element-wise remainder of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// # Panics
+    /// This function will panic if any `rhs` element is 0 or the division results in overflow.
+    ///
+    /// [Euclidean division]: i32::rem_euclid
+    #[inline]
+    pub fn rem_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            self.x.rem_euclid(rhs.x),
+            self.y.rem_euclid(rhs.y),
+            self.z.rem_euclid(rhs.z),
+            self.w.rem_euclid(rhs.w),
+        )
+    }
+
     /// Casts all elements of `self` to `f32`.
     #[inline]
     pub fn as_vec4(&self) -> crate::Vec4 {
diff --git a/src/i64/i64vec2.rs b/src/i64/i64vec2.rs
index 44561a2..ed16052 100644
--- a/src/i64/i64vec2.rs
+++ b/src/i64/i64vec2.rs
@@ -286,6 +286,26 @@ impl I64Vec2 {
         (self - rhs).length_squared()
     }
 
+    /// Returns the element-wise quotient of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// # Panics
+    /// This function will panic if any `rhs` element is 0 or the division results in overflow.
+    #[inline]
+    pub fn div_euclid(self, rhs: Self) -> Self {
+        Self::new(self.x.div_euclid(rhs.x), self.y.div_euclid(rhs.y))
+    }
+
+    /// Returns the element-wise remainder of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// # Panics
+    /// This function will panic if any `rhs` element is 0 or the division results in overflow.
+    ///
+    /// [Euclidean division]: i64::rem_euclid
+    #[inline]
+    pub fn rem_euclid(self, rhs: Self) -> Self {
+        Self::new(self.x.rem_euclid(rhs.x), self.y.rem_euclid(rhs.y))
+    }
+
     /// Returns a vector that is equal to `self` rotated by 90 degrees.
     #[inline]
     pub fn perp(self) -> Self {
diff --git a/src/i64/i64vec3.rs b/src/i64/i64vec3.rs
index 5d2c85e..7c44034 100644
--- a/src/i64/i64vec3.rs
+++ b/src/i64/i64vec3.rs
@@ -330,6 +330,34 @@ impl I64Vec3 {
         (self - rhs).length_squared()
     }
 
+    /// Returns the element-wise quotient of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// # Panics
+    /// This function will panic if any `rhs` element is 0 or the division results in overflow.
+    #[inline]
+    pub fn div_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            self.x.div_euclid(rhs.x),
+            self.y.div_euclid(rhs.y),
+            self.z.div_euclid(rhs.z),
+        )
+    }
+
+    /// Returns the element-wise remainder of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// # Panics
+    /// This function will panic if any `rhs` element is 0 or the division results in overflow.
+    ///
+    /// [Euclidean division]: i64::rem_euclid
+    #[inline]
+    pub fn rem_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            self.x.rem_euclid(rhs.x),
+            self.y.rem_euclid(rhs.y),
+            self.z.rem_euclid(rhs.z),
+        )
+    }
+
     /// Casts all elements of `self` to `f32`.
     #[inline]
     pub fn as_vec3(&self) -> crate::Vec3 {
diff --git a/src/i64/i64vec4.rs b/src/i64/i64vec4.rs
index ce8e051..173e12b 100644
--- a/src/i64/i64vec4.rs
+++ b/src/i64/i64vec4.rs
@@ -356,6 +356,36 @@ impl I64Vec4 {
         (self - rhs).length_squared()
     }
 
+    /// Returns the element-wise quotient of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// # Panics
+    /// This function will panic if any `rhs` element is 0 or the division results in overflow.
+    #[inline]
+    pub fn div_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            self.x.div_euclid(rhs.x),
+            self.y.div_euclid(rhs.y),
+            self.z.div_euclid(rhs.z),
+            self.w.div_euclid(rhs.w),
+        )
+    }
+
+    /// Returns the element-wise remainder of [Euclidean division] of `self` by `rhs`.
+    ///
+    /// # Panics
+    /// This function will panic if any `rhs` element is 0 or the division results in overflow.
+    ///
+    /// [Euclidean division]: i64::rem_euclid
+    #[inline]
+    pub fn rem_euclid(self, rhs: Self) -> Self {
+        Self::new(
+            self.x.rem_euclid(rhs.x),
+            self.y.rem_euclid(rhs.y),
+            self.z.rem_euclid(rhs.z),
+            self.w.rem_euclid(rhs.w),
+        )
+    }
+
     /// Casts all elements of `self` to `f32`.
     #[inline]
     pub fn as_vec4(&self) -> crate::Vec4 {
diff --git a/src/sse2.rs b/src/sse2.rs
index d5dcdbc..e31675a 100644
--- a/src/sse2.rs
+++ b/src/sse2.rs
@@ -174,8 +174,7 @@ pub(crate) unsafe fn m128_trunc(v: __m128) -> __m128 {
     vresult = _mm_and_ps(vresult, _mm_castsi128_ps(vtest));
     // All others, use the ORIGINAL value
     vtest = _mm_andnot_si128(vtest, _mm_castps_si128(v));
-    vresult = _mm_or_ps(vresult, _mm_castsi128_ps(vtest));
-    return vresult;
+    _mm_or_ps(vresult, _mm_castsi128_ps(vtest))
 }
 
 /// Returns a vector whose components are the corresponding components of Angles modulo 2PI.


Test patch:
diff --git a/tests/affine2.rs b/tests/affine2.rs
index e547dbb..c486371 100644
--- a/tests/affine2.rs
+++ b/tests/affine2.rs
@@ -181,10 +181,7 @@ macro_rules! impl_affine2_tests {
 
         glam_test!(test_product, {
             let ident = $affine2::IDENTITY;
-            assert_eq!(
-                vec![ident, ident].iter().product::<$affine2>(),
-                ident * ident
-            );
+            assert_eq!([ident, ident].iter().product::<$affine2>(), ident * ident);
         });
 
         glam_test!(test_affine2_is_finite, {
diff --git a/tests/affine3.rs b/tests/affine3.rs
index 86d5a53..a711da1 100644
--- a/tests/affine3.rs
+++ b/tests/affine3.rs
@@ -331,10 +331,7 @@ macro_rules! impl_affine3_tests {
 
         glam_test!(test_product, {
             let ident = $affine3::IDENTITY;
-            assert_eq!(
-                vec![ident, ident].iter().product::<$affine3>(),
-                ident * ident
-            );
+            assert_eq!([ident, ident].iter().product::<$affine3>(), ident * ident);
         });
 
         glam_test!(test_affine3_is_finite, {
diff --git a/tests/mat2.rs b/tests/mat2.rs
index a19eb7d..9d579e4 100644
--- a/tests/mat2.rs
+++ b/tests/mat2.rs
@@ -202,14 +202,14 @@ macro_rules! impl_mat2_tests {
 
         glam_test!(test_sum, {
             let id = $mat2::IDENTITY;
-            assert_eq!(vec![id, id].iter().sum::<$mat2>(), id + id);
-            assert_eq!(vec![id, id].into_iter().sum::<$mat2>(), id + id);
+            assert_eq!([id, id].iter().sum::<$mat2>(), id + id);
+            assert_eq!([id, id].into_iter().sum::<$mat2>(), id + id);
         });
 
         glam_test!(test_product, {
             let two = $mat2::IDENTITY + $mat2::IDENTITY;
-            assert_eq!(vec![two, two].iter().product::<$mat2>(), two * two);
-            assert_eq!(vec![two, two].into_iter().product::<$mat2>(), two * two);
+            assert_eq!([two, two].iter().product::<$mat2>(), two * two);
+            assert_eq!([two, two].into_iter().product::<$mat2>(), two * two);
         });
 
         glam_test!(test_mat2_is_finite, {
diff --git a/tests/mat3.rs b/tests/mat3.rs
index 6119793..36a8d38 100644
--- a/tests/mat3.rs
+++ b/tests/mat3.rs
@@ -341,14 +341,14 @@ macro_rules! impl_mat3_tests {
 
         glam_test!(test_sum, {
             let id = $mat3::IDENTITY;
-            assert_eq!(vec![id, id].iter().sum::<$mat3>(), id + id);
-            assert_eq!(vec![id, id].into_iter().sum::<$mat3>(), id + id);
+            assert_eq!([id, id].iter().sum::<$mat3>(), id + id);
+            assert_eq!([id, id].into_iter().sum::<$mat3>(), id + id);
         });
 
         glam_test!(test_product, {
             let two = $mat3::IDENTITY + $mat3::IDENTITY;
-            assert_eq!(vec![two, two].iter().product::<$mat3>(), two * two);
-            assert_eq!(vec![two, two].into_iter().product::<$mat3>(), two * two);
+            assert_eq!([two, two].iter().product::<$mat3>(), two * two);
+            assert_eq!([two, two].into_iter().product::<$mat3>(), two * two);
         });
 
         glam_test!(test_mat3_is_finite, {
diff --git a/tests/mat4.rs b/tests/mat4.rs
index 87703f9..d3b9031 100644
--- a/tests/mat4.rs
+++ b/tests/mat4.rs
@@ -647,14 +647,14 @@ macro_rules! impl_mat4_tests {
 
         glam_test!(test_sum, {
             let id = $mat4::IDENTITY;
-            assert_eq!(vec![id, id].iter().sum::<$mat4>(), id + id);
-            assert_eq!(vec![id, id].into_iter().sum::<$mat4>(), id + id);
+            assert_eq!([id, id].iter().sum::<$mat4>(), id + id);
+            assert_eq!([id, id].into_iter().sum::<$mat4>(), id + id);
         });
 
         glam_test!(test_product, {
             let two = $mat4::IDENTITY + $mat4::IDENTITY;
-            assert_eq!(vec![two, two].iter().product::<$mat4>(), two * two);
-            assert_eq!(vec![two, two].into_iter().product::<$mat4>(), two * two);
+            assert_eq!([two, two].iter().product::<$mat4>(), two * two);
+            assert_eq!([two, two].into_iter().product::<$mat4>(), two * two);
         });
 
         glam_test!(test_mat4_is_finite, {
diff --git a/tests/quat.rs b/tests/quat.rs
index 499ff40..5cad940 100644
--- a/tests/quat.rs
+++ b/tests/quat.rs
@@ -407,14 +407,14 @@ macro_rules! impl_quat_tests {
 
         glam_test!(test_sum, {
             let two = $new(2.0, 2.0, 2.0, 2.0);
-            assert_eq!(vec![two, two].iter().sum::<$quat>(), two + two);
-            assert_eq!(vec![two, two].into_iter().sum::<$quat>(), two + two);
+            assert_eq!([two, two].iter().sum::<$quat>(), two + two);
+            assert_eq!([two, two].into_iter().sum::<$quat>(), two + two);
         });
 
         glam_test!(test_product, {
             let two = $new(2.0, 2.0, 2.0, 2.0).normalize();
-            assert_eq!(vec![two, two].iter().product::<$quat>(), two * two);
-            assert_eq!(vec![two, two].into_iter().product::<$quat>(), two * two);
+            assert_eq!([two, two].iter().product::<$quat>(), two * two);
+            assert_eq!([two, two].into_iter().product::<$quat>(), two * two);
         });
 
         glam_test!(test_is_finite, {
diff --git a/tests/vec2.rs b/tests/vec2.rs
index 95982fb..ae4d07d 100644
--- a/tests/vec2.rs
+++ b/tests/vec2.rs
@@ -488,14 +488,14 @@ macro_rules! impl_vec2_tests {
 
         glam_test!(test_sum, {
             let one = $vec2::ONE;
-            assert_eq!(vec![one, one].iter().sum::<$vec2>(), one + one);
-            assert_eq!(vec![one, one].into_iter().sum::<$vec2>(), one + one);
+            assert_eq!([one, one].iter().sum::<$vec2>(), one + one);
+            assert_eq!([one, one].into_iter().sum::<$vec2>(), one + one);
         });
 
         glam_test!(test_product, {
             let two = $vec2::new(2 as $t, 2 as $t);
-            assert_eq!(vec![two, two].iter().product::<$vec2>(), two * two);
-            assert_eq!(vec![two, two].into_iter().product::<$vec2>(), two * two);
+            assert_eq!([two, two].iter().product::<$vec2>(), two * two);
+            assert_eq!([two, two].into_iter().product::<$vec2>(), two * two);
         });
     };
 }
@@ -560,6 +560,27 @@ macro_rules! impl_vec2_signed_tests {
                 $vec2::new(-1 as $t, 1 as $t)
             );
         });
+
+        glam_test!(test_div_euclid, {
+            let one = $vec2::ONE;
+            let two = one + one;
+            let three = two + one;
+            assert_eq!(three.div_euclid(two), one);
+            assert_eq!((-three).div_euclid(two), -two);
+            assert_eq!(three.div_euclid(-two), -one);
+            assert_eq!((-three).div_euclid(-two), two);
+        });
+
+        glam_test!(test_rem_euclid, {
+            let one = $vec2::ONE;
+            let two = one + one;
+            let three = two + one;
+            let four = three + one;
+            assert_eq!(four.rem_euclid(three), one);
+            assert_eq!((-four).rem_euclid(three), two);
+            assert_eq!(four.rem_euclid(-three), one);
+            assert_eq!((-four).rem_euclid(-three), two);
+        });
     };
 }
 
diff --git a/tests/vec3.rs b/tests/vec3.rs
index 0c149f6..b494f47 100644
--- a/tests/vec3.rs
+++ b/tests/vec3.rs
@@ -545,14 +545,14 @@ macro_rules! impl_vec3_tests {
 
         glam_test!(test_sum, {
             let one = $vec3::ONE;
-            assert_eq!(vec![one, one].iter().sum::<$vec3>(), one + one);
-            assert_eq!(vec![one, one].into_iter().sum::<$vec3>(), one + one);
+            assert_eq!([one, one].iter().sum::<$vec3>(), one + one);
+            assert_eq!([one, one].into_iter().sum::<$vec3>(), one + one);
         });
 
         glam_test!(test_product, {
             let two = $vec3::new(2 as $t, 2 as $t, 2 as $t);
-            assert_eq!(vec![two, two].iter().product::<$vec3>(), two * two);
-            assert_eq!(vec![two, two].into_iter().product::<$vec3>(), two * two);
+            assert_eq!([two, two].iter().product::<$vec3>(), two * two);
+            assert_eq!([two, two].into_iter().product::<$vec3>(), two * two);
         });
     };
 }
@@ -627,6 +627,27 @@ macro_rules! impl_vec3_signed_tests {
             assert_eq!(2 as $t, x.distance_squared(y));
             assert_eq!(13 as $t, (2 as $t * x).distance_squared(-3 as $t * z));
         });
+
+        glam_test!(test_div_euclid, {
+            let one = $vec3::ONE;
+            let two = one + one;
+            let three = two + one;
+            assert_eq!(three.div_euclid(two), one);
+            assert_eq!((-three).div_euclid(two), -two);
+            assert_eq!(three.div_euclid(-two), -one);
+            assert_eq!((-three).div_euclid(-two), two);
+        });
+
+        glam_test!(test_rem_euclid, {
+            let one = $vec3::ONE;
+            let two = one + one;
+            let three = two + one;
+            let four = three + one;
+            assert_eq!(four.rem_euclid(three), one);
+            assert_eq!((-four).rem_euclid(three), two);
+            assert_eq!(four.rem_euclid(-three), one);
+            assert_eq!((-four).rem_euclid(-three), two);
+        });
     };
 }
 
diff --git a/tests/vec4.rs b/tests/vec4.rs
index d8a2c1e..8cefbca 100644
--- a/tests/vec4.rs
+++ b/tests/vec4.rs
@@ -633,14 +633,14 @@ macro_rules! impl_vec4_tests {
 
         glam_test!(test_sum, {
             let one = $vec4::ONE;
-            assert_eq!(vec![one, one].iter().sum::<$vec4>(), one + one);
-            assert_eq!(vec![one, one].into_iter().sum::<$vec4>(), one + one);
+            assert_eq!([one, one].iter().sum::<$vec4>(), one + one);
+            assert_eq!([one, one].into_iter().sum::<$vec4>(), one + one);
         });
 
         glam_test!(test_product, {
             let two = $vec4::new(2 as $t, 2 as $t, 2 as $t, 2 as $t);
-            assert_eq!(vec![two, two].iter().product::<$vec4>(), two * two);
-            assert_eq!(vec![two, two].into_iter().product::<$vec4>(), two * two);
+            assert_eq!([two, two].iter().product::<$vec4>(), two * two);
+            assert_eq!([two, two].into_iter().product::<$vec4>(), two * two);
         });
     };
 }
@@ -717,6 +717,27 @@ macro_rules! impl_vec4_signed_tests {
             assert_eq!(2 as $t, x.distance_squared(y));
             assert_eq!(13 as $t, (2 as $t * x).distance_squared(-3 as $t * z));
         });
+
+        glam_test!(test_div_euclid, {
+            let one = $vec4::ONE;
+            let two = one + one;
+            let three = two + one;
+            assert_eq!(three.div_euclid(two), one);
+            assert_eq!((-three).div_euclid(two), -two);
+            assert_eq!(three.div_euclid(-two), -one);
+            assert_eq!((-three).div_euclid(-two), two);
+        });
+
+        glam_test!(test_rem_euclid, {
+            let one = $vec4::ONE;
+            let two = one + one;
+            let three = two + one;
+            let four = three + one;
+            assert_eq!(four.rem_euclid(three), one);
+            assert_eq!((-four).rem_euclid(three), two);
+            assert_eq!(four.rem_euclid(-three), one);
+            assert_eq!((-four).rem_euclid(-three), two);
+        });
     };
 }