From 43a1e3080888a92d0586e05dbd197927299664e5 Mon Sep 17 00:00:00 2001 From: Jason Travis Smith Date: Tue, 27 Jun 2017 18:19:33 -0400 Subject: [PATCH] Added the basic trigonometric functions. These were moved to their own trait and removed from the definition of a Real number. This allows the definition of a trigonometric function to call a different libc trig function depending on type. --- Cargo.lock | 4 - Cargo.toml | 10 +- examples/trig.rs | 47 +++ src/constants.rs | 1 + src/lib.rs | 10 +- src/macros.rs | 32 +- src/quaternion.rs | 62 ++-- src/real.rs | 313 +------------------- src/trig.rs | 716 --------------------------------------------- src/trig/degree.rs | 134 +++++++++ src/trig/mod.rs | 15 + src/trig/radian.rs | 133 +++++++++ src/trig/trig.rs | 421 ++++++++++++++++++++++++++ src/vector.rs | 35 +-- 14 files changed, 839 insertions(+), 1094 deletions(-) delete mode 100644 Cargo.lock create mode 100644 examples/trig.rs delete mode 100644 src/trig.rs create mode 100644 src/trig/degree.rs create mode 100644 src/trig/mod.rs create mode 100644 src/trig/radian.rs create mode 100644 src/trig/trig.rs diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index 7516536..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,4 +0,0 @@ -[root] -name = "sigils" -version = "0.1.0" - diff --git a/Cargo.toml b/Cargo.toml index 0563fdf..149cb98 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,16 @@ [package] name = "sigils" version = "0.1.0" -authors = ["Jason Travis Smith "] +authors = ["Jason Travis Smith "] description = "A mathematics library." license = "" -repository = "https://gitlab.com/CyberMages/sigils.git" +repository = "https://gitlab.com/CyberMages/Core/sigils.git" documentation = "" keywords = ["sigils"] -[dependencies] +[dependencies.binding] +git = "ssh://git@gitlab.com/CyberMages/Core/binding" + +[dependencies.pact] +git = "ssh://git@gitlab.com/CyberMages/Core/pact" diff --git a/examples/trig.rs b/examples/trig.rs new file mode 100644 index 0000000..acefc13 --- /dev/null +++ b/examples/trig.rs @@ -0,0 +1,47 @@ +extern crate pact; +extern crate sigils; + + + +use ::sigils::{Constants, Degree, Radian, Trig}; + + + +fn main() +{ + let mut val: f64; + let mut degrees: Degree; + let mut radians: Radian; + + val = Constants::QUARTER_PI; + val *= 6f64; + radians = Radian::new(val); + degrees = Trig::acos(Trig::cos(radians)); + + println!("{:?}", radians); + println!("{:?}", degrees); + println!(""); + + radians = Radian::new(Constants::QUARTER_PI); + radians = Trig::acos(Trig::cos(radians)); + degrees = Degree::from(radians); + + println!("{:?}", radians); + println!("{:?}", degrees); + println!(""); + + degrees = Degree::new(270.0f64); + radians = Trig::acos(Trig::cos(degrees)); + + println!("{:?}", degrees); + println!("{:?}", radians); + println!(""); + + degrees = Degree::new(90.0f64); + degrees = Trig::acos(Trig::cos(degrees)); + radians = Radian::from(degrees); + + println!("{:?}", degrees); + println!("{:?}", radians); + println!(""); +} diff --git a/src/constants.rs b/src/constants.rs index e8e40b1..52a68ab 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -1,6 +1,7 @@ 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. diff --git a/src/lib.rs b/src/lib.rs index 2ab299d..bd57f31 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,12 @@ //! #![feature(float_extras)] #![feature(associated_consts)] +#![no_std] +extern crate core as std; + +extern crate binding; +extern crate pact; + #[macro_use] @@ -19,11 +25,13 @@ mod real; mod constants; mod trig; + pub mod vector; pub mod matrix; pub mod quaternion; + pub use self::zero::Zero; pub use self::one::One; pub use self::number::Number; @@ -31,4 +39,4 @@ pub use self::whole::Whole; pub use self::integer::Integer; pub use self::real::Real; pub use self::constants::Constants; -pub use self::trig::{Degree, Radian}; +pub use self::trig::{Degree, Radian, Trig}; diff --git a/src/macros.rs b/src/macros.rs index de6da5a..d181956 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -3,11 +3,11 @@ macro_rules! binary_operator_impl { ($traitName: ident :: $funcName: ident, - $structName: ident {$($field: ident),+}, - $generic_type: ident) => + $generic_type: path $(| $generic_types2: path)*, + $structName: ident {$($field: ident),+}) => { impl $traitName for $structName - where T: $generic_type + where T: $generic_type $(+ $generic_types2)* { type Output = $structName; @@ -18,7 +18,7 @@ macro_rules! binary_operator_impl } impl<'a, T> $traitName for &'a $structName - where T: $generic_type + where T: $generic_type $(+ $generic_types2)* { type Output = $structName; @@ -29,7 +29,7 @@ macro_rules! binary_operator_impl } impl<'a, T> $traitName<&'a T> for $structName - where T: $generic_type + where T: $generic_type $(+ $generic_types2)* { type Output = $structName; @@ -40,7 +40,7 @@ macro_rules! binary_operator_impl } impl<'a, 'b, T> $traitName<&'b T> for &'a $structName - where T: $generic_type + where T: $generic_type $(+ $generic_types2)* { type Output = $structName; @@ -51,7 +51,7 @@ macro_rules! binary_operator_impl } impl $traitName<$structName> for $structName - where T: $generic_type + where T: $generic_type $(+ $generic_types2)* { type Output = $structName; @@ -62,7 +62,7 @@ macro_rules! binary_operator_impl } impl<'a, T> $traitName<$structName> for &'a $structName - where T: $generic_type + where T: $generic_type $(+ $generic_types2)* { type Output = $structName; @@ -73,7 +73,7 @@ macro_rules! binary_operator_impl } impl<'a, T> $traitName<&'a $structName> for $structName - where T: $generic_type + where T: $generic_type $(+ $generic_types2)* { type Output = $structName; @@ -84,7 +84,7 @@ macro_rules! binary_operator_impl } impl<'a, 'b, T> $traitName<&'a $structName> for &'b $structName - where T: $generic_type + where T: $generic_type $(+ $generic_types2)* { type Output = $structName; @@ -101,11 +101,11 @@ macro_rules! binary_operator_impl macro_rules! binary_operator_assign_impl { ($traitName: ident :: $funcName: ident, - $structName: ident {$($field: ident),+}, - $generic_type: ident) => + $generic_type: path $(| $generic_types2: path)*, + $structName: ident {$($field: ident),+}) => { impl $traitName<$structName> for $structName - where T: $generic_type + where T: $generic_type $(+ $generic_types2)* { fn $funcName(&mut self, rhs: $structName) { @@ -114,7 +114,7 @@ macro_rules! binary_operator_assign_impl } impl $traitName for $structName - where T: $generic_type + where T: $generic_type $(+ $generic_types2)* { fn $funcName(&mut self, rhs: T) { @@ -123,7 +123,7 @@ macro_rules! binary_operator_assign_impl } impl<'a, T> $traitName<&'a $structName> for $structName - where T: $generic_type + where T: $generic_type $(+ $generic_types2)* { fn $funcName(&mut self, rhs: &'a $structName) { @@ -132,7 +132,7 @@ macro_rules! binary_operator_assign_impl } impl<'a, T> $traitName<&'a T> for $structName - where T: $generic_type + where T: $generic_type $(+ $generic_types2)* { fn $funcName(&mut self, rhs: &'a T) { diff --git a/src/quaternion.rs b/src/quaternion.rs index 8dc3036..6c5c80e 100644 --- a/src/quaternion.rs +++ b/src/quaternion.rs @@ -9,6 +9,8 @@ use std::ops::{Add, Sub, Mul, Div, Neg}; use ::zero::Zero; use ::one::One; use ::real::Real; +use ::trig::Radian; +use ::trig::Trig; use ::vector::{Vector, EuclideanVector, Vector3}; @@ -28,7 +30,7 @@ use ::vector::{Vector, EuclideanVector, Vector3}; /// | jk = 1 | kj = -1 | /// | ki = 1 | ji = -1 | #[derive(Clone, Copy)] -pub struct Quaternion where T: Real +pub struct Quaternion { /// TODO: Describe this. pub scalar: T, @@ -45,7 +47,7 @@ macro_rules! binary_operator_impl { ($traitName: ident :: $funcName: ident, $structName: ident) => { - impl $traitName for $structName where T: Real + impl $traitName for $structName where T: Trig { type Output = $structName; @@ -56,7 +58,7 @@ macro_rules! binary_operator_impl } } - impl<'a, T> $traitName for &'a $structName where T: Real + impl<'a, T> $traitName for &'a $structName where T: Trig { type Output = $structName; @@ -67,7 +69,7 @@ macro_rules! binary_operator_impl } } - impl<'a, T> $traitName<&'a T> for $structName where T: Real + impl<'a, T> $traitName<&'a T> for $structName where T: Trig { type Output = $structName; @@ -78,7 +80,7 @@ macro_rules! binary_operator_impl } } - impl<'a, 'b, T> $traitName<&'b T> for &'a $structName where T: Real + impl<'a, 'b, T> $traitName<&'b T> for &'a $structName where T: Trig { type Output = $structName; @@ -93,7 +95,7 @@ macro_rules! binary_operator_impl // Implement the Quaternion's methods. -impl Quaternion where T: Real +impl Quaternion where T: Trig { /// Create a new Quaternion from a given scalar and Vector. /// @@ -277,7 +279,7 @@ impl Quaternion where T: Real } // Implement the Debug trait for the Quaternion. -impl Debug for Quaternion where T: Real +impl Debug for Quaternion where T: Trig { fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> { @@ -286,7 +288,7 @@ impl Debug for Quaternion where T: Real } // Implement the Display trait for the Quaternion. -impl Display for Quaternion where T: Real +impl Display for Quaternion where T: Trig { fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> { @@ -296,7 +298,7 @@ impl Display for Quaternion where T: Real // Implement a default value for Quaternions which // returns the identity quaternion. -impl Default for Quaternion where T: Real +impl Default for Quaternion where T: Trig { fn default() -> Quaternion { @@ -305,7 +307,7 @@ impl Default for Quaternion where T: Real } // Implement the Zero and One traits for the Quaternion. -impl Zero for Quaternion where T: Real +impl Zero for Quaternion where T: Trig { fn zero() -> Quaternion { @@ -313,7 +315,7 @@ impl Zero for Quaternion where T: Real } } -impl One for Quaternion where T: Real +impl One for Quaternion where T: Trig { fn one() -> Quaternion { @@ -327,7 +329,7 @@ binary_operator_impl!(Mul::mul, Quaternion); //binary_operator_impl!(Neg::neg, Quaternion); // Implement Negating a Quaternion. -impl Neg for Quaternion where T: Real +impl Neg for Quaternion where T: Trig { type Output = Quaternion; @@ -337,7 +339,7 @@ impl Neg for Quaternion where T: Real } } -impl<'a, T> Neg for &'a Quaternion where T: Real +impl<'a, T> Neg for &'a Quaternion where T: Trig { type Output = Quaternion; @@ -348,7 +350,7 @@ impl<'a, T> Neg for &'a Quaternion where T: Real } // Implement Adding Quaternions. -impl Add> for Quaternion where T: Real +impl Add> for Quaternion where T: Trig { type Output = Quaternion; @@ -359,7 +361,7 @@ impl Add> for Quaternion where T: Real } } -impl<'a, T> Add> for &'a Quaternion where T: Real +impl<'a, T> Add> for &'a Quaternion where T: Trig { type Output = Quaternion; @@ -370,7 +372,7 @@ impl<'a, T> Add> for &'a Quaternion where T: Real } } -impl<'a, T> Add<&'a Quaternion> for Quaternion where T: Real +impl<'a, T> Add<&'a Quaternion> for Quaternion where T: Trig { type Output = Quaternion; @@ -381,7 +383,7 @@ impl<'a, T> Add<&'a Quaternion> for Quaternion where T: Real } } -impl<'a, 'b, T> Add<&'b Quaternion> for &'a Quaternion where T: Real +impl<'a, 'b, T> Add<&'b Quaternion> for &'a Quaternion where T: Trig { type Output = Quaternion; @@ -393,7 +395,7 @@ impl<'a, 'b, T> Add<&'b Quaternion> for &'a Quaternion where T: Real } // Implement subtracting Quaternions. -impl Sub> for Quaternion where T: Real +impl Sub> for Quaternion where T: Trig { type Output = Quaternion; @@ -404,7 +406,7 @@ impl Sub> for Quaternion where T: Real } } -impl<'a, T> Sub> for &'a Quaternion where T: Real +impl<'a, T> Sub> for &'a Quaternion where T: Trig { type Output = Quaternion; @@ -415,7 +417,7 @@ impl<'a, T> Sub> for &'a Quaternion where T: Real } } -impl<'a, T> Sub<&'a Quaternion> for Quaternion where T: Real +impl<'a, T> Sub<&'a Quaternion> for Quaternion where T: Trig { type Output = Quaternion; @@ -426,7 +428,7 @@ impl<'a, T> Sub<&'a Quaternion> for Quaternion where T: Real } } -impl<'a, 'b, T> Sub<&'b Quaternion> for &'a Quaternion where T: Real +impl<'a, 'b, T> Sub<&'b Quaternion> for &'a Quaternion where T: Trig { type Output = Quaternion; @@ -438,7 +440,7 @@ impl<'a, 'b, T> Sub<&'b Quaternion> for &'a Quaternion where T: Real } // Implement Dividing Quaternions. -impl Div> for Quaternion where T: Real +impl Div> for Quaternion where T: Trig { type Output = Quaternion; @@ -448,7 +450,7 @@ impl Div> for Quaternion where T: Real } } -impl<'a, T> Div> for &'a Quaternion where T: Real +impl<'a, T> Div> for &'a Quaternion where T: Trig { type Output = Quaternion; @@ -458,7 +460,7 @@ impl<'a, T> Div> for &'a Quaternion where T: Real } } -impl<'a, T> Div<&'a Quaternion> for Quaternion where T: Real +impl<'a, T> Div<&'a Quaternion> for Quaternion where T: Trig { type Output = Quaternion; @@ -468,7 +470,7 @@ impl<'a, T> Div<&'a Quaternion> for Quaternion where T: Real } } -impl<'a, 'b, T> Div<&'b Quaternion> for &'a Quaternion where T: Real +impl<'a, 'b, T> Div<&'b Quaternion> for &'a Quaternion where T: Trig { type Output = Quaternion; @@ -479,7 +481,7 @@ impl<'a, 'b, T> Div<&'b Quaternion> for &'a Quaternion where T: Real } // Implement multiplying Quaternions and Vectors. -impl Mul> for Quaternion where T: Real +impl Mul> for Quaternion where T: Trig { type Output = Quaternion; @@ -492,7 +494,7 @@ impl Mul> for Quaternion where T: Real } } -impl<'a, T> Mul> for &'a Quaternion where T: Real +impl<'a, T> Mul> for &'a Quaternion where T: Trig { type Output = Quaternion; @@ -505,7 +507,7 @@ impl<'a, T> Mul> for &'a Quaternion where T: Real } } -impl<'a, T> Mul<&'a Quaternion> for Quaternion where T: Real +impl<'a, T> Mul<&'a Quaternion> for Quaternion where T: Trig { type Output = Quaternion; @@ -518,7 +520,7 @@ impl<'a, T> Mul<&'a Quaternion> for Quaternion where T: Real } } -impl<'a, 'b, T> Mul<&'b Quaternion> for &'a Quaternion where T: Real +impl<'a, 'b, T> Mul<&'b Quaternion> for &'a Quaternion where T: Trig { type Output = Quaternion; @@ -547,7 +549,7 @@ impl<'a, 'b, T> Mul<&'b Quaternion> for &'a Quaternion where T: Real /// (SaZb + XaYb - YaXb + SbZa)k fn multiply_quaternions(sa: T, xa: T, ya: T, za: T, sb: T, xb: T, yb: T, zb: T) - -> Quaternion where T: Real + -> Quaternion where T: Trig { let i: T; let j: T; diff --git a/src/real.rs b/src/real.rs index a07e1c4..fc78117 100644 --- a/src/real.rs +++ b/src/real.rs @@ -1,8 +1,9 @@ use std::num::FpCategory; use std::ops::Neg; +use ::constants::Constants; use ::number::Number; -use ::trig::Radian; + // TODO: Double check these examples. Most are OK, @@ -19,7 +20,7 @@ use ::trig::Radian; /// [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 + Neg +pub trait Real : Number + Constants + Neg { /// Returns the `NaN` value. /// @@ -675,143 +676,6 @@ pub trait Real : Number + Neg /// ``` 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) -> Radian; - - /// 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) -> Radian; - - /// 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) -> Radian; - - /// 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) -> Radian; - - /// 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. /// @@ -847,133 +711,10 @@ pub trait Real : Number + Neg /// 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) -> Radian; - - /// 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) -> Radian; - - /// 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) -> Radian; } -// Create a macro to ease typing and reading. +// Create some macros to ease typing and reading. /// macro_rules! define_self_func { @@ -998,18 +739,6 @@ macro_rules! define_self_bool_func } } -/// -macro_rules! define_self_rad_func -{ - ($varType: ident, $funcName: ident) => - { - fn $funcName(self) -> Radian<$varType> - { - Radian::new(<$varType>::$funcName(self)) - } - } -} - /// macro_rules! define_self_other_func { @@ -1022,18 +751,6 @@ macro_rules! define_self_other_func } } -/// -macro_rules! define_self_other_rad_func -{ - ($varType: ident, $funcName: ident) => - { - fn $funcName(self, other: $varType) -> Radian<$varType> - { - Radian::new(<$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 @@ -1082,11 +799,6 @@ macro_rules! real_trait_impl <$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); @@ -1118,24 +830,11 @@ macro_rules! real_trait_impl 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_rad_func!($varType, acos); - define_self_rad_func!($varType, asin); - define_self_rad_func!($varType, atan); - define_self_func!($varType, cosh); - define_self_func!($varType, sinh); - define_self_func!($varType, tanh); - define_self_rad_func!($varType, acosh); - define_self_rad_func!($varType, asinh); - define_self_rad_func!($varType, atanh); - define_self_other_rad_func!($varType, atan2); } )*) } // Implement the trait for the types that are Real numbers. -real_trait_impl!(Real for f32 f64); +real_trait_impl!(Real for f32); +real_trait_impl!(Real for f64); diff --git a/src/trig.rs b/src/trig.rs deleted file mode 100644 index a5a3296..0000000 --- a/src/trig.rs +++ /dev/null @@ -1,716 +0,0 @@ -use std::ops::{Add, Sub, Mul, Div, Rem, Neg}; -use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign}; - -use ::constants::Constants; -use ::real::Real; - - - -/// A degree usually denoted by ° (the degree symbol), -/// is a measurement of a plane angle, defined so that a -/// full rotation is 360 degrees. -#[derive(Clone, Copy, Eq, PartialEq, Hash)] -pub struct Degree -{ - value: T -} - -/// A unit of angle, equal to an angle at the center of -/// a circle whose arc is equal in length to the radius. -#[derive(Clone, Copy, Eq, PartialEq, Hash)] -pub struct Radian -{ - value: T -} - - - -impl Degree where T: Real -{ - /// Create a new Degree structure with the given value. - pub fn new(val: T) -> Degree - { - Degree - { - value: val - } - } - - /// Computes the arccosine of a number. Return value is in Degrees in - /// the range [0, 180] or NaN if the number is outside the range - /// [-1, 1]. - /// - ///``` - /// use sigils::{Degree, Real}; - /// - /// let f: Degree; - /// - /// f = Degree::from(45.0f64); - /// assert!((45.0f64 - *Degree::acos(f.cos())) < 1e-10); - ///``` - pub fn acos(val: T) -> Degree - { - let radians: Radian; - - radians = val.acos(); - Degree::from(radians) - } - - /// Computes the arcsine of a number. Return value is in Degrees in - /// the range [-57.2957795/2, 57.2957795/2] or NaN if the number is - /// outside the range [-1, 1]. - /// - ///``` - /// use sigils::{Degree, Real}; - /// - /// let f: Degree; - /// - /// f = Degree::from(45.0f64); - /// assert!((45.0f64 - *Degree::asin(f.sin())) < 1e-10); - ///``` - pub fn asin(val: T) -> Degree - { - let radians: Radian; - - radians = val.asin(); - Degree::from(radians) - } - - /// Computes the arctangent of a number. Return value is in degrees in the - /// range [-57.2957795/2, 57.2957795/2]; - /// - ///``` - /// use sigils::{Degree, Real}; - /// - /// let f: Degree; - /// - /// f = Degree::from(45.0f64); - /// assert!((45.0f64 - *Degree::atan(f.tan())) < 1e-10); - ///``` - pub fn atan(val: T) -> Degree - { - let radians: Radian; - - radians = val.atan(); - Degree::from(radians) - } - - /// Inverse hyperbolic cosine function. - pub fn acosh(val: T) -> Degree - { - let radians: Radian; - - radians = val.acosh(); - Degree::from(radians) - } - - /// Inverse hyperbolic sine function. - pub fn asinh(val: T) -> Degree - { - let radians: Radian; - - radians = val.asinh(); - Degree::from(radians) - } - - /// Inverse hyperbolic tangent function. - pub fn atanh(val: T) -> Degree - { - let radians: Radian; - - radians = val.atanh(); - Degree::from(radians) - } - - /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`). - pub fn atan2(y: T, x: T) -> Degree - { - let radians: Radian; - - radians = y.atan2(x); - Degree::from(radians) - } - - /// Computes the cosine of this angle. - /// - /// ``` - /// use sigils::Degree; - /// use std::f64; - /// - /// let x: Degree = Degree::from(360.0f64); - /// - /// let abs_difference = (x.cos() - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - pub fn cos(&self) -> T - { - let radians: Radian; - - radians = Radian::from(*self); - radians.cos() - } - - /// Computes the sine of this angle. - /// - /// ``` - /// use sigils::Degree; - /// use std::f64; - /// - /// let x: Degree = Degree::from(90.0f64); - /// - /// let abs_difference = (x.sin() - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - pub fn sin(&self) -> T - { - let radians: Radian; - - radians = Radian::from(*self); - radians.sin() - } - - /// Computes the tangent of this angle. - /// - /// ``` - /// use sigils::Degree; - /// use std::f64; - /// - /// let x: Degree = Degree::from(45.0f64); - /// - /// let abs_difference = (x.tan() - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-14); - /// ``` - pub fn tan(&self) -> T - { - let radians: Radian; - - radians = Radian::from(*self); - radians.tan() - } - - /// Hyperbolic cosine function. - /// - /// ``` - /// use sigils::Degree; - /// use sigils::Constants; - /// - /// let e32: f32 = Constants::E; - /// let x32: Degree = Degree::from(f32::INVERSE_PI_DIVIDED_BY_180); - /// 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: Degree = Degree::from(f64::INVERSE_PI_DIVIDED_BY_180); - /// 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); - /// ``` - pub fn cosh(&self) -> T - { - let radians: Radian; - - radians = Radian::from(*self); - radians.cosh() - } - - /// Hyperbolic sine function. - /// - /// ``` - /// use sigils::Degree; - /// use sigils::Constants; - /// - /// let e32: f32 = Constants::E; - /// let x32: Degree = Degree::from(f32::INVERSE_PI_DIVIDED_BY_180); - /// - /// 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: Degree = Degree::from(f64::INVERSE_PI_DIVIDED_BY_180); - /// - /// 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); - /// ``` - pub fn sinh(&self) -> T - { - let radians: Radian; - - radians = Radian::from(*self); - radians.sinh() - } - - /// Hyperbolic tangent function. - /// - /// ``` - /// use sigils::Degree; - /// use sigils::Constants; - /// - /// let e32: f32 = Constants::E; - /// let x32: Degree = Degree::from(f32::INVERSE_PI_DIVIDED_BY_180); - /// - /// 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: Degree = Degree::from(f64::INVERSE_PI_DIVIDED_BY_180); - /// - /// 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); - /// ``` - pub fn tanh(&self) -> T - { - let radians: Radian; - - radians = Radian::from(*self); - radians.tanh() - } -} - -impl ::std::ops::Deref for Degree where T: Real -{ - type Target = T; - - fn deref(&self) -> &T - { - &self.value - } -} - -impl ::std::ops::DerefMut for Degree where T: Real -{ - fn deref_mut<'a>(&'a mut self) -> &'a mut T - { - &mut self.value - } -} - -binary_operator_impl!(Add::add, Degree {value}, Real); -binary_operator_impl!(Sub::sub, Degree {value}, Real); -binary_operator_impl!(Mul::mul, Degree {value}, Real); -binary_operator_impl!(Div::div, Degree {value}, Real); -binary_operator_impl!(Rem::rem, Degree {value}, Real); - -impl ::std::ops::Neg for Degree - where T: Neg -{ - type Output = Degree; - - fn neg(self) -> Degree - { - let mut degrees: Degree; - - degrees = self; - degrees.value = degrees.value.neg(); - degrees - } -} - -binary_operator_assign_impl!(AddAssign::add_assign, - Degree {value}, Real); -binary_operator_assign_impl!(SubAssign::sub_assign, - Degree {value}, Real); -binary_operator_assign_impl!(MulAssign::mul_assign, - Degree {value}, Real); -binary_operator_assign_impl!(DivAssign::div_assign, - Degree {value}, Real); -binary_operator_assign_impl!(RemAssign::rem_assign, - Degree {value}, Real); - -impl ::std::convert::From> for f32 -{ - fn from(degrees: Degree) -> f32 - { - degrees.value - } -} - -impl ::std::convert::From> for f64 -{ - fn from(degrees: Degree) -> f64 - { - degrees.value - } -} - -impl ::std::convert::From for Degree where T: Real -{ - fn from(val: T) -> Degree - { - Degree::new(val) - } -} - -impl ::std::convert::From> for Degree where T: Real -{ - fn from(radians: Radian) -> Degree - { - let degs: T; - - degs = radians.value * Constants::INVERSE_PI_DIVIDED_BY_180; - Degree::new(degs) - } -} - -impl ::std::fmt::Debug for Degree - where T: Real -{ - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result - { - ::std::fmt::Display::fmt(self, f) - } -} - -impl ::std::fmt::Display for Degree - where T: Real -{ - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result - { - write!(f, "{}", self.value) - } -} - -impl Radian where T: Real -{ - /// Create a new Radian structure with the given value. - pub fn new(val: T) -> Radian - { - Radian - { - value: val - } - } - - /// Computes the arccosine of a number. Return value is in Degrees in - /// the range [0, pi] or NaN if the number is outside the range - /// [-1, 1]. - /// - ///``` - /// use sigils::{Constants, Radian, Real}; - /// - /// let f: Radian; - /// - /// f = Radian::from(f64::PI / 4.0f64); - /// assert!(((f64::PI / 4.0f64) - *Radian::acos(f.cos())) < 1e-10); - ///``` - pub fn acos(val: T) -> Radian - { - val.acos() - } - - /// Computes the arcsine of a number. Return value is in Degrees in - /// the range [-pi/2, pi/2] or NaN if the number is - /// outside the range [-1, 1]. - /// - ///``` - /// use sigils::{Constants, Radian, Real}; - /// - /// let f: Radian; - /// - /// f = Radian::from(f64::PI / 4.0f64); - /// assert!(((f64::PI / 4.0f64) - *Radian::asin(f.sin())) < 1e-10); - ///``` - pub fn asin(val: T) -> Radian - { - val.asin() - } - - /// Computes the arctangent of a number. Return value is in degrees in the - /// range [-pi/2, pi/2]; - /// - ///``` - /// use sigils::{Constants, Radian, Real}; - /// - /// let f: Radian; - /// - /// f = Radian::from(f64::PI / 4.0f64); - /// assert!(((f64::PI / 4.0f64) - *Radian::atan(f.tan())) < 1e-10); - ///``` - pub fn atan(val: T) -> Radian - { - val.atan() - } - - /// Inverse hyperbolic cosine function. - pub fn acosh(val: T) -> Radian - { - val.acosh() - } - - /// Inverse hyperbolic sine function. - pub fn asinh(val: T) -> Radian - { - val.asinh() - } - - /// Inverse hyperbolic tangent function. - pub fn atanh(val: T) -> Radian - { - val.atanh() - } - - /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`). - pub fn atan2(y: T, x: T) -> Radian - { - y.atan2(x) - } - - /// Computes the cosine of this angle. - /// - /// ``` - /// use sigils::Radian; - /// use std::f64; - /// - /// let x: Radian = Radian::from(2.0*f64::consts::PI); - /// - /// let abs_difference = (x.cos() - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - pub fn cos(&self) -> T - { - self.value.cos() - } - - /// Computes the sine of this angle. - /// - /// ``` - /// use sigils::Radian; - /// use std::f64; - /// - /// let x: Radian = Radian::from(f64::consts::PI/2.0); - /// - /// let abs_difference = (x.sin() - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - pub fn sin(&self) -> T - { - self.value.sin() - } - - /// Computes the tangent of this angle. - /// - /// ``` - /// use sigils::Radian; - /// use std::f64; - /// - /// let x: Radian = Radian::from(f64::consts::PI/4.0); - /// - /// let abs_difference = (x.tan() - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-14); - /// ``` - pub fn tan(&self) -> T - { - self.value.tan() - } - - /// Hyperbolic cosine function. - /// - /// ``` - /// use sigils::Radian; - /// use sigils::Constants; - /// - /// let e32: f32 = Constants::E; - /// let x32: Radian = Radian::new(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: Radian = Radian::new(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); - /// ``` - pub fn cosh(&self) -> T - { - self.value.cosh() - } - - /// Hyperbolic sine function. - /// - /// ``` - /// use sigils::Radian; - /// use sigils::Constants; - /// - /// let e32: f32 = Constants::E; - /// let x32: Radian = Radian::from(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: Radian = Radian::from(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); - /// ``` - pub fn sinh(&self) -> T - { - self.value.sinh() - } - - /// Hyperbolic tangent function. - /// - /// ``` - /// use sigils::Radian; - /// use sigils::Constants; - /// - /// let e32: f32 = Constants::E; - /// let x32: Radian = Radian::from(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: Radian = Radian::from(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); - /// ``` - pub fn tanh(&self) -> T - { - self.value.tanh() - } -} - -impl ::std::ops::Deref for Radian where T: Real -{ - type Target = T; - - fn deref(&self) -> &T - { - &self.value - } -} - -impl ::std::ops::DerefMut for Radian where T: Real -{ - fn deref_mut<'a>(&'a mut self) -> &'a mut T - { - &mut self.value - } -} - -binary_operator_impl!(Add::add, Radian {value}, Real); -binary_operator_impl!(Sub::sub, Radian {value}, Real); -binary_operator_impl!(Mul::mul, Radian {value}, Real); -binary_operator_impl!(Div::div, Radian {value}, Real); -binary_operator_impl!(Rem::rem, Radian {value}, Real); - -impl ::std::ops::Neg for Radian - where T: Neg -{ - type Output = Radian; - - fn neg(self) -> Radian - { - let mut radians: Radian; - - radians = self; - radians.value = radians.value.neg(); - radians - } -} - -binary_operator_assign_impl!(AddAssign::add_assign, - Radian {value}, Real); -binary_operator_assign_impl!(SubAssign::sub_assign, - Radian {value}, Real); -binary_operator_assign_impl!(MulAssign::mul_assign, - Radian {value}, Real); -binary_operator_assign_impl!(DivAssign::div_assign, - Radian {value}, Real); -binary_operator_assign_impl!(RemAssign::rem_assign, - Radian {value}, Real); - -impl ::std::convert::From> for f32 -{ - fn from(radians: Radian) -> f32 - { - radians.value - } -} - -impl ::std::convert::From> for f64 -{ - fn from(radians: Radian) -> f64 - { - radians.value - } -} - -impl ::std::convert::From for Radian where T: Real -{ - fn from(val: T) -> Radian - { - Radian::new(val) - } -} - -impl ::std::convert::From> for Radian - where T: Real -{ - fn from(degrees: Degree) -> Radian - { - let rads: T; - - rads = degrees.value * Constants::PI_DIVIDED_BY_180; - Radian::new(rads) - } -} - -impl ::std::fmt::Debug for Radian - where T: Real -{ - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result - { - ::std::fmt::Display::fmt(self, f) - } -} - -impl ::std::fmt::Display for Radian - where T: Real -{ - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result - { - write!(f, "{}", self.value) - } -} diff --git a/src/trig/degree.rs b/src/trig/degree.rs new file mode 100644 index 0000000..be88b7a --- /dev/null +++ b/src/trig/degree.rs @@ -0,0 +1,134 @@ +use std::ops::{Add, Sub, Mul, Div, Rem, Neg}; +use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign}; + +use ::constants::Constants; +use ::real::Real; +use ::trig::radian::Radian; + + + +/// A degree usually denoted by ° (the degree symbol), +/// is a measurement of a plane angle, defined so that a +/// full rotation is 360 degree. +#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd, Hash)] +pub struct Degree +{ + value: T +} + + + +impl Degree where T: Real +{ + /// Create a new Degree structure with the given value. + pub fn new(val: T) -> Self + { + Degree + { + value: val + } + } +} + +impl ::std::ops::Deref for Degree where T: Real +{ + type Target = T; + + fn deref(&self) -> &T + { + &self.value + } +} + +impl ::std::ops::DerefMut for Degree where T: Real +{ + fn deref_mut<'a>(&'a mut self) -> &'a mut T + { + &mut self.value + } +} + +binary_operator_impl!(Add::add, Real, Degree {value}); +binary_operator_impl!(Sub::sub, Real, Degree {value}); +binary_operator_impl!(Mul::mul, Real, Degree {value}); +binary_operator_impl!(Div::div, Real, Degree {value}); +binary_operator_impl!(Rem::rem, Real, Degree {value}); + +impl ::std::ops::Neg for Degree + where T: Neg +{ + type Output = Degree; + + fn neg(self) -> Degree + { + let mut degree: Degree; + + degree = self; + degree.value = degree.value.neg(); + degree + } +} + +binary_operator_assign_impl!(AddAssign::add_assign, + Real, Degree {value}); +binary_operator_assign_impl!(SubAssign::sub_assign, + Real, Degree {value}); +binary_operator_assign_impl!(MulAssign::mul_assign, + Real, Degree {value}); +binary_operator_assign_impl!(DivAssign::div_assign, + Real, Degree {value}); +binary_operator_assign_impl!(RemAssign::rem_assign, + Real, Degree {value}); + +impl ::std::convert::From> for f32 +{ + fn from(degree: Degree) -> f32 + { + degree.value + } +} + +impl ::std::convert::From> for f64 +{ + fn from(degree: Degree) -> f64 + { + degree.value + } +} + +impl ::std::convert::From for Degree where T: Real +{ + fn from(val: T) -> Degree + { + Degree::new(val) + } +} + +impl ::std::convert::From> for Degree where T: Real +{ + fn from(radians: Radian) -> Degree + { + let degs: T; + + degs = *radians * Constants::INVERSE_PI_DIVIDED_BY_180; + Degree::new(degs) + } +} + +impl ::std::fmt::Debug for Degree + where T: Real +{ + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result + { + ::std::fmt::Display::fmt(self, f) + } +} + +impl ::std::fmt::Display for Degree + where T: Real +{ + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result + { + write!(f, "Degree({})", self.value) + } +} diff --git a/src/trig/mod.rs b/src/trig/mod.rs new file mode 100644 index 0000000..c8d2e7e --- /dev/null +++ b/src/trig/mod.rs @@ -0,0 +1,15 @@ +//! This section of the library handles the branch of mathematics +//! that studies relationships involving lengths and angles of triangles. + +mod degree; +//mod grad; +mod radian; +mod trig; +//mod turn; + + +pub use self::degree::Degree; +//pub use self::grad::Grad; +pub use self::radian::Radian; +pub use self::trig::Trig; +//pub use self::turn::Turn; diff --git a/src/trig/radian.rs b/src/trig/radian.rs new file mode 100644 index 0000000..956429b --- /dev/null +++ b/src/trig/radian.rs @@ -0,0 +1,133 @@ +use std::ops::{Add, Sub, Mul, Div, Rem, Neg}; +use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign}; + +use ::constants::Constants; +use ::real::Real; +use ::trig::degree::Degree; + + +/// A unit of angle, equal to an angle at the center of +/// a circle whose arc is equal in length to the radius. +#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd, Hash)] +pub struct Radian +{ + value: T +} + + + +impl Radian where T: Real +{ + /// Create a new Radian structure with the given value. + pub fn new(val: T) -> Self + { + Radian + { + value: val + } + } +} + +impl ::std::ops::Deref for Radian where T: Real +{ + type Target = T; + + fn deref(&self) -> &T + { + &self.value + } +} + +impl ::std::ops::DerefMut for Radian where T: Real +{ + fn deref_mut<'a>(&'a mut self) -> &'a mut T + { + &mut self.value + } +} + +binary_operator_impl!(Add::add, Real, Radian {value}); +binary_operator_impl!(Sub::sub, Real, Radian {value}); +binary_operator_impl!(Mul::mul, Real, Radian {value}); +binary_operator_impl!(Div::div, Real, Radian {value}); +binary_operator_impl!(Rem::rem, Real, Radian {value}); + +impl ::std::ops::Neg for Radian + where T: Neg +{ + type Output = Radian; + + fn neg(self) -> Radian + { + let mut radian: Radian; + + radian = self; + radian.value = radian.value.neg(); + radian + } +} + +binary_operator_assign_impl!(AddAssign::add_assign, + Real, Radian {value}); +binary_operator_assign_impl!(SubAssign::sub_assign, + Real, Radian {value}); +binary_operator_assign_impl!(MulAssign::mul_assign, + Real, Radian {value}); +binary_operator_assign_impl!(DivAssign::div_assign, + Real, Radian {value}); +binary_operator_assign_impl!(RemAssign::rem_assign, + Real, Radian {value}); + +impl ::std::convert::From> for f32 +{ + fn from(radian: Radian) -> f32 + { + radian.value + } +} + +impl ::std::convert::From> for f64 +{ + fn from(radian: Radian) -> f64 + { + radian.value + } +} + +impl ::std::convert::From for Radian where T: Real +{ + fn from(val: T) -> Radian + { + Radian::new(val) + } +} + +impl ::std::convert::From> for Radian + where T: Real +{ + fn from(degrees: Degree) -> Radian + { + let rads: T; + + rads = *degrees * Constants::PI_DIVIDED_BY_180; + Radian::new(rads) + } +} + +impl ::std::fmt::Debug for Radian + where T: Real +{ + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result + { + ::std::fmt::Display::fmt(self, f) + } +} + +impl ::std::fmt::Display for Radian + where T: Real +{ + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result + { + write!(f, "Radian({})", self.value) + } +} diff --git a/src/trig/trig.rs b/src/trig/trig.rs new file mode 100644 index 0000000..af4a7c6 --- /dev/null +++ b/src/trig/trig.rs @@ -0,0 +1,421 @@ +use ::binding::{CDouble, CFloat}; + +use ::real::Real; +use ::trig::radian::Radian; + + + +/// The available trigonometric functions. +pub trait Trig: Real +{ + /// Computes the cosine of this angle. + /// + /// ``` + /// use sigils::Radian; + /// use std::f64; + /// + /// let x: Radian = Radian::from(2.0*f64::consts::PI); + /// + /// let abs_difference = (x.cos() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn cos(arg: T) -> Self + where T: Into>; + + /// Computes the sine of this angle. + /// + /// ``` + /// use sigils::Radian; + /// use std::f64; + /// + /// let x: Radian = Radian::from(f64::consts::PI/2.0); + /// + /// let abs_difference = (x.sin() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn sin(arg: T) -> Self + where T: Into>; + + /// Computes the tangent of this angle. + /// + /// ``` + /// use sigils::Radian; + /// use std::f64; + /// + /// let x: Radian = Radian::from(f64::consts::PI/4.0); + /// + /// let abs_difference = (x.tan() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-14); + /// ``` + fn tan(arg: T) -> Self + where T: Into>; + + /// Computes the arccosine of a number. Return value is in Degrees in + /// the range [0, pi] or NaN if the number is outside the range + /// [-1, 1]. + /// + ///``` + /// use sigils::{Constants, Radian, Real}; + /// + /// let f: Radian; + /// + /// f = Radian::from(f64::PI / 4.0f64); + /// assert!(((f64::PI / 4.0f64) - *Radian::acos(f.cos())) < 1e-10); + ///``` + fn acos(arg: Self) -> T + where T: From>; + + /// Computes the arcsine of a number. Return value is in Degrees in + /// the range [-pi/2, pi/2] or NaN if the number is + /// outside the range [-1, 1]. + /// + ///``` + /// use sigils::{Constants, Radian, Real}; + /// + /// let f: Radian; + /// + /// f = Radian::from(f64::PI / 4.0f64); + /// assert!(((f64::PI / 4.0f64) - *Radian::asin(f.sin())) < 1e-10); + ///``` + fn asin(arg: Self) -> T + where T: From>; + + /// Computes the arctangent of a number. Return value is in degrees in the + /// range [-pi/2, pi/2]; + /// + ///``` + /// use sigils::{Constants, Radian, Real}; + /// + /// let f: Radian; + /// + /// f = Radian::from(f64::PI / 4.0f64); + /// assert!(((f64::PI / 4.0f64) - *Radian::atan(f.tan())) < 1e-10); + ///``` + fn atan(arg: Self) -> T + where T: From>; + + /// Computes the four quadrant arctangent of y and x. + fn atan2(y: Self, x: Self) -> T + where T: From>; + + + /// Hyperbolic cosine function. + /// + /// ``` + /// use sigils::Radian; + /// use sigils::Constants; + /// + /// let e32: f32 = Constants::E; + /// let x32: Radian = Radian::new(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: Radian = Radian::new(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(arg: Self) -> Self; + + /// Hyperbolic sine function. + /// + /// ``` + /// use sigils::Radian; + /// use sigils::Constants; + /// + /// let e32: f32 = Constants::E; + /// let x32: Radian = Radian::from(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: Radian = Radian::from(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(arg: Self) -> Self; + + /// Hyperbolic tangent function. + /// + /// ``` + /// use sigils::Radian; + /// use sigils::Constants; + /// + /// let e32: f32 = Constants::E; + /// let x32: Radian = Radian::from(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: Radian = Radian::from(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(arg: Self) -> Self; + + /// Inverse hyperbolic cosine function. + fn acosh(arg: Self) -> Self; + + /// Inverse hyperbolic sine function. + fn asinh(arg: Self) -> Self; + + /// Inverse hyperbolic tangent function. + fn atanh(arg: Self) -> Self; +} + + + +impl Trig for f32 +{ + fn cos(arg: T) -> Self + where T: Into> + { + unsafe + { + ::pact::cosf(*arg.into() as CFloat) as Self + } + } + + fn sin(arg: T) -> Self + where T: Into> + { + unsafe + { + ::pact::sinf(*arg.into() as CFloat) as Self + } + } + + fn tan(arg: T) -> Self + where T: Into> + { + unsafe + { + ::pact::tanf(*arg.into() as CFloat) as Self + } + } + + fn acos(arg: Self) -> T + where T: From> + { + unsafe + { + Radian::new(::pact::acosf(arg as CFloat) as Self).into() + } + } + + fn asin(arg: Self) -> T + where T: From> + { + unsafe + { + Radian::new(::pact::asinf(arg as CFloat) as Self).into() + } + } + + fn atan(arg: Self) -> T + where T: From> + { + unsafe + { + Radian::new(::pact::atanf(arg as CFloat) as Self).into() + } + } + + fn atan2(y: Self, x: Self) -> T + where T: From> + { + unsafe + { + Radian::new(::pact::atan2f(y as CFloat, x as CFloat) as Self).into() + } + } + + + fn cosh(arg: Self) -> Self + { + unsafe + { + ::pact::coshf(arg as CFloat) as Self + } + } + + fn sinh(arg: Self) -> Self + { + unsafe + { + ::pact::sinhf(arg as CFloat) as Self + } + } + + fn tanh(arg: Self) -> Self + { + unsafe + { + ::pact::tanhf(arg as CFloat) as Self + } + } + + fn acosh(arg: Self) -> Self + { + unsafe + { + ::pact::acoshf(arg as CFloat) as Self + } + } + + fn asinh(arg: Self) -> Self + { + unsafe + { + ::pact::asinhf(arg as CFloat) as Self + } + } + + fn atanh(arg: Self) -> Self + { + unsafe + { + ::pact::atanhf(arg as CFloat) as Self + } + } +} + +impl Trig for f64 +{ + fn cos(arg: T) -> Self + where T: Into> + { + unsafe + { + ::pact::cos(*arg.into() as CDouble) as Self + } + } + + fn sin(arg: T) -> Self + where T: Into> + { + unsafe + { + ::pact::sin(*arg.into() as CDouble) as Self + } + } + + fn tan(arg: T) -> Self + where T: Into> + { + unsafe + { + ::pact::tan(*arg.into() as CDouble) as Self + } + } + + fn acos(arg: Self) -> T + where T: From> + { + unsafe + { + Radian::new(::pact::acos(arg as CDouble) as Self).into() + } + } + + fn asin(arg: Self) -> T + where T: From> + { + unsafe + { + Radian::new(::pact::asin(arg as CDouble) as Self).into() + } + } + + fn atan(arg: Self) -> T + where T: From> + { + unsafe + { + Radian::new(::pact::atan(arg as CDouble) as Self).into() + } + } + + fn atan2(y: Self, x: Self) -> T + where T: From> + { + unsafe + { + Radian::new(::pact::atan2(y as CDouble, x as CDouble) as Self).into() + } + } + + + fn cosh(arg: Self) -> Self + { + unsafe + { + ::pact::cosh(arg as CDouble) as Self + } + } + + fn sinh(arg: Self) -> Self + { + unsafe + { + ::pact::sinh(arg as CDouble) as Self + } + } + + fn tanh(arg: Self) -> Self + { + unsafe + { + ::pact::tanh(arg as CDouble) as Self + } + } + + fn acosh(arg: Self) -> Self + { + unsafe + { + ::pact::acosh(arg as CDouble) as Self + } + } + + fn asinh(arg: Self) -> Self + { + unsafe + { + ::pact::asinh(arg as CDouble) as Self + } + } + + fn atanh(arg: Self) -> Self + { + unsafe + { + ::pact::atanh(arg as CDouble) as Self + } + } +} diff --git a/src/vector.rs b/src/vector.rs index 22b9b5e..13aa453 100644 --- a/src/vector.rs +++ b/src/vector.rs @@ -10,6 +10,7 @@ use ::one::One; use ::number::Number; use ::real::Real; use ::trig::Radian; +use ::trig::Trig; @@ -277,7 +278,7 @@ pub trait Vector: Debug + Display + Clone + Default + Zero + One /// Defines the [EuclideanVector][1] trait. /// /// [1]: https://en.wikipedia.org/wiki/Euclidean_vector -pub trait EuclideanVector : Vector where T: Real +pub trait EuclideanVector : Vector where T: Trig { /// Get the length of the Vector. /// @@ -623,23 +624,23 @@ macro_rules! define_vector } // Implement the binary operations for this Vector structure. - binary_operator_impl!(Add::add, $structName {$($field),+}, Number); - binary_operator_impl!(Sub::sub, $structName {$($field),+}, Number); - binary_operator_impl!(Mul::mul, $structName {$($field),+}, Number); - binary_operator_impl!(Div::div, $structName {$($field),+}, Number); - binary_operator_impl!(Rem::rem, $structName {$($field),+}, Number); + binary_operator_impl!(Add::add, Number, $structName {$($field),+}); + binary_operator_impl!(Sub::sub, Number, $structName {$($field),+}); + binary_operator_impl!(Mul::mul, Number, $structName {$($field),+}); + binary_operator_impl!(Div::div, Number, $structName {$($field),+}); + binary_operator_impl!(Rem::rem, Number, $structName {$($field),+}); // Handle the assignment operators. binary_operator_assign_impl!(AddAssign::add_assign, - $structName {$($field),+}, Number); + Number, $structName {$($field),+}); binary_operator_assign_impl!(SubAssign::sub_assign, - $structName {$($field),+}, Number); + Number, $structName {$($field),+}); binary_operator_assign_impl!(MulAssign::mul_assign, - $structName {$($field),+}, Number); + Number, $structName {$($field),+}); binary_operator_assign_impl!(DivAssign::div_assign, - $structName {$($field),+}, Number); + Number, $structName {$($field),+}); binary_operator_assign_impl!(RemAssign::rem_assign, - $structName {$($field),+}, Number); + Number, $structName {$($field),+}); } } @@ -908,29 +909,29 @@ impl Vector4 where T: Number } // Implement the angle specific portion of the EuclideanVector. -impl EuclideanVector for Vector2 where T: Real +impl EuclideanVector for Vector2 where T: Trig { fn angle(&self, vector: &Vector2) -> Radian { // Shortcut. - Radian::atan2(self.perpendicular_dot(vector), self.dot(vector)) + Trig::atan2(self.perpendicular_dot(vector), self.dot(vector)) } } -impl EuclideanVector for Vector3 where T: Real +impl EuclideanVector for Vector3 where T: Trig { fn angle(&self, vector: &Vector3) -> Radian { // Shortcut. - Radian::atan2(self.cross(vector).get_length(), self.dot(vector)) + Trig::atan2(self.cross(vector).get_length(), self.dot(vector)) } } -impl EuclideanVector for Vector4 where T: Real +impl EuclideanVector for Vector4 where T: Trig { fn angle(&self, vector: &Vector4) -> Radian { // The basic equation, this would work for any size Vector. - Radian::acos(self.dot(vector) / (self.get_length()*vector.get_length())) + Trig::acos(self.dot(vector) / (self.get_length()*vector.get_length())) } }