Browse Source

:recycle: made whole unsafe and renamed math functions

Felix Bytow 2 năm trước cách đây
mục cha
commit
edb0ee9935
4 tập tin đã thay đổi với 119 bổ sung96 xóa
  1. 2 1
      CHANGELOG.md
  2. 18 18
      src/traits/float.rs
  3. 50 46
      src/traits/numeric.rs
  4. 49 31
      src/types/complex.rs

+ 2 - 1
CHANGELOG.md

@@ -2,7 +2,8 @@
 
 ## Release 0.3.0
 
-
+- `Numeric::whole` is now `unsafe`.
+- Renamed the mathematical functions (`fabs` to `abs`, `fsqrt` to `sqrt`, etc.)
 
 ## Release 0.2.3
 

+ 18 - 18
src/traits/float.rs

@@ -3,72 +3,72 @@ use std::ops::Neg;
 /// Marker trait, because certain operations only make sense on floating point types.
 pub trait Float: Neg<Output=Self> {
     /// Calculate the absolute value. For primitive floats it just calls their `abs` function.
-    fn fabs(self) -> Self;
+    fn abs(self) -> Self;
 
     /// Calculate the square root. For primitive floats it just calls their `sqrt` function.
-    fn fsqrt(self) -> Self;
+    fn sqrt(self) -> Self;
 
     /// Calculate the sine.
-    fn fsin(self) -> Self;
+    fn sin(self) -> Self;
 
     /// Calculate the cosine.
-    fn fcos(self) -> Self;
+    fn cos(self) -> Self;
 
     /// Calculate the hyperbolic sine.
-    fn fsinh(self) -> Self;
+    fn sinh(self) -> Self;
 
     /// Calculate the hyperbolic cosine.
-    fn fcosh(self) -> Self;
+    fn cosh(self) -> Self;
 }
 
 impl Float for f32 {
-    fn fabs(self) -> Self {
+    fn abs(self) -> Self {
         self.abs()
     }
 
-    fn fsqrt(self) -> Self {
+    fn sqrt(self) -> Self {
         self.sqrt()
     }
 
-    fn fsin(self) -> Self {
+    fn sin(self) -> Self {
         self.sin()
     }
 
-    fn fcos(self) -> Self {
+    fn cos(self) -> Self {
         self.cos()
     }
 
-    fn fsinh(self) -> Self {
+    fn sinh(self) -> Self {
         self.sinh()
     }
 
-    fn fcosh(self) -> Self {
+    fn cosh(self) -> Self {
         self.cosh()
     }
 }
 
 impl Float for f64 {
-    fn fabs(self) -> Self {
+    fn abs(self) -> Self {
         self.abs()
     }
 
-    fn fsqrt(self) -> Self {
+    fn sqrt(self) -> Self {
         self.sqrt()
     }
 
-    fn fsin(self) -> Self {
+    fn sin(self) -> Self {
         self.sin()
     }
 
-    fn fcos(self) -> Self {
+    fn cos(self) -> Self {
         self.cos()
     }
 
-    fn fsinh(self) -> Self {
+    fn sinh(self) -> Self {
         self.sinh()
     }
 
-    fn fcosh(self) -> Self {
+    fn cosh(self) -> Self {
         self.cosh()
     }
 }

+ 50 - 46
src/traits/numeric.rs

@@ -8,89 +8,93 @@ 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.
-    fn whole(value: u32) -> Self;
+    ///
+    /// # 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;
 }
 
 impl Numeric for f32 {
-    fn whole(value: u32) -> Self {
+    unsafe fn whole(value: u32) -> Self {
         value as Self
     }
 }
 
 impl Numeric for f64 {
-    fn whole(value: u32) -> Self {
+    unsafe fn whole(value: u32) -> Self {
         value as Self
     }
 }
 
 impl Numeric for i8 {
-    fn whole(value: u32) -> Self {
+    unsafe fn whole(value: u32) -> Self {
         value as Self
     }
 }
 
 impl Numeric for i16 {
-    fn whole(value: u32) -> Self {
+    unsafe fn whole(value: u32) -> Self {
         value as Self
     }
 }
 
 impl Numeric for i32 {
-    fn whole(value: u32) -> Self {
+    unsafe fn whole(value: u32) -> Self {
         value as Self
     }
 }
 
 impl Numeric for i64 {
-    fn whole(value: u32) -> Self {
+    unsafe fn whole(value: u32) -> Self {
         value as Self
     }
 }
 
 impl Numeric for i128 {
-    fn whole(value: u32) -> Self {
+    unsafe fn whole(value: u32) -> Self {
         value as Self
     }
 }
 
 impl Numeric for isize {
-    fn whole(value: u32) -> Self {
+    unsafe fn whole(value: u32) -> Self {
         value as Self
     }
 }
 
 impl Numeric for u8 {
-    fn whole(value: u32) -> Self {
+    unsafe fn whole(value: u32) -> Self {
         value as Self
     }
 }
 
 impl Numeric for u16 {
-    fn whole(value: u32) -> Self {
+    unsafe fn whole(value: u32) -> Self {
         value as Self
     }
 }
 
 impl Numeric for u32 {
-    fn whole(value: u32) -> Self {
+    unsafe fn whole(value: u32) -> Self {
         value as Self
     }
 }
 
 impl Numeric for u64 {
-    fn whole(value: u32) -> Self {
+    unsafe fn whole(value: u32) -> Self {
         value as Self
     }
 }
 
 impl Numeric for u128 {
-    fn whole(value: u32) -> Self {
+    unsafe fn whole(value: u32) -> Self {
         value as Self
     }
 }
 
 impl Numeric for usize {
-    fn whole(value: u32) -> Self {
+    unsafe fn whole(value: u32) -> Self {
         value as Self
     }
 }
@@ -101,41 +105,41 @@ mod tests {
 
     #[test]
     fn floats_are_numeric() {
-        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);
+        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);
     }
 
     #[test]
     fn integers_are_numeric() {
         // not sure yet, if I want this to be possible
-        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);
+        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);
     }
 }

+ 49 - 31
src/types/complex.rs

@@ -11,16 +11,20 @@ use crate::{Float, Numeric, Primitive};
 /// let c = Complex { real: 9.0, imag: 0.0 };
 /// assert_eq!(format!("{:?}", c), "Complex { real: 9.0, imag: 0.0 }");
 ///
-/// let three = c.fsqrt().real;
+/// let three = c.sqrt().real;
 /// assert_eq!(three, 3.0);
 ///
-/// let i: Complex<f32> = (-Complex::whole(1)).fsqrt();
+/// let i: Complex<f32> = Complex::real(-1.0).sqrt();
 /// assert_eq!(i, Complex::i());
 ///
 /// let a = Complex { real: 2.0, imag: 0.5 };
 /// let a_squared = a * a;
 /// assert_eq!(a_squared, Complex { real: 3.75, imag: 2.0 });
-/// assert_eq!(a_squared.fsqrt(), a);
+/// assert_eq!(a_squared.sqrt(), a);
+///
+/// let x = (16.0).sqrt();
+/// let y = Complex::real(16.0).sqrt().real;
+/// assert_eq!(x, y);
 /// ```
 #[derive(Debug, Copy, Clone)]
 pub struct Complex<T: Float + Numeric + Primitive> {
@@ -29,11 +33,25 @@ pub struct Complex<T: Float + Numeric + Primitive> {
 }
 
 impl<T: Float + Numeric + Primitive> Complex<T> {
+    pub fn real(value: T) -> Self {
+        Self {
+            real: value,
+            imag: unsafe { T::whole(0) },
+        }
+    }
+
+    pub fn imag(value: T) -> Self {
+        Self {
+            real: unsafe { T::whole(0) },
+            imag: value,
+        }
+    }
+
     /// The imaginary unit.
     pub fn i() -> Self {
         Self {
-            real: T::whole(0),
-            imag: T::whole(1),
+            real: unsafe { T::whole(0) },
+            imag: unsafe { T::whole(1) },
         }
     }
 }
@@ -131,24 +149,24 @@ impl<T: Float + Numeric + Primitive> PartialEq for Complex<T> {
 }
 
 impl<T: Float + Primitive + Numeric> Float for Complex<T> {
-    fn fabs(self) -> Self {
+    fn abs(self) -> Self {
         Self {
-            real: (self.real * self.real + self.imag * self.imag).fsqrt(),
-            imag: T::whole(0),
+            real: (self.real * self.real + self.imag * self.imag).sqrt(),
+            imag: unsafe { T::whole(0) },
         }
     }
 
-    fn fsqrt(self) -> Self {
-        let zero = T::whole(0);
-        let two = T::whole(2);
-        let abs_z = self.fabs().real;
+    fn sqrt(self) -> Self {
+        let zero = unsafe { T::whole(0) };
+        let two = unsafe { T::whole(2) };
+        let abs_z = self.abs().real;
 
         let base_re = if self.imag == zero { self.real } else { (abs_z + self.real) / two };
-        let re = if base_re < zero { zero } else { base_re.fsqrt() };
+        let re = if base_re < zero { zero } else { base_re.sqrt() };
 
         let im = if self.imag == zero { zero } else {
-            (self.imag / self.imag.fabs()) * ((abs_z - self.real) / two).fsqrt()
-        } + if base_re < zero { (-base_re).fsqrt() } else { zero };
+            (self.imag / self.imag.abs()) * ((abs_z - self.real) / two).sqrt()
+        } + if base_re < zero { (-base_re).sqrt() } else { zero };
 
         Self {
             real: re,
@@ -156,37 +174,37 @@ impl<T: Float + Primitive + Numeric> Float for Complex<T> {
         }
     }
 
-    fn fsin(self) -> Self {
+    fn sin(self) -> Self {
         Self {
-            real: self.real.fsin() * self.imag.fcosh(),
-            imag: self.real.fcos() * self.imag.fsinh(),
+            real: self.real.sin() * self.imag.cosh(),
+            imag: self.real.cos() * self.imag.sinh(),
         }
     }
 
-    fn fcos(self) -> Self {
+    fn cos(self) -> Self {
         Self {
-            real: self.real.fcos() * self.imag.fcosh(),
-            imag: self.real.fsin() * self.imag.fsinh(),
+            real: self.real.cos() * self.imag.cosh(),
+            imag: self.real.sin() * self.imag.sinh(),
         }
     }
 
-    fn fsinh(self) -> Self {
+    fn sinh(self) -> Self {
         Self {
-            real: self.real.fsinh() * self.imag.fcos(),
-            imag: self.real.fcosh() * self.imag.fsin(),
+            real: self.real.sinh() * self.imag.cos(),
+            imag: self.real.cosh() * self.imag.sin(),
         }
     }
 
-    fn fcosh(self) -> Self {
+    fn cosh(self) -> Self {
         Self {
-            real: self.real.fcosh() * self.imag.fcos(),
-            imag: self.real.fsinh() * self.imag.fsin(),
+            real: self.real.cosh() * self.imag.cos(),
+            imag: self.real.sinh() * self.imag.sin(),
         }
     }
 }
 
 impl<T: Float + Numeric + Primitive> Numeric for Complex<T> {
-    fn whole(value: u32) -> Self {
+    unsafe fn whole(value: u32) -> Self {
         Self { real: T::whole(value), imag: T::whole(0) }
     }
 }
@@ -207,9 +225,9 @@ mod tests {
     #[test]
     fn square_root_with_negatives() {
         let a = Complex { real: -1.0, imag: -1.0 };
-        let root = a.fsqrt();
+        let root = a.sqrt();
         let expected = Complex { real: 0.45508986, imag: -1.09868411 };
-        assert!((root.real - expected.real).fabs() < 0.00001);
-        assert!((root.imag - expected.imag).fabs() < 0.00001);
+        assert!((root.real - expected.real).abs() < 0.00001);
+        assert!((root.imag - expected.imag).abs() < 0.00001);
     }
 }