Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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::str::FromStr;

pub use num_traits::float::FloatCore;
use num_traits::real::Real;

Check failure on line 27 in src/lib.rs

View workflow job for this annotation

GitHub Actions / Tests (stable)

unresolved import `num_traits::real`
use num_traits::{
AsPrimitive, Bounded, FloatConst, FromPrimitive, Num, NumCast, One, Signed, ToPrimitive, Zero,
};
Expand Down Expand Up @@ -1957,6 +1958,170 @@
}
}

#[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
Loading