diff --git a/src/libcore/core.rc b/src/libcore/core.rc index 61fbf98a7c61d..71bbaf557ce38 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -77,9 +77,7 @@ pub use kinds::{Const, Copy, Owned, Durable}; pub use ops::{Drop}; #[cfg(stage0)] pub use ops::{Add, Sub, Mul, Div, Modulo, Neg, Not}; -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] +#[cfg(not(stage0))] pub use ops::{Add, Sub, Mul, Quot, Rem, Neg, Not}; pub use ops::{BitAnd, BitOr, BitXor}; pub use ops::{Shl, Shr, Index}; @@ -105,7 +103,9 @@ pub use iter::{BaseIter, ExtendedIter, EqIter, CopyableIter}; pub use iter::{CopyableOrderedIter, CopyableNonstrictIter, Times}; pub use iter::{ExtendedMutableIter}; -pub use num::{Num, Signed, Unsigned, Natural, NumCast}; +pub use num::{Num, NumCast}; +pub use num::{Signed, Unsigned, Integer}; +pub use num::{Round, 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 5d663844e5b79..7d5807ba5462c 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -10,20 +10,10 @@ //! Operations and constants for `f32` -use num::strconv; -use num::Signed; -use num; -use option::Option; use from_str; -use to_str; - -#[cfg(notest)] use cmp::{Eq, Ord}; -#[cfg(stage0,notest)] -use ops::{Add, Sub, Mul, Div, Modulo, Neg}; -#[cfg(stage1,notest)] -#[cfg(stage2,notest)] -#[cfg(stage3,notest)] -use ops::{Add, Sub, Mul, Quot, Rem, Neg}; +use libc::c_int; +use num::strconv; +use prelude::*; pub use cmath::c_float_targ_consts::*; @@ -233,6 +223,8 @@ pub fn logarithm(n: f32, b: f32) -> f32 { return log2(n) / log2(b); } +impl Num for f32 {} + #[cfg(notest)] impl Eq for f32 { #[inline(always)] @@ -286,10 +278,7 @@ impl Div for f32 { #[inline(always)] fn div(&self, other: &f32) -> f32 { *self / *other } } - -#[cfg(stage1,notest)] -#[cfg(stage2,notest)] -#[cfg(stage3,notest)] +#[cfg(not(stage0),notest)] impl Quot for f32 { #[inline(always)] fn quot(&self, other: &f32) -> f32 { *self / *other } @@ -300,10 +289,7 @@ impl Modulo for f32 { #[inline(always)] fn modulo(&self, other: &f32) -> f32 { *self % *other } } - -#[cfg(stage1,notest)] -#[cfg(stage2,notest)] -#[cfg(stage3,notest)] +#[cfg(not(stage0),notest)] impl Rem for f32 { #[inline(always)] fn rem(&self, other: &f32) -> f32 { *self % *other } @@ -341,31 +327,188 @@ impl Signed for f32 { fn is_negative(&self) -> bool { *self < 0.0 || (1.0 / *self) == neg_infinity } } -impl num::Round for f32 { - #[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) - } - } - +impl Round for f32 { + /// Round half-way cases toward `neg_infinity` #[inline(always)] fn floor(&self) -> f32 { floor(*self) } + + /// Round half-way cases toward `infinity` #[inline(always)] fn ceil(&self) -> f32 { ceil(*self) } + + /// Round half-way cases away from `0.0` #[inline(always)] - fn fract(&self) -> f32 { - if self.is_negative() { - (*self) - ceil(*self) - } else { - (*self) - floor(*self) - } - } + fn round(&self) -> f32 { round(*self) } + + /// The integer part of the number (rounds towards `0.0`) + #[inline(always)] + fn trunc(&self) -> f32 { trunc(*self) } + + /// + /// The fractional part of the number, satisfying: + /// + /// ~~~ + /// assert!(x == trunc(x) + fract(x)) + /// ~~~ + /// + #[inline(always)] + fn fract(&self) -> f32 { *self - self.trunc() } +} + +impl Fractional for f32 { + /// The reciprocal (multiplicative inverse) of the number + #[inline(always)] + 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 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) } } /** @@ -588,6 +731,111 @@ impl num::FromStrRadix for f32 { #[cfg(test)] mod tests { use f32::*; + 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_floor() { + assert_fuzzy_eq!(1.0f32.floor(), 1.0f32); + assert_fuzzy_eq!(1.3f32.floor(), 1.0f32); + assert_fuzzy_eq!(1.5f32.floor(), 1.0f32); + assert_fuzzy_eq!(1.7f32.floor(), 1.0f32); + assert_fuzzy_eq!(0.0f32.floor(), 0.0f32); + assert_fuzzy_eq!((-0.0f32).floor(), -0.0f32); + assert_fuzzy_eq!((-1.0f32).floor(), -1.0f32); + assert_fuzzy_eq!((-1.3f32).floor(), -2.0f32); + assert_fuzzy_eq!((-1.5f32).floor(), -2.0f32); + assert_fuzzy_eq!((-1.7f32).floor(), -2.0f32); + } + + #[test] + fn test_ceil() { + assert_fuzzy_eq!(1.0f32.ceil(), 1.0f32); + assert_fuzzy_eq!(1.3f32.ceil(), 2.0f32); + assert_fuzzy_eq!(1.5f32.ceil(), 2.0f32); + assert_fuzzy_eq!(1.7f32.ceil(), 2.0f32); + assert_fuzzy_eq!(0.0f32.ceil(), 0.0f32); + assert_fuzzy_eq!((-0.0f32).ceil(), -0.0f32); + assert_fuzzy_eq!((-1.0f32).ceil(), -1.0f32); + assert_fuzzy_eq!((-1.3f32).ceil(), -1.0f32); + assert_fuzzy_eq!((-1.5f32).ceil(), -1.0f32); + assert_fuzzy_eq!((-1.7f32).ceil(), -1.0f32); + } + + #[test] + fn test_round() { + assert_fuzzy_eq!(1.0f32.round(), 1.0f32); + assert_fuzzy_eq!(1.3f32.round(), 1.0f32); + assert_fuzzy_eq!(1.5f32.round(), 2.0f32); + assert_fuzzy_eq!(1.7f32.round(), 2.0f32); + assert_fuzzy_eq!(0.0f32.round(), 0.0f32); + assert_fuzzy_eq!((-0.0f32).round(), -0.0f32); + assert_fuzzy_eq!((-1.0f32).round(), -1.0f32); + assert_fuzzy_eq!((-1.3f32).round(), -1.0f32); + assert_fuzzy_eq!((-1.5f32).round(), -2.0f32); + assert_fuzzy_eq!((-1.7f32).round(), -2.0f32); + } + + #[test] + fn test_trunc() { + assert_fuzzy_eq!(1.0f32.trunc(), 1.0f32); + assert_fuzzy_eq!(1.3f32.trunc(), 1.0f32); + assert_fuzzy_eq!(1.5f32.trunc(), 1.0f32); + assert_fuzzy_eq!(1.7f32.trunc(), 1.0f32); + assert_fuzzy_eq!(0.0f32.trunc(), 0.0f32); + assert_fuzzy_eq!((-0.0f32).trunc(), -0.0f32); + assert_fuzzy_eq!((-1.0f32).trunc(), -1.0f32); + assert_fuzzy_eq!((-1.3f32).trunc(), -1.0f32); + assert_fuzzy_eq!((-1.5f32).trunc(), -1.0f32); + assert_fuzzy_eq!((-1.7f32).trunc(), -1.0f32); + } + + #[test] + fn test_fract() { + assert_fuzzy_eq!(1.0f32.fract(), 0.0f32); + assert_fuzzy_eq!(1.3f32.fract(), 0.3f32); + assert_fuzzy_eq!(1.5f32.fract(), 0.5f32); + assert_fuzzy_eq!(1.7f32.fract(), 0.7f32); + assert_fuzzy_eq!(0.0f32.fract(), 0.0f32); + assert_fuzzy_eq!((-0.0f32).fract(), -0.0f32); + assert_fuzzy_eq!((-1.0f32).fract(), -0.0f32); + assert_fuzzy_eq!((-1.3f32).fract(), -0.3f32); + assert_fuzzy_eq!((-1.5f32).fract(), -0.5f32); + assert_fuzzy_eq!((-1.7f32).fract(), -0.7f32); + } + + #[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() { diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 48f23fe8ba946..3b6198bfc472e 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -10,20 +10,10 @@ //! Operations and constants for `f64` -use num::strconv; -use num::Signed; -use num; -use option::Option; -use to_str; use from_str; - -#[cfg(notest)] use cmp::{Eq, Ord}; -#[cfg(stage0,notest)] -use ops::{Add, Sub, Mul, Div, Modulo, Neg}; -#[cfg(stage1,notest)] -#[cfg(stage2,notest)] -#[cfg(stage3,notest)] -use ops::{Add, Sub, Mul, Quot, Rem, Neg}; +use libc::c_int; +use num::strconv; +use prelude::*; pub use cmath::c_double_targ_consts::*; pub use cmp::{min, max}; @@ -254,6 +244,8 @@ pub fn logarithm(n: f64, b: f64) -> f64 { return log2(n) / log2(b); } +impl Num for f64 {} + #[cfg(notest)] impl Eq for f64 { #[inline(always)] @@ -300,9 +292,7 @@ impl Mul for f64 { impl Div for f64 { fn div(&self, other: &f64) -> f64 { *self / *other } } -#[cfg(stage1,notest)] -#[cfg(stage2,notest)] -#[cfg(stage3,notest)] +#[cfg(not(stage0),notest)] impl Quot for f64 { #[inline(always)] fn quot(&self, other: &f64) -> f64 { *self / *other } @@ -311,9 +301,7 @@ impl Quot for f64 { impl Modulo for f64 { fn modulo(&self, other: &f64) -> f64 { *self % *other } } -#[cfg(stage1,notest)] -#[cfg(stage2,notest)] -#[cfg(stage3,notest)] +#[cfg(not(stage0),notest)] impl Rem for f64 { #[inline(always)] fn rem(&self, other: &f64) -> f64 { *self % *other } @@ -349,31 +337,218 @@ impl Signed for f64 { fn is_negative(&self) -> bool { *self < 0.0 || (1.0 / *self) == neg_infinity } } -impl num::Round for f64 { - #[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) - } - } - +impl Round for f64 { + /// Round half-way cases toward `neg_infinity` #[inline(always)] fn floor(&self) -> f64 { floor(*self) } + + /// Round half-way cases toward `infinity` #[inline(always)] fn ceil(&self) -> f64 { ceil(*self) } + + /// Round half-way cases away from `0.0` #[inline(always)] - fn fract(&self) -> f64 { - if self.is_negative() { - (*self) - ceil(*self) - } else { - (*self) - floor(*self) - } + fn round(&self) -> f64 { round(*self) } + + /// The integer part of the number (rounds towards `0.0`) + #[inline(always)] + fn trunc(&self) -> f64 { trunc(*self) } + + /// + /// The fractional part of the number, satisfying: + /// + /// ~~~ + /// assert!(x == trunc(x) + fract(x)) + /// ~~~ + /// + #[inline(always)] + fn fract(&self) -> f64 { *self - self.trunc() } +} + +impl Fractional for f64 { + /// The reciprocal (multiplicative inverse) of the number + #[inline(always)] + 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 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) } } /** @@ -596,6 +771,112 @@ impl num::FromStrRadix for f64 { #[cfg(test)] mod tests { use f64::*; + 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 expected %?", a, b)); + } + }) + ) + + #[test] + fn test_num() { + num::test_num(10f64, 2f64); + } + + #[test] + fn test_floor() { + assert_fuzzy_eq!(1.0f64.floor(), 1.0f64); + assert_fuzzy_eq!(1.3f64.floor(), 1.0f64); + assert_fuzzy_eq!(1.5f64.floor(), 1.0f64); + assert_fuzzy_eq!(1.7f64.floor(), 1.0f64); + assert_fuzzy_eq!(0.0f64.floor(), 0.0f64); + assert_fuzzy_eq!((-0.0f64).floor(), -0.0f64); + assert_fuzzy_eq!((-1.0f64).floor(), -1.0f64); + assert_fuzzy_eq!((-1.3f64).floor(), -2.0f64); + assert_fuzzy_eq!((-1.5f64).floor(), -2.0f64); + assert_fuzzy_eq!((-1.7f64).floor(), -2.0f64); + } + + #[test] + fn test_ceil() { + assert_fuzzy_eq!(1.0f64.ceil(), 1.0f64); + assert_fuzzy_eq!(1.3f64.ceil(), 2.0f64); + assert_fuzzy_eq!(1.5f64.ceil(), 2.0f64); + assert_fuzzy_eq!(1.7f64.ceil(), 2.0f64); + assert_fuzzy_eq!(0.0f64.ceil(), 0.0f64); + assert_fuzzy_eq!((-0.0f64).ceil(), -0.0f64); + assert_fuzzy_eq!((-1.0f64).ceil(), -1.0f64); + assert_fuzzy_eq!((-1.3f64).ceil(), -1.0f64); + assert_fuzzy_eq!((-1.5f64).ceil(), -1.0f64); + assert_fuzzy_eq!((-1.7f64).ceil(), -1.0f64); + } + + #[test] + fn test_round() { + assert_fuzzy_eq!(1.0f64.round(), 1.0f64); + assert_fuzzy_eq!(1.3f64.round(), 1.0f64); + assert_fuzzy_eq!(1.5f64.round(), 2.0f64); + assert_fuzzy_eq!(1.7f64.round(), 2.0f64); + assert_fuzzy_eq!(0.0f64.round(), 0.0f64); + assert_fuzzy_eq!((-0.0f64).round(), -0.0f64); + assert_fuzzy_eq!((-1.0f64).round(), -1.0f64); + assert_fuzzy_eq!((-1.3f64).round(), -1.0f64); + assert_fuzzy_eq!((-1.5f64).round(), -2.0f64); + assert_fuzzy_eq!((-1.7f64).round(), -2.0f64); + } + + #[test] + fn test_trunc() { + assert_fuzzy_eq!(1.0f64.trunc(), 1.0f64); + assert_fuzzy_eq!(1.3f64.trunc(), 1.0f64); + assert_fuzzy_eq!(1.5f64.trunc(), 1.0f64); + assert_fuzzy_eq!(1.7f64.trunc(), 1.0f64); + assert_fuzzy_eq!(0.0f64.trunc(), 0.0f64); + assert_fuzzy_eq!((-0.0f64).trunc(), -0.0f64); + assert_fuzzy_eq!((-1.0f64).trunc(), -1.0f64); + assert_fuzzy_eq!((-1.3f64).trunc(), -1.0f64); + assert_fuzzy_eq!((-1.5f64).trunc(), -1.0f64); + assert_fuzzy_eq!((-1.7f64).trunc(), -1.0f64); + } + + #[test] + fn test_fract() { + assert_fuzzy_eq!(1.0f64.fract(), 0.0f64); + assert_fuzzy_eq!(1.3f64.fract(), 0.3f64); + assert_fuzzy_eq!(1.5f64.fract(), 0.5f64); + assert_fuzzy_eq!(1.7f64.fract(), 0.7f64); + assert_fuzzy_eq!(0.0f64.fract(), 0.0f64); + assert_fuzzy_eq!((-0.0f64).fract(), -0.0f64); + assert_fuzzy_eq!((-1.0f64).fract(), -0.0f64); + assert_fuzzy_eq!((-1.3f64).fract(), -0.3f64); + assert_fuzzy_eq!((-1.5f64).fract(), -0.5f64); + assert_fuzzy_eq!((-1.7f64).fract(), -0.7f64); + } + + #[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() { diff --git a/src/libcore/num/float.rs b/src/libcore/num/float.rs index 036d295943c7b..9c0412b422f52 100644 --- a/src/libcore/num/float.rs +++ b/src/libcore/num/float.rs @@ -20,21 +20,10 @@ // PORT this must match in width according to architecture -use f64; -use num::strconv; -use num::Signed; -use num; -use option::Option; -use to_str; use from_str; - -#[cfg(notest)] use cmp::{Eq, Ord}; -#[cfg(stage0,notest)] -use ops::{Add, Sub, Mul, Div, Modulo, Neg}; -#[cfg(stage1,notest)] -#[cfg(stage2,notest)] -#[cfg(stage3,notest)] -use ops::{Add, Sub, Mul, Quot, Rem, Neg}; +use libc::c_int; +use num::strconv; +use prelude::*; pub use f64::{add, sub, mul, quot, rem, lt, le, eq, ne, ge, gt}; pub use f64::logarithm; @@ -382,6 +371,8 @@ pub fn tan(x: float) -> float { f64::tan(x as f64) as float } +impl Num for float {} + #[cfg(notest)] impl Eq for float { #[inline(always)] @@ -412,37 +403,218 @@ impl num::One for float { fn one() -> float { 1.0 } } -impl num::Round for float { - #[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 - } - } +impl Round for float { + /// Round half-way cases toward `neg_infinity` + #[inline(always)] + fn floor(&self) -> float { floor(*self as f64) as float } + /// Round half-way cases toward `infinity` #[inline(always)] - fn floor(&self) -> float { f64::floor(*self as f64) as float} + fn ceil(&self) -> float { ceil(*self as f64) as float } + + /// Round half-way cases away from `0.0` #[inline(always)] - fn ceil(&self) -> float { f64::ceil(*self as f64) as float} + fn round(&self) -> float { round(*self as f64) as float } + + /// The integer part of the number (rounds towards `0.0`) #[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 trunc(&self) -> float { trunc(*self as f64) as float } + + /// + /// The fractional part of the number, satisfying: + /// + /// ~~~ + /// assert!(x == trunc(x) + fract(x)) + /// ~~~ + /// + #[inline(always)] + fn fract(&self) -> float { *self - self.trunc() } +} + +impl Fractional for float { + /// The reciprocal (multiplicative inverse) of the number + #[inline(always)] + 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 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 tgamma(&self) -> float { tgamma(*self as f64) as float } + + #[inline(always)] + fn j0(&self) -> float { j0(*self as f64) as float } + + #[inline(always)] + 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)] @@ -468,9 +640,7 @@ impl Div for float { #[inline(always)] fn div(&self, other: &float) -> float { *self / *other } } -#[cfg(stage1,notest)] -#[cfg(stage2,notest)] -#[cfg(stage3,notest)] +#[cfg(not(stage0),notest)] impl Quot for float { #[inline(always)] fn quot(&self, other: &float) -> float { *self / *other } @@ -480,9 +650,7 @@ impl Modulo for float { #[inline(always)] fn modulo(&self, other: &float) -> float { *self % *other } } -#[cfg(stage1,notest)] -#[cfg(stage2,notest)] -#[cfg(stage3,notest)] +#[cfg(not(stage0),notest)] impl Rem for float { #[inline(always)] fn rem(&self, other: &float) -> float { *self % *other } @@ -524,6 +692,109 @@ 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_floor() { + assert_fuzzy_eq!(1.0f.floor(), 1.0f); + assert_fuzzy_eq!(1.3f.floor(), 1.0f); + assert_fuzzy_eq!(1.5f.floor(), 1.0f); + assert_fuzzy_eq!(1.7f.floor(), 1.0f); + assert_fuzzy_eq!(0.0f.floor(), 0.0f); + assert_fuzzy_eq!((-0.0f).floor(), -0.0f); + assert_fuzzy_eq!((-1.0f).floor(), -1.0f); + assert_fuzzy_eq!((-1.3f).floor(), -2.0f); + assert_fuzzy_eq!((-1.5f).floor(), -2.0f); + assert_fuzzy_eq!((-1.7f).floor(), -2.0f); + } + + #[test] + fn test_ceil() { + assert_fuzzy_eq!(1.0f.ceil(), 1.0f); + assert_fuzzy_eq!(1.3f.ceil(), 2.0f); + assert_fuzzy_eq!(1.5f.ceil(), 2.0f); + assert_fuzzy_eq!(1.7f.ceil(), 2.0f); + assert_fuzzy_eq!(0.0f.ceil(), 0.0f); + assert_fuzzy_eq!((-0.0f).ceil(), -0.0f); + assert_fuzzy_eq!((-1.0f).ceil(), -1.0f); + assert_fuzzy_eq!((-1.3f).ceil(), -1.0f); + assert_fuzzy_eq!((-1.5f).ceil(), -1.0f); + assert_fuzzy_eq!((-1.7f).ceil(), -1.0f); + } + + #[test] + fn test_round() { + assert_fuzzy_eq!(1.0f.round(), 1.0f); + assert_fuzzy_eq!(1.3f.round(), 1.0f); + assert_fuzzy_eq!(1.5f.round(), 2.0f); + assert_fuzzy_eq!(1.7f.round(), 2.0f); + assert_fuzzy_eq!(0.0f.round(), 0.0f); + assert_fuzzy_eq!((-0.0f).round(), -0.0f); + assert_fuzzy_eq!((-1.0f).round(), -1.0f); + assert_fuzzy_eq!((-1.3f).round(), -1.0f); + assert_fuzzy_eq!((-1.5f).round(), -2.0f); + assert_fuzzy_eq!((-1.7f).round(), -2.0f); + } + + #[test] + fn test_trunc() { + assert_fuzzy_eq!(1.0f.trunc(), 1.0f); + assert_fuzzy_eq!(1.3f.trunc(), 1.0f); + assert_fuzzy_eq!(1.5f.trunc(), 1.0f); + assert_fuzzy_eq!(1.7f.trunc(), 1.0f); + assert_fuzzy_eq!(0.0f.trunc(), 0.0f); + assert_fuzzy_eq!((-0.0f).trunc(), -0.0f); + assert_fuzzy_eq!((-1.0f).trunc(), -1.0f); + assert_fuzzy_eq!((-1.3f).trunc(), -1.0f); + assert_fuzzy_eq!((-1.5f).trunc(), -1.0f); + assert_fuzzy_eq!((-1.7f).trunc(), -1.0f); + } + + #[test] + fn test_fract() { + assert_fuzzy_eq!(1.0f.fract(), 0.0f); + assert_fuzzy_eq!(1.3f.fract(), 0.3f); + assert_fuzzy_eq!(1.5f.fract(), 0.5f); + assert_fuzzy_eq!(1.7f.fract(), 0.7f); + assert_fuzzy_eq!(0.0f.fract(), 0.0f); + assert_fuzzy_eq!((-0.0f).fract(), -0.0f); + assert_fuzzy_eq!((-1.0f).fract(), -0.0f); + assert_fuzzy_eq!((-1.3f).fract(), -0.3f); + assert_fuzzy_eq!((-1.5f).fract(), -0.5f); + assert_fuzzy_eq!((-1.7f).fract(), -0.7f); + } + + #[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); @@ -704,15 +975,6 @@ mod tests { assert_eq!(to_str_digits(infinity, 10u), ~"inf"); assert_eq!(to_str_digits(-infinity, 10u), ~"-inf"); } - - #[test] - pub fn test_round() { - assert_eq!(round(5.8), 6.0); - assert_eq!(round(5.2), 5.0); - assert_eq!(round(3.0), 3.0); - assert_eq!(round(2.5), 3.0); - assert_eq!(round(-3.5), -4.0); - } } // diff --git a/src/libcore/num/int-template.rs b/src/libcore/num/int-template.rs index 426ed8a8b0f6e..f9edf1cefc873 100644 --- a/src/libcore/num/int-template.rs +++ b/src/libcore/num/int-template.rs @@ -10,12 +10,9 @@ use T = self::inst::T; -use to_str::ToStr; use from_str::FromStr; use num::{ToStrRadix, FromStrRadix}; use num::strconv; -use num::Signed; -use num; use prelude::*; pub use cmp::{min, max}; @@ -133,6 +130,8 @@ pub fn compl(i: T) -> T { #[inline(always)] pub fn abs(i: T) -> T { i.abs() } +impl Num for T {} + #[cfg(notest)] impl Ord for T { #[inline(always)] @@ -186,10 +185,7 @@ impl Div for T { #[inline(always)] fn div(&self, other: &T) -> T { *self / *other } } - -#[cfg(stage1,notest)] -#[cfg(stage2,notest)] -#[cfg(stage3,notest)] +#[cfg(not(stage0),notest)] impl Quot for T { /** * Returns the integer quotient, truncated towards 0. As this behaviour reflects @@ -218,10 +214,7 @@ impl Modulo for T { #[inline(always)] fn modulo(&self, other: &T) -> T { *self % *other } } - -#[cfg(stage1,notest)] -#[cfg(stage2,notest)] -#[cfg(stage3,notest)] +#[cfg(not(stage0),notest)] impl Rem for T { /** * Returns the integer remainder after division, satisfying: @@ -286,7 +279,7 @@ impl Signed for T { fn is_negative(&self) -> bool { *self < 0 } } -impl Natural for T { +impl Integer for T { /** * Floored integer division * @@ -305,13 +298,13 @@ impl Natural for T { * ~~~ */ #[inline(always)] - fn div(&self, other: T) -> T { + fn div(&self, other: &T) -> T { // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, // December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) match self.quot_rem(other) { - (q, r) if (r > 0 && other < 0) - || (r < 0 && other > 0) => q - 1, - (q, _) => q, + (q, r) if (r > 0 && *other < 0) + || (r < 0 && *other > 0) => q - 1, + (q, _) => q, } } @@ -337,32 +330,32 @@ impl Natural for T { * ~~~ */ #[inline(always)] - fn modulo(&self, other: T) -> T { + fn modulo(&self, other: &T) -> T { // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, // December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) - match *self % other { - r if (r > 0 && other < 0) - || (r < 0 && other > 0) => r + other, - r => r, + match *self % *other { + r if (r > 0 && *other < 0) + || (r < 0 && *other > 0) => r + *other, + r => r, } } /// Calculates `div` and `modulo` simultaneously #[inline(always)] - fn div_mod(&self, other: T) -> (T,T) { + fn div_mod(&self, other: &T) -> (T,T) { // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, // December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) match self.quot_rem(other) { - (q, r) if (r > 0 && other < 0) - || (r < 0 && other > 0) => (q - 1, r + other), - (q, r) => (q, r), + (q, r) if (r > 0 && *other < 0) + || (r < 0 && *other > 0) => (q - 1, r + *other), + (q, r) => (q, r), } } /// Calculates `quot` (`\`) and `rem` (`%`) simultaneously #[inline(always)] - fn quot_rem(&self, other: T) -> (T,T) { - (*self / other, *self % other) + fn quot_rem(&self, other: &T) -> (T,T) { + (*self / *other, *self % *other) } /** @@ -371,9 +364,9 @@ impl Natural for T { * The result is always positive */ #[inline(always)] - fn gcd(&self, other: T) -> T { + fn gcd(&self, other: &T) -> T { // Use Euclid's algorithm - let mut m = *self, n = other; + let mut m = *self, n = *other; while m != 0 { let temp = m; m = n % temp; @@ -386,17 +379,17 @@ impl Natural for T { * Calculates the Lowest Common Multiple (LCM) of the number and `other` */ #[inline(always)] - fn lcm(&self, other: T) -> T { - ((*self * other) / self.gcd(other)).abs() // should not have to recaluculate abs + fn lcm(&self, other: &T) -> T { + ((*self * *other) / self.gcd(other)).abs() // should not have to recaluculate abs } /// Returns `true` if the number can be divided by `other` without leaving a remainder #[inline(always)] - fn divisible_by(&self, other: T) -> bool { *self % other == 0 } + fn divisible_by(&self, other: &T) -> bool { *self % *other == 0 } /// Returns `true` if the number is divisible by `2` #[inline(always)] - fn is_even(&self) -> bool { self.divisible_by(2) } + fn is_even(&self) -> bool { self.divisible_by(&2) } /// Returns `true` if the number is not divisible by `2` #[inline(always)] @@ -522,6 +515,11 @@ mod tests { use super::inst::T; use prelude::*; + #[test] + fn test_num() { + num::test_num(10 as T, 2 as T); + } + #[test] pub fn test_signed() { assert_eq!((1 as T).abs(), 1 as T); @@ -564,7 +562,7 @@ mod tests { fn test_nd_qr(nd: (T,T), qr: (T,T)) { let (n,d) = nd; let separate_quot_rem = (n / d, n % d); - let combined_quot_rem = n.quot_rem(d); + let combined_quot_rem = n.quot_rem(&d); assert_eq!(separate_quot_rem, qr); assert_eq!(combined_quot_rem, qr); @@ -588,8 +586,8 @@ mod tests { fn test_div_mod() { fn test_nd_dm(nd: (T,T), dm: (T,T)) { let (n,d) = nd; - let separate_div_mod = (n.div(d), n.modulo(d)); - let combined_div_mod = n.div_mod(d); + let separate_div_mod = (n.div(&d), n.modulo(&d)); + let combined_div_mod = n.div_mod(&d); assert_eq!(separate_div_mod, dm); assert_eq!(combined_div_mod, dm); @@ -611,26 +609,26 @@ mod tests { #[test] fn test_gcd() { - assert_eq!((10 as T).gcd(2), 2 as T); - assert_eq!((10 as T).gcd(3), 1 as T); - assert_eq!((0 as T).gcd(3), 3 as T); - assert_eq!((3 as T).gcd(3), 3 as T); - assert_eq!((56 as T).gcd(42), 14 as T); - assert_eq!((3 as T).gcd(-3), 3 as T); - assert_eq!((-6 as T).gcd(3), 3 as T); - assert_eq!((-4 as T).gcd(-2), 2 as T); + assert_eq!((10 as T).gcd(&2), 2 as T); + assert_eq!((10 as T).gcd(&3), 1 as T); + assert_eq!((0 as T).gcd(&3), 3 as T); + assert_eq!((3 as T).gcd(&3), 3 as T); + assert_eq!((56 as T).gcd(&42), 14 as T); + assert_eq!((3 as T).gcd(&-3), 3 as T); + assert_eq!((-6 as T).gcd(&3), 3 as T); + assert_eq!((-4 as T).gcd(&-2), 2 as T); } #[test] fn test_lcm() { - assert_eq!((1 as T).lcm(0), 0 as T); - assert_eq!((0 as T).lcm(1), 0 as T); - assert_eq!((1 as T).lcm(1), 1 as T); - assert_eq!((-1 as T).lcm(1), 1 as T); - assert_eq!((1 as T).lcm(-1), 1 as T); - assert_eq!((-1 as T).lcm(-1), 1 as T); - assert_eq!((8 as T).lcm(9), 72 as T); - assert_eq!((11 as T).lcm(5), 55 as T); + assert_eq!((1 as T).lcm(&0), 0 as T); + assert_eq!((0 as T).lcm(&1), 0 as T); + assert_eq!((1 as T).lcm(&1), 1 as T); + assert_eq!((-1 as T).lcm(&1), 1 as T); + assert_eq!((1 as T).lcm(&-1), 1 as T); + assert_eq!((-1 as T).lcm(&-1), 1 as T); + assert_eq!((8 as T).lcm(&9), 72 as T); + assert_eq!((11 as T).lcm(&5), 55 as T); } #[test] diff --git a/src/libcore/num/num.rs b/src/libcore/num/num.rs index 577bb3f0f150a..e19afdc69c32f 100644 --- a/src/libcore/num/num.rs +++ b/src/libcore/num/num.rs @@ -16,9 +16,7 @@ use ops::{Add, Sub, Mul, Neg}; use Quot = ops::Div; #[cfg(stage0)] use Rem = ops::Modulo; -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] +#[cfg(not(stage0))] use ops::{Add, Sub, Mul, Quot, Rem, Neg}; use option::Option; use kinds::Copy; @@ -33,30 +31,18 @@ pub trait Num: Eq + Zero + One + Quot + Rem {} -impl Num for u8 {} -impl Num for u16 {} -impl Num for u32 {} -impl Num for u64 {} -impl Num for uint {} -impl Num for i8 {} -impl Num for i16 {} -impl Num for i32 {} -impl Num for i64 {} -impl Num for int {} -impl Num for f32 {} -impl Num for f64 {} -impl Num for float {} - pub trait IntConvertible { fn to_int(&self) -> int; fn from_int(n: int) -> Self; } pub trait Zero { + // FIXME (#5527): These should be associated constants fn zero() -> Self; } pub trait One { + // FIXME (#5527): These should be associated constants fn one() -> Self; } @@ -75,35 +61,115 @@ pub fn abs>(v: T) -> T { if v < Zero::zero() { v.neg() } else { v } } -pub trait Natural: Num +pub trait Integer: Num + Ord + Quot + Rem { - fn div(&self, other: Self) -> Self; - fn modulo(&self, other: Self) -> Self; - fn div_mod(&self, other: Self) -> (Self,Self); - fn quot_rem(&self, other: Self) -> (Self,Self); - - fn gcd(&self, other: Self) -> Self; - fn lcm(&self, other: Self) -> Self; - fn divisible_by(&self, other: Self) -> bool; + fn div(&self, other: &Self) -> Self; + fn modulo(&self, other: &Self) -> Self; + fn div_mod(&self, other: &Self) -> (Self,Self); + fn quot_rem(&self, other: &Self) -> (Self,Self); + + fn gcd(&self, other: &Self) -> Self; + fn lcm(&self, other: &Self) -> Self; + fn divisible_by(&self, other: &Self) -> bool; fn is_even(&self) -> bool; fn is_odd(&self) -> bool; } pub trait Round { - fn round(&self, mode: RoundMode) -> Self; - fn floor(&self) -> Self; - fn ceil(&self) -> Self; + fn ceil(&self) -> Self; + fn round(&self) -> Self; + fn trunc(&self) -> Self; fn fract(&self) -> Self; } -pub enum RoundMode { - RoundDown, - RoundUp, - RoundToZero, - RoundFromZero +pub trait Fractional: Num + + Ord + + Round + + Quot { + fn recip(&self) -> Self; +} + +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; + + // 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; } /** @@ -230,8 +296,9 @@ pub fn pow_with_uint+Mul>( total } +/// Helper function for testing numeric operations #[cfg(stage0,test)] -fn test_num(ten: T, two: T) { +pub fn test_num(ten: T, two: T) { assert_eq!(ten.add(&two), cast(12)); assert_eq!(ten.sub(&two), cast(8)); assert_eq!(ten.mul(&two), cast(20)); @@ -247,7 +314,7 @@ fn test_num(ten: T, two: T) { #[cfg(stage1,test)] #[cfg(stage2,test)] #[cfg(stage3,test)] -fn test_num(ten: T, two: T) { +pub fn test_num(ten: T, two: T) { assert_eq!(ten.add(&two), cast(12)); assert_eq!(ten.sub(&two), cast(8)); assert_eq!(ten.mul(&two), cast(20)); @@ -261,20 +328,6 @@ fn test_num(ten: T, two: T) { assert_eq!(ten.rem(&two), ten % two); } -#[test] fn test_u8_num() { test_num(10u8, 2u8) } -#[test] fn test_u16_num() { test_num(10u16, 2u16) } -#[test] fn test_u32_num() { test_num(10u32, 2u32) } -#[test] fn test_u64_num() { test_num(10u64, 2u64) } -#[test] fn test_uint_num() { test_num(10u, 2u) } -#[test] fn test_i8_num() { test_num(10i8, 2i8) } -#[test] fn test_i16_num() { test_num(10i16, 2i16) } -#[test] fn test_i32_num() { test_num(10i32, 2i32) } -#[test] fn test_i64_num() { test_num(10i64, 2i64) } -#[test] fn test_int_num() { test_num(10i, 2i) } -#[test] fn test_f32_num() { test_num(10f32, 2f32) } -#[test] fn test_f64_num() { test_num(10f64, 2f64) } -#[test] fn test_float_num() { test_num(10f, 2f) } - macro_rules! test_cast_20( ($_20:expr) => ({ let _20 = $_20; diff --git a/src/libcore/num/uint-template.rs b/src/libcore/num/uint-template.rs index a0da84a8c5359..96019ddd564d6 100644 --- a/src/libcore/num/uint-template.rs +++ b/src/libcore/num/uint-template.rs @@ -11,13 +11,9 @@ use T = self::inst::T; use T_SIGNED = self::inst::T_SIGNED; -use to_str::ToStr; use from_str::FromStr; use num::{ToStrRadix, FromStrRadix}; use num::strconv; -use num::Unsigned; -use num; -use option::Option; use prelude::*; pub use cmp::{min, max}; @@ -100,6 +96,8 @@ pub fn compl(i: T) -> T { max_value ^ i } +impl Num for T {} + #[cfg(notest)] impl Ord for T { #[inline(always)] @@ -153,10 +151,7 @@ impl Div for T { #[inline(always)] fn div(&self, other: &T) -> T { *self / *other } } - -#[cfg(stage1,notest)] -#[cfg(stage2,notest)] -#[cfg(stage3,notest)] +#[cfg(not(stage0),notest)] impl Quot for T { #[inline(always)] fn quot(&self, other: &T) -> T { *self / *other } @@ -167,10 +162,7 @@ impl Modulo for T { #[inline(always)] fn modulo(&self, other: &T) -> T { *self % *other } } - -#[cfg(stage1,notest)] -#[cfg(stage2,notest)] -#[cfg(stage3,notest)] +#[cfg(not(stage0),notest)] impl Rem for T { #[inline(always)] fn rem(&self, other: &T) -> T { *self % *other } @@ -184,32 +176,32 @@ impl Neg for T { impl Unsigned for T {} -impl Natural for T { +impl Integer for T { /// Unsigned integer division. Returns the same result as `quot` (`/`). #[inline(always)] - fn div(&self, other: T) -> T { *self / other } + fn div(&self, other: &T) -> T { *self / *other } /// Unsigned integer modulo operation. Returns the same result as `rem` (`%`). #[inline(always)] - fn modulo(&self, other: T) -> T { *self / other } + fn modulo(&self, other: &T) -> T { *self / *other } /// Calculates `div` and `modulo` simultaneously #[inline(always)] - fn div_mod(&self, other: T) -> (T,T) { - (*self / other, *self % other) + fn div_mod(&self, other: &T) -> (T,T) { + (*self / *other, *self % *other) } /// Calculates `quot` (`\`) and `rem` (`%`) simultaneously #[inline(always)] - fn quot_rem(&self, other: T) -> (T,T) { - (*self / other, *self % other) + fn quot_rem(&self, other: &T) -> (T,T) { + (*self / *other, *self % *other) } /// Calculates the Greatest Common Divisor (GCD) of the number and `other` #[inline(always)] - fn gcd(&self, other: T) -> T { + fn gcd(&self, other: &T) -> T { // Use Euclid's algorithm - let mut m = *self, n = other; + let mut m = *self, n = *other; while m != 0 { let temp = m; m = n % temp; @@ -220,17 +212,17 @@ impl Natural for T { /// Calculates the Lowest Common Multiple (LCM) of the number and `other` #[inline(always)] - fn lcm(&self, other: T) -> T { - (*self * other) / self.gcd(other) + fn lcm(&self, other: &T) -> T { + (*self * *other) / self.gcd(other) } /// Returns `true` if the number can be divided by `other` without leaving a remainder #[inline(always)] - fn divisible_by(&self, other: T) -> bool { *self % other == 0 } + fn divisible_by(&self, other: &T) -> bool { *self % *other == 0 } /// Returns `true` if the number is divisible by `2` #[inline(always)] - fn is_even(&self) -> bool { self.divisible_by(2) } + fn is_even(&self) -> bool { self.divisible_by(&2) } /// Returns `true` if the number is not divisible by `2` #[inline(always)] @@ -356,23 +348,28 @@ mod tests { use super::inst::T; use prelude::*; + #[test] + fn test_num() { + num::test_num(10 as T, 2 as T); + } + #[test] fn test_gcd() { - assert_eq!((10 as T).gcd(2), 2 as T); - assert_eq!((10 as T).gcd(3), 1 as T); - assert_eq!((0 as T).gcd(3), 3 as T); - assert_eq!((3 as T).gcd(3), 3 as T); - assert_eq!((56 as T).gcd(42), 14 as T); + assert_eq!((10 as T).gcd(&2), 2 as T); + assert_eq!((10 as T).gcd(&3), 1 as T); + assert_eq!((0 as T).gcd(&3), 3 as T); + assert_eq!((3 as T).gcd(&3), 3 as T); + assert_eq!((56 as T).gcd(&42), 14 as T); } #[test] fn test_lcm() { - assert_eq!((1 as T).lcm(0), 0 as T); - assert_eq!((0 as T).lcm(1), 0 as T); - assert_eq!((1 as T).lcm(1), 1 as T); - assert_eq!((8 as T).lcm(9), 72 as T); - assert_eq!((11 as T).lcm(5), 55 as T); - assert_eq!((99 as T).lcm(17), 1683 as T); + assert_eq!((1 as T).lcm(&0), 0 as T); + assert_eq!((0 as T).lcm(&1), 0 as T); + assert_eq!((1 as T).lcm(&1), 1 as T); + assert_eq!((8 as T).lcm(&9), 72 as T); + assert_eq!((11 as T).lcm(&5), 55 as T); + assert_eq!((99 as T).lcm(&17), 1683 as T); } #[test] diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 465a9330f74c0..1aa7aada05c88 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -36,9 +36,7 @@ pub trait Div { fn div(&self, rhs: &RHS) -> Result; } #[lang="quot"] -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] +#[cfg(not(stage0))] pub trait Quot { fn quot(&self, rhs: &RHS) -> Result; } @@ -49,9 +47,7 @@ pub trait Modulo { fn modulo(&self, rhs: &RHS) -> Result; } #[lang="rem"] -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] +#[cfg(not(stage0))] pub trait Rem { fn rem(&self, rhs: &RHS) -> Result; } diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs index 03e6065a85caa..553bb8268102b 100644 --- a/src/libcore/prelude.rs +++ b/src/libcore/prelude.rs @@ -16,9 +16,7 @@ pub use either::{Either, Left, Right}; pub use kinds::{Const, Copy, Owned, Durable}; #[cfg(stage0)] pub use ops::{Add, Sub, Mul, Div, Modulo, Neg, Not}; -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] +#[cfg(not(stage0))] pub use ops::{Add, Sub, Mul, Quot, Rem, Neg, Not}; pub use ops::{BitAnd, BitOr, BitXor}; pub use ops::{Drop}; @@ -39,7 +37,9 @@ pub use hash::Hash; pub use iter::{BaseIter, ReverseIter, MutableIter, ExtendedIter, EqIter}; pub use iter::{CopyableIter, CopyableOrderedIter, CopyableNonstrictIter}; pub use iter::{Times, ExtendedMutableIter}; -pub use num::{Num, Signed, Unsigned, Natural, NumCast}; +pub use num::{Num, NumCast}; +pub use num::{Signed, Unsigned, Integer}; +pub use num::{Round, Fractional, Real, RealExt}; pub use path::GenericPath; pub use path::Path; pub use path::PosixPath; diff --git a/src/libstd/base64.rs b/src/libstd/base64.rs index cbdd2b19d276c..e90f0fb3c81d4 100644 --- a/src/libstd/base64.rs +++ b/src/libstd/base64.rs @@ -118,7 +118,7 @@ pub trait FromBase64 { impl FromBase64 for ~[u8] { /** * Convert base64 `u8` vector into u8 byte values. - * Every 4 encoded characters is converted into 3 octets, rem padding. + * Every 4 encoded characters is converted into 3 octets, modulo padding. * * *Example*: * diff --git a/src/libstd/num/rational.rs b/src/libstd/num/rational.rs index 36652380bff58..8af1d99fa4719 100644 --- a/src/libstd/num/rational.rs +++ b/src/libstd/num/rational.rs @@ -204,20 +204,6 @@ impl /* Utils */ impl Round for Ratio { - fn round(&self, mode: num::RoundMode) -> Ratio { - match mode { - num::RoundUp => { self.ceil() } - num::RoundDown => { self.floor()} - num::RoundToZero => { Ratio::from_integer(self.numer / self.denom) } - num::RoundFromZero => { - if *self < Zero::zero() { - Ratio::from_integer((self.numer - self.denom + One::one()) / self.denom) - } else { - Ratio::from_integer((self.numer + self.denom - One::one()) / self.denom) - } - } - } - } fn floor(&self) -> Ratio { if *self < Zero::zero() { @@ -226,6 +212,7 @@ impl Ratio::from_integer(self.numer / self.denom) } } + fn ceil(&self) -> Ratio { if *self < Zero::zero() { Ratio::from_integer(self.numer / self.denom) @@ -233,6 +220,21 @@ impl Ratio::from_integer((self.numer + self.denom - One::one()) / self.denom) } } + + #[inline(always)] + fn round(&self) -> Ratio { + if *self < Zero::zero() { + Ratio::from_integer((self.numer - self.denom + One::one()) / self.denom) + } else { + Ratio::from_integer((self.numer + self.denom - One::one()) / self.denom) + } + } + + #[inline(always)] + fn trunc(&self) -> Ratio { + Ratio::from_integer(self.numer / self.denom) + } + fn fract(&self) -> Ratio { Ratio::new_raw(self.numer % self.denom, self.denom) } @@ -421,18 +423,18 @@ mod test { fn test_round() { assert_eq!(_1_2.ceil(), _1); assert_eq!(_1_2.floor(), _0); - assert_eq!(_1_2.round(num::RoundToZero), _0); - assert_eq!(_1_2.round(num::RoundFromZero), _1); + assert_eq!(_1_2.round(), _1); + assert_eq!(_1_2.trunc(), _0); assert_eq!(_neg1_2.ceil(), _0); assert_eq!(_neg1_2.floor(), -_1); - assert_eq!(_neg1_2.round(num::RoundToZero), _0); - assert_eq!(_neg1_2.round(num::RoundFromZero), -_1); + assert_eq!(_neg1_2.round(), -_1); + assert_eq!(_neg1_2.trunc(), _0); assert_eq!(_1.ceil(), _1); assert_eq!(_1.floor(), _1); - assert_eq!(_1.round(num::RoundToZero), _1); - assert_eq!(_1.round(num::RoundFromZero), _1); + assert_eq!(_1.round(), _1); + assert_eq!(_1.trunc(), _1); } #[test] diff --git a/src/libstd/std.rc b/src/libstd/std.rc index 7bedef0f84110..07c679409cf68 100644 --- a/src/libstd/std.rc +++ b/src/libstd/std.rc @@ -76,9 +76,7 @@ pub mod rope; pub mod smallintmap; pub mod sort; pub mod dlist; -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] +#[cfg(not(stage0))] pub mod treemap; // And ... other stuff @@ -98,19 +96,13 @@ pub mod cmp; pub mod base64; pub mod rl; pub mod workcache; -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] +#[cfg(not(stage0))] #[path="num/bigint.rs"] pub mod bigint; -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] +#[cfg(not(stage0))] #[path="num/rational.rs"] pub mod rational; -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] +#[cfg(not(stage0))] #[path="num/complex.rs"] pub mod complex; pub mod stats;