diff --git a/README.md b/README.md new file mode 100644 index 0000000..c7af7f0 --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# Sigils # +A mathematics library. + +The code in this library uses macros pretty heavily. As such, +please check the trait's documentation for a function since the +macro definition will not really be documented. This was not +done to make documentation difficult, but to make coding the +library easier and to make it easier to maintain. diff --git a/src/bounded.rs b/src/bounded.rs new file mode 100644 index 0000000..cf01366 --- /dev/null +++ b/src/bounded.rs @@ -0,0 +1,61 @@ +use std::{u8, u16, u32, u64, usize, i8, i16, i32, i64, isize, f32, f64}; + + +/// Primitive types that have upper and lower bounds. +pub trait Bounded +{ + // TODO: I would love for this to be associated consts, but + // they are not currently working inside macros. + // It causes rust's stack to explode. + // Check this on later versions of rustc. + // + // Last version checked: rustc v1.3.0 + /// The minimum value for this type. + //const MIN: Self; + fn min_value() -> Self; + + /// The maximum value for this type. + //const MAX: Self; + fn max_value() -> Self; +} + + +/// A macro for making implementation of +/// the Bounded trait easier. +macro_rules! bounded_trait_impl +{ + ($T: ty, $minVal: expr, $maxVal: expr) => + { + impl Bounded for $T + { + //const MIN: $T = $minVal; + fn min_value() -> $T + { + $minVal + } + + //const MAX: $T = $maxVal; + fn max_value() -> $T + { + $maxVal + } + } + } +} + + +// Implement the Bounded for all the primitive types. +bounded_trait_impl!(u8, u8::MIN, u8::MAX); +bounded_trait_impl!(u16, u16::MIN, u16::MAX); +bounded_trait_impl!(u32, u32::MIN, u32::MAX); +bounded_trait_impl!(u64, u64::MIN, u64::MAX); +bounded_trait_impl!(usize, usize::MIN, usize::MAX); + +bounded_trait_impl!(i8, i8::MIN, i8::MAX); +bounded_trait_impl!(i16, i16::MIN, i16::MAX); +bounded_trait_impl!(i32, i32::MIN, i32::MAX); +bounded_trait_impl!(i64, i64::MIN, i64::MAX); +bounded_trait_impl!(isize, isize::MIN, isize::MAX); + +bounded_trait_impl!(f32, f32::MIN, f32::MAX); +bounded_trait_impl!(f64, f64::MIN, f64::MAX); diff --git a/src/constants.rs b/src/constants.rs new file mode 100644 index 0000000..72eec71 --- /dev/null +++ b/src/constants.rs @@ -0,0 +1,289 @@ +use std::{f32, f64}; + + +// Create the Constants trait so that we can use +// associated constants to define Mathematical constants for +// the f32 and f64 types. +/// Defines Mathematical constants. +pub trait Constants +{ + /// The square root of 2. + /// + ///``` + /// use sigils::Constants; + /// + /// let val32: f32 = Constants::SQRT_2; + /// let val64: f64 = Constants::SQRT_2; + /// # assert_eq!(val32, std::f32::consts::SQRT_2); + /// # assert_eq!(val64, std::f64::consts::SQRT_2); + ///``` + const SQRT_2: Self; + + /// The square root of 3. + /// + ///``` + /// use sigils::Constants; + /// + /// let val32: f32 = Constants::SQRT_3; + /// let val64: f64 = Constants::SQRT_3; + /// # assert_eq!(val32, 1.73205080756887729352f32); + /// # assert_eq!(val64, 1.73205080756887729352f64); + ///``` + const SQRT_3: Self; + + /// The inverse of the square root of 2 + /// + ///``` + /// use sigils::Constants; + /// + /// let val32: f32 = Constants::INVERSE_SQRT_2; + /// let val64: f64 = Constants::INVERSE_SQRT_2; + /// # assert_eq!(val32, 1.0f32 / std::f32::consts::SQRT_2); + /// # assert_eq!(val64, 1.0f64 / std::f64::consts::SQRT_2); + ///``` + const INVERSE_SQRT_2: Self; + + /// The inverse of the square root of 3. + /// + ///``` + /// use sigils::Constants; + /// + /// let val32: f32 = Constants::INVERSE_SQRT_3; + /// let val64: f64 = Constants::INVERSE_SQRT_3; + /// # assert_eq!(val32, 1.0f32 / 1.73205080756887729352f32); + /// # assert_eq!(val64, 1.0f64 / 1.73205080756887729352f64); + ///``` + const INVERSE_SQRT_3: Self; + + /// The mathematical constant [E][1]. Also known as [Euler's number][1]. + /// [1]: https://en.wikipedia.org/wiki/E_(mathematical_constant) + /// + ///``` + /// use sigils::Constants; + /// + /// let val32: f32 = Constants::E; + /// let val64: f64 = Constants::E; + /// # assert_eq!(val32, std::f32::consts::E); + /// # assert_eq!(val64, std::f64::consts::E); + ///``` + const E: Self; + + /// The log base 2 of E. + /// + ///``` + /// use sigils::Constants; + /// + /// let val32: f32 = Constants::LOG2_E; + /// let val64: f64 = Constants::LOG2_E; + /// # assert_eq!(val32, std::f32::consts::LOG2_E); + /// # assert_eq!(val64, std::f64::consts::LOG2_E); + ///``` + const LOG2_E: Self; + + /// The log base 10 of E. + /// + ///``` + /// use sigils::Constants; + /// + /// let val32: f32 = Constants::LOG10_E; + /// let val64: f64 = Constants::LOG10_E; + /// # assert_eq!(val32, std::f32::consts::LOG10_E); + /// # assert_eq!(val64, std::f64::consts::LOG10_E); + ///``` + const LOG10_E: Self; + + /// The natural log(ln) of 2. + /// + ///``` + /// use sigils::Constants; + /// + /// let val32: f32 = Constants::LOGE_2; + /// let val64: f64 = Constants::LOGE_2; + /// # assert_eq!(val32, 2.0f32.ln()); + /// # assert_eq!(val64, 2.0f64.ln()); + ///``` + const LOGE_2: Self; + + /// The natural log(ln) of 10. + /// + ///``` + /// use sigils::Constants; + /// + /// let val32: f32 = Constants::LOGE_10; + /// let val64: f64 = Constants::LOGE_10; + /// # assert_eq!(val32, 10.0f32.ln()); + /// # assert_eq!(val64, 10.0f64.ln()); + ///``` + const LOGE_10: Self; + + /// Two times the value of PI. + /// + ///``` + /// use sigils::Constants; + /// + /// let val32: f32 = Constants::TWO_PI; + /// let val64: f64 = Constants::TWO_PI; + /// # assert_eq!(val32, std::f32::consts::PI * 2.0f32); + /// # assert_eq!(val64, std::f64::consts::PI * 2.0f64); + ///``` + const TWO_PI: Self; + + /// [PI][1]. The ratio of a circles circumference to its diameter. + /// [1]: https://en.wikipedia.org/wiki/Pi + /// + ///``` + /// use sigils::Constants; + /// + /// let val32: f32 = Constants::PI; + /// let val64: f64 = Constants::PI; + /// # assert_eq!(val32, std::f32::consts::PI); + /// # assert_eq!(val64, std::f64::consts::PI); + ///``` + const PI: Self; + + /// One half of PI. (PI/2) + /// + ///``` + /// use sigils::Constants; + /// + /// let val32: f32 = Constants::HALF_PI; + /// let val64: f64 = Constants::HALF_PI; + /// # assert_eq!(val32, std::f32::consts::PI / 2.0f32); + /// # assert_eq!(val64, std::f64::consts::PI / 2.0f64); + ///``` + const HALF_PI: Self; + + /// One third of PI. (PI/3) + /// + ///``` + /// use sigils::Constants; + /// + /// let val32: f32 = Constants::THIRD_PI; + /// let val64: f64 = Constants::THIRD_PI; + /// # assert_eq!(val32, std::f32::consts::PI / 3.0f32); + /// # assert_eq!(val64, std::f64::consts::PI / 3.0f64); + ///``` + const THIRD_PI: Self; + + /// One forth of PI. (PI/4) + /// + ///``` + /// use sigils::Constants; + /// + /// let val32: f32 = Constants::QUARTER_PI; + /// let val64: f64 = Constants::QUARTER_PI; + /// # assert_eq!(val32, std::f32::consts::PI / 4.0f32); + /// # assert_eq!(val64, std::f64::consts::PI / 4.0f64); + ///``` + const QUARTER_PI: Self; + + /// One sixth of PI. (PI/6) + /// + ///``` + /// use sigils::Constants; + /// + /// let val32: f32 = Constants::SIXTH_PI; + /// let val64: f64 = Constants::SIXTH_PI; + /// # assert_eq!(val32, std::f32::consts::PI / 6.0f32); + /// # assert_eq!(val64, std::f64::consts::PI / 6.0f64); + ///``` + const SIXTH_PI: Self; + + /// One eighth of PI. (PI/8) + /// + ///``` + /// use sigils::Constants; + /// + /// let val32: f32 = Constants::EIGHTH_PI; + /// let val64: f64 = Constants::EIGHTH_PI; + /// # assert_eq!(val32, std::f32::consts::PI / 8.0f32); + /// # assert_eq!(val64, std::f64::consts::PI / 8.0f64); + ///``` + const EIGHTH_PI: Self; + + /// The inverse of PI. (1/PI) + /// + ///``` + /// use sigils::Constants; + /// + /// let val32: f32 = Constants::INVERSE_PI; + /// let val64: f64 = Constants::INVERSE_PI; + /// # assert_eq!(val32, 1.0f32 / std::f32::consts::PI); + /// # assert_eq!(val64, 1.0f64 / std::f64::consts::PI); + ///``` + const INVERSE_PI: Self; + + /// Two times the inverse of PI. (2/PI) + /// + ///``` + /// use sigils::Constants; + /// + /// let val32: f32 = Constants::TWO_INVERSE_PI; + /// let val64: f64 = Constants::TWO_INVERSE_PI; + /// # assert_eq!(val32, 2.0f32 / std::f32::consts::PI); + /// # assert_eq!(val64, 2.0f64 / std::f64::consts::PI); + ///``` + const TWO_INVERSE_PI: Self; + + /// Two times the inverse of the square root of PI. (2/sqrt(PI)) + /// + ///``` + /// use sigils::Constants; + /// + /// let val32: f32 = Constants::TWO_INVERSE_SQRT_PI; + /// let val64: f64 = Constants::TWO_INVERSE_SQRT_PI; + /// # assert_eq!(val32, 2.0f32 * (std::f32::consts::PI).sqrt().recip()); + /// # assert_eq!(val64, 2.0f64 * (std::f64::consts::PI).sqrt().recip()); + ///``` + const TWO_INVERSE_SQRT_PI: Self; +} + + +// Implement a macro to simplify defining these constants +// for the two different types, f32 and f64. +macro_rules! constants_trait_impl +{ + ($T: ty, $sqrt2: expr, $sqrt3: expr, $e: expr, + $log2e: expr, $log10e: expr, $loge2: expr, $loge10: expr, + $pi: expr, $sqrtPI: expr) => + { + impl Constants for $T + { + const SQRT_2: $T = $sqrt2; + const SQRT_3: $T = $sqrt3; + const INVERSE_SQRT_2: $T = 1.0 / $sqrt2; + const INVERSE_SQRT_3: $T = 1.0 / $sqrt3; + + const E: $T = $e; + + const LOG2_E: $T = $log2e; + const LOG10_E: $T = $log10e; + const LOGE_2: $T = $loge2; + const LOGE_10: $T = $loge10; + + const TWO_PI: $T = 2.0 * $pi; + const PI: $T = $pi; + const HALF_PI: $T = $pi / 2.0; + const THIRD_PI: $T = $pi / 3.0; + const QUARTER_PI: $T = $pi / 4.0; + const SIXTH_PI: $T = $pi / 6.0; + const EIGHTH_PI: $T = $pi / 8.0; + const INVERSE_PI: $T = 1.0 / $pi; + const TWO_INVERSE_PI: $T = 2.0 / $pi; + const TWO_INVERSE_SQRT_PI: $T = 2.0 / $sqrtPI; + } + } +} + + +// Implement the math Constants. +constants_trait_impl!(f32, f32::consts::SQRT_2, 1.73205080756887729352f32, + f32::consts::E, f32::consts::LOG2_E, + f32::consts::LOG10_E, f32::consts::LN_2, + f32::consts::LN_10, f32::consts::PI, + 1.7724538509055159f32); +constants_trait_impl!(f64, f64::consts::SQRT_2, 1.73205080756887729352f64, + f64::consts::E, f64::consts::LOG2_E, + f64::consts::LOG10_E, f64::consts::LN_2, + f64::consts::LN_10, f64::consts::PI, + 1.7724538509055159f64); diff --git a/src/lib.rs b/src/lib.rs index 909cc3d..bc83066 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,16 +1,28 @@ +//! A mathematical library. +//! License: Proprietary +//! +//! #![feature(zero_one)] #![feature(float_from_str_radix)] +#![feature(float_extras)] +#![feature(associated_consts)] +mod bounded; mod number; mod whole; mod integer; mod real; +mod constants; +pub mod trig; pub mod vector; +pub mod matrix; +pub mod quaternion; -pub use self::vector::Vector; -pub use self::vector::Vector2; -pub use self::vector::Vector3; -pub use self::vector::Vector4; +pub use self::number::Number; +pub use self::whole::Whole; +pub use self::integer::Integer; +pub use self::real::Real; +pub use self::constants::Constants; diff --git a/src/matrix.rs b/src/matrix.rs new file mode 100644 index 0000000..44448f3 --- /dev/null +++ b/src/matrix.rs @@ -0,0 +1 @@ +//! This module defines the 2x2, 3x3, and 4x4 Matrix structures. diff --git a/src/number.rs b/src/number.rs index 7f9c2c2..ce5129f 100644 --- a/src/number.rs +++ b/src/number.rs @@ -1,7 +1,10 @@ use std::cmp::PartialEq; +use std::mem::size_of; use std::num::{Zero, One}; use std::ops::{Add, Sub, Mul, Div, Rem}; +use super::bounded::Bounded; + /// A trait that defines what is required to be considered /// a number. @@ -12,34 +15,751 @@ pub trait Number : Zero + One + Add<Output=Self> + Sub<Output=Self> + type StrRadixError; /// Create a number from a given string and base radix. + /// + ///``` + /// // Parse the hex value "FF" into an i32. + /// // Hex values have a radix (base) of 16. + /// use sigils::Number; + /// + /// let x: i32 = Number::from_str_radix("FF", 16u32).unwrap(); + /// # assert_eq!(x, 255i32); + ///``` fn from_str_radix(src: &str, radix: u32) -> Result<Self, Self::StrRadixError>; } - -// Create some macros to ease typing and reading. -/// A macro to make implementing the trait easier for all the -/// base integer types in rust. -macro_rules! int_trait_impl +/// A trait that defines converting something to a Number. +pub trait ToNumber { - ($traitName: ident for $($varType: ty)*) => - ($( - impl Number for $varType - { - type StrRadixError = ::std::num::ParseIntError; + /// Convert this to an u8. + /// None is returned if the conversion is not possible. + fn to_u8(&self) -> Option<u8> + { + let option: Option<u64>; - fn from_str_radix(src: &str, radix: u32) -> - Result<Self, ::std::num::ParseIntError> - { - <$varType>::from_str_radix(src, radix) - } + option = self.to_u64(); + match option + { + Some(val) => + { + val.to_u8() } - )*) + + None => + { + None + } + } + } + + /// Convert this to an u16. + /// None is returned if the conversion is not possible. + fn to_u16(&self) -> Option<u16> + { + let option: Option<u64>; + + option = self.to_u64(); + match option + { + Some(val) => + { + val.to_u16() + } + + None => + { + None + } + } + } + + /// Convert this to an u32. + /// None is returned if the conversion is not possible. + fn to_u32(&self) -> Option<u32> + { + let option: Option<u64>; + + option = self.to_u64(); + match option + { + Some(val) => + { + val.to_u32() + } + + None => + { + None + } + } + } + + /// Convert this to an u64. + /// None is returned if the conversion is not possible. + fn to_u64(&self) -> Option<u64>; + + /// Convert this to an usize. + /// None is returned if the conversion is not possible. + fn to_usize(&self) -> Option<usize> + { + let option: Option<u64>; + + option = self.to_u64(); + match option + { + Some(val) => + { + val.to_usize() + } + + None => + { + None + } + } + } + + + /// Convert this to an i8. + /// None is returned if the conversion is not possible. + fn to_i8(&self) -> Option<i8> + { + let option: Option<i64>; + + option = self.to_i64(); + match option + { + Some(val) => + { + val.to_i8() + } + + None => + { + None + } + } + } + + /// Convert this to an i16. + /// None is returned if the conversion is not possible. + fn to_i16(&self) -> Option<i16> + { + let option: Option<i64>; + + option = self.to_i64(); + match option + { + Some(val) => + { + val.to_i16() + } + + None => + { + None + } + } + } + + /// Convert this to an i32. + /// None is returned if the conversion is not possible. + fn to_i32(&self) -> Option<i32> + { + let option: Option<i64>; + + option = self.to_i64(); + match option + { + Some(val) => + { + val.to_i32() + } + + None => + { + None + } + } + } + + /// Convert this to an i64. + /// None is returned if the conversion is not possible. + fn to_i64(&self) -> Option<i64>; + + /// Convert this to an isize. + /// None is returned if the conversion is not possible. + fn to_isize(&self) -> Option<isize> + { + let option: Option<i64>; + + option = self.to_i64(); + match option + { + Some(val) => + { + val.to_isize() + } + + None => + { + None + } + } + } + + + /// Convert this to an f32. + /// None is returned if the conversion is not possible. + fn to_f32(&self) -> Option<f32> + { + let option: Option<f64>; + + option = self.to_f64(); + match option + { + Some(val) => + { + val.to_f32() + } + + None => + { + None + } + } + } + + /// Convert this to an f64. + /// None is returned if the conversion is not possible. + fn to_f64(&self) -> Option<f64> + { + let option: Option<i64>; + + option = self.to_i64(); + match option + { + Some(val) => + { + val.to_f64() + } + + None => + { + None + } + } + } } -/// A macro to make implementing the trait easier for all the +/// A trait that defines convertung a Number to something else. +pub trait FromNumber : Sized +{ + /// Convert an i8 to an optional value of this type. + /// None is returned if the conversion is not possible. + fn from_i8(number: i8) -> Option<Self> + { + FromNumber::from_i64(number as i64) + } + + /// Convert an i16 to an optional value of this type. + /// None is returned if the conversion is not possible. + fn from_i16(number: i16) -> Option<Self> + { + FromNumber::from_i64(number as i64) + } + + /// Convert an i32 to an optional value of this type. + /// None is returned if the conversion is not possible. + fn from_i32(number: i32) -> Option<Self> + { + FromNumber::from_i64(number as i64) + } + + /// Convert an i64 to an optional value of this type. + /// None is returned if the conversion is not possible. + fn from_i64(number: i64) -> Option<Self>; + + /// Convert an isize to an optional value of this type. + /// None is returned if the conversion is not possible. + fn from_isize(number: isize) -> Option<Self> + { + FromNumber::from_i64(number as i64) + } + + + /// Convert an u8 to an optional value of this type. + /// None is returned if the conversion is not possible. + fn from_u8(number: u8) -> Option<Self> + { + FromNumber::from_u64(number as u64) + } + + /// Convert an u16 to an optional value of this type. + /// None is returned if the conversion is not possible. + fn from_u16(number: u16) -> Option<Self> + { + FromNumber::from_u64(number as u64) + } + + /// Convert an u32 to an optional value of this type. + /// None is returned if the conversion is not possible. + fn from_u32(number: u32) -> Option<Self> + { + FromNumber::from_u64(number as u64) + } + + /// Convert an u64 to an optional value of this type. + /// None is returned if the conversion is not possible. + fn from_u64(number: u64) -> Option<Self>; + + /// Convert an usize to an optional value of this type. + /// None is returned if the conversion is not possible. + fn from_usize(number: usize) -> Option<Self> + { + FromNumber::from_u64(number as u64) + } + + + /// Convert an f32 to an optional value of this type. + /// None is returned if the conversion is not possible. + fn from_f32(number: f32) -> Option<Self> + { + FromNumber::from_f64(number as f64) + } + + /// Convert an f64 to an optional value of this type. + /// None is returned if the conversion is not possible. + fn from_f64(number: f64) -> Option<Self> + { + FromNumber::from_i64(number as i64) + } +} + + +// Create some macros to ease typing and reading. +macro_rules! convert_int_to_int +{ + ($srcType: ty, $dstType: ty, $val: expr) => + { + { + let num: i64; + let min_value: $dstType; + let max_value: $dstType; + + num = $val as i64; + min_value = Bounded::min_value(); + max_value = Bounded::max_value(); + + if (min_value as i64) <= num && num <= (max_value as i64) + { + Some($val as $dstType) + } + else + { + None + } + } + } +} + +macro_rules! convert_int_to_uint +{ + ($srcType: ty, $dstType: ty, $val: expr) => + { + { + let zero: $srcType; + let max_value: $dstType; + + zero = Zero::zero(); + max_value = Bounded::max_value(); + + if zero <= $val && ($val as u64) <= (max_value as u64) + { + Some($val as $dstType) + } + else + { + None + } + } + } +} + +macro_rules! convert_uint_to_int +{ + ($dstType: ty, $val: expr) => + { + { + let max_value: $dstType; + + max_value = Bounded::max_value(); + if ($val as u64) <= (max_value as u64) + { + Some($val as $dstType) + } + else + { + None + } + } + } +} + +macro_rules! convert_uint_to_uint +{ + ($srcType: ty, $dstType: ty, $val: expr) => + { + if size_of::<$srcType>() <= size_of::<$dstType>() + { + Some($val as $dstType) + } + else + { + let zero: $srcType; + let max_value: $dstType; + + zero = Zero::zero(); + max_value = Bounded::max_value(); + + if zero <= $val && ($val as u64) <= (max_value as u64) + { + Some($val as $dstType) + } + else + { + None + } + } + } +} + +macro_rules! convert_float_to_float +{ + ($srcType: ty, $dstType: ty, $val: expr) => + { + if size_of::<$srcType>() <= size_of::<$dstType>() + { + Some($val as $dstType) + } + else + { + let num: f64; + let min_value: $srcType; + let max_value: $srcType; + + num = $val as f64; + min_value = Bounded::min_value(); + max_value = Bounded::max_value(); + + if (min_value as f64) <= num && num <= (max_value as f64) + { + Some($val as $dstType) + } + else + { + None + } + } + } +} + +macro_rules! int_to_number_impl +{ + ($traitName: ident for $($varType: ty)*) => + ($( + impl $traitName for $varType + { + fn to_u8(&self) -> Option<u8> + { + convert_int_to_uint!($varType, u8, *self) + } + + fn to_u16(&self) -> Option<u16> + { + convert_int_to_uint!($varType, u16, *self) + } + + fn to_u32(&self) -> Option<u32> + { + convert_int_to_uint!($varType, u32, *self) + } + + fn to_u64(&self) -> Option<u64> + { + convert_int_to_uint!($varType, u64, *self) + } + + fn to_usize(&self) -> Option<usize> + { + convert_int_to_uint!($varType, usize, *self) + } + + + fn to_i8(&self) -> Option<i8> + { + convert_int_to_int!($varType, i8, *self) + } + + fn to_i16(&self) -> Option<i16> + { + convert_int_to_int!($varType, i16, *self) + } + + fn to_i32(&self) -> Option<i32> + { + convert_int_to_int!($varType, i32, *self) + } + + fn to_i64(&self) -> Option<i64> + { + convert_int_to_int!($varType, i64, *self) + } + + fn to_isize(&self) -> Option<isize> + { + convert_int_to_int!($varType, isize, *self) + } + + + fn to_f32(&self) -> Option<f32> + { + Some(*self as f32) + } + + fn to_f64(&self) -> Option<f64> + { + Some(*self as f64) + } + } + )*) +} + +macro_rules! uint_to_number_impl +{ + ($traitName: ident for $($varType: ty)*) => + ($( + impl $traitName for $varType + { + fn to_u8(&self) -> Option<u8> + { + convert_uint_to_uint!($varType, u8, *self) + } + + fn to_u16(&self) -> Option<u16> + { + convert_uint_to_uint!($varType, u16, *self) + } + + fn to_u32(&self) -> Option<u32> + { + convert_uint_to_uint!($varType, u32, *self) + } + + fn to_u64(&self) -> Option<u64> + { + convert_uint_to_uint!($varType, u64, *self) + } + + fn to_usize(&self) -> Option<usize> + { + convert_uint_to_uint!($varType, usize, *self) + } + + + fn to_i8(&self) -> Option<i8> + { + convert_uint_to_int!(i8, *self) + } + + fn to_i16(&self) -> Option<i16> + { + convert_uint_to_int!(i16, *self) + } + + fn to_i32(&self) -> Option<i32> + { + convert_uint_to_int!(i32, *self) + } + + fn to_i64(&self) -> Option<i64> + { + convert_uint_to_int!(i64, *self) + } + + fn to_isize(&self) -> Option<isize> + { + convert_uint_to_int!(isize, *self) + } + + + fn to_f32(&self) -> Option<f32> + { + Some(*self as f32) + } + + fn to_f64(&self) -> Option<f64> + { + Some(*self as f64) + } + } + )*) +} + +macro_rules! float_to_number_impl +{ + ($traitName: ident for $($varType: ty)*) => + ($( + impl $traitName for $varType + { + fn to_u8(&self) -> Option<u8> + { + Some(*self as u8) + } + + fn to_u16(&self) -> Option<u16> + { + Some(*self as u16) + } + + fn to_u32(&self) -> Option<u32> + { + Some(*self as u32) + } + + fn to_u64(&self) -> Option<u64> + { + Some(*self as u64) + } + + fn to_usize(&self) -> Option<usize> + { + Some(*self as usize) + } + + + fn to_i8(&self) -> Option<i8> + { + Some(*self as i8) + } + + fn to_i16(&self) -> Option<i16> + { + Some(*self as i16) + } + + fn to_i32(&self) -> Option<i32> + { + Some(*self as i32) + } + + fn to_i64(&self) -> Option<i64> + { + Some(*self as i64) + } + + fn to_isize(&self) -> Option<isize> + { + Some(*self as isize) + } + + + fn to_f32(&self) -> Option<f32> + { + convert_float_to_float!($varType, f32, *self) + } + + fn to_f64(&self) -> Option<f64> + { + convert_float_to_float!($varType, f64, *self) + } + } + )*) +} + +macro_rules! from_number_impl +{ + ($varType: ty, $toTypeFunc: ident) => + { + impl FromNumber for $varType + { + fn from_u8(number: u8) -> Option<$varType> + { + number.$toTypeFunc() + } + + fn from_u16(number: u16) -> Option<$varType> + { + number.$toTypeFunc() + } + + fn from_u32(number: u32) -> Option<$varType> + { + number.$toTypeFunc() + } + + fn from_u64(number: u64) -> Option<$varType> + { + number.$toTypeFunc() + } + + + fn from_i8(number: i8) -> Option<$varType> + { + number.$toTypeFunc() + } + + fn from_i16(number: i16) -> Option<$varType> + { + number.$toTypeFunc() + } + + fn from_i32(number: i32) -> Option<$varType> + { + number.$toTypeFunc() + } + + fn from_i64(number: i64) -> Option<$varType> + { + number.$toTypeFunc() + } + + + fn from_f32(number: f32) -> Option<$varType> + { + number.$toTypeFunc() + } + + fn from_f64(number: f64) -> Option<$varType> + { + number.$toTypeFunc() + } + } + } +} + +/// A macro to make implementing the Number trait easier for all the +/// base integer types in rust. +macro_rules! int_number_trait_impl +{ + ($traitName: ident for $($varType: ty)*) => + ($( + impl $traitName for $varType + { + type StrRadixError = ::std::num::ParseIntError; + + fn from_str_radix(src: &str, radix: u32) -> + Result<Self, ::std::num::ParseIntError> + { + <$varType>::from_str_radix(src, radix) + } + } + )*) +} + +/// A macro to make implementing the Number trait easier for all the /// base float types in rust. -macro_rules! float_trait_impl +macro_rules! float_number_trait_impl { ($traitName: ident for $($varType: ty)*) => ($( @@ -57,7 +777,30 @@ macro_rules! float_trait_impl } -// Implement the trait for the types that are Numbers. -int_trait_impl!(Number for u8 u16 u32 u64 usize); -int_trait_impl!(Number for i8 i16 i32 i64 isize); -float_trait_impl!(Number for f32 f64); +// Implement the Number trait for the types that are Numbers. +int_number_trait_impl!(Number for u8 u16 u32 u64 usize); +int_number_trait_impl!(Number for i8 i16 i32 i64 isize); +float_number_trait_impl!(Number for f32 f64); + +// Implement the ToNumber and FromNumber traits for +// the types that are Numbers. The FromNumber trait needs +// to be defined after ToNumber since FromNumber uses +// ToNumber definitions. +uint_to_number_impl!(ToNumber for u8 u16 u32 u64 usize); +int_to_number_impl!(ToNumber for i8 i16 i32 i64 isize); +float_to_number_impl!(ToNumber for f32 f64); + +from_number_impl!(u8, to_u8); +from_number_impl!(u16, to_u16); +from_number_impl!(u32, to_u32); +from_number_impl!(u64, to_u64); +from_number_impl!(usize, to_usize); + +from_number_impl!(i8, to_i8); +from_number_impl!(i16, to_i16); +from_number_impl!(i32, to_i32); +from_number_impl!(i64, to_i64); +from_number_impl!(isize, to_isize); + +from_number_impl!(f32, to_f32); +from_number_impl!(f64, to_f64); diff --git a/src/quaternion.rs b/src/quaternion.rs new file mode 100644 index 0000000..33f21ba --- /dev/null +++ b/src/quaternion.rs @@ -0,0 +1,5 @@ +//! This module defines the [Quaternion][1] and +//! [DualQuaternion][2] structures. +//! +//! [1]: https://en.wikipedia.org/wiki/Quaternion +//! [2]: https://en.wikipedia.org/wiki/Dual_quaternion diff --git a/src/real.rs b/src/real.rs index 93ab240..d6eae8a 100644 --- a/src/real.rs +++ b/src/real.rs @@ -1,24 +1,1111 @@ +use std::num::FpCategory; + use super::number::Number; +// TODO: Double check these examples. Most are OK, +// but I wanted to have f32 and f64 examples and +// I'm not sure if all of them work correctly. /// A trait that defines what is required to be considered /// a Real number. [List of types of numbers][1] /// +/// This is meant to have all the similarities between +/// [f32][2] and [f64][3]. Most of the comments and documentation +/// were taken from the [rust-lang std docs][4]. +/// /// [1]: https://en.wikipedia.org/wiki/List_of_types_of_numbers -trait Real : Number +/// [2]: https://doc.rust-lang.org/std/primitive.f32.html +/// [3]: https://doc.rust-lang.org/std/primitive.f64.html +/// [4]: https://doc.rust-lang.org/std/index.html +pub trait Real : Number { + /// Returns the `NaN` value. + /// + /// ``` + /// use sigils::Real; + /// + /// let nan32: f32 = Real::nan(); + /// let nan64: f64 = Real::nan(); + /// + /// # assert!(nan32.is_nan()); + /// # assert!(nan64.is_nan()); + /// ``` + fn nan() -> Self; + + /// Returns the infinite value. + /// + /// ``` + /// use std::{f32, f64}; + /// use sigils::Real; + /// + /// let infinity32: f32 = Real::infinity(); + /// let infinity64: f64 = Real::infinity(); + /// + /// # assert!(infinity32.is_infinite()); + /// # assert!(!infinity32.is_finite()); + /// # assert!(infinity32 > f32::MAX); + /// + /// # assert!(infinity64.is_infinite()); + /// # assert!(!infinity64.is_finite()); + /// # assert!(infinity64 > f64::MAX); + /// ``` + fn infinity() -> Self; + + /// Returns the negative infinite value. + /// + /// ``` + /// use std::{f32, f64}; + /// use sigils::Real; + /// + /// let neg_infinity32: f32 = Real::neg_infinity(); + /// let neg_infinity64: f64 = Real::neg_infinity(); + /// + /// # assert!(neg_infinity32.is_infinite()); + /// # assert!(!neg_infinity32.is_finite()); + /// # assert!(neg_infinity32 < f32::MIN); + /// + /// # assert!(neg_infinity64.is_infinite()); + /// # assert!(!neg_infinity64.is_finite()); + /// # assert!(neg_infinity64 < f64::MIN); + /// ``` + fn neg_infinity() -> Self; + + /// Returns `true` if this value is `NaN` and false otherwise. + /// + /// ``` + /// use std::{f32, f64}; + /// use sigils::Real; + /// + /// let nan32 = f32::NAN; + /// let nan64 = f64::NAN; + /// let val32 = 7.0f32; + /// let val64 = 7.0f64; + /// + /// assert!(nan32.is_nan()); + /// assert!(nan64.is_nan()); + /// assert!(!val32.is_nan()); + /// assert!(!val64.is_nan()); + /// ``` + fn is_nan(self) -> bool; + + /// Returns `true` if this value is positive + /// infinity or negative infinity and false otherwise. + /// + /// ``` + /// use std::{f32, f64}; + /// use sigils::Real; + /// + /// let val32 = 7.0f32; + /// let inf32: f32 = Real::infinity(); + /// let neg_inf32: f32 = Real::neg_infinity(); + /// let nan32: f32 = f32::NAN; + /// + /// let val64 = 7.0f64; + /// let inf64: f64 = Real::infinity(); + /// let neg_inf64: f64 = Real::neg_infinity(); + /// let nan64: f64 = f64::NAN; + /// + /// assert!(!val32.is_infinite()); + /// assert!(!nan32.is_infinite()); + /// assert!(inf32.is_infinite()); + /// assert!(neg_inf32.is_infinite()); + /// + /// assert!(!val64.is_infinite()); + /// assert!(!nan64.is_infinite()); + /// assert!(inf64.is_infinite()); + /// assert!(neg_inf64.is_infinite()); + /// ``` + fn is_infinite(self) -> bool; + + /// Returns `true` if this number is neither infinite nor `NaN`. + /// + /// ``` + /// use std::{f32, f64}; + /// use sigils::Real; + /// + /// let val32 = 7.0f32; + /// let inf32: f32 = Real::infinity(); + /// let neg_inf32: f32 = Real::neg_infinity(); + /// let nan32: f32 = f32::NAN; + /// + /// let val64 = 7.0f64; + /// let inf64: f64 = Real::infinity(); + /// let neg_inf64: f64 = Real::neg_infinity(); + /// let nan64: f64 = f64::NAN; + /// + /// assert!(val32.is_finite()); + /// assert!(!nan32.is_finite()); + /// assert!(!inf32.is_finite()); + /// assert!(!neg_inf32.is_finite()); + /// + /// assert!(val64.is_finite()); + /// assert!(!nan64.is_finite()); + /// assert!(!inf64.is_finite()); + /// assert!(!neg_inf64.is_finite()); + /// ``` + fn is_finite(self) -> bool; + + /// Returns `true` if the number is neither zero, infinite, + /// subnormal, or `NaN`. + /// + /// ``` + /// use std::{f32, f64}; + /// use sigils::Real; + /// + /// let min32 = f32::MIN_POSITIVE; + /// let max32 = f32::MAX; + /// let lower_than_min32 = 1.0e-40_f32; + /// let zero32 = 0.0f32; + /// + /// let min64 = f64::MIN_POSITIVE; + /// let max64 = f64::MAX; + /// let lower_than_min64 = 1.0e-40_f64; + /// let zero64 = 0.0f64; + /// + /// // Values between `0` and `min` are Subnormal. + /// assert!(min32.is_normal()); + /// assert!(max32.is_normal()); + /// assert!(!zero32.is_normal()); + /// assert!(!f32::NAN.is_normal()); + /// assert!(!f32::INFINITY.is_normal()); + /// assert!(!lower_than_min32.is_normal()); + /// + /// assert!(min64.is_normal()); + /// assert!(max64.is_normal()); + /// assert!(!zero64.is_normal()); + /// assert!(!f64::NAN.is_normal()); + /// assert!(!f64::INFINITY.is_normal()); + /// //assert!(!lower_than_min64.is_normal()); + /// ``` + fn is_normal(self) -> bool; + + /// Returns the floating point category of the number. + /// If only one property is going to be tested, it is + /// generally faster to use the specific predicate instead. + /// + /// ``` + /// use std::{f32, f64}; + /// use std::num::FpCategory; + /// use sigils::Real; + /// + /// let num32 = 12.4f32; + /// let inf32 = f32::INFINITY; + /// + /// let num64 = 12.4f64; + /// let inf64 = f64::INFINITY; + /// + /// assert_eq!(num32.classify(), FpCategory::Normal); + /// assert_eq!(inf32.classify(), FpCategory::Infinite); + /// + /// assert_eq!(num64.classify(), FpCategory::Normal); + /// assert_eq!(inf64.classify(), FpCategory::Infinite); + /// ``` + fn classify(self) -> FpCategory; + + // TODO: Fix/check this example. + /// Returns the mantissa, base 2 exponent, and sign as + /// integers, respectively. The original number can be + /// recovered by `sign * mantissa * 2 ^ exponent`. + /// + /// ``` + /// use sigils::Real; + /// + /// let num = 2.0f32; + /// + /// // (8388608, -22, 1) + /// let (mantissa, exponent, sign) = Real::integer_decode(num); + /// let sign_f = sign as f32; + /// let mantissa_f = mantissa as f32; + /// let exponent_f = num.powf(exponent as f32); + /// + /// // 1 * 8388608 * 2^(-22) == 2 + /// let abs_difference = + /// (sign_f * mantissa_f * exponent_f - num).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn integer_decode(self) -> (u64, i16, i8); + + /// Returns the largest integer less than or equal to a number. + /// + /// ``` + /// use sigils::Real; + /// + /// let f_val32 = 3.99f32; + /// let g_val32 = 3.0f32; + /// + /// let f_val64 = 3.99f64; + /// let g_val64 = 3.0f64; + /// + /// assert_eq!(f_val32.floor(), 3.0f32); + /// assert_eq!(g_val32.floor(), 3.0f32); + /// + /// assert_eq!(f_val64.floor(), 3.0f64); + /// assert_eq!(g_val64.floor(), 3.0f64); + /// ``` + fn floor(self) -> Self; + + /// Returns the smallest integer greater than or equal to a number. + /// + /// ``` + /// use sigils::Real; + /// + /// let f_val32 = 3.01f32; + /// let g_val32 = 4.0f32; + /// + /// let f_val64 = 3.01f64; + /// let g_val64 = 4.0f64; + /// + /// assert_eq!(f_val32.ceil(), 4.0f32); + /// assert_eq!(g_val32.ceil(), 4.0f32); + /// + /// assert_eq!(f_val64.ceil(), 4.0f64); + /// assert_eq!(g_val64.ceil(), 4.0f64); + /// ``` + fn ceil(self) -> Self; + + /// Returns the nearest integer to a number. Round + /// half-way cases away from `0.0`. + /// + /// ``` + /// use sigils::Real; + /// + /// let f_val32 = 3.3f32; + /// let g_val32 = -3.3f32; + /// + /// let f_val64 = 3.3f64; + /// let g_val64 = -3.3f64; + /// + /// assert_eq!(f_val32.round(), 3.0f32); + /// assert_eq!(g_val32.round(), -3.0f32); + /// + /// assert_eq!(f_val64.round(), 3.0f64); + /// assert_eq!(g_val64.round(), -3.0f64); + /// ``` + fn round(self) -> Self; + + /// Return the integer part of a number. + /// + /// ``` + /// use sigils::Real; + /// + /// let f_val32 = 3.3f32; + /// let g_val32 = -3.7f32; + /// + /// let f_val64 = 3.3f64; + /// let g_val64 = -3.7f64; + /// + /// assert_eq!(f_val32.trunc(), 3.0f32); + /// assert_eq!(g_val32.trunc(), -3.0f32); + /// + /// assert_eq!(f_val64.trunc(), 3.0f64); + /// assert_eq!(g_val64.trunc(), -3.0f64); + /// ``` + fn trunc(self) -> Self; + + /// Returns the fractional part of a number. + /// + /// ``` + /// use sigils::Real; + /// + /// let x32 = 3.5f32; + /// let y32 = -3.5f32; + /// let abs_difference_x32 = (x32.fract() - 0.5f32).abs(); + /// let abs_difference_y32 = (y32.fract() - (-0.5f32)).abs(); + /// + /// let x64 = 3.5f64; + /// let y64 = -3.5f64; + /// let abs_difference_x64 = (x64.fract() - 0.5f64).abs(); + /// let abs_difference_y64 = (y64.fract() - (-0.5f64)).abs(); + /// + /// assert!(abs_difference_x32 < 1e-10); + /// assert!(abs_difference_y32 < 1e-10); + /// + /// assert!(abs_difference_x64 < 1e-10); + /// assert!(abs_difference_y64 < 1e-10); + /// ``` + fn fract(self) -> Self; + + /// Computes the absolute value of `self`. Returns `Real::nan()` if the + /// number is `NaN`. + /// + /// ``` + /// use std::{f32, f64}; + /// use sigils::Real; + /// + /// let x32 = 3.5f32; + /// let y32 = -3.5f32; + /// let abs_difference_x32 = (x32.abs() - x32).abs(); + /// let abs_difference_y32 = (y32.abs() - (-y32)).abs(); + /// + /// let x64 = 3.5f64; + /// let y64 = -3.5f64; + /// let abs_difference_x64 = (x64.abs() - x64).abs(); + /// let abs_difference_y64 = (y64.abs() - (-y64)).abs(); + /// + /// assert!(abs_difference_x32 < 1e-10); + /// assert!(abs_difference_y32 < 1e-10); + /// assert!(f32::NAN.abs().is_nan()); + /// + /// assert!(abs_difference_x64 < 1e-10); + /// assert!(abs_difference_y64 < 1e-10); + /// assert!(f64::NAN.abs().is_nan()); + /// ``` + fn abs(self) -> Self; + + /// Returns a number that represents the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `Real::infinity()` + /// - `-1.0` if the number is negative, `-0.0` or `Real::neg_infinity()` + /// - `Real::nan()` if the number is `Real::nan()` + /// + /// ``` + /// use std::{f32, f64}; + /// use sigils::Real; + /// + /// let val32 = 3.5f32; + /// + /// let val64 = 3.5f64; + /// + /// assert_eq!(val32.signum(), 1.0f32); + /// assert_eq!(f32::NEG_INFINITY.signum(), -1.0f32); + /// assert!(f32::NAN.signum().is_nan()); + /// + /// assert_eq!(val64.signum(), 1.0f64); + /// assert_eq!(f64::NEG_INFINITY.signum(), -1.0f64); + /// assert!(f64::NAN.signum().is_nan()); + /// ``` + fn signum(self) -> Self; + + /// Returns `true` if `self` is positive, including `+0.0` and + /// `Real::infinity()`. + /// + /// ``` + /// use std::{f32, f64}; + /// use sigils::Real; + /// + /// let nan32: f32 = f32::NAN; + /// let f_val32 = 7.0f32; + /// let g_val32 = -7.0f32; + /// + /// let nan64: f64 = f64::NAN; + /// let f_val64 = 7.0f64; + /// let g_val64 = -7.0f64; + /// + /// // Requires both tests to determine if is `NaN` + /// assert!(f_val32.is_sign_positive()); + /// assert!(!g_val32.is_sign_positive()); + /// assert!(!nan32.is_sign_positive() && !nan32.is_sign_negative()); + /// + /// assert!(f_val64.is_sign_positive()); + /// assert!(!g_val64.is_sign_positive()); + /// assert!(!nan64.is_sign_positive() && !nan64.is_sign_negative()); + /// ``` + fn is_sign_positive(self) -> bool; + + /// Returns `true` if `self` is negative, including `-0.0` and + /// `Real::neg_infinity()`. + /// + /// ``` + /// use std::{f32, f64}; + /// use sigils::Real; + /// + /// let nan32: f32 = f32::NAN; + /// let f_val32 = 7.0f32; + /// let g_val32 = -7.0f32; + /// + /// let nan64: f64 = f64::NAN; + /// let f_val64 = 7.0f64; + /// let g_val64 = -7.0f64; + /// + /// // Requires both tests to determine if is `NaN` + /// assert!(!f_val32.is_sign_negative()); + /// assert!(g_val32.is_sign_negative()); + /// assert!(!nan32.is_sign_positive() && !nan32.is_sign_negative()); + /// + /// assert!(!f_val64.is_sign_negative()); + /// assert!(g_val64.is_sign_negative()); + /// assert!(!nan64.is_sign_positive() && !nan64.is_sign_negative()); + /// ``` + fn is_sign_negative(self) -> bool; + + /// Fused multiply-add. Computes `(self * a) + b` with + /// only one rounding error. This produces a more accurate + /// result with better performance than a separate + /// multiplication operation followed by an add. + /// + /// ``` + /// use sigils::Real; + /// + /// let m32 = 10.0f32; + /// let x32 = 4.0f32; + /// let b32 = 60.0f32; + /// let abs_difference32 = + /// (m32.mul_add(x32, b32) - (m32*x32 + b32)).abs(); + /// + /// let m64 = 10.0f64; + /// let x64 = 4.0f64; + /// let b64 = 60.0f64; + /// let abs_difference64 = + /// (m64.mul_add(x64, b64) - (m64*x64 + b64)).abs(); + /// + /// assert!(abs_difference32 < 1e-10); + /// assert!(abs_difference64 < 1e-10); + /// ``` + fn mul_add(self, a: Self, b: Self) -> Self; + + /// Take the reciprocal (inverse) of a number, `1/x`. + /// + /// ``` + /// use sigils::Real; + /// + /// let x32 = 2.0f32; + /// let abs_difference32 = + /// (x32.recip() - (1.0f32/x32)).abs(); + /// + /// let x64 = 2.0f64; + /// let abs_difference64 = + /// (x64.recip() - (1.0f64/x64)).abs(); + /// + /// assert!(abs_difference32 < 1e-10); + /// assert!(abs_difference64 < 1e-10); + /// ``` + fn recip(self) -> Self; + + /// Raise a number to an integer power. + /// + /// Using this function is generally faster than using `powf` + /// + /// ``` + /// use sigils::Real; + /// + /// let x32 = 2.0f32; + /// let abs_difference32 = (x32.powi(2i32) - x32*x32).abs(); + /// + /// let x64 = 2.0f64; + /// let abs_difference64 = (x64.powi(2i32) - x64*x64).abs(); + /// + /// assert!(abs_difference32 < 1e-10); + /// assert!(abs_difference64 < 1e-10); + /// ``` + fn powi(self, n: i32) -> Self; + + /// Raise a number to a floating point power. + /// + /// ``` + /// use sigils::Real; + /// + /// let x32 = 2.0f32; + /// let abs_difference32 = (x32.powf(2.0f32) - x32*x32).abs(); + /// + /// let x64 = 2.0f64; + /// let abs_difference64 = (x64.powf(2.0f64) - x64*x64).abs(); + /// + /// assert!(abs_difference32 < 1e-10); + /// assert!(abs_difference64 < 1e-10); + /// ``` + fn powf(self, n: Self) -> Self; + + /// Take the square root of a number. + /// + /// Returns NaN if `self` is a negative number. + /// + /// ``` + /// use sigils::Real; + /// + /// let positive = 4.0; + /// let negative = -4.0; + /// + /// let abs_difference = (positive.sqrt() - 2.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// assert!(negative.sqrt().is_nan()); + /// ``` + fn sqrt(self) -> Self; + + /// Returns `e^(self)`, (the exponential function). + /// + /// ``` + /// use sigils::Real; + /// + /// let one = 1.0; + /// // e^1 + /// let e = one.exp(); + /// + /// // ln(e) - 1 == 0 + /// let abs_difference = (e.ln() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn exp(self) -> Self; + + /// Returns `2^(self)`. + /// + /// ``` + /// use sigils::Real; + /// + /// let f = 2.0; + /// + /// // 2^2 - 4 == 0 + /// let abs_difference = (f.exp2() - 4.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn exp2(self) -> Self; + + /// Returns the natural logarithm of the number. + /// + /// ``` + /// use sigils::Real; + /// + /// let one = 1.0; + /// // e^1 + /// let e = one.exp(); + /// + /// // ln(e) - 1 == 0 + /// let abs_difference = (e.ln() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn ln(self) -> Self; + + /// Returns the logarithm of the number with respect to an arbitrary base. + /// + /// ``` + /// use sigils::Real; + /// + /// let ten = 10.0; + /// let two = 2.0; + /// + /// // log10(10) - 1 == 0 + /// let abs_difference_10 = (ten.log(10.0) - 1.0).abs(); + /// + /// // log2(2) - 1 == 0 + /// let abs_difference_2 = (two.log(2.0) - 1.0).abs(); + /// + /// assert!(abs_difference_10 < 1e-10); + /// assert!(abs_difference_2 < 1e-10); + /// ``` + fn log(self, base: Self) -> Self; + + /// Returns the base 2 logarithm of the number. + /// + /// ``` + /// use sigils::Real; + /// + /// let two = 2.0; + /// + /// // log2(2) - 1 == 0 + /// let abs_difference = (two.log2() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn log2(self) -> Self; + + /// Returns the base 10 logarithm of the number. + /// + /// ``` + /// use sigils::Real; + /// + /// let ten = 10.0; + /// + /// // log10(10) - 1 == 0 + /// let abs_difference = (ten.log10() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn log10(self) -> Self; + + /// Returns the maximum of the two numbers. + /// + /// ``` + /// use sigils::Real; + /// + /// let x = 1.0; + /// let y = 2.0; + /// + /// assert_eq!(x.max(y), y); + /// ``` + fn max(self, other: Self) -> Self; + + /// Returns the minimum of the two numbers. + /// + /// ``` + /// use sigils::Real; + /// + /// let x = 1.0; + /// let y = 2.0; + /// + /// assert_eq!(x.min(y), x); + /// ``` + fn min(self, other: Self) -> Self; + + /// The positive difference of two numbers. + /// + /// * If `self <= other`: `0:0` + /// * Else: `self - other` + /// + /// ``` + /// use sigils::Real; + /// + /// let x = 3.0; + /// let y = -3.0; + /// + /// let abs_difference_x = (x.abs_sub(1.0) - 2.0).abs(); + /// let abs_difference_y = (y.abs_sub(1.0) - 0.0).abs(); + /// + /// assert!(abs_difference_x < 1e-10); + /// assert!(abs_difference_y < 1e-10); + /// ``` + fn abs_sub(self, other: Self) -> Self; + + /// Take the cubic root of a number. + /// + /// ``` + /// use sigils::Real; + /// + /// let x = 8.0; + /// + /// // x^(1/3) - 2 == 0 + /// let abs_difference = (x.cbrt() - 2.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn cbrt(self) -> Self; + + /// Computes the sine of a number (in radians). + /// + /// ``` + /// use sigils::Real; + /// use std::f64; + /// + /// let x = f64::consts::PI/2.0; + /// + /// let abs_difference = (x.sin() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn sin(self) -> Self; + + /// Computes the cosine of a number (in radians). + /// + /// ``` + /// use sigils::Real; + /// use std::f64; + /// + /// let x = 2.0*f64::consts::PI; + /// + /// let abs_difference = (x.cos() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn cos(self) -> Self; + + /// Computes the tangent of a number (in radians). + /// + /// ``` + /// use sigils::Real; + /// use std::f64; + /// + /// let x = f64::consts::PI/4.0; + /// let abs_difference = (x.tan() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-14); + /// ``` + fn tan(self) -> Self; + + /// Computes the arcsine of a number. Return value is in radians in + /// the range [-pi/2, pi/2] or NaN if the number is outside the range + /// [-1, 1]. + /// + /// ``` + /// use sigils::Real; + /// use std::f64; + /// + /// let f = f64::consts::PI / 2.0; + /// + /// // asin(sin(pi/2)) + /// let abs_difference = (f.sin().asin() - f64::consts::PI / 2.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn asin(self) -> Self; + + /// Computes the arccosine of a number. Return value is in radians in + /// the range [0, pi] or NaN if the number is outside the range + /// [-1, 1]. + /// + /// ``` + /// use sigils::Real; + /// use std::f64; + /// + /// let f = f64::consts::PI / 4.0; + /// + /// // acos(cos(pi/4)) + /// let abs_difference = (f.cos().acos() - f64::consts::PI / 4.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn acos(self) -> Self; + + /// Computes the arctangent of a number. Return value is in radians in the + /// range [-pi/2, pi/2]; + /// + /// ``` + /// use sigils::Real; + /// + /// let f = 1.0; + /// + /// // atan(tan(1)) + /// let abs_difference = (f.tan().atan() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn atan(self) -> Self; + + /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`). + /// + /// * `x = 0`, `y = 0`: `0` + /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]` + /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]` + /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)` + /// + /// ``` + /// use sigils::Real; + /// use std::f64; + /// + /// let pi = f64::consts::PI; + /// // All angles from horizontal right (+x) + /// // 45 deg counter-clockwise + /// let x1 = 3.0; + /// let y1 = -3.0; + /// + /// // 135 deg clockwise + /// let x2 = -3.0; + /// let y2 = 3.0; + /// + /// let abs_difference_1 = (y1.atan2(x1) - (-pi/4.0)).abs(); + /// let abs_difference_2 = (y2.atan2(x2) - 3.0*pi/4.0).abs(); + /// + /// assert!(abs_difference_1 < 1e-10); + /// assert!(abs_difference_2 < 1e-10); + /// ``` + fn atan2(self, other: Self) -> Self; + + /// Simultaneously computes the sine and cosine of the number, `x`. Returns + /// `(sin(x), cos(x))`. + /// + /// ``` + /// use sigils::Real; + /// use std::f64; + /// + /// let x = f64::consts::PI/4.0; + /// let f = x.sin_cos(); + /// + /// let abs_difference_0 = (f.0 - x.sin()).abs(); + /// let abs_difference_1 = (f.1 - x.cos()).abs(); + /// + /// assert!(abs_difference_0 < 1e-10); + /// assert!(abs_difference_0 < 1e-10); + /// ``` + fn sin_cos(self) -> (Self, Self); + + /// Returns `e^(self) - 1` in a way that is accurate even if the + /// number is close to zero. + /// + /// ``` + /// use sigils::Real; + /// + /// let x = 7.0; + /// + /// // e^(ln(7)) - 1 + /// let abs_difference = (x.ln().exp_m1() - 6.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn exp_m1(self) -> Self; + + /// Returns `ln(1+n)` (natural logarithm) more accurately than if + /// the operations were performed separately. + /// + /// ``` + /// use sigils::Real; + /// use sigils::Constants; + /// + /// // ln(1 + (e - 1)) == ln(e) == 1 + /// let mut x32: f32 = Constants::E; + /// x32 -= 1.0f32; + /// let abs_difference32 = (x32.ln_1p() - 1.0f32).abs(); + /// + /// let mut x64: f64 = Constants::E; + /// x64 -= 1.0f64; + /// let abs_difference64 = (x64.ln_1p() - 1.0f64).abs(); + /// + /// //assert!(abs_difference32 < 1e-10); + /// assert!(abs_difference64 < 1e-10); + /// ``` + fn ln_1p(self) -> Self; + + /// Hyperbolic sine function. + /// + /// ``` + /// use sigils::Real; + /// use sigils::Constants; + /// + /// let e32: f32 = Constants::E; + /// let x32: f32 = 1.0f32; + /// + /// let f_val32 = x32.sinh(); + /// let g_val32 = (e32*e32 - 1.0f32)/(2.0f32*e32); + /// let abs_difference32 = (f_val32 - g_val32).abs(); + /// + /// let e64: f64 = Constants::E; + /// let x64: f64 = 1.0f64; + /// + /// let f_val64 = x64.sinh(); + /// let g_val64 = (e64*e64 - 1.0f64)/(2.0f64*e64); + /// let abs_difference64 = (f_val64 - g_val64).abs(); + /// + /// // Solving sinh() at 1 gives `(e^2-1)/(2e)` + /// //assert!(abs_difference32 < 1e-10); + /// assert!(abs_difference64 < 1e-10); + /// ``` + fn sinh(self) -> Self; + + /// Hyperbolic cosine function. + /// + /// ``` + /// use sigils::Real; + /// use sigils::Constants; + /// + /// let e32: f32 = Constants::E; + /// let x32: f32 = 1.0f32; + /// let f_val32 = x32.cosh(); + /// let g_val32 = (e32*e32 + 1.0f32)/(2.0f32*e32); + /// let abs_difference32 = (f_val32 - g_val32).abs(); + /// + /// let e64: f64 = Constants::E; + /// let x64: f64 = 1.0f64; + /// let f_val64 = x64.cosh(); + /// let g_val64 = (e64*e64 + 1.0f64)/(2.0f64*e64); + /// let abs_difference64 = (f_val64 - g_val64).abs(); + /// + /// // Solving cosh() at 1 gives this result + /// //assert!(abs_difference32 < 1.0e-10); + /// assert!(abs_difference64 < 1.0e-10); + /// ``` + fn cosh(self) -> Self; + + /// Hyperbolic tangent function. + /// + /// ``` + /// use sigils::Real; + /// use sigils::Constants; + /// + /// let e32: f32 = Constants::E; + /// let x32: f32 = 1.0f32; + /// + /// let f_val32 = x32.tanh(); + /// let g_val32 = (1.0f32 - e32.powi(-2i32))/(1.0f32 + e32.powi(-2i32)); + /// let abs_difference32 = (f_val32 - g_val32).abs(); + /// + /// let e64: f64 = Constants::E; + /// let x64: f64 = 1.0f64; + /// + /// let f_val64 = x64.tanh(); + /// let g_val64 = (1.0f64 - e64.powi(-2i32))/(1.0f64 + e64.powi(-2i32)); + /// let abs_difference64 = (f_val64 - g_val64).abs(); + /// + /// // Solving tanh() at 1 gives `(1 - e^(-2))/(1 + e^(-2))` + /// //assert!(abs_difference32 < 1.0e-10); + /// assert!(abs_difference64 < 1.0e-10); + /// ``` + fn tanh(self) -> Self; + + /// Inverse hyperbolic sine function. + /// + /// ``` + /// use sigils::Real; + /// + /// let x = 1.0; + /// let f = x.sinh().asinh(); + /// + /// let abs_difference = (f - x).abs(); + /// + /// assert!(abs_difference < 1.0e-10); + /// ``` + fn asinh(self) -> Self; + + /// Inverse hyperbolic cosine function. + /// + /// ``` + /// use sigils::Real; + /// + /// let x = 1.0; + /// let f = x.cosh().acosh(); + /// + /// let abs_difference = (f - x).abs(); + /// + /// assert!(abs_difference < 1.0e-10); + /// ``` + fn acosh(self) -> Self; + + /// Inverse hyperbolic tangent function. + /// + /// ``` + /// use sigils::Real; + /// use sigils::Constants; + /// + /// let e32: f32 = Constants::E; + /// let f_val32 = e32.tanh().atanh(); + /// let abs_difference32 = (f_val32 - e32).abs(); + /// + /// let e64: f64 = Constants::E; + /// let f_val64 = e64.tanh().atanh(); + /// let abs_difference64 = (f_val64 - e64).abs(); + /// + /// //assert!(abs_difference32 < 1.0e-10); + /// assert!(abs_difference64 < 1.0e-10); + /// ``` + fn atanh(self) -> Self; } // Create a macro to ease typing and reading. +/// +macro_rules! define_self_func +{ + ($varType: ident, $funcName: ident) => + { + fn $funcName(self) -> $varType + { + <$varType>::$funcName(self) + } + } +} + +/// +macro_rules! define_self_bool_func +{ + ($varType: ident, $funcName: ident) => + { + fn $funcName(self) -> bool + { + <$varType>::$funcName(self) + } + } +} + +/// +macro_rules! define_self_other_func +{ + ($varType: ident, $funcName: ident) => + { + fn $funcName(self, other: $varType) -> $varType + { + <$varType>::$funcName(self, other) + } + } +} + /// A macro to make implementing the trait easier for all the /// base float types in rust. macro_rules! real_trait_impl { - ($traitName: ident for $($varType: ty)*) => + ($traitName: ident for $($varType: ident)*) => ($( impl Real for $varType { + fn nan() -> $varType + { + ::std::$varType::NAN + } + + fn infinity() -> $varType + { + ::std::$varType::INFINITY + } + + fn neg_infinity() -> $varType + { + ::std::$varType::NEG_INFINITY + } + + fn classify(self) -> FpCategory + { + <$varType>::classify(self) + } + + fn integer_decode(self) -> (u64, i16, i8) + { + <$varType>::integer_decode(self) + } + + fn mul_add(self, a: $varType, b: $varType) -> $varType + { + <$varType>::mul_add(self, a, b) + } + + fn powi(self, n: i32) -> $varType + { + <$varType>::powi(self, n) + } + + fn powf(self, n: $varType) -> $varType + { + <$varType>::powf(self, n) + } + + fn sin_cos(self) -> ($varType, $varType) + { + <$varType>::sin_cos(self) + } + + define_self_bool_func!($varType, is_nan); + define_self_bool_func!($varType, is_infinite); + define_self_bool_func!($varType, is_finite); + define_self_bool_func!($varType, is_normal); + define_self_bool_func!($varType, is_sign_positive); + define_self_bool_func!($varType, is_sign_negative); + define_self_func!($varType, signum); + + define_self_func!($varType, floor); + define_self_func!($varType, ceil); + define_self_func!($varType, round); + define_self_func!($varType, trunc); + + define_self_func!($varType, fract); + define_self_func!($varType, abs); + define_self_other_func!($varType, abs_sub); + define_self_func!($varType, recip); + define_self_func!($varType, sqrt); + define_self_func!($varType, cbrt); + define_self_func!($varType, exp); + define_self_func!($varType, exp2); + define_self_func!($varType, exp_m1); + define_self_func!($varType, ln_1p); + + define_self_other_func!($varType, min); + define_self_other_func!($varType, max); + + define_self_func!($varType, ln); + define_self_other_func!($varType, log); + define_self_func!($varType, log2); + define_self_func!($varType, log10); + + define_self_func!($varType, cos); + define_self_func!($varType, sin); + define_self_func!($varType, tan); + define_self_func!($varType, acos); + define_self_func!($varType, asin); + define_self_func!($varType, atan); + define_self_func!($varType, cosh); + define_self_func!($varType, sinh); + define_self_func!($varType, tanh); + define_self_func!($varType, acosh); + define_self_func!($varType, asinh); + define_self_func!($varType, atanh); + define_self_other_func!($varType, atan2); } )*) } diff --git a/src/trig.rs b/src/trig.rs new file mode 100644 index 0000000..247d822 --- /dev/null +++ b/src/trig.rs @@ -0,0 +1,26 @@ +//use super::constants::Constants; +use super::real::Real; + + +/* +pub struct Radians<T> where T: Real +{ + pub value: T +} + +pub struct Degrees<T> where T: Real +{ + pub value: T +} +*/ + + +pub fn acos<T>(x: T) -> T where T: Real +{ + x.acos() +} + +pub fn atan2<T>(x: T, y: T) -> T where T: Real +{ + x.atan2(y) +} diff --git a/src/vector.rs b/src/vector.rs index b81c6a2..9bc24fd 100644 --- a/src/vector.rs +++ b/src/vector.rs @@ -1,11 +1,18 @@ +//! This module defines 2, 3, and 4 component [Vector][1] structures. +//! +//! [1]: https://en.wikipedia.org/wiki/Vector_(mathematics_and_physics) use std::num::{Zero, One}; -use std::ops::{Add, Sub, Mul, Div, Rem}; +use std::ops::{Add, Sub, Mul, Div, Rem, Neg}; use super::number::Number; +use super::real::Real; +use super::trig::{acos, atan2}; /// A trait that defines the minimum set of -/// functions a Vector must implement. +/// functions a [Vector][1] must implement. +/// +/// [1]: https://en.wikipedia.org/wiki/Vector_(mathematics_and_physics) pub trait Vector<T> : Clone where T: Number { // Creation functions. @@ -23,26 +30,6 @@ pub trait Vector<T> : Clone where T: Number ///``` fn from_value(val: T) -> Self; - /// Create a zero Vector. All components will be set to zero. - /// - /// ``` - /// // Create a new Vector4<u8> where all - /// // the components are 0. - /// use sigils::vector::*; - /// - /// let vector = Vector4::<u8>::zero(); - /// # assert_eq!(vector.x, 0u8); - /// # assert_eq!(vector.y, 0u8); - /// # assert_eq!(vector.z, 0u8); - /// # assert_eq!(vector.w, 0u8); - /// ``` - // TODO: Should Vectors implement the Zero trait - // instead of defining a function for it? - fn zero() -> Self - { - Self::from_value(T::zero()) - } - /// Create an identity Vector. All components will be set to one. /// /// ``` @@ -54,78 +41,75 @@ pub trait Vector<T> : Clone where T: Number /// # assert_eq!(vector.x, 1i32); /// # assert_eq!(vector.y, 1i32); /// ``` - // TODO: Should Vectors implement the One trait - // instead of defining an identity function? fn identity() -> Self { Self::from_value(T::one()) } - // Scalar operations that result in a new Vector. - /// Add a scalar value to this Vector and return a new Vector. + // Scalar operations that change this Vector. + /// Add a scalar value to this Vector. /// /// ``` /// // Create a new Vector2<i32> where all /// // the components are 1. Then add 1 to it. /// use sigils::vector::*; /// - /// let vector = Vector2::<i32>::identity(); - /// let vector_two = vector.add_scalar(1i32); - /// # assert_eq!(vector_two.x, 2i32); - /// # assert_eq!(vector_two.y, 2i32); + /// let mut vector = Vector2::<i32>::identity(); + /// vector.add_scalar(1i32); + /// # assert_eq!(vector.x, 2i32); + /// # assert_eq!(vector.y, 2i32); /// ``` - fn add_scalar(&self, scalar: T) -> Self; + fn add_scalar(&mut self, scalar: T); - /// Subtract a scalar value from this Vector and return a new Vector. + /// Subtract a scalar value from this Vector. /// /// ``` /// // Create a new Vector4<f64> where all /// // the components are 1. Then subtract 1 from it. /// use sigils::vector::*; /// - /// let vector = Vector4::<f64>::identity(); - /// let vector_two = vector.sub_scalar(1.0f64); - /// # assert_eq!(vector_two.x, 0f64); - /// # assert_eq!(vector_two.y, 0f64); - /// # assert_eq!(vector_two.z, 0f64); - /// # assert_eq!(vector_two.w, 0f64); + /// let mut vector = Vector4::<f64>::identity(); + /// vector.sub_scalar(1.0f64); + /// # assert_eq!(vector.x, 0f64); + /// # assert_eq!(vector.y, 0f64); + /// # assert_eq!(vector.z, 0f64); + /// # assert_eq!(vector.w, 0f64); /// ``` - fn sub_scalar(&self, scalar: T) -> Self; + fn sub_scalar(&mut self, scalar: T); - /// Multiply this Vector by a scalar value and return a new Vector. + /// Multiply this Vector by a scalar value. /// /// ``` /// // Create a new Vector4<f64> where all /// // the components are 5. Then multiply it by 5. /// use sigils::vector::*; /// - /// let vector = Vector4::<f32>::from_value(5f32); - /// let vector_two = vector.mul_scalar(5f32); - /// # assert_eq!(vector_two.x, 25f32); - /// # assert_eq!(vector_two.y, 25f32); - /// # assert_eq!(vector_two.z, 25f32); - /// # assert_eq!(vector_two.w, 25f32); + /// let mut vector = Vector4::<f32>::from_value(5f32); + /// vector.mul_scalar(5f32); + /// # assert_eq!(vector.x, 25f32); + /// # assert_eq!(vector.y, 25f32); + /// # assert_eq!(vector.z, 25f32); + /// # assert_eq!(vector.w, 25f32); /// ``` - fn mul_scalar(&self, scalar: T) -> Self; + fn mul_scalar(&mut self, scalar: T); - /// Divide this Vector by a scalar value and return a new Vector. + /// Divide this Vector by a scalar value. /// /// ``` /// // Create a new Vector3<u8> where all /// // the components are 25. Then divide it by 5. /// use sigils::vector::*; /// - /// let vector = Vector3::<u8>::from_value(25u8); - /// let vector_two = vector.div_scalar(5u8); - /// # assert_eq!(vector_two.x, 5u8); - /// # assert_eq!(vector_two.y, 5u8); - /// # assert_eq!(vector_two.z, 5u8); + /// let mut vector = Vector3::<u8>::from_value(25u8); + /// vector.div_scalar(5u8); + /// # assert_eq!(vector.x, 5u8); + /// # assert_eq!(vector.y, 5u8); + /// # assert_eq!(vector.z, 5u8); /// ``` - fn div_scalar(&self, scalar: T) -> Self; + fn div_scalar(&mut self, scalar: T); - /// Divide this Vector by a scalar value, take the remainder, - /// and return a new Vector. + /// Divide this Vector by a scalar value and store the remainder. /// /// ``` /// // Create a new Vector3<isize> where all @@ -133,79 +117,226 @@ pub trait Vector<T> : Clone where T: Number /// // and take the remainder. /// use sigils::vector::*; /// - /// let vector = Vector3::<isize>::from_value(25isize); - /// let vector_two = vector.rem_scalar(7isize); - /// # assert_eq!(vector_two.x, 4isize); - /// # assert_eq!(vector_two.y, 4isize); - /// # assert_eq!(vector_two.z, 4isize); + /// let mut vector = Vector3::<isize>::from_value(25isize); + /// vector.rem_scalar(7isize); + /// # assert_eq!(vector.x, 4isize); + /// # assert_eq!(vector.y, 4isize); + /// # assert_eq!(vector.z, 4isize); /// ``` - fn rem_scalar(&self, scalar: T) -> Self; - - - // Vector operations that result in a new Vector. - /// Add a Vector to this Vector and return a new Vector. - fn add_vector(&self, vector: &Self) -> Self; - - /// Subtract a Vector from this Vector and return a new Vector. - fn sub_vector(&self, vector: &Self) -> Self; - - /// Multiply this Vector by a Vector and return a new Vector. - fn mul_vector(&self, vector: &Self) -> Self; - - /// Divide this Vector by a Vector and return a new Vector. - fn div_vector(&self, vector: &Self) -> Self; - - /// Divide this Vector by a Vector, take the remainder, - /// and return a new Vector. - fn rem_vector(&self, vector: &Self) -> Self; - - - // Scalar operations that change this Vector. - /// Add a scalar value to this Vector. - fn add_scalar_self(&mut self, scalar: T); - - /// Subtract a scalar value from this Vector. - fn sub_scalar_self(&mut self, scalar: T); - - /// Multiply this Vector by a scalar value. - fn mul_scalar_self(&mut self, scalar: T); - - /// Divide this Vector by a scalar value. - fn div_scalar_self(&mut self, scalar: T); - - /// Divide this Vector by a scalar value and take the remainder. - fn rem_scalar_self(&mut self, scalar: T); + fn rem_scalar(&mut self, scalar: T); // Vector operations that change this Vector. /// Add a Vector to this Vector. - fn add_vector_self(&mut self, vector: &Self); + /// + /// ``` + /// // Create a new Vector2<i32> where all + /// // the components are 1. Then add + /// // another Vector2<i32>, where all the + /// // components are 1, to it. + /// use sigils::vector::*; + /// + /// let mut vector = Vector2::<i32>::identity(); + /// let vector_two = Vector2::<i32>::identity(); + /// vector.add_vector(&vector_two); + /// # assert_eq!(vector.x, 2i32); + /// # assert_eq!(vector.y, 2i32); + /// ``` + fn add_vector(&mut self, vector: &Self); /// Subtract a Vector from this Vector. - fn sub_vector_self(&mut self, vector: &Self); + /// + /// ``` + /// // Create a new Vector3<i64> where all + /// // the components are 5. Then subtract + /// // a Vector3<i64>, where all the + /// // components are 2, from it. + /// use sigils::vector::*; + /// + /// let mut vector = Vector3::<i64>::from_value(5i64); + /// let vector_two = Vector3::<i64>::from_value(2i64); + /// vector.sub_vector(&vector_two); + /// # assert_eq!(vector.x, 3i64); + /// # assert_eq!(vector.y, 3i64); + /// # assert_eq!(vector.z, 3i64); + /// ``` + fn sub_vector(&mut self, vector: &Self); /// Multiply this Vector by a Vector. - fn mul_vector_self(&mut self, vector: &Self); + /// + /// ``` + /// // Create a new Vector4<f32> where all + /// // the components are 6.5. Then multiply + /// // it by another Vector4<f32>, where all the + /// // components are 4.0. + /// use sigils::vector::*; + /// + /// let mut vector = Vector4::<f32>::from_value(6.5f32); + /// let vector_two = Vector4::<f32>::from_value(4.0f32); + /// vector.mul_vector(&vector_two); + /// # assert_eq!(vector.x, 26.0f32); + /// # assert_eq!(vector.y, 26.0f32); + /// # assert_eq!(vector.z, 26.0f32); + /// # assert_eq!(vector.w, 26.0f32); + /// ``` + fn mul_vector(&mut self, vector: &Self); /// Divide this Vector by a Vector. - fn div_vector_self(&mut self, vector: &Self); + /// + /// ``` + /// // Create a new Vector2<f64> where all + /// // the components are 19. Then + /// // divide it by another Vector2<f64>, + /// // where all the components are 2.0. + /// use sigils::vector::*; + /// + /// let mut vector = Vector2::<f64>::from_value(19.0f64); + /// let vector_two = Vector2::<f64>::from_value(2.0f64); + /// vector.div_vector(&vector_two); + /// # assert_eq!(vector.x, 9.5f64); + /// # assert_eq!(vector.y, 9.5f64); + /// ``` + fn div_vector(&mut self, vector: &Self); - /// Divide this Vector by a Vector and take the remainder. - fn rem_vector_self(&mut self, vector: &Self); + /// Divide this Vector by a Vector and store the remainder. + /// + /// ``` + /// // Create a new Vector3<usize> where all + /// // the components are 22. Then + /// // divide it by another Vector3<usize>, + /// // where all the components are 6. + /// use sigils::vector::*; + /// + /// let mut vector = Vector3::<usize>::from_value(22usize); + /// let vector_two = Vector3::<usize>::from_value(6usize); + /// vector.rem_vector(&vector_two); + /// # assert_eq!(vector.x, 4usize); + /// # assert_eq!(vector.y, 4usize); + /// # assert_eq!(vector.z, 4usize); + /// ``` + fn rem_vector(&mut self, vector: &Self); - // TODO: Look at defining negation // Basic Vector functions. /// Get the sum of all the components of the Vector. + /// + ///``` + /// // Create a new Vector4<f32> where all + /// // the components are 5.125. Then get + /// // the sum of the Vector's components. + /// use sigils::vector::*; + /// + /// let vector: Vector4<f32> = Vector4::<f32>::from_value(5.125f32); + /// let sum: f32 = vector.get_sum(); + /// # assert_eq!(sum, 20.5f32); + ///``` fn get_sum(&self) -> T; /// Get the product of all the components of the Vector. + /// + ///``` + /// // Create a new Vector3<isize> where all + /// // the components are 3. Then get + /// // the product of the Vector's components. + /// use sigils::vector::*; + /// + /// let vector: Vector3<isize> = Vector3::<isize>::from_value(3isize); + /// let sum: isize = vector.get_product(); + /// # assert_eq!(sum, 27isize); + ///``` fn get_product(&self) -> T; /// Get the dot product between this and another Vector. - fn dot(&self, vector: &Self) -> T + /// + ///``` + /// // Create a two new Vector3<i64> where all + /// // the components are 3. Then get the + /// // dot product of the two Vectors. + /// use sigils::vector::*; + /// + /// let vector: Vector3<i64> = Vector3::<i64>::from_value(3i64); + /// let vector_two: Vector3<i64> = Vector3::<i64>::from_value(3i64); + /// let dotProduct: i64 = vector.dot(&vector_two); + /// # assert_eq!(dotProduct, 27i64); + ///``` + fn dot(&self, vector: &Self) -> T; +} + +/// Defines the [EuclideanVector][1] trait. +/// +/// [1]: https://en.wikipedia.org/wiki/Euclidean_vector +pub trait EuclideanVector<T> : Vector<T> where T: Real +{ + /// Get the length of the Vector. + fn get_length(&self) -> T { - self.mul_vector(vector).get_sum() + self.dot(self).sqrt() + } + + /// Get the squared length of the Vector. + fn get_length_squared(&self) -> T + { + self.dot(self) + } + + /// Normalizes the Vector by multplying all the + /// components by 1/|V|. + fn normalize(&self) -> Self + { + let mut new_vector: Self; + + new_vector = self.clone(); + new_vector.mul_scalar(self.get_length().recip()); + new_vector + } + + /// Normalizes the Vector by multplying all the + /// components by 1/|V|. + fn normalize_self(&mut self) + { + let length: T; + + length = self.get_length().recip(); + self.mul_scalar(length) + } + + /// Determines if this Vector is perpendicular to another Vector. + fn is_perpendicular_to(&self, vector: &Self) -> bool + { + // TODO: Make this work with a fudge factor since floats + // are tricky. + self.dot(vector) == T::zero() + } + + /// Calculates the angle between this vector and + /// another Vector, in radians. + fn angle(&self, vector: &Self) -> T; + + /// Linearly interpolate the length of this Vector + /// towards the length of another Vector by a given amount. + fn lerp(&self, vector: &Self, amount: T) -> Self + { + let mut temp: Self; + let mut new_vector: Self; + + temp = vector.clone(); + temp.sub_vector(&self); + temp.mul_scalar(amount); + + new_vector = self.clone(); + new_vector.add_vector(&temp); + new_vector + } + + /// Linearly interpolate the length of this Vector + /// towards the length of another Vector by a given amount. + fn lerp_self(&mut self, vector: &Self, amount: T) + { + let mut temp: Self; + + temp = vector.clone(); + temp.mul_scalar(amount); + self.add_vector(&temp); } } @@ -239,6 +370,16 @@ macro_rules! binary_operator_impl ($traitName: ident :: $funcName: ident, $structName: ident {$($field: ident),+}) => { + impl<T> $traitName<T> for $structName<T> where T: Number + { + type Output = $structName<T>; + + fn $funcName(self, scalar: T) -> $structName<T> + { + $structName::new($(self.$field.$funcName(scalar)),+) + } + } + impl<'a, T> $traitName<T> for &'a $structName<T> where T: Number { type Output = $structName<T>; @@ -249,6 +390,59 @@ macro_rules! binary_operator_impl } } + impl<'a, T> $traitName<&'a T> for $structName<T> where T: Number + { + type Output = $structName<T>; + + fn $funcName(self, scalar: &'a T) -> $structName<T> + { + $structName::new($(self.$field.$funcName(*scalar)),+) + } + } + + impl<'a, 'b, T> $traitName<&'b T> for &'a $structName<T> where T: Number + { + type Output = $structName<T>; + + fn $funcName(self, scalar: &'b T) -> $structName<T> + { + $structName::new($(self.$field.$funcName(*scalar)),+) + } + } + + impl<'a, T> $traitName<$structName<T>> for $structName<T> + where T: Number + { + type Output = $structName<T>; + + fn $funcName(self, vector: $structName<T>) -> $structName<T> + { + $structName::new($(self.$field.$funcName(vector.$field)),+) + } + } + + impl<'a, T> $traitName<$structName<T>> for &'a $structName<T> + where T: Number + { + type Output = $structName<T>; + + fn $funcName(self, vector: $structName<T>) -> $structName<T> + { + $structName::new($(self.$field.$funcName(vector.$field)),+) + } + } + + impl<'a, 'b, T> $traitName<&'a $structName<T>> for $structName<T> + where T: Number + { + type Output = $structName<T>; + + fn $funcName(self, vector: &'a $structName<T>) -> $structName<T> + { + $structName::new($(self.$field.$funcName(vector.$field)),+) + } + } + impl<'a, 'b, T> $traitName<&'a $structName<T>> for &'b $structName<T> where T: Number { @@ -268,12 +462,17 @@ macro_rules! define_vector { ($structName: ident <$T: ident> {$($field: ident),+}) => { + // Do not add a where clause here or implementing + // generic traits were the generic is different + // will not work properly. /// This structure was defined with the macro /// define_vector. /// - /// Please excuse the lack of comments. + /// Please excuse the lack of comments and refer + /// to the trait definitions for comments about + /// the implementation. #[derive(PartialEq, Eq, Copy, Clone, Hash)] - pub struct $structName<T> where T: Number + pub struct $structName<T> { $(pub $field: T),+ } @@ -286,6 +485,21 @@ macro_rules! define_vector } } + // Give this vector a negation function when the + // type stored in it is negatable. + impl<$T> $structName<$T> where T: Copy + Neg<Output = $T> + { + /// Negate this vector in-place (multiply by -1). + /// + ///``` + /// + ///``` + pub fn negate(&mut self) + { + $(self.$field = -self.$field);+ + } + } + impl<T> Vector<T> for $structName<T> where T: Number { fn from_value(val: T) -> $structName<T> @@ -293,105 +507,53 @@ macro_rules! define_vector $structName {$($field: val),+} } - fn add_scalar(&self, scalar: T) -> $structName<T> - { - self + scalar - } - - fn sub_scalar(&self, scalar: T) -> $structName<T> - { - self - scalar - } - - fn mul_scalar(&self, scalar: T) -> $structName<T> - { - self * scalar - } - - fn div_scalar(&self, scalar: T) -> $structName<T> - { - self / scalar - } - - fn rem_scalar(&self, scalar: T) -> $structName<T> - { - self % scalar - } - - - fn add_vector(&self, vector: &$structName<T>) -> $structName<T> - { - self + vector - } - - fn sub_vector(&self, vector: &$structName<T>) -> $structName<T> - { - self - vector - } - - fn mul_vector(&self, vector: &$structName<T>) -> $structName<T> - { - self * vector - } - - fn div_vector(&self, vector: &$structName<T>) -> $structName<T> - { - self / vector - } - - fn rem_vector(&self, vector: &$structName<T>) -> $structName<T> - { - self % vector - } - - - fn add_scalar_self(&mut self, scalar: T) + fn add_scalar(&mut self, scalar: T) { *self = &*self + scalar; } - fn sub_scalar_self(&mut self, scalar: T) + fn sub_scalar(&mut self, scalar: T) { *self = &*self - scalar; } - fn mul_scalar_self(&mut self, scalar: T) + fn mul_scalar(&mut self, scalar: T) { *self = &*self * scalar; } - fn div_scalar_self(&mut self, scalar: T) + fn div_scalar(&mut self, scalar: T) { *self = &*self / scalar; } - fn rem_scalar_self(&mut self, scalar: T) + fn rem_scalar(&mut self, scalar: T) { *self = &*self % scalar; } - fn add_vector_self(&mut self, vector: &$structName<T>) + fn add_vector(&mut self, vector: &$structName<T>) { *self = &*self + vector; } - fn sub_vector_self(&mut self, vector: &$structName<T>) + fn sub_vector(&mut self, vector: &$structName<T>) { *self = &*self - vector; } - fn mul_vector_self(&mut self, vector: &$structName<T>) + fn mul_vector(&mut self, vector: &$structName<T>) { *self = &*self * vector; } - fn div_vector_self(&mut self, vector: &$structName<T>) + fn div_vector(&mut self, vector: &$structName<T>) { *self = &*self / vector; } - fn rem_vector_self(&mut self, vector: &$structName<T>) + fn rem_vector(&mut self, vector: &$structName<T>) { *self = &*self % vector; } @@ -406,8 +568,42 @@ macro_rules! define_vector { perform_method_on_components!(mul, {$(self.$field),+}) } + + fn dot(&self, vector: &$structName<T>) -> T + { + self.mul(vector).get_sum() + } } + // Implement the Zero and One traits for the Vector. + impl<T> Zero for $structName<T> where T: Number + { + fn zero() -> $structName<T> + { + $structName::from_value(T::zero()) + } + } + + impl<T> One for $structName<T> where T: Number + { + fn one() -> $structName<T> + { + $structName::identity() + } + } + + // Implement the negation operator for the Vector structure. + impl<T> Neg for $structName<T> where T: Neg<Output = T> + { + type Output = $structName<T>; + + fn neg(self) -> $structName<T> + { + $structName::<T> {$($field: -self.$field),+} + } + } + + // Implement the binary operations for this Vector structure. binary_operator_impl!(Add::add, $structName {$($field),+}); binary_operator_impl!(Sub::sub, $structName {$($field),+}); binary_operator_impl!(Mul::mul, $structName {$($field),+}); @@ -439,10 +635,17 @@ impl<T> Vector2<T> where T: Number Vector2::new(T::zero(), T::one()) } + /// Calculate the perpendicular dot product. pub fn perpendicular_dot(&self, vector: &Vector2<T>) -> T { (self.x * vector.y) - (self.y * vector.x) } + + /// Adds a z component with the given value to the Vector. + pub fn extend(&self, val: T) -> Vector3<T> + { + Vector3::new(self.x, self.y, val) + } } impl<T> Vector3<T> where T: Number @@ -473,6 +676,39 @@ impl<T> Vector3<T> where T: Number (self.z * vector.x) - (self.x * vector.z), (self.x * vector.y) - (self.y * vector.x)) } + + /// Calculate the cross product between this and another Vector + /// and store it in this Vector. + /// The final result will be a Vector perpendicular to both + /// of the input Vectors. + pub fn cross_self(&mut self, vector: &Vector3<T>) + { + *self = self.cross(&vector); + } + + /// Adds a w component with the given value to the Vector. + pub fn extend(&self, val: T) -> Vector4<T> + { + Vector4::new(self.x, self.y, self.z, val) + } + + /// Discards the z component of the Vector. + pub fn truncate(&self) -> Vector2<T> + { + self.truncate_component(2) + } + + /// Discards the component at the given index from the Vector. + pub fn truncate_component(&self, index: isize) -> Vector2<T> + { + match index + { + 0 => Vector2::new(self.y, self.z), + 1 => Vector2::new(self.x, self.z), + 2 => Vector2::new(self.x, self.y), + _ => panic!("Component index {:?} is out of range.", index) + } + } } impl<T> Vector4<T> where T: Number @@ -500,4 +736,51 @@ impl<T> Vector4<T> where T: Number { Vector4::new(T::zero(), T::zero(), T::zero(), T::one()) } + + /// Discards the w component of the Vector. + pub fn truncate(&self) -> Vector3<T> + { + self.truncate_component(3) + } + + /// Discards the component at the given index from the Vector. + pub fn truncate_component(&self, index: isize) -> Vector3<T> + { + match index + { + 0 => Vector3::new(self.y, self.z, self.w), + 1 => Vector3::new(self.x, self.z, self.w), + 2 => Vector3::new(self.x, self.y, self.w), + 3 => Vector3::new(self.x, self.y, self.z), + _ => panic!("Component index {:?} is out of range.", index) + } + } +} + +// Implement the angle specific portion of the EuclideanVector. +impl<T> EuclideanVector<T> for Vector2<T> where T: Real +{ + fn angle(&self, vector: &Vector2<T>) -> T + { + //unimplemented!(); + atan2(self.perpendicular_dot(vector), self.dot(vector)) + } +} + +impl<T> EuclideanVector<T> for Vector3<T> where T: Real +{ + fn angle(&self, vector: &Vector3<T>) -> T + { + //unimplemented!(); + atan2(self.cross(vector).get_length(), self.dot(vector)) + } +} + +impl<T> EuclideanVector<T> for Vector4<T> where T: Real +{ + fn angle(&self, vector: &Vector4<T>) -> T + { + //unimplemented!(); + acos(self.dot(vector) / (self.get_length() * vector.get_length())) + } } diff --git a/tests/constants.rs b/tests/constants.rs new file mode 100644 index 0000000..374e351 --- /dev/null +++ b/tests/constants.rs @@ -0,0 +1,97 @@ +extern crate sigils; + +use std::{f32, f64}; +use sigils::Constants; + + +#[test] +fn constant_check_f32() +{ + let val: f32 = Constants::SQRT_2; + assert_eq!(val, f32::consts::SQRT_2); + let val: f32 = Constants::SQRT_3; + assert_eq!(val, 1.73205080756887729352f32); + let val: f32 = Constants::INVERSE_SQRT_2; + assert_eq!(val, 1.0f32 / f32::consts::SQRT_2); + let val: f32 = Constants::INVERSE_SQRT_3; + assert_eq!(val, 1.0f32 / 1.73205080756887729352f32); + + let val: f32 = Constants::E; + assert_eq!(val, f32::consts::E); + + let val: f32 = Constants::LOG2_E; + assert_eq!(val, f32::consts::LOG2_E); + let val: f32 = Constants::LOG10_E; + assert_eq!(val, f32::consts::LOG10_E); + let val: f32 = Constants::LOGE_2; + assert_eq!(val, 2f32.ln()); + let val: f32 = Constants::LOGE_10; + assert_eq!(val, 10f32.ln()); + + let val: f32 = Constants::TWO_PI; + assert_eq!(val, 2f32 * f32::consts::PI); + let val: f32 = Constants::PI; + assert_eq!(val, f32::consts::PI); + let val: f32 = Constants::HALF_PI; + assert_eq!(val, f32::consts::PI / 2f32); + let val: f32 = Constants::THIRD_PI; + assert_eq!(val, f32::consts::PI / 3f32); + let val: f32 = Constants::QUARTER_PI; + assert_eq!(val, f32::consts::PI / 4f32); + let val: f32 = Constants::SIXTH_PI; + assert_eq!(val, f32::consts::PI / 6f32); + let val: f32 = Constants::EIGHTH_PI; + assert_eq!(val, f32::consts::PI / 8f32); + let val: f32 = Constants::INVERSE_PI; + assert_eq!(val, 1.0f32 / f32::consts::PI); + let val: f32 = Constants::TWO_INVERSE_PI; + assert_eq!(val, 2.0f32 / f32::consts::PI); + let val: f32 = Constants::TWO_INVERSE_SQRT_PI; + assert_eq!(val, 2.0f32 / (f32::consts::PI).sqrt()); +} + +#[test] +fn constant_check_f64() +{ + let val: f64 = Constants::SQRT_2; + assert_eq!(val, f64::consts::SQRT_2); + let val: f64 = Constants::SQRT_3; + assert_eq!(val, 1.73205080756887729352f64); + let val: f64 = Constants::INVERSE_SQRT_2; + assert_eq!(val, 1.0f64 / f64::consts::SQRT_2); + let val: f64 = Constants::INVERSE_SQRT_3; + assert_eq!(val, 1.0f64 / 1.73205080756887729352f64); + + let val: f64 = Constants::E; + assert_eq!(val, f64::consts::E); + + let val: f64 = Constants::LOG2_E; + assert_eq!(val, f64::consts::LOG2_E); + let val: f64 = Constants::LOG10_E; + assert_eq!(val, f64::consts::LOG10_E); + let val: f64 = Constants::LOGE_2; + assert_eq!(val, 2f64.ln()); + let val: f64 = Constants::LOGE_10; + assert_eq!(val, 10f64.ln()); + + let val: f64 = Constants::TWO_PI; + assert_eq!(val, 2f64 * f64::consts::PI); + let val: f64 = Constants::PI; + assert_eq!(val, f64::consts::PI); + let val: f64 = Constants::HALF_PI; + assert_eq!(val, f64::consts::PI / 2f64); + let val: f64 = Constants::THIRD_PI; + assert_eq!(val, f64::consts::PI / 3f64); + let val: f64 = Constants::QUARTER_PI; + assert_eq!(val, f64::consts::PI / 4f64); + let val: f64 = Constants::SIXTH_PI; + assert_eq!(val, f64::consts::PI / 6f64); + let val: f64 = Constants::EIGHTH_PI; + assert_eq!(val, f64::consts::PI / 8f64); + let val: f64 = Constants::INVERSE_PI; + assert_eq!(val, 1.0f64 / f64::consts::PI); + let val: f64 = Constants::TWO_INVERSE_PI; + assert_eq!(val, 2.0f64 / f64::consts::PI); + let val: f64 = Constants::TWO_INVERSE_SQRT_PI; + assert_eq!(val, 2.0f64 / (f64::consts::PI).sqrt()); +} diff --git a/tests/lib.rs b/tests/lib.rs index 253aac6..36b1ab2 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -1,3 +1,5 @@ extern crate sigils; + +mod constants; mod vector; diff --git a/tests/vector.rs b/tests/vector.rs index 9ef7487..5ff6375 100644 --- a/tests/vector.rs +++ b/tests/vector.rs @@ -1,5 +1,6 @@ extern crate sigils; +use std::ops::{Add, Sub, Mul, Div, Rem}; use sigils::vector::*; @@ -10,3 +11,348 @@ fn vector_creation() assert_eq!(v.x, 1.0f32); } + +#[test] +fn vector_add() +{ + let v: Vector3<f32> = Vector3::<f32>::from_value(1.0f32); + + let v_two: Vector3<f32> = Vector3::<f32>::from_value(4.0f32); + let scalar: f32 = 4.0f32; + + let v_three = v.add(&v_two); + assert_eq!(v_three.x, 5.0f32); + assert_eq!(v_three.y, 5.0f32); + assert_eq!(v_three.z, 5.0f32); + + let v_three = v.add(v_two); + assert_eq!(v_three.x, 5.0f32); + assert_eq!(v_three.y, 5.0f32); + assert_eq!(v_three.z, 5.0f32); + + let v_three = v + &v_two; + assert_eq!(v_three.x, 5.0f32); + assert_eq!(v_three.y, 5.0f32); + assert_eq!(v_three.z, 5.0f32); + + let v_three = v + v_two; + assert_eq!(v_three.x, 5.0f32); + assert_eq!(v_three.y, 5.0f32); + assert_eq!(v_three.z, 5.0f32); + + let v_three = &v + &v_two; + assert_eq!(v_three.x, 5.0f32); + assert_eq!(v_three.y, 5.0f32); + assert_eq!(v_three.z, 5.0f32); + + let v_three = &v + v_two; + assert_eq!(v_three.x, 5.0f32); + assert_eq!(v_three.y, 5.0f32); + assert_eq!(v_three.z, 5.0f32); + + let v_three = &v + 4.0f32; + assert_eq!(v_three.x, 5.0f32); + assert_eq!(v_three.y, 5.0f32); + assert_eq!(v_three.z, 5.0f32); + + let v_three = v + 4.0f32; + assert_eq!(v_three.x, 5.0f32); + assert_eq!(v_three.y, 5.0f32); + assert_eq!(v_three.z, 5.0f32); + + let v_three = &v + scalar; + assert_eq!(v_three.x, 5.0f32); + assert_eq!(v_three.y, 5.0f32); + assert_eq!(v_three.z, 5.0f32); + + let v_three = v + scalar; + assert_eq!(v_three.x, 5.0f32); + assert_eq!(v_three.y, 5.0f32); + assert_eq!(v_three.z, 5.0f32); + + let v_three = &v + &scalar; + assert_eq!(v_three.x, 5.0f32); + assert_eq!(v_three.y, 5.0f32); + assert_eq!(v_three.z, 5.0f32); + + let v_three = v + &scalar; + assert_eq!(v_three.x, 5.0f32); + assert_eq!(v_three.y, 5.0f32); + assert_eq!(v_three.z, 5.0f32); +} + +#[test] +fn vector_sub() +{ + let v: Vector3<f32> = Vector3::<f32>::from_value(9.0f32); + + let v_two: Vector3<f32> = Vector3::<f32>::from_value(4.0f32); + let scalar: f32 = 4.0f32; + + let v_three = v.sub(&v_two); + assert_eq!(v_three.x, 5.0f32); + assert_eq!(v_three.y, 5.0f32); + assert_eq!(v_three.z, 5.0f32); + + let v_three = v.sub(v_two); + assert_eq!(v_three.x, 5.0f32); + assert_eq!(v_three.y, 5.0f32); + assert_eq!(v_three.z, 5.0f32); + + let v_three = v - &v_two; + assert_eq!(v_three.x, 5.0f32); + assert_eq!(v_three.y, 5.0f32); + assert_eq!(v_three.z, 5.0f32); + + let v_three = v - v_two; + assert_eq!(v_three.x, 5.0f32); + assert_eq!(v_three.y, 5.0f32); + assert_eq!(v_three.z, 5.0f32); + + let v_three = &v - &v_two; + assert_eq!(v_three.x, 5.0f32); + assert_eq!(v_three.y, 5.0f32); + assert_eq!(v_three.z, 5.0f32); + + let v_three = &v - v_two; + assert_eq!(v_three.x, 5.0f32); + assert_eq!(v_three.y, 5.0f32); + assert_eq!(v_three.z, 5.0f32); + + let v_three = &v - 4.0f32; + assert_eq!(v_three.x, 5.0f32); + assert_eq!(v_three.y, 5.0f32); + assert_eq!(v_three.z, 5.0f32); + + let v_three = v - 4.0f32; + assert_eq!(v_three.x, 5.0f32); + assert_eq!(v_three.y, 5.0f32); + assert_eq!(v_three.z, 5.0f32); + + let v_three = &v - scalar; + assert_eq!(v_three.x, 5.0f32); + assert_eq!(v_three.y, 5.0f32); + assert_eq!(v_three.z, 5.0f32); + + let v_three = v - scalar; + assert_eq!(v_three.x, 5.0f32); + assert_eq!(v_three.y, 5.0f32); + assert_eq!(v_three.z, 5.0f32); + + let v_three = &v - &scalar; + assert_eq!(v_three.x, 5.0f32); + assert_eq!(v_three.y, 5.0f32); + assert_eq!(v_three.z, 5.0f32); + + let v_three = v - &scalar; + assert_eq!(v_three.x, 5.0f32); + assert_eq!(v_three.y, 5.0f32); + assert_eq!(v_three.z, 5.0f32); +} + +#[test] +fn vector_mul() +{ + let v: Vector3<f32> = Vector3::<f32>::from_value(3.0f32); + + let v_two: Vector3<f32> = Vector3::<f32>::from_value(5.0f32); + let scalar: f32 = 5.0f32; + + let v_three = v.mul(&v_two); + assert_eq!(v_three.x, 15.0f32); + assert_eq!(v_three.y, 15.0f32); + assert_eq!(v_three.z, 15.0f32); + + let v_three = v.mul(v_two); + assert_eq!(v_three.x, 15.0f32); + assert_eq!(v_three.y, 15.0f32); + assert_eq!(v_three.z, 15.0f32); + + let v_three = v * &v_two; + assert_eq!(v_three.x, 15.0f32); + assert_eq!(v_three.y, 15.0f32); + assert_eq!(v_three.z, 15.0f32); + + let v_three = v * v_two; + assert_eq!(v_three.x, 15.0f32); + assert_eq!(v_three.y, 15.0f32); + assert_eq!(v_three.z, 15.0f32); + + let v_three = &v * &v_two; + assert_eq!(v_three.x, 15.0f32); + assert_eq!(v_three.y, 15.0f32); + assert_eq!(v_three.z, 15.0f32); + + let v_three = &v * v_two; + assert_eq!(v_three.x, 15.0f32); + assert_eq!(v_three.y, 15.0f32); + assert_eq!(v_three.z, 15.0f32); + + let v_three = &v * 5.0f32; + assert_eq!(v_three.x, 15.0f32); + assert_eq!(v_three.y, 15.0f32); + assert_eq!(v_three.z, 15.0f32); + + let v_three = v * 5.0f32; + assert_eq!(v_three.x, 15.0f32); + assert_eq!(v_three.y, 15.0f32); + assert_eq!(v_three.z, 15.0f32); + + let v_three = &v * scalar; + assert_eq!(v_three.x, 15.0f32); + assert_eq!(v_three.y, 15.0f32); + assert_eq!(v_three.z, 15.0f32); + + let v_three = v * scalar; + assert_eq!(v_three.x, 15.0f32); + assert_eq!(v_three.y, 15.0f32); + assert_eq!(v_three.z, 15.0f32); + + let v_three = &v * &scalar; + assert_eq!(v_three.x, 15.0f32); + assert_eq!(v_three.y, 15.0f32); + assert_eq!(v_three.z, 15.0f32); + + let v_three = v * &scalar; + assert_eq!(v_three.x, 15.0f32); + assert_eq!(v_three.y, 15.0f32); + assert_eq!(v_three.z, 15.0f32); +} + +#[test] +fn vector_div() +{ + let v: Vector3<f32> = Vector3::<f32>::from_value(15.0f32); + + let v_two: Vector3<f32> = Vector3::<f32>::from_value(5.0f32); + let scalar: f32 = 5.0f32; + + let v_three = v.div(&v_two); + assert_eq!(v_three.x, 3.0f32); + assert_eq!(v_three.y, 3.0f32); + assert_eq!(v_three.z, 3.0f32); + + let v_three = v.div(v_two); + assert_eq!(v_three.x, 3.0f32); + assert_eq!(v_three.y, 3.0f32); + assert_eq!(v_three.z, 3.0f32); + + let v_three = v / &v_two; + assert_eq!(v_three.x, 3.0f32); + assert_eq!(v_three.y, 3.0f32); + assert_eq!(v_three.z, 3.0f32); + + let v_three = v / v_two; + assert_eq!(v_three.x, 3.0f32); + assert_eq!(v_three.y, 3.0f32); + assert_eq!(v_three.z, 3.0f32); + + let v_three = &v / &v_two; + assert_eq!(v_three.x, 3.0f32); + assert_eq!(v_three.y, 3.0f32); + assert_eq!(v_three.z, 3.0f32); + + let v_three = &v / v_two; + assert_eq!(v_three.x, 3.0f32); + assert_eq!(v_three.y, 3.0f32); + assert_eq!(v_three.z, 3.0f32); + + let v_three = &v / 5.0f32; + assert_eq!(v_three.x, 3.0f32); + assert_eq!(v_three.y, 3.0f32); + assert_eq!(v_three.z, 3.0f32); + + let v_three = v / 5.0f32; + assert_eq!(v_three.x, 3.0f32); + assert_eq!(v_three.y, 3.0f32); + assert_eq!(v_three.z, 3.0f32); + + let v_three = &v / scalar; + assert_eq!(v_three.x, 3.0f32); + assert_eq!(v_three.y, 3.0f32); + assert_eq!(v_three.z, 3.0f32); + + let v_three = v / scalar; + assert_eq!(v_three.x, 3.0f32); + assert_eq!(v_three.y, 3.0f32); + assert_eq!(v_three.z, 3.0f32); + + let v_three = &v / &scalar; + assert_eq!(v_three.x, 3.0f32); + assert_eq!(v_three.y, 3.0f32); + assert_eq!(v_three.z, 3.0f32); + + let v_three = v / &scalar; + assert_eq!(v_three.x, 3.0f32); + assert_eq!(v_three.y, 3.0f32); + assert_eq!(v_three.z, 3.0f32); +} + +#[test] +fn vector_rem() +{ + let v: Vector3<f32> = Vector3::<f32>::from_value(15.0f32); + + let v_two: Vector3<f32> = Vector3::<f32>::from_value(6.0f32); + let scalar: f32 = 6.0f32; + + let v_three = v.rem(&v_two); + assert_eq!(v_three.x, 3.0f32); + assert_eq!(v_three.y, 3.0f32); + assert_eq!(v_three.z, 3.0f32); + + let v_three = v.rem(v_two); + assert_eq!(v_three.x, 3.0f32); + assert_eq!(v_three.y, 3.0f32); + assert_eq!(v_three.z, 3.0f32); + + let v_three = v % &v_two; + assert_eq!(v_three.x, 3.0f32); + assert_eq!(v_three.y, 3.0f32); + assert_eq!(v_three.z, 3.0f32); + + let v_three = v % v_two; + assert_eq!(v_three.x, 3.0f32); + assert_eq!(v_three.y, 3.0f32); + assert_eq!(v_three.z, 3.0f32); + + let v_three = &v % &v_two; + assert_eq!(v_three.x, 3.0f32); + assert_eq!(v_three.y, 3.0f32); + assert_eq!(v_three.z, 3.0f32); + + let v_three = &v % v_two; + assert_eq!(v_three.x, 3.0f32); + assert_eq!(v_three.y, 3.0f32); + assert_eq!(v_three.z, 3.0f32); + + let v_three = &v % 6.0f32; + assert_eq!(v_three.x, 3.0f32); + assert_eq!(v_three.y, 3.0f32); + assert_eq!(v_three.z, 3.0f32); + + let v_three = v % 6.0f32; + assert_eq!(v_three.x, 3.0f32); + assert_eq!(v_three.y, 3.0f32); + assert_eq!(v_three.z, 3.0f32); + + let v_three = &v % scalar; + assert_eq!(v_three.x, 3.0f32); + assert_eq!(v_three.y, 3.0f32); + assert_eq!(v_three.z, 3.0f32); + + let v_three = v % scalar; + assert_eq!(v_three.x, 3.0f32); + assert_eq!(v_three.y, 3.0f32); + assert_eq!(v_three.z, 3.0f32); + + let v_three = &v % &scalar; + assert_eq!(v_three.x, 3.0f32); + assert_eq!(v_three.y, 3.0f32); + assert_eq!(v_three.z, 3.0f32); + + let v_three = v % &scalar; + assert_eq!(v_three.x, 3.0f32); + assert_eq!(v_three.y, 3.0f32); + assert_eq!(v_three.z, 3.0f32); +}