From cfe2b1bf7a27a511c326ca2668bdfb6b41977b27 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Fri, 26 Jul 2013 01:09:15 +1000 Subject: [PATCH 1/4] Divide Num trait into Semiring, Ring, and Field. Rename Orderable to OrderedRing. These names follow the mathematical conventions. The greater fidelity of these traits allows them to be used on other mathematical structures such as vectors and quaternions. --- src/libextra/num/bigint.rs | 16 +++++--- src/libextra/num/complex.rs | 24 +++++------ src/libextra/num/rational.rs | 11 +++-- src/libstd/num/f32.rs | 10 +++-- src/libstd/num/f64.rs | 10 +++-- src/libstd/num/float.rs | 10 +++-- src/libstd/num/int_macros.rs | 10 +++-- src/libstd/num/num.rs | 75 ++++++++++++++++++----------------- src/libstd/num/uint_macros.rs | 6 ++- src/libstd/prelude.rs | 5 +-- 10 files changed, 101 insertions(+), 76 deletions(-) diff --git a/src/libextra/num/bigint.rs b/src/libextra/num/bigint.rs index 46a7445727491..464292514ef35 100644 --- a/src/libextra/num/bigint.rs +++ b/src/libextra/num/bigint.rs @@ -22,7 +22,7 @@ A BigInt is a combination of BigUint and Sign. use std::cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater}; use std::int; use std::num; -use std::num::{IntConvertible, Zero, One, ToStrRadix, FromStrRadix, Orderable}; +use std::num::{IntConvertible, Zero, One, ToStrRadix, FromStrRadix, OrderedRing}; use std::str; use std::uint; use std::vec; @@ -151,9 +151,11 @@ impl FromStr for BigUint { } } -impl Num for BigUint {} +impl Semiring for BigUint; -impl Orderable for BigUint { +impl Ring for BigUint; + +impl OrderedRing for BigUint { fn min(&self, other: &BigUint) -> BigUint { if self < other { self.clone() } else { other.clone() } @@ -202,7 +204,7 @@ impl One for BigUint { fn one() -> BigUint { BigUint::new(~[1]) } } -impl Unsigned for BigUint {} +impl Unsigned for BigUint; impl Add for BigUint { @@ -826,9 +828,11 @@ impl FromStr for BigInt { } } -impl Num for BigInt {} +impl Semiring for BigUint; + +impl Ring for BigInt; -impl Orderable for BigInt { +impl OrderedRing for BigInt { fn min(&self, other: &BigInt) -> BigInt { if self < other { self.clone() } else { other.clone() } diff --git a/src/libextra/num/complex.rs b/src/libextra/num/complex.rs index 00224f8b06d98..fc9cbfbb4453d 100644 --- a/src/libextra/num/complex.rs +++ b/src/libextra/num/complex.rs @@ -34,7 +34,7 @@ pub type Complex = Cmplx; pub type Complex32 = Cmplx; pub type Complex64 = Cmplx; -impl Cmplx { +impl Cmplx { /// Create a new Cmplx #[inline] pub fn new(re: T, im: T) -> Cmplx { @@ -79,7 +79,7 @@ impl Cmplx { } } -impl Cmplx { +impl Cmplx { /// Calculate |self| #[inline] pub fn norm(&self) -> T { @@ -87,7 +87,7 @@ impl Cmplx { } } -impl Cmplx { +impl Cmplx { /// Calculate the principal Arg of self. #[inline] pub fn arg(&self) -> T { @@ -108,21 +108,21 @@ impl Cmplx { /* arithmetic */ // (a + i b) + (c + i d) == (a + c) + i (b + d) -impl Add, Cmplx> for Cmplx { +impl Add, Cmplx> for Cmplx { #[inline] fn add(&self, other: &Cmplx) -> Cmplx { Cmplx::new(self.re + other.re, self.im + other.im) } } // (a + i b) - (c + i d) == (a - c) + i (b - d) -impl Sub, Cmplx> for Cmplx { +impl Sub, Cmplx> for Cmplx { #[inline] fn sub(&self, other: &Cmplx) -> Cmplx { Cmplx::new(self.re - other.re, self.im - other.im) } } // (a + i b) * (c + i d) == (a*c - b*d) + i (a*d + b*c) -impl Mul, Cmplx> for Cmplx { +impl Mul, Cmplx> for Cmplx { #[inline] fn mul(&self, other: &Cmplx) -> Cmplx { Cmplx::new(self.re*other.re - self.im*other.im, @@ -132,7 +132,7 @@ impl Mul, Cmplx> for Cmplx { // (a + i b) / (c + i d) == [(a + i b) * (c - i d)] / (c*c + d*d) // == [(a*c + b*d) / (c*c + d*d)] + i [(b*c - a*d) / (c*c + d*d)] -impl Div, Cmplx> for Cmplx { +impl Div, Cmplx> for Cmplx { #[inline] fn div(&self, other: &Cmplx) -> Cmplx { let norm_sqr = other.norm_sqr(); @@ -141,7 +141,7 @@ impl Div, Cmplx> for Cmplx { } } -impl Neg> for Cmplx { +impl Neg> for Cmplx { #[inline] fn neg(&self) -> Cmplx { Cmplx::new(-self.re, -self.im) @@ -149,7 +149,7 @@ impl Neg> for Cmplx { } /* constants */ -impl Zero for Cmplx { +impl Zero for Cmplx { #[inline] fn zero() -> Cmplx { Cmplx::new(Zero::zero(), Zero::zero()) @@ -161,7 +161,7 @@ impl Zero for Cmplx { } } -impl One for Cmplx { +impl One for Cmplx { #[inline] fn one() -> Cmplx { Cmplx::new(One::one(), Zero::zero()) @@ -169,7 +169,7 @@ impl One for Cmplx { } /* string conversions */ -impl ToStr for Cmplx { +impl ToStr for Cmplx { fn to_str(&self) -> ~str { if self.im < Zero::zero() { fmt!("%s-%si", self.re.to_str(), (-self.im).to_str()) @@ -179,7 +179,7 @@ impl ToStr for Cmplx { } } -impl ToStrRadix for Cmplx { +impl ToStrRadix for Cmplx { fn to_str_radix(&self, radix: uint) -> ~str { if self.im < Zero::zero() { fmt!("%s-%si", self.re.to_str_radix(radix), (-self.im).to_str_radix(radix)) diff --git a/src/libextra/num/rational.rs b/src/libextra/num/rational.rs index ff14009e5561a..f8e9d46654fbd 100644 --- a/src/libextra/num/rational.rs +++ b/src/libextra/num/rational.rs @@ -110,7 +110,7 @@ cmp_impl!(impl TotalEq, equals) cmp_impl!(impl Ord, lt, gt, le, ge) cmp_impl!(impl TotalOrd, cmp -> cmp::Ordering) -impl Orderable for Ratio { +impl OrderedRing for Ratio { #[inline] fn min(&self, other: &Ratio) -> Ratio { if *self < *other { self.clone() } else { other.clone() } @@ -201,8 +201,9 @@ impl } } -impl - Num for Ratio {} +impl Semiring for Ratio; + +impl Ring for Ratio; /* Utils */ impl @@ -243,13 +244,15 @@ impl } } -impl Fractional for Ratio { +impl Field for Ratio { #[inline] fn recip(&self) -> Ratio { Ratio::new_raw(self.denom.clone(), self.numer.clone()) } } +impl Fractional for Ratio; + /* String conversions */ impl ToStr for Ratio { /// Renders as `numer/denom`. diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index faf9b2e2390dc..45e465d066772 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -165,7 +165,9 @@ pub mod consts { pub static ln_10: f32 = 2.30258509299404568401799145468436421_f32; } -impl Num for f32 {} +impl Semiring for f32; + +impl Ring for f32; #[cfg(not(test))] impl Eq for f32 { @@ -203,7 +205,7 @@ impl Ord for f32 { fn gt(&self, other: &f32) -> bool { (*self) > (*other) } } -impl Orderable for f32 { +impl OrderedRing for f32 { /// Returns `NaN` if either of the numbers are `NaN`. #[inline] fn min(&self, other: &f32) -> f32 { @@ -350,12 +352,14 @@ impl Round for f32 { fn fract(&self) -> f32 { *self - self.trunc() } } -impl Fractional for f32 { +impl Field for f32 { /// The reciprocal (multiplicative inverse) of the number #[inline] fn recip(&self) -> f32 { 1.0 / *self } } +impl Fractional for f32; + impl Algebraic for f32 { #[inline] fn pow(&self, n: &f32) -> f32 { pow(*self, *n) } diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index c7db60e6fd264..23905845da4b5 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -188,7 +188,9 @@ pub mod consts { pub static ln_10: f64 = 2.30258509299404568401799145468436421_f64; } -impl Num for f64 {} +impl Semiring for f64; + +impl Ring for f64; #[cfg(not(test))] impl Eq for f64 { @@ -226,7 +228,7 @@ impl Ord for f64 { fn gt(&self, other: &f64) -> bool { (*self) > (*other) } } -impl Orderable for f64 { +impl OrderedRing for f64 { /// Returns `NaN` if either of the numbers are `NaN`. #[inline] fn min(&self, other: &f64) -> f64 { @@ -363,12 +365,14 @@ impl Round for f64 { fn fract(&self) -> f64 { *self - self.trunc() } } -impl Fractional for f64 { +impl Field for f64 { /// The reciprocal (multiplicative inverse) of the number #[inline] fn recip(&self) -> f64 { 1.0 / *self } } +impl Fractional for f64; + impl Algebraic for f64 { #[inline] fn pow(&self, n: &f64) -> f64 { pow(*self, *n) } diff --git a/src/libstd/num/float.rs b/src/libstd/num/float.rs index 486d35620899a..595366b487942 100644 --- a/src/libstd/num/float.rs +++ b/src/libstd/num/float.rs @@ -332,7 +332,9 @@ pub fn pow_with_uint(base: uint, pow: uint) -> float { return total; } -impl Num for float {} +impl Semiring for float; + +impl Ring for float; #[cfg(not(test))] impl Eq for float { @@ -370,7 +372,7 @@ impl Ord for float { fn gt(&self, other: &float) -> bool { (*self) > (*other) } } -impl Orderable for float { +impl OrderedRing for float { /// Returns `NaN` if either of the numbers are `NaN`. #[inline] fn min(&self, other: &float) -> float { @@ -433,12 +435,14 @@ impl Round for float { fn fract(&self) -> float { *self - self.trunc() } } -impl Fractional for float { +impl Field for float { /// The reciprocal (multiplicative inverse) of the number #[inline] fn recip(&self) -> float { 1.0 / *self } } +impl Fractional for float; + impl Algebraic for float { #[inline] fn pow(&self, n: &float) -> float { diff --git a/src/libstd/num/int_macros.rs b/src/libstd/num/int_macros.rs index cef32b5c7e445..c182c1f8edcd0 100644 --- a/src/libstd/num/int_macros.rs +++ b/src/libstd/num/int_macros.rs @@ -138,7 +138,9 @@ pub fn range_rev(hi: $T, lo: $T, it: &fn($T) -> bool) -> bool { range_step_inclusive(hi-1, lo, -1 as $T, it) } -impl Num for $T {} +impl Semiring for $T; + +impl Ring for $T; #[cfg(not(test))] impl Ord for $T { @@ -160,7 +162,7 @@ impl Eq for $T { fn ne(&self, other: &$T) -> bool { return (*self) != (*other); } } -impl Orderable for $T { +impl OrderedRing for $T { #[inline] fn min(&self, other: &$T) -> $T { if *self < *other { *self } else { *other } @@ -425,7 +427,7 @@ impl Integer for $T { fn is_odd(&self) -> bool { !self.is_even() } } -impl Bitwise for $T {} +impl Bitwise for $T; #[cfg(not(test))] impl BitOr<$T,$T> for $T { @@ -471,7 +473,7 @@ impl Bounded for $T { fn max_value() -> $T { max_value } } -impl Int for $T {} +impl Int for $T; impl Primitive for $T { #[inline] diff --git a/src/libstd/num/num.rs b/src/libstd/num/num.rs index f35f495def3a1..dfaf1fafab1fb 100644 --- a/src/libstd/num/num.rs +++ b/src/libstd/num/num.rs @@ -19,23 +19,40 @@ use option::Option; pub mod strconv; -/// -/// The base trait for numeric types -/// -pub trait Num: Eq + Zero + One - + Neg - + Add - + Sub - + Mul - + Div - + Rem {} +pub trait Zero { + fn zero() -> Self; // FIXME (#5527): This should be an associated constant + fn is_zero(&self) -> bool; +} + +pub trait One { + fn one() -> Self; // FIXME (#5527): This should be an associated constant +} pub trait IntConvertible { fn to_int(&self) -> int; fn from_int(n: int) -> Self; } -pub trait Orderable: Ord { +/// An algebraic structure that generalizes the addition and multiplication +/// operations and their respective identities (`Zero` and `One`). +pub trait Semiring: Eq + + Add + + Mul + + Zero + One {} + +/// A `Semiring` that also requires the additive inverse operation (subtraction). +pub trait Ring: Semiring + + Neg + + Sub {} + +/// A `Ring` that also requires the multiplicative inverse operation (division). +pub trait Field: Ring + + Div + + Rem { + fn recip(&self) -> Self; +} + +pub trait OrderedRing: Ring + Ord { // These should be methods on `Ord`, with overridable default implementations. We don't want // to encumber all implementors of Ord by requiring them to implement these functions, but at // the same time we want to be able to take advantage of the speed of the specific numeric @@ -45,19 +62,10 @@ pub trait Orderable: Ord { fn clamp(&self, mn: &Self, mx: &Self) -> Self; } -#[inline(always)] pub fn min(a: T, b: T) -> T { a.min(&b) } -#[inline(always)] pub fn max(a: T, b: T) -> T { a.max(&b) } - -pub trait Zero { - fn zero() -> Self; // FIXME (#5527): This should be an associated constant - fn is_zero(&self) -> bool; -} - -pub trait One { - fn one() -> Self; // FIXME (#5527): This should be an associated constant -} +#[inline(always)] pub fn min(a: T, b: T) -> T { a.min(&b) } +#[inline(always)] pub fn max(a: T, b: T) -> T { a.max(&b) } -pub trait Signed: Num +pub trait Signed: Ring + Neg { fn abs(&self) -> Self; fn abs_sub(&self, other: &Self) -> Self; @@ -70,10 +78,9 @@ pub trait Signed: Num #[inline(always)] pub fn abs(value: T) -> T { value.abs() } #[inline(always)] pub fn signum(value: T) -> T { value.signum() } -pub trait Unsigned: Num {} +pub trait Unsigned: Ring {} -pub trait Integer: Num - + Orderable +pub trait Integer: OrderedRing + Div + Rem { fn div_rem(&self, other: &Self) -> (Self,Self); @@ -98,12 +105,9 @@ pub trait Round { fn fract(&self) -> Self; } -pub trait Fractional: Num - + Orderable - + Round - + Div { - fn recip(&self) -> Self; -} +pub trait Fractional: Field + + OrderedRing + + Round {} pub trait Algebraic { fn pow(&self, n: &Self) -> Self; @@ -250,7 +254,7 @@ pub trait Bounded { /// These may not always make sense from a purely mathematical point of view, but /// may be useful for systems programming. /// -pub trait Primitive: Num +pub trait Primitive: OrderedRing + NumCast + Bounded + Neg @@ -293,7 +297,6 @@ pub enum FPCategory { /// Primitive floating point numbers /// pub trait Float: Real - + Signed + Primitive + ApproxEq { // FIXME (#5527): These should be associated constants @@ -461,9 +464,9 @@ impl Zero for ~T { fn is_zero(&self) -> bool { (**self).is_zero() } } -/// Helper function for testing numeric operations +/// Helper function for testing numeric primitives #[cfg(test)] -pub 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)); diff --git a/src/libstd/num/uint_macros.rs b/src/libstd/num/uint_macros.rs index acf7ea683fb54..fe94184477925 100644 --- a/src/libstd/num/uint_macros.rs +++ b/src/libstd/num/uint_macros.rs @@ -138,7 +138,9 @@ pub fn range_rev(hi: $T, lo: $T, it: &fn($T) -> bool) -> bool { range_step_inclusive(hi-1, lo, -1 as $T_SIGNED, it) } -impl Num for $T {} +impl Semiring for $T; + +impl Ring for $T; #[cfg(not(test))] impl Ord for $T { @@ -160,7 +162,7 @@ impl Eq for $T { fn ne(&self, other: &$T) -> bool { return (*self) != (*other); } } -impl Orderable for $T { +impl OrderedRing for $T { #[inline] fn min(&self, other: &$T) -> $T { if *self < *other { *self } else { *other } diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index 0d9446bcfca7d..aa59eb377bbef 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -50,12 +50,11 @@ pub use hash::Hash; pub use iter::Times; pub use iterator::{Iterator, IteratorUtil, DoubleEndedIterator, DoubleEndedIteratorUtil}; pub use iterator::OrdIterator; -pub use num::{Num, NumCast}; -pub use num::{Orderable, Signed, Unsigned, Round}; +pub use num::{Semiring, Ring, Field, OrderedRing, Signed, Unsigned, Round}; pub use num::{Algebraic, Trigonometric, Exponential, Hyperbolic}; pub use num::{Integer, Fractional, Real, RealExt}; pub use num::{Bitwise, BitCount, Bounded}; -pub use num::{Primitive, Int, Float}; +pub use num::{Primitive, Int, Float, NumCast}; pub use path::GenericPath; pub use path::Path; pub use path::PosixPath; From e3a3d79c3ec4c0cd933aea6b3d91ac53e0270ba6 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Fri, 26 Jul 2013 09:00:40 +1000 Subject: [PATCH 2/4] Add `zero` and `one` wrapper functions --- src/libstd/num/num.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libstd/num/num.rs b/src/libstd/num/num.rs index dfaf1fafab1fb..b344bdf1ecafb 100644 --- a/src/libstd/num/num.rs +++ b/src/libstd/num/num.rs @@ -28,6 +28,9 @@ pub trait One { fn one() -> Self; // FIXME (#5527): This should be an associated constant } +#[inline] pub fn zero() -> T { Zero::zero() } +#[inline] pub fn one() -> T { One::one() } + pub trait IntConvertible { fn to_int(&self) -> int; fn from_int(n: int) -> Self; From c005f3232f7a7c517479261c730ff321ce5496c9 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Fri, 26 Jul 2013 09:04:09 +1000 Subject: [PATCH 3/4] Update tests --- src/test/run-pass/trait-inheritance-num.rs | 3 +-- src/test/run-pass/trait-inheritance-num0.rs | 2 +- src/test/run-pass/trait-inheritance-num1.rs | 2 +- src/test/run-pass/trait-inheritance-num2.rs | 4 +--- src/test/run-pass/trait-inheritance-num3.rs | 3 +-- src/test/run-pass/trait-inheritance-num5.rs | 3 +-- 6 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/test/run-pass/trait-inheritance-num.rs b/src/test/run-pass/trait-inheritance-num.rs index 87de3a2be1496..586d46a30473e 100644 --- a/src/test/run-pass/trait-inheritance-num.rs +++ b/src/test/run-pass/trait-inheritance-num.rs @@ -12,10 +12,9 @@ extern mod extra; -use std::cmp::{Eq, Ord}; use std::num::NumCast; -pub trait NumExt: Num + NumCast + Eq + Ord {} +pub trait NumExt: OrderedRing + NumCast {} pub trait FloatExt: NumExt + ApproxEq {} diff --git a/src/test/run-pass/trait-inheritance-num0.rs b/src/test/run-pass/trait-inheritance-num0.rs index ae285f3bc958b..5189e5f37f8da 100644 --- a/src/test/run-pass/trait-inheritance-num0.rs +++ b/src/test/run-pass/trait-inheritance-num0.rs @@ -19,7 +19,7 @@ trait Num { fn gt(&self, other: &Self) -> bool; } -pub trait NumExt: Num + NumCast { } +pub trait NumExt: Ring + NumCast { } fn greater_than_one(n: &T) -> bool { n.gt(&NumCast::from(1)) diff --git a/src/test/run-pass/trait-inheritance-num1.rs b/src/test/run-pass/trait-inheritance-num1.rs index d22a8154a5b25..23a146a210974 100644 --- a/src/test/run-pass/trait-inheritance-num1.rs +++ b/src/test/run-pass/trait-inheritance-num1.rs @@ -11,7 +11,7 @@ use std::cmp::Ord; use std::num::NumCast; -pub trait NumExt: Num + NumCast + Ord { } +pub trait NumExt: Ring + NumCast + Ord { } fn greater_than_one(n: &T) -> bool { *n > NumCast::from(1) diff --git a/src/test/run-pass/trait-inheritance-num2.rs b/src/test/run-pass/trait-inheritance-num2.rs index 4003a83e80bb0..7f3342c43d79c 100644 --- a/src/test/run-pass/trait-inheritance-num2.rs +++ b/src/test/run-pass/trait-inheritance-num2.rs @@ -14,8 +14,6 @@ extern mod extra; -use std::cmp::{Eq, Ord}; - pub trait TypeExt {} @@ -36,7 +34,7 @@ impl TypeExt for f64 {} impl TypeExt for float {} -pub trait NumExt: TypeExt + Eq + Ord + Num + NumCast {} +pub trait NumExt: TypeExt + OrderedRing + NumCast {} impl NumExt for u8 {} impl NumExt for u16 {} diff --git a/src/test/run-pass/trait-inheritance-num3.rs b/src/test/run-pass/trait-inheritance-num3.rs index 2d6b5e1132536..b27353fff5e3b 100644 --- a/src/test/run-pass/trait-inheritance-num3.rs +++ b/src/test/run-pass/trait-inheritance-num3.rs @@ -8,10 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::cmp::{Eq, Ord}; use std::num::NumCast; -pub trait NumExt: Eq + Ord + Num + NumCast {} +pub trait NumExt: OrderedRing + NumCast {} impl NumExt for f32 {} diff --git a/src/test/run-pass/trait-inheritance-num5.rs b/src/test/run-pass/trait-inheritance-num5.rs index f56eca693ea53..b9a5ea0d8881a 100644 --- a/src/test/run-pass/trait-inheritance-num5.rs +++ b/src/test/run-pass/trait-inheritance-num5.rs @@ -8,10 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::cmp::{Eq, Ord}; use std::num::NumCast; -pub trait NumExt: Eq + Num + NumCast {} +pub trait NumExt: OrderedRing + NumCast {} impl NumExt for f32 {} impl NumExt for int {} From 065e97435904084a37dc785907be95634dde309d Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Fri, 26 Jul 2013 09:27:56 +1000 Subject: [PATCH 4/4] Fix duplicate trait definition --- src/libextra/num/bigint.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libextra/num/bigint.rs b/src/libextra/num/bigint.rs index 464292514ef35..0094164357087 100644 --- a/src/libextra/num/bigint.rs +++ b/src/libextra/num/bigint.rs @@ -828,7 +828,7 @@ impl FromStr for BigInt { } } -impl Semiring for BigUint; +impl Semiring for BigInt; impl Ring for BigInt;