Skip to content

Commit 1841f05

Browse files
authored
Merge pull request #176 from DouisLavid/master
Implements num_traits::real::Real for NotNan<T>
2 parents abc0019 + 1ae6383 commit 1841f05

File tree

2 files changed

+294
-0
lines changed

2 files changed

+294
-0
lines changed

src/lib.rs

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ use core::ops::{
2424
use core::str::FromStr;
2525

2626
pub use num_traits::float::FloatCore;
27+
#[cfg(any(feature = "std", feature = "libm"))]
28+
use num_traits::real::Real;
2729
use num_traits::{
2830
AsPrimitive, Bounded, FloatConst, FromPrimitive, Num, NumCast, One, Signed, ToPrimitive, Zero,
2931
};
@@ -1957,6 +1959,170 @@ impl<T: FloatCore> NumCast for NotNan<T> {
19571959
}
19581960
}
19591961

1962+
#[cfg(any(feature = "std", feature = "libm"))]
1963+
impl<T: Real + FloatCore> Real for NotNan<T> {
1964+
fn min_value() -> Self {
1965+
NotNan(<T as Real>::min_value())
1966+
}
1967+
fn min_positive_value() -> Self {
1968+
NotNan(<T as Real>::min_positive_value())
1969+
}
1970+
fn epsilon() -> Self {
1971+
NotNan(Real::epsilon())
1972+
}
1973+
fn max_value() -> Self {
1974+
NotNan(<T as Real>::max_value())
1975+
}
1976+
fn floor(self) -> Self {
1977+
NotNan(Real::floor(self.0))
1978+
}
1979+
fn ceil(self) -> Self {
1980+
NotNan(Real::ceil(self.0))
1981+
}
1982+
fn round(self) -> Self {
1983+
NotNan(Real::round(self.0))
1984+
}
1985+
fn trunc(self) -> Self {
1986+
NotNan(Real::trunc(self.0))
1987+
}
1988+
fn fract(self) -> Self {
1989+
NotNan(Real::fract(self.0))
1990+
}
1991+
fn abs(self) -> Self {
1992+
NotNan(Real::abs(self.0))
1993+
}
1994+
fn signum(self) -> Self {
1995+
NotNan(Real::signum(self.0))
1996+
}
1997+
fn is_sign_positive(self) -> bool {
1998+
Real::is_sign_positive(self.0)
1999+
}
2000+
fn is_sign_negative(self) -> bool {
2001+
Real::is_sign_negative(self.0)
2002+
}
2003+
fn mul_add(self, a: Self, b: Self) -> Self {
2004+
NotNan(self.0.mul_add(a.0, b.0))
2005+
}
2006+
fn recip(self) -> Self {
2007+
NotNan(Real::recip(self.0))
2008+
}
2009+
fn powi(self, n: i32) -> Self {
2010+
NotNan(Real::powi(self.0, n))
2011+
}
2012+
fn powf(self, n: Self) -> Self {
2013+
// Panics if self < 0 and n is not an integer
2014+
NotNan::new(self.0.powf(n.0)).expect("Power resulted in NaN")
2015+
}
2016+
fn sqrt(self) -> Self {
2017+
// Panics if self < 0
2018+
NotNan::new(self.0.sqrt()).expect("Square root resulted in NaN")
2019+
}
2020+
fn exp(self) -> Self {
2021+
NotNan(self.0.exp())
2022+
}
2023+
fn exp2(self) -> Self {
2024+
NotNan(self.0.exp2())
2025+
}
2026+
fn ln(self) -> Self {
2027+
// Panics if self <= 0
2028+
NotNan::new(self.0.ln()).expect("Natural logarithm resulted in NaN")
2029+
}
2030+
fn log(self, base: Self) -> Self {
2031+
// Panics if self <= 0 or base <= 0
2032+
NotNan::new(self.0.log(base.0)).expect("Logarithm resulted in NaN")
2033+
}
2034+
fn log2(self) -> Self {
2035+
// Panics if self <= 0
2036+
NotNan::new(self.0.log2()).expect("Logarithm resulted in NaN")
2037+
}
2038+
fn log10(self) -> Self {
2039+
// Panics if self <= 0
2040+
NotNan::new(self.0.log10()).expect("Logarithm resulted in NaN")
2041+
}
2042+
fn to_degrees(self) -> Self {
2043+
NotNan(Real::to_degrees(self.0))
2044+
}
2045+
fn to_radians(self) -> Self {
2046+
NotNan(Real::to_radians(self.0))
2047+
}
2048+
fn max(self, other: Self) -> Self {
2049+
NotNan(Real::max(self.0, other.0))
2050+
}
2051+
fn min(self, other: Self) -> Self {
2052+
NotNan(Real::min(self.0, other.0))
2053+
}
2054+
fn abs_sub(self, other: Self) -> Self {
2055+
NotNan(self.0.abs_sub(other.0))
2056+
}
2057+
fn cbrt(self) -> Self {
2058+
NotNan(self.0.cbrt())
2059+
}
2060+
fn hypot(self, other: Self) -> Self {
2061+
NotNan(self.0.hypot(other.0))
2062+
}
2063+
fn sin(self) -> Self {
2064+
// Panics if self is +/-infinity
2065+
NotNan::new(self.0.sin()).expect("Sine resulted in NaN")
2066+
}
2067+
fn cos(self) -> Self {
2068+
// Panics if self is +/-infinity
2069+
NotNan::new(self.0.cos()).expect("Cosine resulted in NaN")
2070+
}
2071+
fn tan(self) -> Self {
2072+
// Panics if self is +/-infinity or self == pi/2 + k*pi
2073+
NotNan::new(self.0.tan()).expect("Tangent resulted in NaN")
2074+
}
2075+
fn asin(self) -> Self {
2076+
// Panics if self < -1.0 or self > 1.0
2077+
NotNan::new(self.0.asin()).expect("Arcsine resulted in NaN")
2078+
}
2079+
fn acos(self) -> Self {
2080+
// Panics if self < -1.0 or self > 1.0
2081+
NotNan::new(self.0.acos()).expect("Arccosine resulted in NaN")
2082+
}
2083+
fn atan(self) -> Self {
2084+
NotNan(self.0.atan())
2085+
}
2086+
fn atan2(self, other: Self) -> Self {
2087+
NotNan(self.0.atan2(other.0))
2088+
}
2089+
fn sin_cos(self) -> (Self, Self) {
2090+
// Panics if self is +/-infinity
2091+
let (a, b) = self.0.sin_cos();
2092+
(
2093+
NotNan::new(a).expect("Sine resulted in NaN"),
2094+
NotNan::new(b).expect("Cosine resulted in NaN"),
2095+
)
2096+
}
2097+
fn exp_m1(self) -> Self {
2098+
NotNan(self.0.exp_m1())
2099+
}
2100+
fn ln_1p(self) -> Self {
2101+
// Panics if self <= -1.0
2102+
NotNan::new(self.0.ln_1p()).expect("Natural logarithm resulted in NaN")
2103+
}
2104+
fn sinh(self) -> Self {
2105+
NotNan(self.0.sinh())
2106+
}
2107+
fn cosh(self) -> Self {
2108+
NotNan(self.0.cosh())
2109+
}
2110+
fn tanh(self) -> Self {
2111+
NotNan(self.0.tanh())
2112+
}
2113+
fn asinh(self) -> Self {
2114+
NotNan(self.0.asinh())
2115+
}
2116+
fn acosh(self) -> Self {
2117+
// Panics if self < 1.0
2118+
NotNan::new(self.0.acosh()).expect("Arccosh resulted in NaN")
2119+
}
2120+
fn atanh(self) -> Self {
2121+
// Panics if self < -1.0 or self > 1.0
2122+
NotNan::new(self.0.atanh()).expect("Arctanh resulted in NaN")
2123+
}
2124+
}
2125+
19602126
macro_rules! impl_float_const_method {
19612127
($wrapper:expr, $method:ident) => {
19622128
#[allow(non_snake_case)]

tests/test.rs

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,134 @@ fn test_ref_ref_binop_regression() {
772772
assert_eq!(&x - &y, OrderedFloat(10.0));
773773
}
774774

775+
#[cfg(any(feature = "std", feature = "libm"))]
776+
#[test]
777+
#[should_panic]
778+
fn test_powf_fails_on_negative() {
779+
use num_traits::real::Real;
780+
Real::powf(not_nan(-1.0), not_nan(-1.5));
781+
}
782+
783+
#[cfg(any(feature = "std", feature = "libm"))]
784+
#[test]
785+
#[should_panic]
786+
fn test_sqrt_fails_on_negative() {
787+
use num_traits::real::Real;
788+
Real::sqrt(not_nan(-1.0));
789+
}
790+
791+
#[cfg(any(feature = "std", feature = "libm"))]
792+
#[test]
793+
#[should_panic]
794+
fn test_ln_fails_on_negative() {
795+
use num_traits::real::Real;
796+
Real::ln(not_nan(-1.0));
797+
}
798+
799+
#[cfg(any(feature = "std", feature = "libm"))]
800+
#[test]
801+
#[should_panic]
802+
fn test_log_fails_on_negative() {
803+
use num_traits::real::Real;
804+
Real::log(not_nan(-1.0), not_nan(2.0));
805+
}
806+
807+
#[cfg(any(feature = "std", feature = "libm"))]
808+
#[test]
809+
#[should_panic]
810+
fn test_log_fails_on_negative_base() {
811+
use num_traits::real::Real;
812+
Real::log(not_nan(1.0), not_nan(-2.0));
813+
}
814+
815+
#[cfg(any(feature = "std", feature = "libm"))]
816+
#[test]
817+
#[should_panic]
818+
fn test_log2_fails_on_negative() {
819+
use num_traits::real::Real;
820+
Real::log2(not_nan(-1.0));
821+
}
822+
823+
#[cfg(any(feature = "std", feature = "libm"))]
824+
#[test]
825+
#[should_panic]
826+
fn test_log10_fails_on_negative() {
827+
use num_traits::real::Real;
828+
Real::log10(not_nan(-1.0));
829+
}
830+
831+
#[cfg(any(feature = "std", feature = "libm"))]
832+
#[test]
833+
#[should_panic]
834+
fn test_sin_fails_on_infinite() {
835+
use num_traits::real::Real;
836+
Real::sin(not_nan(f64::INFINITY));
837+
}
838+
839+
#[cfg(any(feature = "std", feature = "libm"))]
840+
#[test]
841+
#[should_panic]
842+
fn test_cos_fails_on_infinite() {
843+
use num_traits::real::Real;
844+
Real::cos(not_nan(f64::INFINITY));
845+
}
846+
847+
#[cfg(any(feature = "std", feature = "libm"))]
848+
#[test]
849+
#[should_panic]
850+
fn test_tan_fails_on_infinite() {
851+
use num_traits::real::Real;
852+
Real::tan(not_nan(f64::INFINITY));
853+
}
854+
855+
#[cfg(any(feature = "std", feature = "libm"))]
856+
#[test]
857+
#[should_panic]
858+
fn test_asin_fails_on_big() {
859+
use num_traits::real::Real;
860+
Real::asin(not_nan(10.0));
861+
}
862+
863+
#[cfg(any(feature = "std", feature = "libm"))]
864+
#[test]
865+
#[should_panic]
866+
fn test_acos_fails_on_big() {
867+
use num_traits::real::Real;
868+
Real::acos(not_nan(10.0));
869+
}
870+
871+
#[cfg(any(feature = "std", feature = "libm"))]
872+
#[test]
873+
#[should_panic]
874+
fn test_sin_cos_fails_on_infinite() {
875+
use num_traits::real::Real;
876+
Real::sin_cos(not_nan(f64::INFINITY));
877+
}
878+
879+
#[cfg(any(feature = "std", feature = "libm"))]
880+
#[test]
881+
#[should_panic]
882+
fn test_ln_1p_fails_on_negative() {
883+
use num_traits::real::Real;
884+
Real::ln_1p(not_nan(-1.1));
885+
}
886+
887+
#[cfg(any(feature = "std", feature = "libm"))]
888+
#[test]
889+
#[should_panic]
890+
fn test_acosh_fails_on_zero() {
891+
use num_traits::real::Real;
892+
Real::acosh(not_nan(-0.0));
893+
}
894+
895+
#[cfg(any(feature = "std", feature = "libm"))]
896+
#[test]
897+
#[should_panic]
898+
fn test_atanh_fails_on_big() {
899+
use num_traits::real::Real;
900+
Real::atanh(not_nan(10.0));
901+
}
902+
775903
#[cfg(feature = "arbitrary")]
776904
mod arbitrary_test {
777905
use super::{NotNan, OrderedFloat};

0 commit comments

Comments
 (0)