From b62908d4260d1e3a9806a70e37aead2ea803a912 Mon Sep 17 00:00:00 2001 From: Adam Reichold Date: Tue, 5 May 2020 15:12:25 +0200 Subject: [PATCH] Implement inverse trigonometric functions from ratio to angle. --- src/si/angle.rs | 25 ++++++++++++++ src/si/ratio.rs | 89 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) diff --git a/src/si/angle.rs b/src/si/angle.rs index a7b4d87c..13857507 100644 --- a/src/si/angle.rs +++ b/src/si/angle.rs @@ -76,6 +76,22 @@ where } } +#[cfg(feature = "std")] +impl ::si::Quantity +where + D: ::si::Dimension + ?Sized, + U: ::si::Units + ?Sized, + V: ::num::Float + ::Conversion, + radian: ::Conversion, +{ + /// Computes the four quadrant arctangent of self (y) and other (x). + #[inline(always)] + pub fn atan2(self, other: Self) -> Angle + { + Angle::new::(self.value.atan2(other.value)) + } +} + mod convert { use super::*; @@ -148,6 +164,7 @@ mod tests { use ::lib::f64::consts::PI; use num::{FromPrimitive, Zero}; use si::angle as a; + use si::length as l; use si::quantities::*; use tests::Test; @@ -190,6 +207,14 @@ mod tests { Test::assert_approx_eq(&zero.tanh(), &0.0); Test::assert_approx_eq(&nzero.tanh(), &0.0); } + + quickcheck! { + #[allow(trivial_casts)] + fn atan2(y: V, x: V) -> bool { + Test::eq(&y.atan2(x), + &Length::new::(y).atan2(Length::new::(x)).get::()) + } + } } } } diff --git a/src/si/ratio.rs b/src/si/ratio.rs index bd0d4942..4a3f853b 100644 --- a/src/si/ratio.rs +++ b/src/si/ratio.rs @@ -1,5 +1,8 @@ //! Ratio (dimensionless quantity). +#[cfg(feature = "std")] +use super::angle::{Angle, radian}; + quantity! { /// Ratio (dimensionless quantity). quantity: Ratio; "ratio"; @@ -29,6 +32,51 @@ quantity! { } } +/// Implementation of various stdlib inverse trigonometric functions +#[cfg(feature = "std")] +impl Ratio +where + U: ::si::Units + ?Sized, + V: ::num::Float + ::Conversion, + radian: ::Conversion, +{ + /// Computes the value of the inverse cosine of the ratio. + #[inline(always)] + pub fn acos(self) -> Angle { + Angle::new::(self.value.acos()) + } + + /// Computes the value of the inverse hyperbolic cosine of the ratio. + #[inline(always)] + pub fn acosh(self) -> Angle { + Angle::new::(self.value.acosh()) + } + + /// Computes the value of the inverse sine of the ratio. + #[inline(always)] + pub fn asin(self) -> Angle { + Angle::new::(self.value.asin()) + } + + /// Computes the value of the inverse hyperbolic sine of the ratio. + #[inline(always)] + pub fn asinh(self) -> Angle { + Angle::new::(self.value.asinh()) + } + + /// Computes the value of the inverse tangent of the ratio. + #[inline(always)] + pub fn atan(self) -> Angle { + Angle::new::(self.value.atan()) + } + + /// Computes the value of the inverse hyperbolic tangent of the ratio. + #[inline(always)] + pub fn atanh(self) -> Angle { + Angle::new::(self.value.atanh()) + } +} + mod convert { use super::*; @@ -103,4 +151,45 @@ mod tests { &Ratio::new::(V::one())); } } + + #[cfg(feature = "std")] + mod inv_trig { + storage_types! { + types: Float; + + use si::angle as a; + use si::quantities::*; + use tests::Test; + + fn test_nan_or_eq(yl: V, yr: V) -> bool { + (yl.is_nan() && yr.is_nan()) || Test::eq(&yl, &yr) + } + + quickcheck! { + fn acos(x: V) -> bool { + test_nan_or_eq(x.acos(), Ratio::from(x).acos().get::()) + } + + fn acosh(x: V) -> bool { + test_nan_or_eq(x.acosh(), Ratio::from(x).acosh().get::()) + } + + fn asin(x: V) -> bool { + test_nan_or_eq(x.asin(), Ratio::from(x).asin().get::()) + } + + fn asinh(x: V) -> bool { + test_nan_or_eq(x.asinh(), Ratio::from(x).asinh().get::()) + } + + fn atan(x: V) -> bool { + test_nan_or_eq(x.atan(), Ratio::from(x).atan().get::()) + } + + fn atanh(x: V) -> bool { + test_nan_or_eq(x.atanh(), Ratio::from(x).atanh().get::()) + } + } + } + } }