From 593bdd9be3959f166c303e3da0678cc9598bffc4 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Wed, 24 Apr 2013 17:25:41 +1000 Subject: [PATCH 1/8] Fix incorrect replacement of `modulo` with `rem` --- src/libstd/base64.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/base64.rs b/src/libstd/base64.rs index cbdd2b19d276..e90f0fb3c81d 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*: * From 03932f0b84e94f0ef96e4a6de6cb16ab436311e4 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Wed, 24 Apr 2013 20:08:08 +1000 Subject: [PATCH 2/8] Move impls of `Num` out of core::num and clean up imports --- src/libcore/num/f32.rs | 25 +++++++++++------------ src/libcore/num/f64.rs | 25 +++++++++++------------ src/libcore/num/float.rs | 24 +++++++++------------- src/libcore/num/int-template.rs | 10 ++++++--- src/libcore/num/num.rs | 35 +++++--------------------------- src/libcore/num/uint-template.rs | 11 ++++++---- 6 files changed, 53 insertions(+), 77 deletions(-) diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 5d663844e5b7..e72356aa3cbd 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)] @@ -588,6 +580,13 @@ impl num::FromStrRadix for f32 { #[cfg(test)] mod tests { use f32::*; + use super::*; + use prelude::*; + + #[test] + fn test_num() { + num::test_num(10f32, 2f32); + } #[test] pub fn test_signed() { diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 48f23fe8ba94..c9867f5e6d40 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)] @@ -596,6 +588,13 @@ impl num::FromStrRadix for f64 { #[cfg(test)] mod tests { use f64::*; + use super::*; + use prelude::*; + + #[test] + fn test_num() { + num::test_num(10f64, 2f64); + } #[test] pub fn test_signed() { diff --git a/src/libcore/num/float.rs b/src/libcore/num/float.rs index 036d295943c7..e2f3a4cbcdb1 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)] @@ -524,6 +515,11 @@ mod tests { use super::*; use prelude::*; + #[test] + fn test_num() { + num::test_num(10f, 2f); + } + #[test] pub fn test_signed() { assert_eq!(infinity.abs(), infinity); diff --git a/src/libcore/num/int-template.rs b/src/libcore/num/int-template.rs index 426ed8a8b0f6..6598efa759ec 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)] @@ -522,6 +521,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); diff --git a/src/libcore/num/num.rs b/src/libcore/num/num.rs index 577bb3f0f150..62ed80114d34 100644 --- a/src/libcore/num/num.rs +++ b/src/libcore/num/num.rs @@ -33,30 +33,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; } @@ -230,8 +218,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 +236,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 +250,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 a0da84a8c535..fc0fe2d3a4d2 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)] @@ -356,6 +354,11 @@ 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); From d4868ee74085c2dc2943ef9407ced2d06e43abf6 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Wed, 24 Apr 2013 22:26:14 +1000 Subject: [PATCH 3/8] Use #[cfg(not(stage0))] to exclude items from stage0 As requested on the mailing list: https://mail.mozilla.org/pipermail/rust-dev/2013-April/003713.html --- src/libcore/core.rc | 4 +--- src/libcore/num/f32.rs | 10 ++-------- src/libcore/num/f64.rs | 8 ++------ src/libcore/num/float.rs | 8 ++------ src/libcore/num/int-template.rs | 10 ++-------- src/libcore/num/num.rs | 4 +--- src/libcore/num/uint-template.rs | 10 ++-------- src/libcore/ops.rs | 8 ++------ src/libcore/prelude.rs | 4 +--- src/libstd/std.rc | 16 ++++------------ 10 files changed, 19 insertions(+), 63 deletions(-) diff --git a/src/libcore/core.rc b/src/libcore/core.rc index 61fbf98a7c61..7890d611e853 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}; diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index e72356aa3cbd..9e4140adcd13 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -278,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 } @@ -292,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 } diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index c9867f5e6d40..12f86337e850 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -292,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 } @@ -303,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 } diff --git a/src/libcore/num/float.rs b/src/libcore/num/float.rs index e2f3a4cbcdb1..88321e6b8bf0 100644 --- a/src/libcore/num/float.rs +++ b/src/libcore/num/float.rs @@ -459,9 +459,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 } @@ -471,9 +469,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 } diff --git a/src/libcore/num/int-template.rs b/src/libcore/num/int-template.rs index 6598efa759ec..cb29b9e44863 100644 --- a/src/libcore/num/int-template.rs +++ b/src/libcore/num/int-template.rs @@ -185,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 @@ -217,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: diff --git a/src/libcore/num/num.rs b/src/libcore/num/num.rs index 62ed80114d34..8304179c346a 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; diff --git a/src/libcore/num/uint-template.rs b/src/libcore/num/uint-template.rs index fc0fe2d3a4d2..2ee64d4e4eaa 100644 --- a/src/libcore/num/uint-template.rs +++ b/src/libcore/num/uint-template.rs @@ -151,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 } @@ -165,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 } diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 465a9330f74c..1aa7aada05c8 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 03e6065a85ca..0af0cdf08c91 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}; diff --git a/src/libstd/std.rc b/src/libstd/std.rc index 7bedef0f8411..07c679409cf6 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; From 024bf2ec72bdc2428d5c58a59bfed7da1bbc4efd Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Wed, 24 Apr 2013 22:45:57 +1000 Subject: [PATCH 4/8] Rename Natural to Integer 'Natural' normally means 'positive integer' in mathematics. It is therefore strange to implement it on signed integer types. 'Integer' is probably a better choice. --- src/libcore/core.rc | 3 ++- src/libcore/num/int-template.rs | 2 +- src/libcore/num/num.rs | 2 +- src/libcore/num/uint-template.rs | 2 +- src/libcore/prelude.rs | 3 ++- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/libcore/core.rc b/src/libcore/core.rc index 7890d611e853..2a8de6a80322 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -103,7 +103,8 @@ 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 ptr::Ptr; pub use to_str::ToStr; pub use clone::Clone; diff --git a/src/libcore/num/int-template.rs b/src/libcore/num/int-template.rs index cb29b9e44863..e322e5edeb90 100644 --- a/src/libcore/num/int-template.rs +++ b/src/libcore/num/int-template.rs @@ -279,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 * diff --git a/src/libcore/num/num.rs b/src/libcore/num/num.rs index 8304179c346a..1c3c699603b0 100644 --- a/src/libcore/num/num.rs +++ b/src/libcore/num/num.rs @@ -61,7 +61,7 @@ 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 { diff --git a/src/libcore/num/uint-template.rs b/src/libcore/num/uint-template.rs index 2ee64d4e4eaa..69483f33e528 100644 --- a/src/libcore/num/uint-template.rs +++ b/src/libcore/num/uint-template.rs @@ -176,7 +176,7 @@ 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 } diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs index 0af0cdf08c91..ec332adb8323 100644 --- a/src/libcore/prelude.rs +++ b/src/libcore/prelude.rs @@ -37,7 +37,8 @@ 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 path::GenericPath; pub use path::Path; pub use path::PosixPath; From 6fa054df968198eff4513e483dee07e1e3612dad Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Wed, 24 Apr 2013 22:50:56 +1000 Subject: [PATCH 5/8] Use borrowed pointers for Integer methods This brings them in line with the quot and rem traits, and is be better for large Integer types like BigInt and BigUint because they don't need to be copied unnecessarily. --- src/libcore/num/int-template.rs | 80 ++++++++++++++++---------------- src/libcore/num/num.rs | 14 +++--- src/libcore/num/uint-template.rs | 46 +++++++++--------- 3 files changed, 70 insertions(+), 70 deletions(-) diff --git a/src/libcore/num/int-template.rs b/src/libcore/num/int-template.rs index e322e5edeb90..f9edf1cefc87 100644 --- a/src/libcore/num/int-template.rs +++ b/src/libcore/num/int-template.rs @@ -298,13 +298,13 @@ impl Integer 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, } } @@ -330,32 +330,32 @@ impl Integer 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) } /** @@ -364,9 +364,9 @@ impl Integer 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; @@ -379,17 +379,17 @@ impl Integer 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)] @@ -562,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); @@ -586,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); @@ -609,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 1c3c699603b0..076d90707f62 100644 --- a/src/libcore/num/num.rs +++ b/src/libcore/num/num.rs @@ -65,14 +65,14 @@ 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 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 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; } diff --git a/src/libcore/num/uint-template.rs b/src/libcore/num/uint-template.rs index 69483f33e528..96019ddd564d 100644 --- a/src/libcore/num/uint-template.rs +++ b/src/libcore/num/uint-template.rs @@ -179,29 +179,29 @@ impl Unsigned 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; @@ -212,17 +212,17 @@ impl Integer 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)] @@ -355,21 +355,21 @@ 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!((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] From dcd49ccd0ba5616995da00454389b6454423813c Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Thu, 25 Apr 2013 08:12:26 +1000 Subject: [PATCH 6/8] Add Fractional, Real and RealExt traits --- src/libcore/core.rc | 1 + src/libcore/num/f32.rs | 209 ++++++++++++++++++++++++++++++--- src/libcore/num/f64.rs | 237 ++++++++++++++++++++++++++++++++++--- src/libcore/num/float.rs | 247 +++++++++++++++++++++++++++++++++++---- src/libcore/num/num.rs | 100 ++++++++++++++-- src/libcore/prelude.rs | 1 + 6 files changed, 724 insertions(+), 71 deletions(-) diff --git a/src/libcore/core.rc b/src/libcore/core.rc index 2a8de6a80322..0a24fba66633 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 9e4140adcd13..57ac6c551766 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 12f86337e850..53ad78c29f39 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 88321e6b8bf0..ae2d0ce0d719 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 076d90707f62..733b37e2a4a6 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 ec332adb8323..c161bd4cf59e 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; From 48c24188f9191888110ebea2bc5193de9a0b26d5 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Thu, 25 Apr 2013 11:53:04 +1000 Subject: [PATCH 7/8] Restore Round trait and move appropriate methods out of Real --- src/libcore/core.rc | 2 +- src/libcore/num/f32.rs | 114 +++++++++++++++++++++++++++++++----- src/libcore/num/f64.rs | 117 +++++++++++++++++++++++++++++++------ src/libcore/num/float.rs | 123 +++++++++++++++++++++++++++++++-------- src/libcore/num/num.rs | 16 ++--- src/libcore/prelude.rs | 2 +- 6 files changed, 307 insertions(+), 67 deletions(-) diff --git a/src/libcore/core.rc b/src/libcore/core.rc index 0a24fba66633..71bbaf557ce3 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -105,7 +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 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 57ac6c551766..7d5807ba5462 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -327,6 +327,34 @@ impl Signed for f32 { fn is_negative(&self) -> bool { *self < 0.0 || (1.0 / *self) == neg_infinity } } +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 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)] @@ -402,22 +430,6 @@ impl Real for f32 { #[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 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) } @@ -736,6 +748,76 @@ mod tests { 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::()); diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 53ad78c29f39..3b6198bfc472 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -337,6 +337,34 @@ impl Signed for f64 { fn is_negative(&self) -> bool { *self < 0.0 || (1.0 / *self) == neg_infinity } } +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 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)] @@ -412,22 +440,6 @@ impl Real for f64 { #[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 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) } @@ -766,7 +778,8 @@ mod tests { ($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)); + fail!(fmt!("The values were not approximately equal. \ + Found: %? and expected %?", a, b)); } }) ) @@ -776,6 +789,76 @@ mod tests { 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::()); diff --git a/src/libcore/num/float.rs b/src/libcore/num/float.rs index ae2d0ce0d719..9c0412b422f5 100644 --- a/src/libcore/num/float.rs +++ b/src/libcore/num/float.rs @@ -403,6 +403,34 @@ impl num::One for float { fn one() -> float { 1.0 } } +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 ceil(&self) -> float { ceil(*self as f64) as float } + + /// Round half-way cases away from `0.0` + #[inline(always)] + fn round(&self) -> float { round(*self as f64) as float } + + /// The integer part of the number (rounds towards `0.0`) + #[inline(always)] + 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)] @@ -478,22 +506,6 @@ impl Real for float { #[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 } @@ -694,6 +706,76 @@ mod tests { 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::()); @@ -893,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/num.rs b/src/libcore/num/num.rs index 733b37e2a4a6..e19afdc69c32 100644 --- a/src/libcore/num/num.rs +++ b/src/libcore/num/num.rs @@ -77,8 +77,17 @@ pub trait Integer: Num fn is_odd(&self) -> bool; } +pub trait Round { + fn floor(&self) -> Self; + fn ceil(&self) -> Self; + fn round(&self) -> Self; + fn trunc(&self) -> Self; + fn fract(&self) -> Self; +} + pub trait Fractional: Num + Ord + + Round + Quot { fn recip(&self) -> Self; } @@ -108,13 +117,6 @@ pub trait Real: Signed 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; diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs index c161bd4cf59e..553bb8268102 100644 --- a/src/libcore/prelude.rs +++ b/src/libcore/prelude.rs @@ -39,7 +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 num::{Round, Fractional, Real, RealExt}; pub use path::GenericPath; pub use path::Path; pub use path::PosixPath; From 225ac216157cf530332cef1c926875e2023e48e6 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Thu, 25 Apr 2013 11:53:51 +1000 Subject: [PATCH 8/8] Update impl of Round for Ratio --- src/libstd/num/rational.rs | 42 ++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/libstd/num/rational.rs b/src/libstd/num/rational.rs index 36652380bff5..8af1d99fa471 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]