ソースを参照

:sparkles: less unsafe and column vectors can be divided by square matrices

Felix Bytow 2 年 前
コミット
b4e90c423a

+ 11 - 0
src/traits/float.rs

@@ -17,6 +17,9 @@ pub trait Float: Neg<Output=Self> {
     /// Calculate the hyperbolic cosine.
     fn cosh(self) -> Self;
 
+    /// Create a float with the given value.
+    fn value(f: f32) -> Self;
+
     #[cfg(feature = "angular")]
     fn pi() -> Self;
 }
@@ -42,6 +45,10 @@ impl Float for f32 {
         self.cosh()
     }
 
+    fn value(f: f32) -> Self {
+        f
+    }
+
     #[cfg(feature = "angular")]
     fn pi() -> Self { std::f32::consts::PI }
 }
@@ -67,6 +74,10 @@ impl Float for f64 {
         self.cosh()
     }
 
+    fn value(f: f32) -> Self {
+        f as f64
+    }
+
     #[cfg(feature = "angular")]
     fn pi() -> Self { std::f64::consts::PI }
 }

+ 46 - 50
src/traits/numeric.rs

@@ -8,18 +8,14 @@ Add<Output=Self> + AddAssign + Sub<Output=Self> + SubAssign +
 Mul<Output=Self> + MulAssign + Div<Output=Self> + DivAssign +
 PartialEq {
     /// Function returning the whole number in the requested type.
-    ///
-    /// # Safety
-    /// The caller must make sure, that the given value can be represented in the target type.
-    /// Otherwise behaviour is undefined.
-    unsafe fn whole(value: u32) -> Self;
+    fn whole(value: u8) -> Self;
 
     /// Calculate the absolute value.
     fn abs(self) -> Self;
 }
 
 impl Numeric for f32 {
-    unsafe fn whole(value: u32) -> Self {
+    fn whole(value: u8) -> Self {
         value as Self
     }
 
@@ -29,7 +25,7 @@ impl Numeric for f32 {
 }
 
 impl Numeric for f64 {
-    unsafe fn whole(value: u32) -> Self {
+    fn whole(value: u8) -> Self {
         value as Self
     }
 
@@ -39,7 +35,7 @@ impl Numeric for f64 {
 }
 
 impl Numeric for i8 {
-    unsafe fn whole(value: u32) -> Self {
+    fn whole(value: u8) -> Self {
         value as Self
     }
 
@@ -49,7 +45,7 @@ impl Numeric for i8 {
 }
 
 impl Numeric for i16 {
-    unsafe fn whole(value: u32) -> Self {
+    fn whole(value: u8) -> Self {
         value as Self
     }
 
@@ -59,7 +55,7 @@ impl Numeric for i16 {
 }
 
 impl Numeric for i32 {
-    unsafe fn whole(value: u32) -> Self {
+    fn whole(value: u8) -> Self {
         value as Self
     }
 
@@ -69,7 +65,7 @@ impl Numeric for i32 {
 }
 
 impl Numeric for i64 {
-    unsafe fn whole(value: u32) -> Self {
+    fn whole(value: u8) -> Self {
         value as Self
     }
 
@@ -79,7 +75,7 @@ impl Numeric for i64 {
 }
 
 impl Numeric for i128 {
-    unsafe fn whole(value: u32) -> Self {
+    fn whole(value: u8) -> Self {
         value as Self
     }
 
@@ -89,7 +85,7 @@ impl Numeric for i128 {
 }
 
 impl Numeric for isize {
-    unsafe fn whole(value: u32) -> Self {
+    fn whole(value: u8) -> Self {
         value as Self
     }
 
@@ -99,7 +95,7 @@ impl Numeric for isize {
 }
 
 impl Numeric for u8 {
-    unsafe fn whole(value: u32) -> Self {
+    fn whole(value: u8) -> Self {
         value as Self
     }
 
@@ -109,7 +105,7 @@ impl Numeric for u8 {
 }
 
 impl Numeric for u16 {
-    unsafe fn whole(value: u32) -> Self {
+    fn whole(value: u8) -> Self {
         value as Self
     }
 
@@ -119,7 +115,7 @@ impl Numeric for u16 {
 }
 
 impl Numeric for u32 {
-    unsafe fn whole(value: u32) -> Self {
+    fn whole(value: u8) -> Self {
         value as Self
     }
 
@@ -129,7 +125,7 @@ impl Numeric for u32 {
 }
 
 impl Numeric for u64 {
-    unsafe fn whole(value: u32) -> Self {
+    fn whole(value: u8) -> Self {
         value as Self
     }
 
@@ -139,7 +135,7 @@ impl Numeric for u64 {
 }
 
 impl Numeric for u128 {
-    unsafe fn whole(value: u32) -> Self {
+    fn whole(value: u8) -> Self {
         value as Self
     }
 
@@ -149,7 +145,7 @@ impl Numeric for u128 {
 }
 
 impl Numeric for usize {
-    unsafe fn whole(value: u32) -> Self {
+    fn whole(value: u8) -> Self {
         value as Self
     }
 
@@ -164,41 +160,41 @@ mod tests {
 
     #[test]
     fn floats_are_numeric() {
-        assert_eq!(unsafe { f32::whole(0) }, 0.0);
-        assert_eq!(unsafe { f32::whole(1) }, 1.0);
-        assert_eq!(unsafe { f64::whole(0) }, 0.0);
-        assert_eq!(unsafe { f64::whole(1) }, 1.0);
+        assert_eq!(f32::whole(0), 0.0);
+        assert_eq!(f32::whole(1), 1.0);
+        assert_eq!(f64::whole(0), 0.0);
+        assert_eq!(f64::whole(1), 1.0);
     }
 
     #[test]
     fn integers_are_numeric() {
         // not sure yet, if I want this to be possible
-        assert_eq!(unsafe { i8::whole(255) }, -1);
-
-        assert_eq!(unsafe { i8::whole(0) }, 0);
-        assert_eq!(unsafe { i8::whole(1) }, 1);
-        assert_eq!(unsafe { i16::whole(0) }, 0);
-        assert_eq!(unsafe { i16::whole(1) }, 1);
-        assert_eq!(unsafe { i32::whole(0) }, 0);
-        assert_eq!(unsafe { i32::whole(1) }, 1);
-        assert_eq!(unsafe { i64::whole(0) }, 0);
-        assert_eq!(unsafe { i64::whole(1) }, 1);
-        assert_eq!(unsafe { i128::whole(0) }, 0);
-        assert_eq!(unsafe { i128::whole(1) }, 1);
-        assert_eq!(unsafe { isize::whole(0) }, 0);
-        assert_eq!(unsafe { isize::whole(1) }, 1);
-
-        assert_eq!(unsafe { u8::whole(0) }, 0);
-        assert_eq!(unsafe { u8::whole(1) }, 1);
-        assert_eq!(unsafe { u16::whole(0) }, 0);
-        assert_eq!(unsafe { u16::whole(1) }, 1);
-        assert_eq!(unsafe { u32::whole(0) }, 0);
-        assert_eq!(unsafe { u32::whole(1) }, 1);
-        assert_eq!(unsafe { u64::whole(0) }, 0);
-        assert_eq!(unsafe { u64::whole(1) }, 1);
-        assert_eq!(unsafe { u128::whole(0) }, 0);
-        assert_eq!(unsafe { u128::whole(1) }, 1);
-        assert_eq!(unsafe { usize::whole(0) }, 0);
-        assert_eq!(unsafe { usize::whole(1) }, 1);
+        assert_eq!(i8::whole(255), -1);
+
+        assert_eq!(i8::whole(0), 0);
+        assert_eq!(i8::whole(1), 1);
+        assert_eq!(i16::whole(0), 0);
+        assert_eq!(i16::whole(1), 1);
+        assert_eq!(i32::whole(0), 0);
+        assert_eq!(i32::whole(1), 1);
+        assert_eq!(i64::whole(0), 0);
+        assert_eq!(i64::whole(1), 1);
+        assert_eq!(i128::whole(0), 0);
+        assert_eq!(i128::whole(1), 1);
+        assert_eq!(isize::whole(0), 0);
+        assert_eq!(isize::whole(1), 1);
+
+        assert_eq!(u8::whole(0), 0);
+        assert_eq!(u8::whole(1), 1);
+        assert_eq!(u16::whole(0), 0);
+        assert_eq!(u16::whole(1), 1);
+        assert_eq!(u32::whole(0), 0);
+        assert_eq!(u32::whole(1), 1);
+        assert_eq!(u64::whole(0), 0);
+        assert_eq!(u64::whole(1), 1);
+        assert_eq!(u128::whole(0), 0);
+        assert_eq!(u128::whole(1), 1);
+        assert_eq!(usize::whole(0), 0);
+        assert_eq!(usize::whole(1), 1);
     }
 }

+ 2 - 2
src/types/angular.rs

@@ -20,7 +20,7 @@ impl<T: Numeric + Float + Primitive> Degree<T> {
 
 impl<T: Numeric + Float + Primitive> From<Radiant<T>> for Degree<T> {
     fn from(source: Radiant<T>) -> Self {
-        Degree::new(source.value * T::pi() / unsafe { T::whole(180) })
+        Degree::new(source.value * T::pi() / T::whole(180))
     }
 }
 
@@ -48,7 +48,7 @@ impl<T: Numeric + Float + Primitive> Radiant<T> {
 
 impl<T: Numeric + Float + Primitive> From<Degree<T>> for Radiant<T> {
     fn from(source: Degree<T>) -> Self {
-        Radiant::new(source.value * unsafe { T::whole(180) } / T::pi())
+        Radiant::new(source.value * T::whole(180) / T::pi())
     }
 }
 

+ 16 - 9
src/types/complex.rs

@@ -75,7 +75,7 @@ macro_rules! cplx {
 
 impl<T: Float + Numeric + Primitive> Default for Complex<T> {
     fn default() -> Self {
-        unsafe { Complex::whole(0) }
+        Complex::whole(0)
     }
 }
 
@@ -84,21 +84,21 @@ impl<T: Float + Numeric + Primitive> Complex<T> {
     pub fn real(value: T) -> Self {
         Self {
             r: value,
-            i: unsafe { T::whole(0) },
+            i: T::whole(0),
         }
     }
 
     /// Create a complex number with its real component being zero.
     pub fn imag(value: T) -> Self {
         Self {
-            r: unsafe { T::whole(0) },
+            r: T::whole(0),
             i: value,
         }
     }
 
     /// The imaginary unit.
     pub fn i() -> Self {
-        Self::imag(unsafe { T::whole(1) })
+        Self::imag(T::whole(1))
     }
 }
 
@@ -196,8 +196,8 @@ impl<T: Float + Numeric + Primitive> PartialEq for Complex<T> {
 
 impl<T: Float + Primitive + Numeric> Float for Complex<T> {
     fn sqrt(self) -> Self {
-        let zero = unsafe { T::whole(0) };
-        let two = unsafe { T::whole(2) };
+        let zero = T::whole(0);
+        let two = T::whole(2);
         let abs_z = self.abs().r;
 
         let base_re = if self.i == zero { self.r } else { (abs_z + self.r) / two };
@@ -241,24 +241,31 @@ impl<T: Float + Primitive + Numeric> Float for Complex<T> {
         }
     }
 
+    fn value(f: f32) -> Self {
+        Self {
+            r: T::value(f),
+            i: T::whole(0),
+        }
+    }
+
     #[cfg(feature = "angular")]
     fn pi() -> Self {
         Self {
             r: T::pi(),
-            i: unsafe { T::whole(0) },
+            i: T::whole(0),
         }
     }
 }
 
 impl<T: Float + Numeric + Primitive> Numeric for Complex<T> {
-    unsafe fn whole(value: u32) -> Self {
+    fn whole(value: u8) -> Self {
         Self { r: T::whole(value), i: T::whole(0) }
     }
 
     fn abs(self) -> Self {
         Self {
             r: (self.r * self.r + self.i * self.i).sqrt(),
-            i: unsafe { T::whole(0) },
+            i: T::whole(0),
         }
     }
 }

+ 15 - 7
src/types/matrix/generic.rs

@@ -70,7 +70,7 @@ macro_rules! cvec {
 impl<T: Numeric, const ROWS: usize, const COLUMNS: usize> Default for GenericMatrix<T, ROWS, COLUMNS> {
     /// Create a matrix with all cells being zero.
     fn default() -> Self {
-        let zero = unsafe { T::whole(0) };
+        let zero = T::whole(0);
         Self {
             data: [[zero; COLUMNS]; ROWS],
         }
@@ -122,7 +122,7 @@ impl<T: Numeric, const DIMENSION: usize> SquareMatrix<T, DIMENSION> {
     /// ```
     pub fn identity() -> Self {
         let mut mat = Self::default();
-        let one = unsafe { T::whole(1) };
+        let one = T::whole(1);
         for i in 0..DIMENSION {
             mat.data[i][i] = one;
         }
@@ -272,8 +272,8 @@ impl<T: Numeric + Float + PartialOrd, const DIMENSION: usize> SquareMatrix<T, DI
 
         let mut result = Self::new();
 
-        let zero = unsafe { T::whole(0) };
-        let one = unsafe { T::whole(1) };
+        let zero = T::whole(0);
+        let one = T::whole(1);
 
         for j in 0..DIMENSION {
             for i in 0..DIMENSION {
@@ -413,6 +413,14 @@ impl<T: Numeric, const ROWS: usize, const COLUMNS: usize> DivAssign<T> for Gener
     }
 }
 
+impl<T: Numeric + Float + PartialOrd, const DIMENSION: usize> Div<SquareMatrix<T, DIMENSION>> for ColumnVector<T, DIMENSION> {
+    type Output = RowVector<T, DIMENSION>;
+
+    fn div(self, rhs: SquareMatrix<T, DIMENSION>) -> Self::Output {
+        rhs.solve(&self, T::value(1e-9)).unwrap()
+    }
+}
+
 impl<T: Numeric, const ROWS: usize, const COMMON: usize, const COLUMNS: usize> Mul<GenericMatrix<T, COMMON, COLUMNS>> for GenericMatrix<T, ROWS, COMMON> {
     type Output = GenericMatrix<T, ROWS, COLUMNS>;
 
@@ -458,13 +466,13 @@ impl<T: Numeric + Float + Primitive> SquareMatrix<T, 4> {
 
     /// Create a 3D scale matrix.
     pub fn scale(x: T, y: T, z: T) -> Self {
-        let one = unsafe { T::whole(1) };
+        let one = T::whole(1);
         SquareMatrix::diagonal(&[x, y, z, one])
     }
 
     fn rotation_impl(angle: T, x: T, y: T, z: T) -> Self {
-        let zero = unsafe { T::whole(0) };
-        let one = unsafe { T::whole(1) };
+        let zero = T::whole(0);
+        let one = T::whole(1);
 
         let c = angle.cos();
         let s = angle.sin();

+ 1 - 1
src/types/quaternion.rs

@@ -10,7 +10,7 @@ pub struct Quaternion<T: Float + Numeric + Primitive> {
 
 impl<T: Float + Numeric + Primitive> Default for Quaternion<T> {
     fn default() -> Self {
-        let zero = unsafe { T::whole(0) };
+        let zero = T::whole(0);
         Self {
             r: zero,
             i: zero,