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.
This commit is contained in:
Myrddin Dundragon 2017-06-27 18:19:33 -04:00
parent cbde731b74
commit 43a1e30808
14 changed files with 839 additions and 1094 deletions

4
Cargo.lock generated
View File

@ -1,4 +0,0 @@
[root]
name = "sigils"
version = "0.1.0"

View File

@ -1,12 +1,16 @@
[package]
name = "sigils"
version = "0.1.0"
authors = ["Jason Travis Smith <Jason@CyberMagesLLC.com>"]
authors = ["Jason Travis Smith <Myrddin@CyberMagesLLC.com>"]
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"

47
examples/trig.rs Normal file
View File

@ -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<f64>;
let mut radians: Radian<f64>;
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!("");
}

View File

@ -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.

View File

@ -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};

View File

@ -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<T> $traitName<T> for $structName<T>
where T: $generic_type
where T: $generic_type $(+ $generic_types2)*
{
type Output = $structName<T>;
@ -18,7 +18,7 @@ macro_rules! binary_operator_impl
}
impl<'a, T> $traitName<T> for &'a $structName<T>
where T: $generic_type
where T: $generic_type $(+ $generic_types2)*
{
type Output = $structName<T>;
@ -29,7 +29,7 @@ macro_rules! binary_operator_impl
}
impl<'a, T> $traitName<&'a T> for $structName<T>
where T: $generic_type
where T: $generic_type $(+ $generic_types2)*
{
type Output = $structName<T>;
@ -40,7 +40,7 @@ macro_rules! binary_operator_impl
}
impl<'a, 'b, T> $traitName<&'b T> for &'a $structName<T>
where T: $generic_type
where T: $generic_type $(+ $generic_types2)*
{
type Output = $structName<T>;
@ -51,7 +51,7 @@ macro_rules! binary_operator_impl
}
impl<T> $traitName<$structName<T>> for $structName<T>
where T: $generic_type
where T: $generic_type $(+ $generic_types2)*
{
type Output = $structName<T>;
@ -62,7 +62,7 @@ macro_rules! binary_operator_impl
}
impl<'a, T> $traitName<$structName<T>> for &'a $structName<T>
where T: $generic_type
where T: $generic_type $(+ $generic_types2)*
{
type Output = $structName<T>;
@ -73,7 +73,7 @@ macro_rules! binary_operator_impl
}
impl<'a, T> $traitName<&'a $structName<T>> for $structName<T>
where T: $generic_type
where T: $generic_type $(+ $generic_types2)*
{
type Output = $structName<T>;
@ -84,7 +84,7 @@ macro_rules! binary_operator_impl
}
impl<'a, 'b, T> $traitName<&'a $structName<T>> for &'b $structName<T>
where T: $generic_type
where T: $generic_type $(+ $generic_types2)*
{
type Output = $structName<T>;
@ -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<T> $traitName<$structName<T>> for $structName<T>
where T: $generic_type
where T: $generic_type $(+ $generic_types2)*
{
fn $funcName(&mut self, rhs: $structName<T>)
{
@ -114,7 +114,7 @@ macro_rules! binary_operator_assign_impl
}
impl<T> $traitName<T> for $structName<T>
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<T>> for $structName<T>
where T: $generic_type
where T: $generic_type $(+ $generic_types2)*
{
fn $funcName(&mut self, rhs: &'a $structName<T>)
{
@ -132,7 +132,7 @@ macro_rules! binary_operator_assign_impl
}
impl<'a, T> $traitName<&'a T> for $structName<T>
where T: $generic_type
where T: $generic_type $(+ $generic_types2)*
{
fn $funcName(&mut self, rhs: &'a T)
{

View File

@ -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<T> where T: Real
pub struct Quaternion<T>
{
/// TODO: Describe this.
pub scalar: T,
@ -45,7 +47,7 @@ macro_rules! binary_operator_impl
{
($traitName: ident :: $funcName: ident, $structName: ident) =>
{
impl<T> $traitName<T> for $structName<T> where T: Real
impl<T> $traitName<T> for $structName<T> where T: Trig
{
type Output = $structName<T>;
@ -56,7 +58,7 @@ macro_rules! binary_operator_impl
}
}
impl<'a, T> $traitName<T> for &'a $structName<T> where T: Real
impl<'a, T> $traitName<T> for &'a $structName<T> where T: Trig
{
type Output = $structName<T>;
@ -67,7 +69,7 @@ macro_rules! binary_operator_impl
}
}
impl<'a, T> $traitName<&'a T> for $structName<T> where T: Real
impl<'a, T> $traitName<&'a T> for $structName<T> where T: Trig
{
type Output = $structName<T>;
@ -78,7 +80,7 @@ macro_rules! binary_operator_impl
}
}
impl<'a, 'b, T> $traitName<&'b T> for &'a $structName<T> where T: Real
impl<'a, 'b, T> $traitName<&'b T> for &'a $structName<T> where T: Trig
{
type Output = $structName<T>;
@ -93,7 +95,7 @@ macro_rules! binary_operator_impl
// Implement the Quaternion's methods.
impl<T> Quaternion<T> where T: Real
impl<T> Quaternion<T> where T: Trig
{
/// Create a new Quaternion from a given scalar and Vector.
///
@ -277,7 +279,7 @@ impl<T> Quaternion<T> where T: Real
}
// Implement the Debug trait for the Quaternion.
impl<T> Debug for Quaternion<T> where T: Real
impl<T> Debug for Quaternion<T> where T: Trig
{
fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error>
{
@ -286,7 +288,7 @@ impl<T> Debug for Quaternion<T> where T: Real
}
// Implement the Display trait for the Quaternion.
impl<T> Display for Quaternion<T> where T: Real
impl<T> Display for Quaternion<T> where T: Trig
{
fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error>
{
@ -296,7 +298,7 @@ impl<T> Display for Quaternion<T> where T: Real
// Implement a default value for Quaternions which
// returns the identity quaternion.
impl<T> Default for Quaternion<T> where T: Real
impl<T> Default for Quaternion<T> where T: Trig
{
fn default() -> Quaternion<T>
{
@ -305,7 +307,7 @@ impl<T> Default for Quaternion<T> where T: Real
}
// Implement the Zero and One traits for the Quaternion.
impl<T> Zero for Quaternion<T> where T: Real
impl<T> Zero for Quaternion<T> where T: Trig
{
fn zero() -> Quaternion<T>
{
@ -313,7 +315,7 @@ impl<T> Zero for Quaternion<T> where T: Real
}
}
impl<T> One for Quaternion<T> where T: Real
impl<T> One for Quaternion<T> where T: Trig
{
fn one() -> Quaternion<T>
{
@ -327,7 +329,7 @@ binary_operator_impl!(Mul::mul, Quaternion);
//binary_operator_impl!(Neg::neg, Quaternion);
// Implement Negating a Quaternion.
impl<T> Neg for Quaternion<T> where T: Real
impl<T> Neg for Quaternion<T> where T: Trig
{
type Output = Quaternion<T>;
@ -337,7 +339,7 @@ impl<T> Neg for Quaternion<T> where T: Real
}
}
impl<'a, T> Neg for &'a Quaternion<T> where T: Real
impl<'a, T> Neg for &'a Quaternion<T> where T: Trig
{
type Output = Quaternion<T>;
@ -348,7 +350,7 @@ impl<'a, T> Neg for &'a Quaternion<T> where T: Real
}
// Implement Adding Quaternions.
impl<T> Add<Quaternion<T>> for Quaternion<T> where T: Real
impl<T> Add<Quaternion<T>> for Quaternion<T> where T: Trig
{
type Output = Quaternion<T>;
@ -359,7 +361,7 @@ impl<T> Add<Quaternion<T>> for Quaternion<T> where T: Real
}
}
impl<'a, T> Add<Quaternion<T>> for &'a Quaternion<T> where T: Real
impl<'a, T> Add<Quaternion<T>> for &'a Quaternion<T> where T: Trig
{
type Output = Quaternion<T>;
@ -370,7 +372,7 @@ impl<'a, T> Add<Quaternion<T>> for &'a Quaternion<T> where T: Real
}
}
impl<'a, T> Add<&'a Quaternion<T>> for Quaternion<T> where T: Real
impl<'a, T> Add<&'a Quaternion<T>> for Quaternion<T> where T: Trig
{
type Output = Quaternion<T>;
@ -381,7 +383,7 @@ impl<'a, T> Add<&'a Quaternion<T>> for Quaternion<T> where T: Real
}
}
impl<'a, 'b, T> Add<&'b Quaternion<T>> for &'a Quaternion<T> where T: Real
impl<'a, 'b, T> Add<&'b Quaternion<T>> for &'a Quaternion<T> where T: Trig
{
type Output = Quaternion<T>;
@ -393,7 +395,7 @@ impl<'a, 'b, T> Add<&'b Quaternion<T>> for &'a Quaternion<T> where T: Real
}
// Implement subtracting Quaternions.
impl<T> Sub<Quaternion<T>> for Quaternion<T> where T: Real
impl<T> Sub<Quaternion<T>> for Quaternion<T> where T: Trig
{
type Output = Quaternion<T>;
@ -404,7 +406,7 @@ impl<T> Sub<Quaternion<T>> for Quaternion<T> where T: Real
}
}
impl<'a, T> Sub<Quaternion<T>> for &'a Quaternion<T> where T: Real
impl<'a, T> Sub<Quaternion<T>> for &'a Quaternion<T> where T: Trig
{
type Output = Quaternion<T>;
@ -415,7 +417,7 @@ impl<'a, T> Sub<Quaternion<T>> for &'a Quaternion<T> where T: Real
}
}
impl<'a, T> Sub<&'a Quaternion<T>> for Quaternion<T> where T: Real
impl<'a, T> Sub<&'a Quaternion<T>> for Quaternion<T> where T: Trig
{
type Output = Quaternion<T>;
@ -426,7 +428,7 @@ impl<'a, T> Sub<&'a Quaternion<T>> for Quaternion<T> where T: Real
}
}
impl<'a, 'b, T> Sub<&'b Quaternion<T>> for &'a Quaternion<T> where T: Real
impl<'a, 'b, T> Sub<&'b Quaternion<T>> for &'a Quaternion<T> where T: Trig
{
type Output = Quaternion<T>;
@ -438,7 +440,7 @@ impl<'a, 'b, T> Sub<&'b Quaternion<T>> for &'a Quaternion<T> where T: Real
}
// Implement Dividing Quaternions.
impl<T> Div<Quaternion<T>> for Quaternion<T> where T: Real
impl<T> Div<Quaternion<T>> for Quaternion<T> where T: Trig
{
type Output = Quaternion<T>;
@ -448,7 +450,7 @@ impl<T> Div<Quaternion<T>> for Quaternion<T> where T: Real
}
}
impl<'a, T> Div<Quaternion<T>> for &'a Quaternion<T> where T: Real
impl<'a, T> Div<Quaternion<T>> for &'a Quaternion<T> where T: Trig
{
type Output = Quaternion<T>;
@ -458,7 +460,7 @@ impl<'a, T> Div<Quaternion<T>> for &'a Quaternion<T> where T: Real
}
}
impl<'a, T> Div<&'a Quaternion<T>> for Quaternion<T> where T: Real
impl<'a, T> Div<&'a Quaternion<T>> for Quaternion<T> where T: Trig
{
type Output = Quaternion<T>;
@ -468,7 +470,7 @@ impl<'a, T> Div<&'a Quaternion<T>> for Quaternion<T> where T: Real
}
}
impl<'a, 'b, T> Div<&'b Quaternion<T>> for &'a Quaternion<T> where T: Real
impl<'a, 'b, T> Div<&'b Quaternion<T>> for &'a Quaternion<T> where T: Trig
{
type Output = Quaternion<T>;
@ -479,7 +481,7 @@ impl<'a, 'b, T> Div<&'b Quaternion<T>> for &'a Quaternion<T> where T: Real
}
// Implement multiplying Quaternions and Vectors.
impl<T> Mul<Quaternion<T>> for Quaternion<T> where T: Real
impl<T> Mul<Quaternion<T>> for Quaternion<T> where T: Trig
{
type Output = Quaternion<T>;
@ -492,7 +494,7 @@ impl<T> Mul<Quaternion<T>> for Quaternion<T> where T: Real
}
}
impl<'a, T> Mul<Quaternion<T>> for &'a Quaternion<T> where T: Real
impl<'a, T> Mul<Quaternion<T>> for &'a Quaternion<T> where T: Trig
{
type Output = Quaternion<T>;
@ -505,7 +507,7 @@ impl<'a, T> Mul<Quaternion<T>> for &'a Quaternion<T> where T: Real
}
}
impl<'a, T> Mul<&'a Quaternion<T>> for Quaternion<T> where T: Real
impl<'a, T> Mul<&'a Quaternion<T>> for Quaternion<T> where T: Trig
{
type Output = Quaternion<T>;
@ -518,7 +520,7 @@ impl<'a, T> Mul<&'a Quaternion<T>> for Quaternion<T> where T: Real
}
}
impl<'a, 'b, T> Mul<&'b Quaternion<T>> for &'a Quaternion<T> where T: Real
impl<'a, 'b, T> Mul<&'b Quaternion<T>> for &'a Quaternion<T> where T: Trig
{
type Output = Quaternion<T>;
@ -547,7 +549,7 @@ impl<'a, 'b, T> Mul<&'b Quaternion<T>> for &'a Quaternion<T> where T: Real
/// (SaZb + XaYb - YaXb + SbZa)k
fn multiply_quaternions<T>(sa: T, xa: T, ya: T, za: T,
sb: T, xb: T, yb: T, zb: T)
-> Quaternion<T> where T: Real
-> Quaternion<T> where T: Trig
{
let i: T;
let j: T;

View File

@ -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<Output=Self>
pub trait Real : Number + Constants + Neg<Output=Self>
{
/// Returns the `NaN` value.
///
@ -675,143 +676,6 @@ pub trait Real : Number + Neg<Output=Self>
/// ```
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<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) -> Radian<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) -> Radian<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) -> Radian<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.
///
@ -847,133 +711,10 @@ pub trait Real : Number + Neg<Output=Self>
/// 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<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) -> Radian<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) -> Radian<Self>;
}
// 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);

View File

@ -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<T>
{
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<T>
{
value: T
}
impl<T> Degree<T> where T: Real
{
/// Create a new Degree structure with the given value.
pub fn new(val: T) -> Degree<T>
{
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<f64>;
///
/// f = Degree::from(45.0f64);
/// assert!((45.0f64 - *Degree::acos(f.cos())) < 1e-10);
///```
pub fn acos(val: T) -> Degree<T>
{
let radians: Radian<T>;
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<f64>;
///
/// f = Degree::from(45.0f64);
/// assert!((45.0f64 - *Degree::asin(f.sin())) < 1e-10);
///```
pub fn asin(val: T) -> Degree<T>
{
let radians: Radian<T>;
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<f64>;
///
/// f = Degree::from(45.0f64);
/// assert!((45.0f64 - *Degree::atan(f.tan())) < 1e-10);
///```
pub fn atan(val: T) -> Degree<T>
{
let radians: Radian<T>;
radians = val.atan();
Degree::from(radians)
}
/// Inverse hyperbolic cosine function.
pub fn acosh(val: T) -> Degree<T>
{
let radians: Radian<T>;
radians = val.acosh();
Degree::from(radians)
}
/// Inverse hyperbolic sine function.
pub fn asinh(val: T) -> Degree<T>
{
let radians: Radian<T>;
radians = val.asinh();
Degree::from(radians)
}
/// Inverse hyperbolic tangent function.
pub fn atanh(val: T) -> Degree<T>
{
let radians: Radian<T>;
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<T>
{
let radians: Radian<T>;
radians = y.atan2(x);
Degree::from(radians)
}
/// Computes the cosine of this angle.
///
/// ```
/// use sigils::Degree;
/// use std::f64;
///
/// let x: Degree<f64> = 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<T>;
radians = Radian::from(*self);
radians.cos()
}
/// Computes the sine of this angle.
///
/// ```
/// use sigils::Degree;
/// use std::f64;
///
/// let x: Degree<f64> = 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<T>;
radians = Radian::from(*self);
radians.sin()
}
/// Computes the tangent of this angle.
///
/// ```
/// use sigils::Degree;
/// use std::f64;
///
/// let x: Degree<f64> = 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<T>;
radians = Radian::from(*self);
radians.tan()
}
/// Hyperbolic cosine function.
///
/// ```
/// use sigils::Degree;
/// use sigils::Constants;
///
/// let e32: f32 = Constants::E;
/// let x32: Degree<f32> = 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<f64> = 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<T>;
radians = Radian::from(*self);
radians.cosh()
}
/// Hyperbolic sine function.
///
/// ```
/// use sigils::Degree;
/// use sigils::Constants;
///
/// let e32: f32 = Constants::E;
/// let x32: Degree<f32> = 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<f64> = 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<T>;
radians = Radian::from(*self);
radians.sinh()
}
/// Hyperbolic tangent function.
///
/// ```
/// use sigils::Degree;
/// use sigils::Constants;
///
/// let e32: f32 = Constants::E;
/// let x32: Degree<f32> = 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<f64> = 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<T>;
radians = Radian::from(*self);
radians.tanh()
}
}
impl<T> ::std::ops::Deref for Degree<T> where T: Real
{
type Target = T;
fn deref(&self) -> &T
{
&self.value
}
}
impl<T> ::std::ops::DerefMut for Degree<T> 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<T> ::std::ops::Neg for Degree<T>
where T: Neg<Output = T>
{
type Output = Degree<T>;
fn neg(self) -> Degree<T>
{
let mut degrees: Degree<T>;
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<Degree<f32>> for f32
{
fn from(degrees: Degree<f32>) -> f32
{
degrees.value
}
}
impl ::std::convert::From<Degree<f64>> for f64
{
fn from(degrees: Degree<f64>) -> f64
{
degrees.value
}
}
impl<T> ::std::convert::From<T> for Degree<T> where T: Real
{
fn from(val: T) -> Degree<T>
{
Degree::new(val)
}
}
impl<T> ::std::convert::From<Radian<T>> for Degree<T> where T: Real
{
fn from(radians: Radian<T>) -> Degree<T>
{
let degs: T;
degs = radians.value * Constants::INVERSE_PI_DIVIDED_BY_180;
Degree::new(degs)
}
}
impl<T> ::std::fmt::Debug for Degree<T>
where T: Real
{
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result
{
::std::fmt::Display::fmt(self, f)
}
}
impl<T> ::std::fmt::Display for Degree<T>
where T: Real
{
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result
{
write!(f, "{}", self.value)
}
}
impl<T> Radian<T> where T: Real
{
/// Create a new Radian structure with the given value.
pub fn new(val: T) -> Radian<T>
{
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<f64>;
///
/// f = Radian::from(f64::PI / 4.0f64);
/// assert!(((f64::PI / 4.0f64) - *Radian::acos(f.cos())) < 1e-10);
///```
pub fn acos(val: T) -> Radian<T>
{
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<f64>;
///
/// f = Radian::from(f64::PI / 4.0f64);
/// assert!(((f64::PI / 4.0f64) - *Radian::asin(f.sin())) < 1e-10);
///```
pub fn asin(val: T) -> Radian<T>
{
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<f64>;
///
/// f = Radian::from(f64::PI / 4.0f64);
/// assert!(((f64::PI / 4.0f64) - *Radian::atan(f.tan())) < 1e-10);
///```
pub fn atan(val: T) -> Radian<T>
{
val.atan()
}
/// Inverse hyperbolic cosine function.
pub fn acosh(val: T) -> Radian<T>
{
val.acosh()
}
/// Inverse hyperbolic sine function.
pub fn asinh(val: T) -> Radian<T>
{
val.asinh()
}
/// Inverse hyperbolic tangent function.
pub fn atanh(val: T) -> Radian<T>
{
val.atanh()
}
/// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`).
pub fn atan2(y: T, x: T) -> Radian<T>
{
y.atan2(x)
}
/// Computes the cosine of this angle.
///
/// ```
/// use sigils::Radian;
/// use std::f64;
///
/// let x: Radian<f64> = 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<f64> = 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<f64> = 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<f32> = 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<f64> = 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<f32> = 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<f64> = 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<f32> = 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<f64> = 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<T> ::std::ops::Deref for Radian<T> where T: Real
{
type Target = T;
fn deref(&self) -> &T
{
&self.value
}
}
impl<T> ::std::ops::DerefMut for Radian<T> 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<T> ::std::ops::Neg for Radian<T>
where T: Neg<Output = T>
{
type Output = Radian<T>;
fn neg(self) -> Radian<T>
{
let mut radians: Radian<T>;
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<Radian<f32>> for f32
{
fn from(radians: Radian<f32>) -> f32
{
radians.value
}
}
impl ::std::convert::From<Radian<f64>> for f64
{
fn from(radians: Radian<f64>) -> f64
{
radians.value
}
}
impl<T> ::std::convert::From<T> for Radian<T> where T: Real
{
fn from(val: T) -> Radian<T>
{
Radian::new(val)
}
}
impl<T> ::std::convert::From<Degree<T>> for Radian<T>
where T: Real
{
fn from(degrees: Degree<T>) -> Radian<T>
{
let rads: T;
rads = degrees.value * Constants::PI_DIVIDED_BY_180;
Radian::new(rads)
}
}
impl<T> ::std::fmt::Debug for Radian<T>
where T: Real
{
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result
{
::std::fmt::Display::fmt(self, f)
}
}
impl<T> ::std::fmt::Display for Radian<T>
where T: Real
{
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result
{
write!(f, "{}", self.value)
}
}

134
src/trig/degree.rs Normal file
View File

@ -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<T>
{
value: T
}
impl<T> Degree<T> where T: Real
{
/// Create a new Degree structure with the given value.
pub fn new(val: T) -> Self
{
Degree
{
value: val
}
}
}
impl<T> ::std::ops::Deref for Degree<T> where T: Real
{
type Target = T;
fn deref(&self) -> &T
{
&self.value
}
}
impl<T> ::std::ops::DerefMut for Degree<T> 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<T> ::std::ops::Neg for Degree<T>
where T: Neg<Output = T>
{
type Output = Degree<T>;
fn neg(self) -> Degree<T>
{
let mut degree: Degree<T>;
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<Degree<f32>> for f32
{
fn from(degree: Degree<f32>) -> f32
{
degree.value
}
}
impl ::std::convert::From<Degree<f64>> for f64
{
fn from(degree: Degree<f64>) -> f64
{
degree.value
}
}
impl<T> ::std::convert::From<T> for Degree<T> where T: Real
{
fn from(val: T) -> Degree<T>
{
Degree::new(val)
}
}
impl<T> ::std::convert::From<Radian<T>> for Degree<T> where T: Real
{
fn from(radians: Radian<T>) -> Degree<T>
{
let degs: T;
degs = *radians * Constants::INVERSE_PI_DIVIDED_BY_180;
Degree::new(degs)
}
}
impl<T> ::std::fmt::Debug for Degree<T>
where T: Real
{
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result
{
::std::fmt::Display::fmt(self, f)
}
}
impl<T> ::std::fmt::Display for Degree<T>
where T: Real
{
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result
{
write!(f, "Degree({})", self.value)
}
}

15
src/trig/mod.rs Normal file
View File

@ -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;

133
src/trig/radian.rs Normal file
View File

@ -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<T>
{
value: T
}
impl<T> Radian<T> where T: Real
{
/// Create a new Radian structure with the given value.
pub fn new(val: T) -> Self
{
Radian
{
value: val
}
}
}
impl<T> ::std::ops::Deref for Radian<T> where T: Real
{
type Target = T;
fn deref(&self) -> &T
{
&self.value
}
}
impl<T> ::std::ops::DerefMut for Radian<T> 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<T> ::std::ops::Neg for Radian<T>
where T: Neg<Output = T>
{
type Output = Radian<T>;
fn neg(self) -> Radian<T>
{
let mut radian: Radian<T>;
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<Radian<f32>> for f32
{
fn from(radian: Radian<f32>) -> f32
{
radian.value
}
}
impl ::std::convert::From<Radian<f64>> for f64
{
fn from(radian: Radian<f64>) -> f64
{
radian.value
}
}
impl<T> ::std::convert::From<T> for Radian<T> where T: Real
{
fn from(val: T) -> Radian<T>
{
Radian::new(val)
}
}
impl<T> ::std::convert::From<Degree<T>> for Radian<T>
where T: Real
{
fn from(degrees: Degree<T>) -> Radian<T>
{
let rads: T;
rads = *degrees * Constants::PI_DIVIDED_BY_180;
Radian::new(rads)
}
}
impl<T> ::std::fmt::Debug for Radian<T>
where T: Real
{
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result
{
::std::fmt::Display::fmt(self, f)
}
}
impl<T> ::std::fmt::Display for Radian<T>
where T: Real
{
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result
{
write!(f, "Radian({})", self.value)
}
}

421
src/trig/trig.rs Normal file
View File

@ -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<f64> = Radian::from(2.0*f64::consts::PI);
///
/// let abs_difference = (x.cos() - 1.0).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
fn cos<T>(arg: T) -> Self
where T: Into<Radian<Self>>;
/// Computes the sine of this angle.
///
/// ```
/// use sigils::Radian;
/// use std::f64;
///
/// let x: Radian<f64> = Radian::from(f64::consts::PI/2.0);
///
/// let abs_difference = (x.sin() - 1.0).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
fn sin<T>(arg: T) -> Self
where T: Into<Radian<Self>>;
/// Computes the tangent of this angle.
///
/// ```
/// use sigils::Radian;
/// use std::f64;
///
/// let x: Radian<f64> = Radian::from(f64::consts::PI/4.0);
///
/// let abs_difference = (x.tan() - 1.0).abs();
///
/// assert!(abs_difference < 1e-14);
/// ```
fn tan<T>(arg: T) -> Self
where T: Into<Radian<Self>>;
/// 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<f64>;
///
/// f = Radian::from(f64::PI / 4.0f64);
/// assert!(((f64::PI / 4.0f64) - *Radian::acos(f.cos())) < 1e-10);
///```
fn acos<T>(arg: Self) -> T
where T: From<Radian<Self>>;
/// 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<f64>;
///
/// f = Radian::from(f64::PI / 4.0f64);
/// assert!(((f64::PI / 4.0f64) - *Radian::asin(f.sin())) < 1e-10);
///```
fn asin<T>(arg: Self) -> T
where T: From<Radian<Self>>;
/// 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<f64>;
///
/// f = Radian::from(f64::PI / 4.0f64);
/// assert!(((f64::PI / 4.0f64) - *Radian::atan(f.tan())) < 1e-10);
///```
fn atan<T>(arg: Self) -> T
where T: From<Radian<Self>>;
/// Computes the four quadrant arctangent of y and x.
fn atan2<T>(y: Self, x: Self) -> T
where T: From<Radian<Self>>;
/// Hyperbolic cosine function.
///
/// ```
/// use sigils::Radian;
/// use sigils::Constants;
///
/// let e32: f32 = Constants::E;
/// let x32: Radian<f32> = 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<f64> = 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<f32> = 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<f64> = 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<f32> = 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<f64> = 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<T>(arg: T) -> Self
where T: Into<Radian<Self>>
{
unsafe
{
::pact::cosf(*arg.into() as CFloat) as Self
}
}
fn sin<T>(arg: T) -> Self
where T: Into<Radian<Self>>
{
unsafe
{
::pact::sinf(*arg.into() as CFloat) as Self
}
}
fn tan<T>(arg: T) -> Self
where T: Into<Radian<Self>>
{
unsafe
{
::pact::tanf(*arg.into() as CFloat) as Self
}
}
fn acos<T>(arg: Self) -> T
where T: From<Radian<Self>>
{
unsafe
{
Radian::new(::pact::acosf(arg as CFloat) as Self).into()
}
}
fn asin<T>(arg: Self) -> T
where T: From<Radian<Self>>
{
unsafe
{
Radian::new(::pact::asinf(arg as CFloat) as Self).into()
}
}
fn atan<T>(arg: Self) -> T
where T: From<Radian<Self>>
{
unsafe
{
Radian::new(::pact::atanf(arg as CFloat) as Self).into()
}
}
fn atan2<T>(y: Self, x: Self) -> T
where T: From<Radian<Self>>
{
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<T>(arg: T) -> Self
where T: Into<Radian<Self>>
{
unsafe
{
::pact::cos(*arg.into() as CDouble) as Self
}
}
fn sin<T>(arg: T) -> Self
where T: Into<Radian<Self>>
{
unsafe
{
::pact::sin(*arg.into() as CDouble) as Self
}
}
fn tan<T>(arg: T) -> Self
where T: Into<Radian<Self>>
{
unsafe
{
::pact::tan(*arg.into() as CDouble) as Self
}
}
fn acos<T>(arg: Self) -> T
where T: From<Radian<Self>>
{
unsafe
{
Radian::new(::pact::acos(arg as CDouble) as Self).into()
}
}
fn asin<T>(arg: Self) -> T
where T: From<Radian<Self>>
{
unsafe
{
Radian::new(::pact::asin(arg as CDouble) as Self).into()
}
}
fn atan<T>(arg: Self) -> T
where T: From<Radian<Self>>
{
unsafe
{
Radian::new(::pact::atan(arg as CDouble) as Self).into()
}
}
fn atan2<T>(y: Self, x: Self) -> T
where T: From<Radian<Self>>
{
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
}
}
}

View File

@ -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<T>: Debug + Display + Clone + Default + Zero + One
/// Defines the [EuclideanVector][1] trait.
///
/// [1]: https://en.wikipedia.org/wiki/Euclidean_vector
pub trait EuclideanVector<T> : Vector<T> where T: Real
pub trait EuclideanVector<T> : Vector<T> 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<T> Vector4<T> where T: Number
}
// Implement the angle specific portion of the EuclideanVector.
impl<T> EuclideanVector<T> for Vector2<T> where T: Real
impl<T> EuclideanVector<T> for Vector2<T> where T: Trig
{
fn angle(&self, vector: &Vector2<T>) -> Radian<T>
{
// Shortcut.
Radian::atan2(self.perpendicular_dot(vector), self.dot(vector))
Trig::atan2(self.perpendicular_dot(vector), self.dot(vector))
}
}
impl<T> EuclideanVector<T> for Vector3<T> where T: Real
impl<T> EuclideanVector<T> for Vector3<T> where T: Trig
{
fn angle(&self, vector: &Vector3<T>) -> Radian<T>
{
// Shortcut.
Radian::atan2(self.cross(vector).get_length(), self.dot(vector))
Trig::atan2(self.cross(vector).get_length(), self.dot(vector))
}
}
impl<T> EuclideanVector<T> for Vector4<T> where T: Real
impl<T> EuclideanVector<T> for Vector4<T> where T: Trig
{
fn angle(&self, vector: &Vector4<T>) -> Radian<T>
{
// 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()))
}
}