diff --git a/src/libcore/core.rc b/src/libcore/core.rc index 2a8de6a8032..0a24fba6663 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -105,6 +105,7 @@ pub use iter::{ExtendedMutableIter}; pub use num::{Num, NumCast}; pub use num::{Signed, Unsigned, Integer}; +pub use num::{Fractional, Real, RealExt}; pub use ptr::Ptr; pub use to_str::ToStr; pub use clone::Clone; diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 9e4140adcd1..57ac6c55176 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -327,31 +327,176 @@ impl Signed for f32 { fn is_negative(&self) -> bool { *self < 0.0 || (1.0 / *self) == neg_infinity } } -impl num::Round for f32 { +impl Fractional for f32 { + /// The reciprocal (multiplicative inverse) of the number #[inline(always)] - fn round(&self, mode: num::RoundMode) -> f32 { - match mode { - num::RoundDown => floor(*self), - num::RoundUp => ceil(*self), - num::RoundToZero if self.is_negative() => ceil(*self), - num::RoundToZero => floor(*self), - num::RoundFromZero if self.is_negative() => floor(*self), - num::RoundFromZero => ceil(*self) - } - } + fn recip(&self) -> f32 { 1.0 / *self } +} + +impl Real for f32 { + /// Archimedes' constant + #[inline(always)] + fn pi() -> f32 { 3.14159265358979323846264338327950288 } + + /// 2.0 * pi + #[inline(always)] + fn two_pi() -> f32 { 6.28318530717958647692528676655900576 } + + /// pi / 2.0 + #[inline(always)] + fn frac_pi_2() -> f32 { 1.57079632679489661923132169163975144 } + + /// pi / 3.0 + #[inline(always)] + fn frac_pi_3() -> f32 { 1.04719755119659774615421446109316763 } + + /// pi / 4.0 + #[inline(always)] + fn frac_pi_4() -> f32 { 0.785398163397448309615660845819875721 } + + /// pi / 6.0 + #[inline(always)] + fn frac_pi_6() -> f32 { 0.52359877559829887307710723054658381 } + + /// pi / 8.0 + #[inline(always)] + fn frac_pi_8() -> f32 { 0.39269908169872415480783042290993786 } + + /// 1 .0/ pi + #[inline(always)] + fn frac_1_pi() -> f32 { 0.318309886183790671537767526745028724 } + + /// 2.0 / pi + #[inline(always)] + fn frac_2_pi() -> f32 { 0.636619772367581343075535053490057448 } + + /// 2.0 / sqrt(pi) + #[inline(always)] + fn frac_2_sqrtpi() -> f32 { 1.12837916709551257389615890312154517 } + + /// sqrt(2.0) + #[inline(always)] + fn sqrt2() -> f32 { 1.41421356237309504880168872420969808 } + + /// 1.0 / sqrt(2.0) + #[inline(always)] + fn frac_1_sqrt2() -> f32 { 0.707106781186547524400844362104849039 } + + /// Euler's number + #[inline(always)] + fn e() -> f32 { 2.71828182845904523536028747135266250 } + + /// log2(e) + #[inline(always)] + fn log2_e() -> f32 { 1.44269504088896340735992468100189214 } + + /// log10(e) + #[inline(always)] + fn log10_e() -> f32 { 0.434294481903251827651128918916605082 } + + /// log(2.0) + #[inline(always)] + fn log_2() -> f32 { 0.693147180559945309417232121458176568 } + + /// log(10.0) + #[inline(always)] + fn log_10() -> f32 { 2.30258509299404568401799145468436421 } #[inline(always)] fn floor(&self) -> f32 { floor(*self) } + #[inline(always)] fn ceil(&self) -> f32 { ceil(*self) } + #[inline(always)] - fn fract(&self) -> f32 { - if self.is_negative() { - (*self) - ceil(*self) - } else { - (*self) - floor(*self) - } - } + fn round(&self) -> f32 { round(*self) } + + #[inline(always)] + fn trunc(&self) -> f32 { trunc(*self) } + + /// The fractional part of the number, calculated using: `n - floor(n)` + #[inline(always)] + fn fract(&self) -> f32 { *self - self.floor() } + + #[inline(always)] + fn pow(&self, n: f32) -> f32 { pow(*self, n) } + + #[inline(always)] + fn exp(&self) -> f32 { exp(*self) } + + #[inline(always)] + fn exp2(&self) -> f32 { exp2(*self) } + + #[inline(always)] + fn expm1(&self) -> f32 { expm1(*self) } + + #[inline(always)] + fn ldexp(&self, n: int) -> f32 { ldexp(*self, n as c_int) } + + #[inline(always)] + fn log(&self) -> f32 { ln(*self) } + + #[inline(always)] + fn log2(&self) -> f32 { log2(*self) } + + #[inline(always)] + fn log10(&self) -> f32 { log10(*self) } + + #[inline(always)] + fn log_radix(&self) -> f32 { log_radix(*self) as f32 } + + #[inline(always)] + fn ilog_radix(&self) -> int { ilog_radix(*self) as int } + + #[inline(always)] + fn sqrt(&self) -> f32 { sqrt(*self) } + + #[inline(always)] + fn rsqrt(&self) -> f32 { self.sqrt().recip() } + + #[inline(always)] + fn cbrt(&self) -> f32 { cbrt(*self) } + + /// Converts to degrees, assuming the number is in radians + #[inline(always)] + fn to_degrees(&self) -> f32 { *self * (180.0 / Real::pi::()) } + + /// Converts to radians, assuming the number is in degrees + #[inline(always)] + fn to_radians(&self) -> f32 { *self * (Real::pi::() / 180.0) } + + #[inline(always)] + fn hypot(&self, other: f32) -> f32 { hypot(*self, other) } + + #[inline(always)] + fn sin(&self) -> f32 { sin(*self) } + + #[inline(always)] + fn cos(&self) -> f32 { cos(*self) } + + #[inline(always)] + fn tan(&self) -> f32 { tan(*self) } + + #[inline(always)] + fn asin(&self) -> f32 { asin(*self) } + + #[inline(always)] + fn acos(&self) -> f32 { acos(*self) } + + #[inline(always)] + fn atan(&self) -> f32 { atan(*self) } + + #[inline(always)] + fn atan2(&self, other: f32) -> f32 { atan2(*self, other) } + + #[inline(always)] + fn sinh(&self) -> f32 { sinh(*self) } + + #[inline(always)] + fn cosh(&self) -> f32 { cosh(*self) } + + #[inline(always)] + fn tanh(&self) -> f32 { tanh(*self) } } /** @@ -577,11 +722,39 @@ mod tests { use super::*; use prelude::*; + macro_rules! assert_fuzzy_eq( + ($a:expr, $b:expr) => ({ + let a = $a, b = $b; + if !((a - b).abs() < 1.0e-6) { + fail!(fmt!("The values were not approximately equal. Found: %? and %?", a, b)); + } + }) + ) + #[test] fn test_num() { num::test_num(10f32, 2f32); } + #[test] + fn test_real_consts() { + assert_fuzzy_eq!(Real::two_pi::(), 2f32 * Real::pi::()); + assert_fuzzy_eq!(Real::frac_pi_2::(), Real::pi::() / 2f32); + assert_fuzzy_eq!(Real::frac_pi_3::(), Real::pi::() / 3f32); + assert_fuzzy_eq!(Real::frac_pi_4::(), Real::pi::() / 4f32); + assert_fuzzy_eq!(Real::frac_pi_6::(), Real::pi::() / 6f32); + assert_fuzzy_eq!(Real::frac_pi_8::(), Real::pi::() / 8f32); + assert_fuzzy_eq!(Real::frac_1_pi::(), 1f32 / Real::pi::()); + assert_fuzzy_eq!(Real::frac_2_pi::(), 2f32 / Real::pi::()); + assert_fuzzy_eq!(Real::frac_2_sqrtpi::(), 2f32 / Real::pi::().sqrt()); + assert_fuzzy_eq!(Real::sqrt2::(), 2f32.sqrt()); + assert_fuzzy_eq!(Real::frac_1_sqrt2::(), 1f32 / 2f32.sqrt()); + assert_fuzzy_eq!(Real::log2_e::(), Real::e::().log2()); + assert_fuzzy_eq!(Real::log10_e::(), Real::e::().log10()); + assert_fuzzy_eq!(Real::log_2::(), 2f32.log()); + assert_fuzzy_eq!(Real::log_10::(), 10f32.log()); + } + #[test] pub fn test_signed() { assert_eq!(infinity.abs(), infinity); diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 12f86337e85..53ad78c29f3 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -337,31 +337,206 @@ impl Signed for f64 { fn is_negative(&self) -> bool { *self < 0.0 || (1.0 / *self) == neg_infinity } } -impl num::Round for f64 { +impl Fractional for f64 { + /// The reciprocal (multiplicative inverse) of the number #[inline(always)] - fn round(&self, mode: num::RoundMode) -> f64 { - match mode { - num::RoundDown => floor(*self), - num::RoundUp => ceil(*self), - num::RoundToZero if self.is_negative() => ceil(*self), - num::RoundToZero => floor(*self), - num::RoundFromZero if self.is_negative() => floor(*self), - num::RoundFromZero => ceil(*self) - } - } + fn recip(&self) -> f64 { 1.0 / *self } +} + +impl Real for f64 { + /// Archimedes' constant + #[inline(always)] + fn pi() -> f64 { 3.14159265358979323846264338327950288 } + + /// 2.0 * pi + #[inline(always)] + fn two_pi() -> f64 { 6.28318530717958647692528676655900576 } + + /// pi / 2.0 + #[inline(always)] + fn frac_pi_2() -> f64 { 1.57079632679489661923132169163975144 } + + /// pi / 3.0 + #[inline(always)] + fn frac_pi_3() -> f64 { 1.04719755119659774615421446109316763 } + + /// pi / 4.0 + #[inline(always)] + fn frac_pi_4() -> f64 { 0.785398163397448309615660845819875721 } + + /// pi / 6.0 + #[inline(always)] + fn frac_pi_6() -> f64 { 0.52359877559829887307710723054658381 } + + /// pi / 8.0 + #[inline(always)] + fn frac_pi_8() -> f64 { 0.39269908169872415480783042290993786 } + + /// 1.0 / pi + #[inline(always)] + fn frac_1_pi() -> f64 { 0.318309886183790671537767526745028724 } + + /// 2.0 / pi + #[inline(always)] + fn frac_2_pi() -> f64 { 0.636619772367581343075535053490057448 } + + /// 2.0 / sqrt(pi) + #[inline(always)] + fn frac_2_sqrtpi() -> f64 { 1.12837916709551257389615890312154517 } + + /// sqrt(2.0) + #[inline(always)] + fn sqrt2() -> f64 { 1.41421356237309504880168872420969808 } + + /// 1.0 / sqrt(2.0) + #[inline(always)] + fn frac_1_sqrt2() -> f64 { 0.707106781186547524400844362104849039 } + + /// Euler's number + #[inline(always)] + fn e() -> f64 { 2.71828182845904523536028747135266250 } + + /// log2(e) + #[inline(always)] + fn log2_e() -> f64 { 1.44269504088896340735992468100189214 } + + /// log10(e) + #[inline(always)] + fn log10_e() -> f64 { 0.434294481903251827651128918916605082 } + + /// log(2.0) + #[inline(always)] + fn log_2() -> f64 { 0.693147180559945309417232121458176568 } + + /// log(10.0) + #[inline(always)] + fn log_10() -> f64 { 2.30258509299404568401799145468436421 } #[inline(always)] fn floor(&self) -> f64 { floor(*self) } + #[inline(always)] fn ceil(&self) -> f64 { ceil(*self) } + #[inline(always)] - fn fract(&self) -> f64 { - if self.is_negative() { - (*self) - ceil(*self) - } else { - (*self) - floor(*self) - } + fn round(&self) -> f64 { round(*self) } + + #[inline(always)] + fn trunc(&self) -> f64 { trunc(*self) } + + /// The fractional part of the number, calculated using: `n - floor(n)` + #[inline(always)] + fn fract(&self) -> f64 { *self - self.floor() } + + #[inline(always)] + fn pow(&self, n: f64) -> f64 { pow(*self, n) } + + #[inline(always)] + fn exp(&self) -> f64 { exp(*self) } + + #[inline(always)] + fn exp2(&self) -> f64 { exp2(*self) } + + #[inline(always)] + fn expm1(&self) -> f64 { expm1(*self) } + + #[inline(always)] + fn ldexp(&self, n: int) -> f64 { ldexp(*self, n as c_int) } + + #[inline(always)] + fn log(&self) -> f64 { ln(*self) } + + #[inline(always)] + fn log2(&self) -> f64 { log2(*self) } + + #[inline(always)] + fn log10(&self) -> f64 { log10(*self) } + + #[inline(always)] + fn log_radix(&self) -> f64 { log_radix(*self) } + + #[inline(always)] + fn ilog_radix(&self) -> int { ilog_radix(*self) as int } + + #[inline(always)] + fn sqrt(&self) -> f64 { sqrt(*self) } + + #[inline(always)] + fn rsqrt(&self) -> f64 { self.sqrt().recip() } + + #[inline(always)] + fn cbrt(&self) -> f64 { cbrt(*self) } + + /// Converts to degrees, assuming the number is in radians + #[inline(always)] + fn to_degrees(&self) -> f64 { *self * (180.0 / Real::pi::()) } + + /// Converts to radians, assuming the number is in degrees + #[inline(always)] + fn to_radians(&self) -> f64 { *self * (Real::pi::() / 180.0) } + + #[inline(always)] + fn hypot(&self, other: f64) -> f64 { hypot(*self, other) } + + #[inline(always)] + fn sin(&self) -> f64 { sin(*self) } + + #[inline(always)] + fn cos(&self) -> f64 { cos(*self) } + + #[inline(always)] + fn tan(&self) -> f64 { tan(*self) } + + #[inline(always)] + fn asin(&self) -> f64 { asin(*self) } + + #[inline(always)] + fn acos(&self) -> f64 { acos(*self) } + + #[inline(always)] + fn atan(&self) -> f64 { atan(*self) } + + #[inline(always)] + fn atan2(&self, other: f64) -> f64 { atan2(*self, other) } + + #[inline(always)] + fn sinh(&self) -> f64 { sinh(*self) } + + #[inline(always)] + fn cosh(&self) -> f64 { cosh(*self) } + + #[inline(always)] + fn tanh(&self) -> f64 { tanh(*self) } +} + +impl RealExt for f64 { + #[inline(always)] + fn lgamma(&self) -> (int, f64) { + let mut sign = 0; + let result = lgamma(*self, &mut sign); + (sign as int, result) } + + #[inline(always)] + fn tgamma(&self) -> f64 { tgamma(*self) } + + #[inline(always)] + fn j0(&self) -> f64 { j0(*self) } + + #[inline(always)] + fn j1(&self) -> f64 { j1(*self) } + + #[inline(always)] + fn jn(&self, n: int) -> f64 { jn(n as c_int, *self) } + + #[inline(always)] + fn y0(&self) -> f64 { y0(*self) } + + #[inline(always)] + fn y1(&self) -> f64 { y1(*self) } + + #[inline(always)] + fn yn(&self, n: int) -> f64 { yn(n as c_int, *self) } } /** @@ -587,11 +762,39 @@ mod tests { use super::*; use prelude::*; + macro_rules! assert_fuzzy_eq( + ($a:expr, $b:expr) => ({ + let a = $a, b = $b; + if !((a - b).abs() < 1.0e-6) { + fail!(fmt!("The values were not approximately equal. Found: %? and %?", a, b)); + } + }) + ) + #[test] fn test_num() { num::test_num(10f64, 2f64); } + #[test] + fn test_real_consts() { + assert_fuzzy_eq!(Real::two_pi::(), 2.0 * Real::pi::()); + assert_fuzzy_eq!(Real::frac_pi_2::(), Real::pi::() / 2f64); + assert_fuzzy_eq!(Real::frac_pi_3::(), Real::pi::() / 3f64); + assert_fuzzy_eq!(Real::frac_pi_4::(), Real::pi::() / 4f64); + assert_fuzzy_eq!(Real::frac_pi_6::(), Real::pi::() / 6f64); + assert_fuzzy_eq!(Real::frac_pi_8::(), Real::pi::() / 8f64); + assert_fuzzy_eq!(Real::frac_1_pi::(), 1f64 / Real::pi::()); + assert_fuzzy_eq!(Real::frac_2_pi::(), 2f64 / Real::pi::()); + assert_fuzzy_eq!(Real::frac_2_sqrtpi::(), 2f64 / Real::pi::().sqrt()); + assert_fuzzy_eq!(Real::sqrt2::(), 2f64.sqrt()); + assert_fuzzy_eq!(Real::frac_1_sqrt2::(), 1f64 / 2f64.sqrt()); + assert_fuzzy_eq!(Real::log2_e::(), Real::e::().log2()); + assert_fuzzy_eq!(Real::log10_e::(), Real::e::().log10()); + assert_fuzzy_eq!(Real::log_2::(), 2f64.log()); + assert_fuzzy_eq!(Real::log_10::(), 10f64.log()); + } + #[test] pub fn test_signed() { assert_eq!(infinity.abs(), infinity); diff --git a/src/libcore/num/float.rs b/src/libcore/num/float.rs index 88321e6b8bf..ae2d0ce0d71 100644 --- a/src/libcore/num/float.rs +++ b/src/libcore/num/float.rs @@ -403,37 +403,206 @@ impl num::One for float { fn one() -> float { 1.0 } } -impl num::Round for float { +impl Fractional for float { + /// The reciprocal (multiplicative inverse) of the number #[inline(always)] - fn round(&self, mode: num::RoundMode) -> float { - match mode { - num::RoundDown - => f64::floor(*self as f64) as float, - num::RoundUp - => f64::ceil(*self as f64) as float, - num::RoundToZero if self.is_negative() - => f64::ceil(*self as f64) as float, - num::RoundToZero - => f64::floor(*self as f64) as float, - num::RoundFromZero if self.is_negative() - => f64::floor(*self as f64) as float, - num::RoundFromZero - => f64::ceil(*self as f64) as float - } + fn recip(&self) -> float { 1.0 / *self } +} + +impl Real for float { + /// Archimedes' constant + #[inline(always)] + fn pi() -> float { 3.14159265358979323846264338327950288 } + + /// 2.0 * pi + #[inline(always)] + fn two_pi() -> float { 6.28318530717958647692528676655900576 } + + /// pi / 2.0 + #[inline(always)] + fn frac_pi_2() -> float { 1.57079632679489661923132169163975144 } + + /// pi / 3.0 + #[inline(always)] + fn frac_pi_3() -> float { 1.04719755119659774615421446109316763 } + + /// pi / 4.0 + #[inline(always)] + fn frac_pi_4() -> float { 0.785398163397448309615660845819875721 } + + /// pi / 6.0 + #[inline(always)] + fn frac_pi_6() -> float { 0.52359877559829887307710723054658381 } + + /// pi / 8.0 + #[inline(always)] + fn frac_pi_8() -> float { 0.39269908169872415480783042290993786 } + + /// 1.0 / pi + #[inline(always)] + fn frac_1_pi() -> float { 0.318309886183790671537767526745028724 } + + /// 2.0 / pi + #[inline(always)] + fn frac_2_pi() -> float { 0.636619772367581343075535053490057448 } + + /// 2 .0/ sqrt(pi) + #[inline(always)] + fn frac_2_sqrtpi() -> float { 1.12837916709551257389615890312154517 } + + /// sqrt(2.0) + #[inline(always)] + fn sqrt2() -> float { 1.41421356237309504880168872420969808 } + + /// 1.0 / sqrt(2.0) + #[inline(always)] + fn frac_1_sqrt2() -> float { 0.707106781186547524400844362104849039 } + + /// Euler's number + #[inline(always)] + fn e() -> float { 2.71828182845904523536028747135266250 } + + /// log2(e) + #[inline(always)] + fn log2_e() -> float { 1.44269504088896340735992468100189214 } + + /// log10(e) + #[inline(always)] + fn log10_e() -> float { 0.434294481903251827651128918916605082 } + + /// log(2.0) + #[inline(always)] + fn log_2() -> float { 0.693147180559945309417232121458176568 } + + /// log(10.0) + #[inline(always)] + fn log_10() -> float { 2.30258509299404568401799145468436421 } + + #[inline(always)] + fn floor(&self) -> float { floor(*self as f64) as float } + + #[inline(always)] + fn ceil(&self) -> float { ceil(*self as f64) as float } + + #[inline(always)] + fn round(&self) -> float { round(*self as f64) as float } + + #[inline(always)] + fn trunc(&self) -> float { trunc(*self as f64) as float } + + /// The fractional part of the number, calculated using: `n - floor(n)` + #[inline(always)] + fn fract(&self) -> float { *self - self.floor() } + + #[inline(always)] + fn pow(&self, n: float) -> float { pow(*self as f64, n as f64) as float } + + #[inline(always)] + fn exp(&self) -> float { exp(*self as f64) as float } + + #[inline(always)] + fn exp2(&self) -> float { exp2(*self as f64) as float } + + #[inline(always)] + fn expm1(&self) -> float { expm1(*self as f64) as float } + + #[inline(always)] + fn ldexp(&self, n: int) -> float { ldexp(*self as f64, n as c_int) as float } + + #[inline(always)] + fn log(&self) -> float { ln(*self as f64) as float } + + #[inline(always)] + fn log2(&self) -> float { log2(*self as f64) as float } + + #[inline(always)] + fn log10(&self) -> float { log10(*self as f64) as float } + + #[inline(always)] + fn log_radix(&self) -> float { log_radix(*self as f64) as float } + + #[inline(always)] + fn ilog_radix(&self) -> int { ilog_radix(*self as f64) as int } + + #[inline(always)] + fn sqrt(&self) -> float { sqrt(*self) } + + #[inline(always)] + fn rsqrt(&self) -> float { self.sqrt().recip() } + + #[inline(always)] + fn cbrt(&self) -> float { cbrt(*self as f64) as float } + + /// Converts to degrees, assuming the number is in radians + #[inline(always)] + fn to_degrees(&self) -> float { *self * (180.0 / Real::pi::()) } + + /// Converts to radians, assuming the number is in degrees + #[inline(always)] + fn to_radians(&self) -> float { *self * (Real::pi::() / 180.0) } + + #[inline(always)] + fn hypot(&self, other: float) -> float { hypot(*self as f64, other as f64) as float } + + #[inline(always)] + fn sin(&self) -> float { sin(*self) } + + #[inline(always)] + fn cos(&self) -> float { cos(*self) } + + #[inline(always)] + fn tan(&self) -> float { tan(*self) } + + #[inline(always)] + fn asin(&self) -> float { asin(*self as f64) as float } + + #[inline(always)] + fn acos(&self) -> float { acos(*self as f64) as float } + + #[inline(always)] + fn atan(&self) -> float { atan(*self) } + + #[inline(always)] + fn atan2(&self, other: float) -> float { atan2(*self as f64, other as f64) as float } + + #[inline(always)] + fn sinh(&self) -> float { sinh(*self as f64) as float } + + #[inline(always)] + fn cosh(&self) -> float { cosh(*self as f64) as float } + + #[inline(always)] + fn tanh(&self) -> float { tanh(*self as f64) as float } +} + +impl RealExt for float { + #[inline(always)] + fn lgamma(&self) -> (int, float) { + let mut sign = 0; + let result = lgamma(*self as f64, &mut sign); + (sign as int, result as float) } #[inline(always)] - fn floor(&self) -> float { f64::floor(*self as f64) as float} + fn tgamma(&self) -> float { tgamma(*self as f64) as float } + #[inline(always)] - fn ceil(&self) -> float { f64::ceil(*self as f64) as float} + fn j0(&self) -> float { j0(*self as f64) as float } + #[inline(always)] - fn fract(&self) -> float { - if self.is_negative() { - (*self) - (f64::ceil(*self as f64) as float) - } else { - (*self) - (f64::floor(*self as f64) as float) - } - } + fn j1(&self) -> float { j1(*self as f64) as float } + + #[inline(always)] + fn jn(&self, n: int) -> float { jn(n as c_int, *self as f64) as float } + + #[inline(always)] + fn y0(&self) -> float { y0(*self as f64) as float } + + #[inline(always)] + fn y1(&self) -> float { y1(*self as f64) as float } + + #[inline(always)] + fn yn(&self, n: int) -> float { yn(n as c_int, *self as f64) as float } } #[cfg(notest)] @@ -511,11 +680,39 @@ mod tests { use super::*; use prelude::*; + macro_rules! assert_fuzzy_eq( + ($a:expr, $b:expr) => ({ + let a = $a, b = $b; + if !((a - b).abs() < 1.0e-6) { + fail!(fmt!("The values were not approximately equal. Found: %? and %?", a, b)); + } + }) + ) + #[test] fn test_num() { num::test_num(10f, 2f); } + #[test] + fn test_real_consts() { + assert_fuzzy_eq!(Real::two_pi::(), 2f * Real::pi::()); + assert_fuzzy_eq!(Real::frac_pi_2::(), Real::pi::() / 2f); + assert_fuzzy_eq!(Real::frac_pi_3::(), Real::pi::() / 3f); + assert_fuzzy_eq!(Real::frac_pi_4::(), Real::pi::() / 4f); + assert_fuzzy_eq!(Real::frac_pi_6::(), Real::pi::() / 6f); + assert_fuzzy_eq!(Real::frac_pi_8::(), Real::pi::() / 8f); + assert_fuzzy_eq!(Real::frac_1_pi::(), 1f / Real::pi::()); + assert_fuzzy_eq!(Real::frac_2_pi::(), 2f / Real::pi::()); + assert_fuzzy_eq!(Real::frac_2_sqrtpi::(), 2f / Real::pi::().sqrt()); + assert_fuzzy_eq!(Real::sqrt2::(), 2f.sqrt()); + assert_fuzzy_eq!(Real::frac_1_sqrt2::(), 1f / 2f.sqrt()); + assert_fuzzy_eq!(Real::log2_e::(), Real::e::().log2()); + assert_fuzzy_eq!(Real::log10_e::(), Real::e::().log10()); + assert_fuzzy_eq!(Real::log_2::(), 2f.log()); + assert_fuzzy_eq!(Real::log_10::(), 10f.log()); + } + #[test] pub fn test_signed() { assert_eq!(infinity.abs(), infinity); diff --git a/src/libcore/num/num.rs b/src/libcore/num/num.rs index 076d90707f6..733b37e2a4a 100644 --- a/src/libcore/num/num.rs +++ b/src/libcore/num/num.rs @@ -77,19 +77,97 @@ pub trait Integer: Num fn is_odd(&self) -> bool; } -pub trait Round { - fn round(&self, mode: RoundMode) -> Self; - - fn floor(&self) -> Self; - fn ceil(&self) -> Self; - fn fract(&self) -> Self; +pub trait Fractional: Num + + Ord + + Quot { + fn recip(&self) -> Self; } -pub enum RoundMode { - RoundDown, - RoundUp, - RoundToZero, - RoundFromZero +pub trait Real: Signed + + Fractional { + // FIXME (#5527): usages of `int` should be replaced with an associated + // integer type once these are implemented + + // Common Constants + // FIXME (#5527): These should be associated constants + fn pi() -> Self; + fn two_pi() -> Self; + fn frac_pi_2() -> Self; + fn frac_pi_3() -> Self; + fn frac_pi_4() -> Self; + fn frac_pi_6() -> Self; + fn frac_pi_8() -> Self; + fn frac_1_pi() -> Self; + fn frac_2_pi() -> Self; + fn frac_2_sqrtpi() -> Self; + fn sqrt2() -> Self; + fn frac_1_sqrt2() -> Self; + fn e() -> Self; + fn log2_e() -> Self; + fn log10_e() -> Self; + fn log_2() -> Self; + fn log_10() -> Self; + + // Rounding operations + fn floor(&self) -> Self; + fn ceil(&self) -> Self; + fn round(&self) -> Self; + fn trunc(&self) -> Self; + fn fract(&self) -> Self; + + // Exponential functions + fn pow(&self, n: Self) -> Self; + fn exp(&self) -> Self; + fn exp2(&self) -> Self; + fn expm1(&self) -> Self; + fn ldexp(&self, n: int) -> Self; + fn log(&self) -> Self; + fn log2(&self) -> Self; + fn log10(&self) -> Self; + fn log_radix(&self) -> Self; + fn ilog_radix(&self) -> int; + fn sqrt(&self) -> Self; + fn rsqrt(&self) -> Self; + fn cbrt(&self) -> Self; + + // Angular conversions + fn to_degrees(&self) -> Self; + fn to_radians(&self) -> Self; + + // Triganomic functions + fn hypot(&self, other: Self) -> Self; + fn sin(&self) -> Self; + fn cos(&self) -> Self; + fn tan(&self) -> Self; + + // Inverse triganomic functions + fn asin(&self) -> Self; + fn acos(&self) -> Self; + fn atan(&self) -> Self; + fn atan2(&self, other: Self) -> Self; + + // Hyperbolic triganomic functions + fn sinh(&self) -> Self; + fn cosh(&self) -> Self; + fn tanh(&self) -> Self; +} + +/// Methods that are harder to implement and not commonly used. +pub trait RealExt: Real { + // FIXME (#5527): usages of `int` should be replaced with an associated + // integer type once these are implemented + + // Gamma functions + fn lgamma(&self) -> (int, Self); + fn tgamma(&self) -> Self; + + // Bessel functions + fn j0(&self) -> Self; + fn j1(&self) -> Self; + fn jn(&self, n: int) -> Self; + fn y0(&self) -> Self; + fn y1(&self) -> Self; + fn yn(&self, n: int) -> Self; } /** diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs index ec332adb832..c161bd4cf59 100644 --- a/src/libcore/prelude.rs +++ b/src/libcore/prelude.rs @@ -39,6 +39,7 @@ pub use iter::{CopyableIter, CopyableOrderedIter, CopyableNonstrictIter}; pub use iter::{Times, ExtendedMutableIter}; pub use num::{Num, NumCast}; pub use num::{Signed, Unsigned, Integer}; +pub use num::{Fractional, Real, RealExt}; pub use path::GenericPath; pub use path::Path; pub use path::PosixPath;