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

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