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 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*: * 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 5d663844e5b79..e72356aa3cbd3 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 48f23fe8ba946..c9867f5e6d40f 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 036d295943c7b..e2f3a4cbcdb13 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 426ed8a8b0f6e..6598efa759ec2 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 577bb3f0f150a..62ed80114d345 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 a0da84a8c5359..fc0fe2d3a4d28 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 61fbf98a7c61d..7890d611e853d 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 e72356aa3cbd3..9e4140adcd131 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 c9867f5e6d40f..12f86337e8500 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 e2f3a4cbcdb13..88321e6b8bf0f 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 6598efa759ec2..cb29b9e448633 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 62ed80114d345..8304179c346ae 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 fc0fe2d3a4d28..2ee64d4e4eaa6 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 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..0af0cdf08c91b 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 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; 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 7890d611e853d..2a8de6a80322c 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 cb29b9e448633..e322e5edeb90e 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 8304179c346ae..1c3c699603b0d 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 2ee64d4e4eaa6..69483f33e5281 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 0af0cdf08c91b..ec332adb8323b 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 | 16 +++---- src/libcore/num/uint-template.rs | 46 +++++++++--------- 3 files changed, 71 insertions(+), 71 deletions(-) diff --git a/src/libcore/num/int-template.rs b/src/libcore/num/int-template.rs index e322e5edeb90e..f9edf1cefc873 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 1c3c699603b0d..076d90707f62e 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 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; } diff --git a/src/libcore/num/uint-template.rs b/src/libcore/num/uint-template.rs index 69483f33e5281..96019ddd564d6 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 | 211 ++++++++++++++++++++++++++++++--- src/libcore/num/f64.rs | 239 ++++++++++++++++++++++++++++++++++--- src/libcore/num/float.rs | 249 +++++++++++++++++++++++++++++++++++---- src/libcore/num/num.rs | 94 +++++++++++++-- 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 2a8de6a80322c..0a24fba666334 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 9e4140adcd131..57ac6c551766b 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 { - #[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 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 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 12f86337e8500..53ad78c29f392 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 { - #[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 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 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 88321e6b8bf0f..ae2d0ce0d7194 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 { - #[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 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 floor(&self) -> float { f64::floor(*self as f64) as float} + fn pi() -> float { 3.14159265358979323846264338327950288 } + + /// 2.0 * pi #[inline(always)] - fn ceil(&self) -> float { f64::ceil(*self as f64) as float} + fn two_pi() -> float { 6.28318530717958647692528676655900576 } + + /// pi / 2.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 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 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)] @@ -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 076d90707f62e..733b37e2a4a62 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; +pub trait Fractional: Num + + Ord + + 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; + + // Rounding operations fn floor(&self) -> Self; - fn ceil(&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; } -pub enum RoundMode { - RoundDown, - RoundUp, - RoundToZero, - RoundFromZero +/// 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 ec332adb8323b..c161bd4cf59e2 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 0a24fba666334..71bbaf557ce38 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 57ac6c551766b..7d5807ba5462c 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 53ad78c29f392..3b6198bfc472e 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 ae2d0ce0d7194..9c0412b422f52 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 733b37e2a4a62..e19afdc69c32f 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 c161bd4cf59e2..553bb8268102b 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 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]