提交 bf89b68a 编写于 作者: B bors

auto merge of #11664 : bjz/rust/identities, r=alexcrichton

`Zero` and `One` have precise definitions in mathematics as the identities of the `Add` and `Mul` operations respectively. As such, types that implement these identities are now also required to implement their respective operator traits. This should reduce their misuse whilst still enabling them to be used in generalized algebraic structures (not just numbers). Existing usages of `#[deriving(Zero)]` in client code could break under these new rules, but this is probably a sign that they should have been using something like `#[deriving(Default)]` in the first place.

For more information regarding the mathematical definitions of the additive and multiplicative identities, see the following Wikipedia articles:

- http://wikipedia.org/wiki/Additive_identity
- http://wikipedia.org/wiki/Multiplicative_identity

Note that for floating point numbers the laws specified in the doc comments of `Zero::zero` and `One::one` may not always hold. This is true however for many other traits currently implemented by floating point numbers. What traits floating point numbers should and should not implement is an open question that is beyond the scope of this pull request.

The implementation of `std::num::pow` has been made more succinct and no longer requires `Clone`. The coverage of the associated unit test has also been increased to test for more combinations of bases, exponents, and expected results.
......@@ -57,7 +57,7 @@ fn main() {
use std::str;
use std::vec;
use std::num::{FromStrRadix, Zero};
use std::num::FromStrRadix;
use std::char::Char;
use std::container::Container;
use std::to_str::ToStr;
......@@ -158,9 +158,8 @@ fn to_str(&self) -> ~str {
/// UUID support
impl Uuid {
/// Returns a nil or empty UUID (containing all zeroes)
pub fn new_nil() -> Uuid {
pub fn nil() -> Uuid {
let uuid = Uuid{ bytes: [0, .. 16] };
uuid
}
......@@ -423,24 +422,17 @@ pub fn parse_string(us: &str) -> Result<Uuid, ParseError> {
Ok(Uuid::from_bytes(ub).unwrap())
}
}
impl Default for Uuid {
/// Returns the nil UUID, which is all zeroes
fn default() -> Uuid {
Uuid::new_nil()
/// Tests if the UUID is nil
pub fn is_nil(&self) -> bool {
return self.bytes.iter().all(|&b| b == 0);
}
}
impl Zero for Uuid {
impl Default for Uuid {
/// Returns the nil UUID, which is all zeroes
fn zero() -> Uuid {
Uuid::new_nil()
}
/// Tests if the UUID is nil or all zeroes
fn is_zero(&self) -> bool {
return self.bytes.iter().all(|&b| b == 0);
fn default() -> Uuid {
Uuid::nil()
}
}
......@@ -521,24 +513,15 @@ mod test {
use super::*;
use std::str;
use std::rand;
use std::num::Zero;
use std::io::MemWriter;
#[test]
fn test_new_nil() {
let nil = Uuid::new_nil();
let nb = nil.to_bytes();
assert!(nb.iter().all(|&b| b == 0));
}
#[test]
fn test_zero() {
let uz: Uuid = Zero::zero();
let nz = Uuid::new_v4();
fn test_nil() {
let nil = Uuid::nil();
let not_nil = Uuid::new_v4();
assert!(uz.is_zero());
assert!(! nz.is_zero());
assert!(nil.is_nil());
assert!(!not_nil.is_nil());
}
#[test]
......@@ -619,7 +602,7 @@ fn test_parse_uuid_v4() {
assert!(Uuid::parse_string("urn:uuid:67e55044-10b1-426f-9247-bb680e5fe0c8").is_ok());
// Nil
let nil = Uuid::new_nil();
let nil = Uuid::nil();
assert!(Uuid::parse_string("00000000000000000000000000000000").unwrap() == nil);
assert!(Uuid::parse_string("00000000-0000-0000-0000-000000000000").unwrap() == nil);
......
......@@ -40,7 +40,6 @@
#[cfg(not(test))] use cmp::{Eq, Ord, TotalOrd, Ordering};
#[cfg(not(test))] use ops::{Not, BitAnd, BitOr, BitXor};
#[cfg(not(test))] use default::Default;
#[cfg(not(test))] use num::Zero;
/////////////////////////////////////////////////////////////////////////////
// Freestanding functions
......@@ -309,12 +308,6 @@ impl Default for bool {
fn default() -> bool { false }
}
#[cfg(not(test))]
impl Zero for bool {
fn zero() -> bool { false }
fn is_zero(&self) -> bool { *self == false }
}
#[cfg(test)]
mod tests {
use prelude::*;
......
......@@ -22,7 +22,6 @@
#[cfg(not(test))] use cmp::{Eq, Ord};
#[cfg(not(test))] use default::Default;
#[cfg(not(test))] use num::Zero;
// UTF-8 ranges and tags for encoding characters
static TAG_CONT: uint = 128u;
......@@ -449,15 +448,6 @@ impl Default for char {
fn default() -> char { '\x00' }
}
#[cfg(not(test))]
impl Zero for char {
#[inline]
fn zero() -> char { '\x00' }
#[inline]
fn is_zero(&self) -> bool { *self == '\x00' }
}
#[test]
fn test_is_lowercase() {
assert!('a'.is_lowercase());
......
......@@ -2872,6 +2872,12 @@ fn clone(&self) -> Foo {
}
}
impl Mul<Foo, Foo> for Foo {
fn mul(&self, _: &Foo) -> Foo {
Foo
}
}
impl num::One for Foo {
fn one() -> Foo {
Foo
......
......@@ -50,19 +50,59 @@ pub trait Orderable: Ord {
/// Returns the number constrained within the range `mn <= self <= mx`.
#[inline(always)] pub fn clamp<T: Orderable>(value: T, mn: T, mx: T) -> T { value.clamp(&mn, &mx) }
pub trait Zero {
fn zero() -> Self; // FIXME (#5527): This should be an associated constant
/// Defines an additive identity element for `Self`.
///
/// # Deriving
///
/// This trait can be automatically be derived using `#[deriving(Zero)]`
/// attribute. If you choose to use this, make sure that the laws outlined in
/// the documentation for `Zero::zero` still hold.
pub trait Zero: Add<Self, Self> {
/// Returns the additive identity element of `Self`, `0`.
///
/// # Laws
///
/// ~~~
/// a + 0 = a ∀ a ∈ Self
/// 0 + a = a ∀ a ∈ Self
/// ~~~
///
/// # Purity
///
/// This function should return the same result at all times regardless of
/// external mutable state, for example values stored in TLS or in
/// `static mut`s.
// FIXME (#5527): This should be an associated constant
fn zero() -> Self;
/// Returns `true` if `self` is equal to the additive identity.
fn is_zero(&self) -> bool;
}
/// Returns `0` of appropriate type.
/// Returns the additive identity, `0`.
#[inline(always)] pub fn zero<T: Zero>() -> T { Zero::zero() }
pub trait One {
fn one() -> Self; // FIXME (#5527): This should be an associated constant
/// Defines a multiplicative identity element for `Self`.
pub trait One: Mul<Self, Self> {
/// Returns the multiplicative identity element of `Self`, `1`.
///
/// # Laws
///
/// ~~~
/// a * 1 = a ∀ a ∈ Self
/// 1 * a = a ∀ a ∈ Self
/// ~~~
///
/// # Purity
///
/// This function should return the same result at all times regardless of
/// external mutable state, for example values stored in TLS or in
/// `static mut`s.
// FIXME (#5527): This should be an associated constant
fn one() -> Self;
}
/// Returns `1` of appropriate type.
/// Returns the multiplicative identity, `1`.
#[inline(always)] pub fn one<T: One>() -> T { One::one() }
pub trait Signed: Num
......@@ -264,48 +304,29 @@ pub trait Real: Signed
fn to_radians(&self) -> Self;
}
/// Raises a value to the power of exp, using
/// exponentiation by squaring.
/// Raises a value to the power of exp, using exponentiation by squaring.
///
/// # Example
///
/// ```rust
/// use std::num;
///
/// let sixteen = num::pow(2, 4u);
/// assert_eq!(sixteen, 16);
/// assert_eq!(num::pow(2, 4), 16);
/// ```
#[inline]
pub fn pow<T: Clone+One+Mul<T, T>>(num: T, exp: uint) -> T {
let one: uint = One::one();
let num_one: T = One::one();
if exp.is_zero() { return num_one; }
if exp == one { return num.clone(); }
let mut i: uint = exp;
let mut v: T;
let mut r: T = num_one;
// This if is to avoid cloning self.
if (i & one) == one {
r = r * num;
i = i - one;
}
i = i >> one;
v = num * num;
while !i.is_zero() {
if (i & one) == one {
r = r * v;
i = i - one;
pub fn pow<T: One + Mul<T, T>>(mut base: T, mut exp: uint) -> T {
if exp == 1 { base }
else {
let mut acc = one::<T>();
while exp > 0 {
if (exp & 1) == 1 {
acc = acc * base;
}
base = base * base;
exp = exp >> 1;
}
i = i >> one;
v = v * v;
acc
}
r
}
/// Raise a number to a power.
......@@ -993,16 +1014,6 @@ pub fn from_str_radix<T: FromStrRadix>(str: &str, radix: uint) -> Option<T> {
FromStrRadix::from_str_radix(str, radix)
}
impl<T: Zero + 'static> Zero for @T {
fn zero() -> @T { @Zero::zero() }
fn is_zero(&self) -> bool { (**self).is_zero() }
}
impl<T: Zero> Zero for ~T {
fn zero() -> ~T { ~Zero::zero() }
fn is_zero(&self) -> bool { (**self).is_zero() }
}
/// Saturating math operations
pub trait Saturating {
/// Saturating addition operator.
......@@ -1640,17 +1651,24 @@ fn test_from_primitive() {
#[test]
fn test_pow() {
fn assert_pow<T: Eq+Clone+One+Mul<T, T>>(num: T, exp: uint) -> () {
assert_eq!(num::pow(num.clone(), exp),
range(1u, exp).fold(num.clone(), |acc, _| acc * num));
fn naive_pow<T: One + Mul<T, T>>(base: T, exp: uint) -> T {
range(0, exp).fold(one::<T>(), |acc, _| acc * base)
}
assert_eq!(num::pow(3, 0), 1);
assert_eq!(num::pow(5, 1), 5);
assert_pow(-4, 2);
assert_pow(8, 3);
assert_pow(8, 5);
assert_pow(2u64, 50);
macro_rules! assert_pow(
(($num:expr, $exp:expr) => $expected:expr) => {{
let result = pow($num, $exp);
assert_eq!(result, $expected);
assert_eq!(result, naive_pow($num, $exp));
}}
)
assert_pow!((3, 0 ) => 1);
assert_pow!((5, 1 ) => 5);
assert_pow!((-4, 2 ) => 16);
assert_pow!((0.5, 5 ) => 0.03125);
assert_pow!((8, 3 ) => 512);
assert_pow!((8.0, 5 ) => 32768.0);
assert_pow!((8.5, 5 ) => 44370.53125);
assert_pow!((2u64, 50) => 1125899906842624);
}
}
......
......@@ -15,7 +15,6 @@
use clone::Clone;
#[cfg(not(test))] use cmp::*;
#[cfg(not(test))] use default::Default;
#[cfg(not(test))] use num::Zero;
/// Method extensions to pairs where both types satisfy the `Clone` bound
pub trait CopyableTuple<T, U> {
......@@ -177,18 +176,6 @@ fn default() -> ($($T,)+) {
($({ let x: $T = Default::default(); x},)+)
}
}
#[cfg(not(test))]
impl<$($T:Zero),+> Zero for ($($T,)+) {
#[inline]
fn zero() -> ($($T,)+) {
($({ let x: $T = Zero::zero(); x},)+)
}
#[inline]
fn is_zero(&self) -> bool {
$(self.$get_ref_fn().is_zero())&&+
}
}
)+
}
}
......
......@@ -12,8 +12,6 @@
#[cfg(not(test))]
use prelude::*;
#[cfg(not(test))]
use num::Zero;
#[cfg(not(test))]
impl Eq for () {
......@@ -46,11 +44,3 @@ impl Default for () {
#[inline]
fn default() -> () { () }
}
#[cfg(not(test))]
impl Zero for () {
#[inline]
fn zero() -> () { () }
#[inline]
fn is_zero(&self) -> bool { true }
}
......@@ -10,32 +10,55 @@
#[feature(managed_boxes)];
use std::util;
use std::num::Zero;
#[deriving(Zero)]
struct A;
#[deriving(Zero)]
struct B(int);
#[deriving(Zero)]
struct C(int, int);
#[deriving(Zero)]
struct D { a: int }
struct Vector2<T>(T, T);
impl<T: Add<T, T>> Add<Vector2<T>, Vector2<T>> for Vector2<T> {
fn add(&self, other: &Vector2<T>) -> Vector2<T> {
match (self, other) {
(&Vector2(ref x0, ref y0), &Vector2(ref x1, ref y1)) => {
Vector2(*x0 + *x1, *y0 + *y1)
}
}
}
}
#[deriving(Zero)]
struct E { a: int, b: int }
struct Vector3<T> {
x: T, y: T, z: T,
}
impl<T: Add<T, T>> Add<Vector3<T>, Vector3<T>> for Vector3<T> {
fn add(&self, other: &Vector3<T>) -> Vector3<T> {
Vector3 {
x: self.x + other.x,
y: self.y + other.y,
z: self.z + other.z,
}
}
}
#[deriving(Zero)]
struct Lots {
d: u8,
e: char,
f: f64,
g: (f32, char),
h: @(int, int),
i: bool,
j: (),
struct Matrix3x2<T> {
x: Vector2<T>,
y: Vector2<T>,
z: Vector2<T>,
}
impl<T: Add<T, T>> Add<Matrix3x2<T>, Matrix3x2<T>> for Matrix3x2<T> {
fn add(&self, other: &Matrix3x2<T>) -> Matrix3x2<T> {
Matrix3x2 {
x: self.x + other.x,
y: self.y + other.y,
z: self.z + other.z,
}
}
}
pub fn main() {
let lots: Lots = Zero::zero();
assert!(lots.is_zero());
let _: Vector2<int> = Zero::zero();
let _: Vector3<f64> = Zero::zero();
let _: Matrix3x2<u8> = Zero::zero();
}
......@@ -10,30 +10,25 @@
#[feature(macro_rules)];
use std::num::Zero;
use std::default::Default;
pub struct X<T> {
a: T
a: T,
}
// reordering these bounds stops the ICE
impl<T: Zero + Eq + Zero>
Zero for X<T> {
fn zero() -> X<T> {
X { a: Zero::zero() }
}
fn is_zero(&self) -> bool {
self.a.is_zero()
impl<T: Default + Eq + Default> Default for X<T> {
fn default() -> X<T> {
X { a: Default::default() }
}
}
macro_rules! constants {
() => {
let _0 : X<int> = Zero::zero();
}
() => {
let _ : X<int> = Default::default();
}
}
pub fn main() {
constants!();
constants!();
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册