Skip to content

Implements num_traits::real::Real for NotNan<T> #176

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 165 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use core::ops::{
use core::str::FromStr;

pub use num_traits::float::FloatCore;
use num_traits::real::Real;
use num_traits::{
AsPrimitive, Bounded, FloatConst, FromPrimitive, Num, NumCast, One, Signed, ToPrimitive, Zero,
};
Expand Down Expand Up @@ -1957,6 +1958,170 @@ impl<T: FloatCore> NumCast for NotNan<T> {
}
}

#[cfg(any(feature = "std", feature = "libm"))]
impl<T: Real + FloatCore> Real for NotNan<T> {
fn min_value() -> Self {
NotNan(<T as Real>::min_value())
}
fn min_positive_value() -> Self {
NotNan(<T as Real>::min_positive_value())
}
fn epsilon() -> Self {
NotNan(Real::epsilon())
}
fn max_value() -> Self {
NotNan(<T as Real>::max_value())
}
fn floor(self) -> Self {
NotNan(Real::floor(self.0))
}
fn ceil(self) -> Self {
NotNan(Real::ceil(self.0))
}
fn round(self) -> Self {
NotNan(Real::round(self.0))
}
fn trunc(self) -> Self {
NotNan(Real::trunc(self.0))
}
fn fract(self) -> Self {
NotNan(Real::fract(self.0))
}
fn abs(self) -> Self {
NotNan(Real::abs(self.0))
}
fn signum(self) -> Self {
NotNan(Real::signum(self.0))
}
fn is_sign_positive(self) -> bool {
Real::is_sign_positive(self.0)
}
fn is_sign_negative(self) -> bool {
Real::is_sign_negative(self.0)
}
fn mul_add(self, a: Self, b: Self) -> Self {
NotNan(self.0.mul_add(a.0, b.0))
}
fn recip(self) -> Self {
NotNan(Real::recip(self.0))
}
fn powi(self, n: i32) -> Self {
NotNan(Real::powi(self.0, n))
}
fn powf(self, n: Self) -> Self {
// Panics if self < 0 and n is not an integer
NotNan::new(self.0.powf(n.0)).expect("Power resulted in NaN")
}
fn sqrt(self) -> Self {
// Panics if self < 0
NotNan::new(self.0.sqrt()).expect("Square root resulted in NaN")
}
fn exp(self) -> Self {
NotNan(self.0.exp())
}
fn exp2(self) -> Self {
NotNan(self.0.exp2())
}
fn ln(self) -> Self {
// Panics if self <= 0
NotNan::new(self.0.ln()).expect("Natural logarithm resulted in NaN")
}
fn log(self, base: Self) -> Self {
// Panics if self <= 0 or base <= 0
NotNan::new(self.0.log(base.0)).expect("Logarithm resulted in NaN")
}
fn log2(self) -> Self {
// Panics if self <= 0
NotNan::new(self.0.log2()).expect("Logarithm resulted in NaN")
}
fn log10(self) -> Self {
// Panics if self <= 0
NotNan::new(self.0.log10()).expect("Logarithm resulted in NaN")
}
fn to_degrees(self) -> Self {
NotNan(Real::to_degrees(self.0))
}
fn to_radians(self) -> Self {
NotNan(Real::to_radians(self.0))
}
fn max(self, other: Self) -> Self {
NotNan(Real::max(self.0, other.0))
}
fn min(self, other: Self) -> Self {
NotNan(Real::min(self.0, other.0))
}
fn abs_sub(self, other: Self) -> Self {
NotNan(self.0.abs_sub(other.0))
}
fn cbrt(self) -> Self {
NotNan(self.0.cbrt())
}
fn hypot(self, other: Self) -> Self {
NotNan(self.0.hypot(other.0))
}
fn sin(self) -> Self {
// Panics if self is +/-infinity
NotNan::new(self.0.sin()).expect("Sine resulted in NaN")
}
fn cos(self) -> Self {
// Panics if self is +/-infinity
NotNan::new(self.0.cos()).expect("Cosine resulted in NaN")
}
fn tan(self) -> Self {
// Panics if self is +/-infinity or self == pi/2 + k*pi
NotNan::new(self.0.tan()).expect("Tangent resulted in NaN")
}
fn asin(self) -> Self {
// Panics if self < -1.0 or self > 1.0
NotNan::new(self.0.asin()).expect("Arcsine resulted in NaN")
}
fn acos(self) -> Self {
// Panics if self < -1.0 or self > 1.0
NotNan::new(self.0.acos()).expect("Arccosine resulted in NaN")
}
fn atan(self) -> Self {
NotNan(self.0.atan())
}
fn atan2(self, other: Self) -> Self {
NotNan(self.0.atan2(other.0))
}
fn sin_cos(self) -> (Self, Self) {
// Panics if self is +/-infinity
let (a, b) = self.0.sin_cos();
(
NotNan::new(a).expect("Sine resulted in NaN"),
NotNan::new(b).expect("Cosine resulted in NaN"),
)
}
fn exp_m1(self) -> Self {
NotNan(self.0.exp_m1())
}
fn ln_1p(self) -> Self {
// Panics if self <= -1.0
NotNan::new(self.0.ln_1p()).expect("Natural logarithm resulted in NaN")
}
fn sinh(self) -> Self {
NotNan(self.0.sinh())
}
fn cosh(self) -> Self {
NotNan(self.0.cosh())
}
fn tanh(self) -> Self {
NotNan(self.0.tanh())
}
fn asinh(self) -> Self {
NotNan(self.0.asinh())
}
fn acosh(self) -> Self {
// Panics if self < 1.0
NotNan::new(self.0.acosh()).expect("Arccosh resulted in NaN")
}
fn atanh(self) -> Self {
// Panics if self < -1.0 or self > 1.0
NotNan::new(self.0.atanh()).expect("Arctanh resulted in NaN")
}
}

macro_rules! impl_float_const_method {
($wrapper:expr, $method:ident) => {
#[allow(non_snake_case)]
Expand Down
128 changes: 128 additions & 0 deletions tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -772,6 +772,134 @@ fn test_ref_ref_binop_regression() {
assert_eq!(&x - &y, OrderedFloat(10.0));
}

#[cfg(any(feature = "std", feature = "libm"))]
#[test]
#[should_panic]
fn test_powf_fails_on_negative() {
use num_traits::real::Real;
Real::powf(not_nan(-1.0), not_nan(-1.5));
}

#[cfg(any(feature = "std", feature = "libm"))]
#[test]
#[should_panic]
fn test_sqrt_fails_on_negative() {
use num_traits::real::Real;
Real::sqrt(not_nan(-1.0));
}

#[cfg(any(feature = "std", feature = "libm"))]
#[test]
#[should_panic]
fn test_ln_fails_on_negative() {
use num_traits::real::Real;
Real::ln(not_nan(-1.0));
}

#[cfg(any(feature = "std", feature = "libm"))]
#[test]
#[should_panic]
fn test_log_fails_on_negative() {
use num_traits::real::Real;
Real::log(not_nan(-1.0), not_nan(2.0));
}

#[cfg(any(feature = "std", feature = "libm"))]
#[test]
#[should_panic]
fn test_log_fails_on_negative_base() {
use num_traits::real::Real;
Real::log(not_nan(1.0), not_nan(-2.0));
}

#[cfg(any(feature = "std", feature = "libm"))]
#[test]
#[should_panic]
fn test_log2_fails_on_negative() {
use num_traits::real::Real;
Real::log2(not_nan(-1.0));
}

#[cfg(any(feature = "std", feature = "libm"))]
#[test]
#[should_panic]
fn test_log10_fails_on_negative() {
use num_traits::real::Real;
Real::log10(not_nan(-1.0));
}

#[cfg(any(feature = "std", feature = "libm"))]
#[test]
#[should_panic]
fn test_sin_fails_on_infinite() {
use num_traits::real::Real;
Real::sin(not_nan(f64::INFINITY));
}

#[cfg(any(feature = "std", feature = "libm"))]
#[test]
#[should_panic]
fn test_cos_fails_on_infinite() {
use num_traits::real::Real;
Real::cos(not_nan(f64::INFINITY));
}

#[cfg(any(feature = "std", feature = "libm"))]
#[test]
#[should_panic]
fn test_tan_fails_on_infinite() {
use num_traits::real::Real;
Real::tan(not_nan(f64::INFINITY));
}

#[cfg(any(feature = "std", feature = "libm"))]
#[test]
#[should_panic]
fn test_asin_fails_on_big() {
use num_traits::real::Real;
Real::asin(not_nan(10.0));
}

#[cfg(any(feature = "std", feature = "libm"))]
#[test]
#[should_panic]
fn test_acos_fails_on_big() {
use num_traits::real::Real;
Real::acos(not_nan(10.0));
}

#[cfg(any(feature = "std", feature = "libm"))]
#[test]
#[should_panic]
fn test_sin_cos_fails_on_infinite() {
use num_traits::real::Real;
Real::sin_cos(not_nan(f64::INFINITY));
}

#[cfg(any(feature = "std", feature = "libm"))]
#[test]
#[should_panic]
fn test_ln_1p_fails_on_negative() {
use num_traits::real::Real;
Real::ln_1p(not_nan(-1.1));
}

#[cfg(any(feature = "std", feature = "libm"))]
#[test]
#[should_panic]
fn test_acosh_fails_on_zero() {
use num_traits::real::Real;
Real::acosh(not_nan(-0.0));
}

#[cfg(any(feature = "std", feature = "libm"))]
#[test]
#[should_panic]
fn test_atanh_fails_on_big() {
use num_traits::real::Real;
Real::atanh(not_nan(10.0));
}

#[cfg(feature = "arbitrary")]
mod arbitrary_test {
use super::{NotNan, OrderedFloat};
Expand Down