Update to 1.0.0-beta (stable only)

Along the way, this commit also rationalizes the traits a bit more.

Moving to stable required vendoring a couple of minor things (notably,
radix formatting).
This commit is contained in:
Aaron Turon 2015-04-02 23:29:17 -07:00
parent 03db5c9d1b
commit 63c7a25ed9
7 changed files with 435 additions and 394 deletions

View File

@ -62,12 +62,10 @@ extern crate rustc_serialize;
use Integer; use Integer;
use core::num::ParseIntError;
use std::default::Default; use std::default::Default;
use std::error::Error; use std::error::Error;
use std::iter::repeat; use std::iter::repeat;
use std::num::{Int, ToPrimitive, FromPrimitive, FromStrRadix}; use std::num::ParseIntError;
use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Rem, Shl, Shr, Sub}; use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Rem, Shl, Shr, Sub};
use std::str::{self, FromStr}; use std::str::{self, FromStr};
use std::{cmp, fmt, hash, mem}; use std::{cmp, fmt, hash, mem};
@ -77,6 +75,8 @@ use std::{i64, u64};
use rand::Rng; use rand::Rng;
use rustc_serialize::hex::ToHex; use rustc_serialize::hex::ToHex;
use traits::{ToPrimitive, FromPrimitive, cast};
use {Num, Unsigned, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, Signed, Zero, One}; use {Num, Unsigned, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, Signed, Zero, One};
use self::Sign::{Minus, NoSign, Plus}; use self::Sign::{Minus, NoSign, Plus};
@ -99,7 +99,7 @@ pub mod big_digit {
pub const BITS: usize = 32; pub const BITS: usize = 32;
pub const BASE: DoubleBigDigit = 1 << BITS; pub const BASE: DoubleBigDigit = 1 << BITS;
const LO_MASK: DoubleBigDigit = (-1 as DoubleBigDigit) >> BITS; const LO_MASK: DoubleBigDigit = (-1i32 as DoubleBigDigit) >> BITS;
#[inline] #[inline]
fn get_hi(n: DoubleBigDigit) -> BigDigit { (n >> BITS) as BigDigit } fn get_hi(n: DoubleBigDigit) -> BigDigit { (n >> BITS) as BigDigit }
@ -190,11 +190,47 @@ impl FromStr for BigUint {
#[inline] #[inline]
fn from_str(s: &str) -> Result<BigUint, ParseBigIntError> { fn from_str(s: &str) -> Result<BigUint, ParseBigIntError> {
FromStrRadix::from_str_radix(s, 10) BigUint::from_str_radix(s, 10)
} }
} }
impl Num for BigUint {} impl Num for BigUint {
type FromStrRadixErr = ParseBigIntError;
/// Creates and initializes a `BigUint`.
#[inline]
fn from_str_radix(s: &str, radix: u32) -> Result<BigUint, ParseBigIntError> {
let (base, unit_len) = get_radix_base(radix);
let base_num = match base.to_biguint() {
Some(base_num) => base_num,
None => { return Err(ParseBigIntError::Other); }
};
let mut end = s.len();
let mut n: BigUint = Zero::zero();
let mut power: BigUint = One::one();
loop {
let start = cmp::max(end, unit_len) - unit_len;
let d = try!(usize::from_str_radix(&s[start .. end], radix));
let d: Option<BigUint> = FromPrimitive::from_usize(d);
match d {
Some(d) => {
// FIXME(#5992): assignment operator overloads
// n += d * &power;
n = n + d * &power;
}
None => { return Err(ParseBigIntError::Other); }
}
if end <= unit_len {
return Ok(n);
}
end -= unit_len;
// FIXME(#5992): assignment operator overloads
// power *= &base_num;
power = power * &base_num;
}
}
}
macro_rules! forward_val_val_binop { macro_rules! forward_val_val_binop {
(impl $imp:ident for $res:ty, $method:ident) => { (impl $imp:ident for $res:ty, $method:ident) => {
@ -264,7 +300,7 @@ impl<'a, 'b> BitOr<&'b BigUint> for &'a BigUint {
let (a, b) = if self.data.len() > other.data.len() { (self, other) } else { (other, self) }; let (a, b) = if self.data.len() > other.data.len() { (self, other) } else { (other, self) };
let ored = a.data.iter().zip(b.data.iter().chain(zeros)).map( let ored = a.data.iter().zip(b.data.iter().chain(zeros)).map(
|(ai, bi)| *ai | *bi |(ai, bi)| *ai | *bi
).collect(); ).collect();
return BigUint::new(ored); return BigUint::new(ored);
} }
} }
@ -279,7 +315,7 @@ impl<'a, 'b> BitXor<&'b BigUint> for &'a BigUint {
let (a, b) = if self.data.len() > other.data.len() { (self, other) } else { (other, self) }; let (a, b) = if self.data.len() > other.data.len() { (self, other) } else { (other, self) };
let xored = a.data.iter().zip(b.data.iter().chain(zeros)).map( let xored = a.data.iter().zip(b.data.iter().chain(zeros)).map(
|(ai, bi)| *ai ^ *bi |(ai, bi)| *ai ^ *bi
).collect(); ).collect();
return BigUint::new(xored); return BigUint::new(xored);
} }
} }
@ -373,11 +409,11 @@ impl<'a, 'b> Sub<&'b BigUint> for &'a BigUint {
+ (*ai as DoubleBigDigit) + (*ai as DoubleBigDigit)
- (*bi as DoubleBigDigit) - (*bi as DoubleBigDigit)
- (borrow as DoubleBigDigit) - (borrow as DoubleBigDigit)
); );
/* /*
hi * (base) + lo == 1*(base) + ai - bi - borrow hi * (base) + lo == 1*(base) + ai - bi - borrow
=> ai - bi - borrow < 0 <=> hi == 0 => ai - bi - borrow < 0 <=> hi == 0
*/ */
borrow = if hi == 0 { 1 } else { 0 }; borrow = if hi == 0 { 1 } else { 0 };
lo lo
}).collect(); }).collect();
@ -433,7 +469,7 @@ impl<'a, 'b> Mul<&'b BigUint> for &'a BigUint {
let mut prod: Vec<BigDigit> = a.data.iter().map(|ai| { let mut prod: Vec<BigDigit> = a.data.iter().map(|ai| {
let (hi, lo) = big_digit::from_doublebigdigit( let (hi, lo) = big_digit::from_doublebigdigit(
(*ai as DoubleBigDigit) * (n as DoubleBigDigit) + (carry as DoubleBigDigit) (*ai as DoubleBigDigit) * (n as DoubleBigDigit) + (carry as DoubleBigDigit)
); );
carry = hi; carry = hi;
lo lo
}).collect(); }).collect();
@ -605,33 +641,33 @@ impl Integer for BigUint {
fn div_estimate(a: &BigUint, b: &BigUint, n: usize) fn div_estimate(a: &BigUint, b: &BigUint, n: usize)
-> (BigUint, BigUint, BigUint) { -> (BigUint, BigUint, BigUint) {
if a.data.len() < n { if a.data.len() < n {
return (Zero::zero(), Zero::zero(), (*a).clone()); return (Zero::zero(), Zero::zero(), (*a).clone());
} }
let an = &a.data[a.data.len() - n ..]; let an = &a.data[a.data.len() - n ..];
let bn = *b.data.last().unwrap(); let bn = *b.data.last().unwrap();
let mut d = Vec::with_capacity(an.len()); let mut d = Vec::with_capacity(an.len());
let mut carry = 0; let mut carry = 0;
for elt in an.iter().rev() { for elt in an.iter().rev() {
let ai = big_digit::to_doublebigdigit(carry, *elt); let ai = big_digit::to_doublebigdigit(carry, *elt);
let di = ai / (bn as DoubleBigDigit); let di = ai / (bn as DoubleBigDigit);
assert!(di < big_digit::BASE); assert!(di < big_digit::BASE);
carry = (ai % (bn as DoubleBigDigit)) as BigDigit; carry = (ai % (bn as DoubleBigDigit)) as BigDigit;
d.push(di as BigDigit) d.push(di as BigDigit)
} }
d.reverse(); d.reverse();
let shift = (a.data.len() - an.len()) - (b.data.len() - 1); let shift = (a.data.len() - an.len()) - (b.data.len() - 1);
if shift == 0 { if shift == 0 {
return (BigUint::new(d), One::one(), (*b).clone()); return (BigUint::new(d), One::one(), (*b).clone());
} }
let one: BigUint = One::one(); let one: BigUint = One::one();
return (BigUint::new(d).shl_unit(shift), return (BigUint::new(d).shl_unit(shift),
one.shl_unit(shift), one.shl_unit(shift),
b.shl_unit(shift)); b.shl_unit(shift));
} }
} }
/// Calculates the Greatest Common Divisor (GCD) of the number and `other`. /// Calculates the Greatest Common Divisor (GCD) of the number and `other`.
@ -776,6 +812,58 @@ impl_to_biguint!(u16, FromPrimitive::from_u16);
impl_to_biguint!(u32, FromPrimitive::from_u32); impl_to_biguint!(u32, FromPrimitive::from_u32);
impl_to_biguint!(u64, FromPrimitive::from_u64); impl_to_biguint!(u64, FromPrimitive::from_u64);
// Cribbed from core/fmt/num.rs
#[derive(Copy, Clone)]
pub struct RadixFmt {
data: BigDigit,
base: u8
}
impl RadixFmt {
fn digit(&self, x: u8) -> u8 {
match x {
x @ 0 ... 9 => b'0' + x,
x if x < self.base => b'a' + (x - 10),
x => panic!("number not in the range 0..{}: {}", self.base - 1, x),
}
}
}
impl fmt::Display for RadixFmt {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// The radix can be as low as 2, so we need a buffer of at least 64
// characters for a base 2 number.
let mut x = self.data;
let zero = 0;
let is_positive = x >= zero;
let mut buf = [0u8; 64];
let mut curr = buf.len();
let base = self.base as BigDigit;
if is_positive {
// Accumulate each digit of the number from the least significant
// to the most significant figure.
for byte in buf.iter_mut().rev() {
let n = x % base; // Get the current place value.
x = x / base; // Deaccumulate the number.
*byte = self.digit(cast(n).unwrap()); // Store the digit in the buffer.
curr -= 1;
if x == zero { break }; // No more digits left to accumulate.
}
} else {
// Do the same as above, but accounting for two's complement.
for byte in buf.iter_mut().rev() {
let n = zero - (x % base); // Get the current place value.
x = x / base; // Deaccumulate the number.
*byte = self.digit(cast(n).unwrap()); // Store the digit in the buffer.
curr -= 1;
if x == zero { break }; // No more digits left to accumulate.
}
}
let buf = unsafe { str::from_utf8_unchecked(&buf[curr..]) };
f.pad_integral(is_positive, "", buf)
}
}
fn to_str_radix(me: &BigUint, radix: u32) -> String { fn to_str_radix(me: &BigUint, radix: u32) -> String {
assert!(1 < radix && radix <= 16, "The radix must be within (1, 16]"); assert!(1 < radix && radix <= 16, "The radix must be within (1, 16]");
let (base, max_len) = get_radix_base(radix); let (base, max_len) = get_radix_base(radix);
@ -805,7 +893,7 @@ fn to_str_radix(me: &BigUint, radix: u32) -> String {
} }
let mut s = String::with_capacity(v.len() * l); let mut s = String::with_capacity(v.len() * l);
for n in v.iter().rev() { for n in v.iter().rev() {
let ss = fmt::radix(*n as usize, radix as u8).to_string(); let ss = format!("{}", RadixFmt { data: *n, base: radix as u8 });
s.extend(repeat("0").take(l - ss.len())); s.extend(repeat("0").take(l - ss.len()));
s.push_str(&ss); s.push_str(&ss);
} }
@ -821,44 +909,6 @@ fn to_str_radix_signed(me: &BigInt, radix: u32) -> String {
} }
} }
impl FromStrRadix for BigUint {
type Err = ParseBigIntError;
/// Creates and initializes a `BigUint`.
#[inline]
fn from_str_radix(s: &str, radix: u32) -> Result<BigUint, ParseBigIntError> {
let (base, unit_len) = get_radix_base(radix);
let base_num = match base.to_biguint() {
Some(base_num) => base_num,
None => { return Err(ParseBigIntError::Other); }
};
let mut end = s.len();
let mut n: BigUint = Zero::zero();
let mut power: BigUint = One::one();
loop {
let start = cmp::max(end, unit_len) - unit_len;
let d = try!(FromStrRadix::from_str_radix(&s[start .. end], radix));
let d: Option<BigUint> = FromPrimitive::from_usize(d);
match d {
Some(d) => {
// FIXME(#5992): assignment operator overloads
// n += d * &power;
n = n + d * &power;
}
None => { return Err(ParseBigIntError::Other); }
}
if end <= unit_len {
return Ok(n);
}
end -= unit_len;
// FIXME(#5992): assignment operator overloads
// power *= &base_num;
power = power * &base_num;
}
}
}
impl BigUint { impl BigUint {
/// Creates and initializes a `BigUint`. /// Creates and initializes a `BigUint`.
/// ///
@ -961,7 +1011,7 @@ impl BigUint {
/// ``` /// ```
#[inline] #[inline]
pub fn parse_bytes(buf: &[u8], radix: u32) -> Option<BigUint> { pub fn parse_bytes(buf: &[u8], radix: u32) -> Option<BigUint> {
str::from_utf8(buf).ok().and_then(|s| FromStrRadix::from_str_radix(s, radix).ok()) str::from_utf8(buf).ok().and_then(|s| BigUint::from_str_radix(s, radix).ok())
} }
#[inline] #[inline]
@ -969,7 +1019,7 @@ impl BigUint {
if n_unit == 0 || self.is_zero() { return (*self).clone(); } if n_unit == 0 || self.is_zero() { return (*self).clone(); }
let mut v = repeat(ZERO_BIG_DIGIT).take(n_unit).collect::<Vec<_>>(); let mut v = repeat(ZERO_BIG_DIGIT).take(n_unit).collect::<Vec<_>>();
v.push_all(&self.data); v.extend(self.data.iter().cloned());
BigUint::new(v) BigUint::new(v)
} }
@ -1119,11 +1169,27 @@ impl FromStr for BigInt {
#[inline] #[inline]
fn from_str(s: &str) -> Result<BigInt, ParseBigIntError> { fn from_str(s: &str) -> Result<BigInt, ParseBigIntError> {
FromStrRadix::from_str_radix(s, 10) BigInt::from_str_radix(s, 10)
} }
} }
impl Num for BigInt {} impl Num for BigInt {
type FromStrRadixErr = ParseBigIntError;
/// Creates and initializes a BigInt.
#[inline]
fn from_str_radix(s: &str, radix: u32) -> Result<BigInt, ParseBigIntError> {
if s.is_empty() { return Err(ParseBigIntError::Other); }
let mut sign = Plus;
let mut start = 0;
if s.starts_with("-") {
sign = Minus;
start = 1;
}
BigUint::from_str_radix(&s[start ..], radix)
.map(|bu| BigInt::from_biguint(sign, bu))
}
}
impl Shl<usize> for BigInt { impl Shl<usize> for BigInt {
type Output = BigInt; type Output = BigInt;
@ -1527,24 +1593,6 @@ impl_to_bigint!(u16, FromPrimitive::from_u16);
impl_to_bigint!(u32, FromPrimitive::from_u32); impl_to_bigint!(u32, FromPrimitive::from_u32);
impl_to_bigint!(u64, FromPrimitive::from_u64); impl_to_bigint!(u64, FromPrimitive::from_u64);
impl FromStrRadix for BigInt {
type Err = ParseBigIntError;
/// Creates and initializes a BigInt.
#[inline]
fn from_str_radix(s: &str, radix: u32) -> Result<BigInt, ParseBigIntError> {
if s.is_empty() { return Err(ParseBigIntError::Other); }
let mut sign = Plus;
let mut start = 0;
if s.starts_with("-") {
sign = Minus;
start = 1;
}
FromStrRadix::from_str_radix(&s[start ..], radix)
.map(|bu| BigInt::from_biguint(sign, bu))
}
}
pub trait RandBigInt { pub trait RandBigInt {
/// Generate a random `BigUint` of the given bit size. /// Generate a random `BigUint` of the given bit size.
fn gen_biguint(&mut self, bit_size: usize) -> BigUint; fn gen_biguint(&mut self, bit_size: usize) -> BigUint;
@ -1712,7 +1760,7 @@ impl BigInt {
/// ``` /// ```
#[inline] #[inline]
pub fn parse_bytes(buf: &[u8], radix: u32) -> Option<BigInt> { pub fn parse_bytes(buf: &[u8], radix: u32) -> Option<BigInt> {
str::from_utf8(buf).ok().and_then(|s| FromStrRadix::from_str_radix(s, radix).ok()) str::from_utf8(buf).ok().and_then(|s| BigInt::from_str_radix(s, radix).ok())
} }
@ -1785,13 +1833,12 @@ mod biguint_tests {
use std::cmp::Ordering::{Less, Equal, Greater}; use std::cmp::Ordering::{Less, Equal, Greater};
use std::i64; use std::i64;
use std::iter::repeat; use std::iter::repeat;
use std::num::FromStrRadix;
use std::num::{ToPrimitive, FromPrimitive};
use std::str::FromStr; use std::str::FromStr;
use std::u64; use std::u64;
use rand::thread_rng; use rand::thread_rng;
use {Zero, One, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv}; use {Num, Zero, One, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv};
use {ToPrimitive, FromPrimitive};
#[test] #[test]
fn test_from_slice() { fn test_from_slice() {
@ -1803,7 +1850,7 @@ mod biguint_tests {
check(&[1, 2, 0, 0], &[1, 2]); check(&[1, 2, 0, 0], &[1, 2]);
check(&[0, 0, 1, 2], &[0, 0, 1, 2]); check(&[0, 0, 1, 2], &[0, 0, 1, 2]);
check(&[0, 0, 1, 2, 0, 0], &[0, 0, 1, 2]); check(&[0, 0, 1, 2, 0, 0], &[0, 0, 1, 2]);
check(&[-1], &[-1]); check(&[-1i32 as BigDigit], &[-1i32 as BigDigit]);
} }
#[test] #[test]
@ -1833,7 +1880,7 @@ mod biguint_tests {
assert_eq!(b.to_bytes_be(), [0]); assert_eq!(b.to_bytes_be(), [0]);
// Test with leading/trailing zero bytes and a full BigDigit of value 0 // Test with leading/trailing zero bytes and a full BigDigit of value 0
let b: BigUint = FromStrRadix::from_str_radix("00010000000000000200", 16).unwrap(); let b = BigUint::from_str_radix("00010000000000000200", 16).unwrap();
assert_eq!(b.to_bytes_be(), [1, 0, 0, 0, 0, 0, 0, 2, 0]); assert_eq!(b.to_bytes_be(), [1, 0, 0, 0, 0, 0, 0, 2, 0]);
} }
@ -1864,7 +1911,7 @@ mod biguint_tests {
assert_eq!(b.to_bytes_le(), [0]); assert_eq!(b.to_bytes_le(), [0]);
// Test with leading/trailing zero bytes and a full BigDigit of value 0 // Test with leading/trailing zero bytes and a full BigDigit of value 0
let b: BigUint = FromStrRadix::from_str_radix("00010000000000000200", 16).unwrap(); let b = BigUint::from_str_radix("00010000000000000200", 16).unwrap();
assert_eq!(b.to_bytes_le(), [0, 2, 0, 0, 0, 0, 0, 0, 1]); assert_eq!(b.to_bytes_le(), [0, 2, 0, 0, 0, 0, 0, 0, 1]);
} }
@ -1963,7 +2010,7 @@ mod biguint_tests {
#[test] #[test]
fn test_shl() { fn test_shl() {
fn check(s: &str, shift: usize, ans: &str) { fn check(s: &str, shift: usize, ans: &str) {
let opt_biguint: Option<BigUint> = FromStrRadix::from_str_radix(s, 16).ok(); let opt_biguint = BigUint::from_str_radix(s, 16).ok();
let bu = to_str_radix(&(opt_biguint.unwrap() << shift), 16); let bu = to_str_radix(&(opt_biguint.unwrap() << shift), 16);
assert_eq!(bu, ans); assert_eq!(bu, ans);
} }
@ -2084,8 +2131,7 @@ mod biguint_tests {
#[test] #[test]
fn test_shr() { fn test_shr() {
fn check(s: &str, shift: usize, ans: &str) { fn check(s: &str, shift: usize, ans: &str) {
let opt_biguint: Option<BigUint> = let opt_biguint = BigUint::from_str_radix(s, 16).ok();
FromStrRadix::from_str_radix(s, 16).ok();
let bu = to_str_radix(&(opt_biguint.unwrap() >> shift), 16); let bu = to_str_radix(&(opt_biguint.unwrap() >> shift), 16);
assert_eq!(bu, ans); assert_eq!(bu, ans);
} }
@ -2199,6 +2245,9 @@ mod biguint_tests {
"88887777666655554444333322221111"); "88887777666655554444333322221111");
} }
const N1: BigDigit = -1i32 as BigDigit;
const N2: BigDigit = -2i32 as BigDigit;
// `DoubleBigDigit` size dependent // `DoubleBigDigit` size dependent
#[test] #[test]
fn test_convert_i64() { fn test_convert_i64() {
@ -2214,14 +2263,14 @@ mod biguint_tests {
check(BigUint::new(vec!( )), 0); check(BigUint::new(vec!( )), 0);
check(BigUint::new(vec!( 1 )), (1 << (0*big_digit::BITS))); check(BigUint::new(vec!( 1 )), (1 << (0*big_digit::BITS)));
check(BigUint::new(vec!(-1 )), (1 << (1*big_digit::BITS)) - 1); check(BigUint::new(vec!(N1 )), (1 << (1*big_digit::BITS)) - 1);
check(BigUint::new(vec!( 0, 1 )), (1 << (1*big_digit::BITS))); check(BigUint::new(vec!( 0, 1 )), (1 << (1*big_digit::BITS)));
check(BigUint::new(vec!(-1, -1 >> 1)), i64::MAX); check(BigUint::new(vec!(N1, N1 >> 1)), i64::MAX);
assert_eq!(i64::MIN.to_biguint(), None); assert_eq!(i64::MIN.to_biguint(), None);
assert_eq!(BigUint::new(vec!(-1, -1 )).to_i64(), None); assert_eq!(BigUint::new(vec!(N1, N1 )).to_i64(), None);
assert_eq!(BigUint::new(vec!( 0, 0, 1)).to_i64(), None); assert_eq!(BigUint::new(vec!( 0, 0, 1)).to_i64(), None);
assert_eq!(BigUint::new(vec!(-1, -1, -1)).to_i64(), None); assert_eq!(BigUint::new(vec!(N1, N1, N1)).to_i64(), None);
} }
// `DoubleBigDigit` size dependent // `DoubleBigDigit` size dependent
@ -2240,12 +2289,12 @@ mod biguint_tests {
check(BigUint::new(vec!( )), 0); check(BigUint::new(vec!( )), 0);
check(BigUint::new(vec!( 1 )), (1 << (0*big_digit::BITS))); check(BigUint::new(vec!( 1 )), (1 << (0*big_digit::BITS)));
check(BigUint::new(vec!(-1 )), (1 << (1*big_digit::BITS)) - 1); check(BigUint::new(vec!(N1 )), (1 << (1*big_digit::BITS)) - 1);
check(BigUint::new(vec!( 0, 1)), (1 << (1*big_digit::BITS))); check(BigUint::new(vec!( 0, 1)), (1 << (1*big_digit::BITS)));
check(BigUint::new(vec!(-1, -1)), u64::MAX); check(BigUint::new(vec!(N1, N1)), u64::MAX);
assert_eq!(BigUint::new(vec!( 0, 0, 1)).to_u64(), None); assert_eq!(BigUint::new(vec!( 0, 0, 1)).to_u64(), None);
assert_eq!(BigUint::new(vec!(-1, -1, -1)).to_u64(), None); assert_eq!(BigUint::new(vec!(N1, N1, N1)).to_u64(), None);
} }
#[test] #[test]
@ -2266,11 +2315,11 @@ mod biguint_tests {
(&[], &[ 1], &[ 1]), (&[], &[ 1], &[ 1]),
(&[ 1], &[ 1], &[ 2]), (&[ 1], &[ 1], &[ 2]),
(&[ 1], &[ 1, 1], &[ 2, 1]), (&[ 1], &[ 1, 1], &[ 2, 1]),
(&[ 1], &[-1], &[ 0, 1]), (&[ 1], &[N1], &[ 0, 1]),
(&[ 1], &[-1, -1], &[ 0, 0, 1]), (&[ 1], &[N1, N1], &[ 0, 0, 1]),
(&[-1, -1], &[-1, -1], &[-2, -1, 1]), (&[N1, N1], &[N1, N1], &[N2, N1, 1]),
(&[ 1, 1, 1], &[-1, -1], &[ 0, 1, 2]), (&[ 1, 1, 1], &[N1, N1], &[ 0, 1, 2]),
(&[ 2, 2, 1], &[-1, -2], &[ 1, 1, 2]) (&[ 2, 2, 1], &[N1, N2], &[ 1, 1, 2])
]; ];
#[test] #[test]
@ -2317,18 +2366,18 @@ mod biguint_tests {
(&[ 2], &[ 3], &[ 6]), (&[ 2], &[ 3], &[ 6]),
(&[ 1], &[ 1, 1, 1], &[1, 1, 1]), (&[ 1], &[ 1, 1, 1], &[1, 1, 1]),
(&[ 1, 2, 3], &[ 3], &[ 3, 6, 9]), (&[ 1, 2, 3], &[ 3], &[ 3, 6, 9]),
(&[ 1, 1, 1], &[-1], &[-1, -1, -1]), (&[ 1, 1, 1], &[N1], &[N1, N1, N1]),
(&[ 1, 2, 3], &[-1], &[-1, -2, -2, 2]), (&[ 1, 2, 3], &[N1], &[N1, N2, N2, 2]),
(&[ 1, 2, 3, 4], &[-1], &[-1, -2, -2, -2, 3]), (&[ 1, 2, 3, 4], &[N1], &[N1, N2, N2, N2, 3]),
(&[-1], &[-1], &[ 1, -2]), (&[N1], &[N1], &[ 1, N2]),
(&[-1, -1], &[-1], &[ 1, -1, -2]), (&[N1, N1], &[N1], &[ 1, N1, N2]),
(&[-1, -1, -1], &[-1], &[ 1, -1, -1, -2]), (&[N1, N1, N1], &[N1], &[ 1, N1, N1, N2]),
(&[-1, -1, -1, -1], &[-1], &[ 1, -1, -1, -1, -2]), (&[N1, N1, N1, N1], &[N1], &[ 1, N1, N1, N1, N2]),
(&[ M/2 + 1], &[ 2], &[ 0, 1]), (&[ M/2 + 1], &[ 2], &[ 0, 1]),
(&[0, M/2 + 1], &[ 2], &[ 0, 0, 1]), (&[0, M/2 + 1], &[ 2], &[ 0, 0, 1]),
(&[ 1, 2], &[ 1, 2, 3], &[1, 4, 7, 6]), (&[ 1, 2], &[ 1, 2, 3], &[1, 4, 7, 6]),
(&[-1, -1], &[-1, -1, -1], &[1, 0, -1, -2, -1]), (&[N1, N1], &[N1, N1, N1], &[1, 0, N1, N2, N1]),
(&[-1, -1, -1], &[-1, -1, -1, -1], &[1, 0, 0, -1, -2, -1, -1]), (&[N1, N1, N1], &[N1, N1, N1, N1], &[1, 0, 0, N1, N2, N1, N1]),
(&[ 0, 0, 1], &[ 1, 2, 3], &[0, 0, 1, 2, 3]), (&[ 0, 0, 1], &[ 1, 2, 3], &[0, 0, 1, 2, 3]),
(&[ 0, 0, 1], &[ 0, 0, 0, 1], &[0, 0, 0, 0, 0, 1]) (&[ 0, 0, 1], &[ 0, 0, 0, 1], &[0, 0, 0, 0, 0, 1])
]; ];
@ -2341,8 +2390,8 @@ mod biguint_tests {
(&[ 1], &[ 2], &[], &[1]), (&[ 1], &[ 2], &[], &[1]),
(&[ 1, 1], &[ 2], &[ M/2+1], &[1]), (&[ 1, 1], &[ 2], &[ M/2+1], &[1]),
(&[ 1, 1, 1], &[ 2], &[ M/2+1, M/2+1], &[1]), (&[ 1, 1, 1], &[ 2], &[ M/2+1, M/2+1], &[1]),
(&[ 0, 1], &[-1], &[1], &[1]), (&[ 0, 1], &[N1], &[1], &[1]),
(&[-1, -1], &[-2], &[2, 1], &[3]) (&[N1, N1], &[N2], &[2, 1], &[3])
]; ];
#[test] #[test]
@ -2600,17 +2649,15 @@ mod biguint_tests {
for str_pair in rs.iter() { for str_pair in rs.iter() {
let &(ref radix, ref str) = str_pair; let &(ref radix, ref str) = str_pair;
assert_eq!(n, assert_eq!(n,
&FromStrRadix::from_str_radix(str, &BigUint::from_str_radix(str, *radix).unwrap());
*radix).unwrap());
} }
} }
let zed: Option<BigUint> = FromStrRadix::from_str_radix("Z", 10).ok(); let zed = BigUint::from_str_radix("Z", 10).ok();
assert_eq!(zed, None); assert_eq!(zed, None);
let blank: Option<BigUint> = FromStrRadix::from_str_radix("_", 2).ok(); let blank = BigUint::from_str_radix("_", 2).ok();
assert_eq!(blank, None); assert_eq!(blank, None);
let minus_one: Option<BigUint> = FromStrRadix::from_str_radix("-1", let minus_one = BigUint::from_str_radix("-1", 10).ok();
10).ok();
assert_eq!(minus_one, None); assert_eq!(minus_one, None);
} }
@ -2629,7 +2676,7 @@ mod biguint_tests {
fn check(n: usize, s: &str) { fn check(n: usize, s: &str) {
let n = factor(n); let n = factor(n);
let ans = match FromStrRadix::from_str_radix(s, 10) { let ans = match BigUint::from_str_radix(s, 10) {
Ok(x) => x, Err(_) => panic!() Ok(x) => x, Err(_) => panic!()
}; };
assert_eq!(n, ans); assert_eq!(n, ans);
@ -2650,7 +2697,7 @@ mod biguint_tests {
assert_eq!(n.bits(), 1); assert_eq!(n.bits(), 1);
let n: BigUint = FromPrimitive::from_usize(3).unwrap(); let n: BigUint = FromPrimitive::from_usize(3).unwrap();
assert_eq!(n.bits(), 2); assert_eq!(n.bits(), 2);
let n: BigUint = FromStrRadix::from_str_radix("4000000000", 16).unwrap(); let n: BigUint = BigUint::from_str_radix("4000000000", 16).unwrap();
assert_eq!(n.bits(), 39); assert_eq!(n.bits(), 39);
let one: BigUint = One::one(); let one: BigUint = One::one();
assert_eq!((one << 426).bits(), 427); assert_eq!((one << 426).bits(), 427);
@ -2713,14 +2760,12 @@ mod bigint_tests {
use std::cmp::Ordering::{Less, Equal, Greater}; use std::cmp::Ordering::{Less, Equal, Greater};
use std::i64; use std::i64;
use std::iter::repeat; use std::iter::repeat;
use std::num::FromStrRadix;
use std::num::{ToPrimitive, FromPrimitive};
use std::u64; use std::u64;
use std::ops::{Neg}; use std::ops::{Neg};
use rand::thread_rng; use rand::thread_rng;
use {Zero, One, Signed}; use {Zero, One, Signed, ToPrimitive, FromPrimitive, Num};
#[test] #[test]
fn test_from_biguint() { fn test_from_biguint() {
@ -2764,7 +2809,7 @@ mod bigint_tests {
assert_eq!(b.to_bytes_be(), (NoSign, vec![0])); assert_eq!(b.to_bytes_be(), (NoSign, vec![0]));
// Test with leading/trailing zero bytes and a full BigDigit of value 0 // Test with leading/trailing zero bytes and a full BigDigit of value 0
let b: BigInt = FromStrRadix::from_str_radix("00010000000000000200", 16).unwrap(); let b = BigInt::from_str_radix("00010000000000000200", 16).unwrap();
assert_eq!(b.to_bytes_be(), (Plus, vec![1, 0, 0, 0, 0, 0, 0, 2, 0])); assert_eq!(b.to_bytes_be(), (Plus, vec![1, 0, 0, 0, 0, 0, 0, 2, 0]));
} }
@ -2797,7 +2842,7 @@ mod bigint_tests {
assert_eq!(b.to_bytes_le(), (NoSign, vec![0])); assert_eq!(b.to_bytes_le(), (NoSign, vec![0]));
// Test with leading/trailing zero bytes and a full BigDigit of value 0 // Test with leading/trailing zero bytes and a full BigDigit of value 0
let b: BigInt = FromStrRadix::from_str_radix("00010000000000000200", 16).unwrap(); let b = BigInt::from_str_radix("00010000000000000200", 16).unwrap();
assert_eq!(b.to_bytes_le(), (Plus, vec![0, 2, 0, 0, 0, 0, 0, 0, 1])); assert_eq!(b.to_bytes_le(), (Plus, vec![0, 2, 0, 0, 0, 0, 0, 0, 1]));
} }
@ -2929,6 +2974,9 @@ mod bigint_tests {
assert_eq!(negative.to_biguint(), None); assert_eq!(negative.to_biguint(), None);
} }
const N1: BigDigit = -1i32 as BigDigit;
const N2: BigDigit = -2i32 as BigDigit;
const SUM_TRIPLES: &'static [(&'static [BigDigit], const SUM_TRIPLES: &'static [(&'static [BigDigit],
&'static [BigDigit], &'static [BigDigit],
&'static [BigDigit])] = &[ &'static [BigDigit])] = &[
@ -2936,11 +2984,11 @@ mod bigint_tests {
(&[], &[ 1], &[ 1]), (&[], &[ 1], &[ 1]),
(&[ 1], &[ 1], &[ 2]), (&[ 1], &[ 1], &[ 2]),
(&[ 1], &[ 1, 1], &[ 2, 1]), (&[ 1], &[ 1, 1], &[ 2, 1]),
(&[ 1], &[-1], &[ 0, 1]), (&[ 1], &[N1], &[ 0, 1]),
(&[ 1], &[-1, -1], &[ 0, 0, 1]), (&[ 1], &[N1, N1], &[ 0, 0, 1]),
(&[-1, -1], &[-1, -1], &[-2, -1, 1]), (&[N1, N1], &[N1, N1], &[N2, N1, 1]),
(&[ 1, 1, 1], &[-1, -1], &[ 0, 1, 2]), (&[ 1, 1, 1], &[N1, N1], &[ 0, 1, 2]),
(&[ 2, 2, 1], &[-1, -2], &[ 1, 1, 2]) (&[ 2, 2, 1], &[N1, N2], &[ 1, 1, 2])
]; ];
#[test] #[test]
@ -2992,18 +3040,18 @@ mod bigint_tests {
(&[ 2], &[ 3], &[ 6]), (&[ 2], &[ 3], &[ 6]),
(&[ 1], &[ 1, 1, 1], &[1, 1, 1]), (&[ 1], &[ 1, 1, 1], &[1, 1, 1]),
(&[ 1, 2, 3], &[ 3], &[ 3, 6, 9]), (&[ 1, 2, 3], &[ 3], &[ 3, 6, 9]),
(&[ 1, 1, 1], &[-1], &[-1, -1, -1]), (&[ 1, 1, 1], &[N1], &[N1, N1, N1]),
(&[ 1, 2, 3], &[-1], &[-1, -2, -2, 2]), (&[ 1, 2, 3], &[N1], &[N1, N2, N2, 2]),
(&[ 1, 2, 3, 4], &[-1], &[-1, -2, -2, -2, 3]), (&[ 1, 2, 3, 4], &[N1], &[N1, N2, N2, N2, 3]),
(&[-1], &[-1], &[ 1, -2]), (&[N1], &[N1], &[ 1, N2]),
(&[-1, -1], &[-1], &[ 1, -1, -2]), (&[N1, N1], &[N1], &[ 1, N1, N2]),
(&[-1, -1, -1], &[-1], &[ 1, -1, -1, -2]), (&[N1, N1, N1], &[N1], &[ 1, N1, N1, N2]),
(&[-1, -1, -1, -1], &[-1], &[ 1, -1, -1, -1, -2]), (&[N1, N1, N1, N1], &[N1], &[ 1, N1, N1, N1, N2]),
(&[ M/2 + 1], &[ 2], &[ 0, 1]), (&[ M/2 + 1], &[ 2], &[ 0, 1]),
(&[0, M/2 + 1], &[ 2], &[ 0, 0, 1]), (&[0, M/2 + 1], &[ 2], &[ 0, 0, 1]),
(&[ 1, 2], &[ 1, 2, 3], &[1, 4, 7, 6]), (&[ 1, 2], &[ 1, 2, 3], &[1, 4, 7, 6]),
(&[-1, -1], &[-1, -1, -1], &[1, 0, -1, -2, -1]), (&[N1, N1], &[N1, N1, N1], &[1, 0, N1, N2, N1]),
(&[-1, -1, -1], &[-1, -1, -1, -1], &[1, 0, 0, -1, -2, -1, -1]), (&[N1, N1, N1], &[N1, N1, N1, N1], &[1, 0, 0, N1, N2, N1, N1]),
(&[ 0, 0, 1], &[ 1, 2, 3], &[0, 0, 1, 2, 3]), (&[ 0, 0, 1], &[ 1, 2, 3], &[0, 0, 1, 2, 3]),
(&[ 0, 0, 1], &[ 0, 0, 0, 1], &[0, 0, 0, 0, 0, 1]) (&[ 0, 0, 1], &[ 0, 0, 0, 1], &[0, 0, 0, 0, 0, 1])
]; ];
@ -3016,8 +3064,8 @@ mod bigint_tests {
(&[ 1], &[ 2], &[], &[1]), (&[ 1], &[ 2], &[], &[1]),
(&[ 1, 1], &[ 2], &[ M/2+1], &[1]), (&[ 1, 1], &[ 2], &[ M/2+1], &[1]),
(&[ 1, 1, 1], &[ 2], &[ M/2+1, M/2+1], &[1]), (&[ 1, 1, 1], &[ 2], &[ M/2+1, M/2+1], &[1]),
(&[ 0, 1], &[-1], &[1], &[1]), (&[ 0, 1], &[N1], &[1], &[1]),
(&[-1, -1], &[-2], &[2, 1], &[3]) (&[N1, N1], &[N2], &[2, 1], &[3])
]; ];
#[test] #[test]
@ -3292,7 +3340,7 @@ mod bigint_tests {
let x: BigInt = FromPrimitive::from_isize(n).unwrap(); let x: BigInt = FromPrimitive::from_isize(n).unwrap();
x x
}); });
assert_eq!(FromStrRadix::from_str_radix(s, 10).ok(), ans); assert_eq!(BigInt::from_str_radix(s, 10).ok(), ans);
} }
check("10", Some(10)); check("10", Some(10));
check("1", Some(1)); check("1", Some(1));
@ -3374,15 +3422,13 @@ mod bench {
extern crate test; extern crate test;
use self::test::Bencher; use self::test::Bencher;
use super::BigUint; use super::BigUint;
use std::iter;
use std::mem::replace; use std::mem::replace;
use std::num::FromPrimitive;
use {Zero, One}; use {Zero, One, FromPrimitive};
fn factorial(n: usize) -> BigUint { fn factorial(n: usize) -> BigUint {
let mut f: BigUint = One::one(); let mut f: BigUint = One::one();
for i in iter::range_inclusive(1, n) { for i in 1..(n+1) {
let bu: BigUint = FromPrimitive::from_usize(i).unwrap(); let bu: BigUint = FromPrimitive::from_usize(i).unwrap();
f = f * bu; f = f * bu;
} }

View File

@ -12,10 +12,9 @@
//! Complex numbers. //! Complex numbers.
use std::fmt; use std::fmt;
use std::num::Float;
use std::ops::{Add, Div, Mul, Neg, Sub}; use std::ops::{Add, Div, Mul, Neg, Sub};
use {Zero, One, Num}; use {Zero, One, Num, Float};
// FIXME #1284: handle complex NaN & infinity etc. This // FIXME #1284: handle complex NaN & infinity etc. This
// probably doesn't map to C's _Complex correctly. // probably doesn't map to C's _Complex correctly.
@ -46,14 +45,6 @@ impl<T: Clone + Num> Complex<T> {
self.re.clone() * self.re.clone() + self.im.clone() * self.im.clone() self.re.clone() * self.re.clone() + self.im.clone() * self.im.clone()
} }
/// Returns the complex conjugate. i.e. `re - i im`
#[inline]
pub fn conj(&self) -> Complex<T> {
Complex::new(self.re.clone(), -self.im.clone())
}
/// Multiplies `self` by the scalar `t`. /// Multiplies `self` by the scalar `t`.
#[inline] #[inline]
pub fn scale(&self, t: T) -> Complex<T> { pub fn scale(&self, t: T) -> Complex<T> {
@ -66,12 +57,18 @@ impl<T: Clone + Num> Complex<T> {
Complex::new(self.re.clone() / t.clone(), self.im.clone() / t) Complex::new(self.re.clone() / t.clone(), self.im.clone() / t)
} }
/// Returns the complex conjugate. i.e. `re - i im`
#[inline]
pub fn conj(&self) -> Complex<T> {
Complex::new(self.re.clone(), T::zero() - self.im.clone())
}
/// Returns `1/self` /// Returns `1/self`
#[inline] #[inline]
pub fn inv(&self) -> Complex<T> { pub fn inv(&self) -> Complex<T> {
let norm_sqr = self.norm_sqr(); let norm_sqr = self.norm_sqr();
Complex::new(self.re.clone() / norm_sqr.clone(), Complex::new(self.re.clone() / norm_sqr.clone(),
-self.im.clone() / norm_sqr) T::zero() - self.im.clone() / norm_sqr)
} }
} }
@ -204,14 +201,14 @@ impl<'a, 'b, T: Clone + Num> Div<&'b Complex<T>> for &'a Complex<T> {
} }
} }
impl<T: Clone + Num> Neg for Complex<T> { impl<T: Clone + Num + Neg<Output = T>> Neg for Complex<T> {
type Output = Complex<T>; type Output = Complex<T>;
#[inline] #[inline]
fn neg(self) -> Complex<T> { -&self } fn neg(self) -> Complex<T> { -&self }
} }
impl<'a, T: Clone + Num> Neg for &'a Complex<T> { impl<'a, T: Clone + Num + Neg<Output = T>> Neg for &'a Complex<T> {
type Output = Complex<T>; type Output = Complex<T>;
#[inline] #[inline]
@ -241,10 +238,12 @@ impl<T: Clone + Num> One for Complex<T> {
} }
/* string conversions */ /* string conversions */
impl<T: fmt::Display + Num + PartialOrd + Clone> fmt::Display for Complex<T> { impl<T> fmt::Display for Complex<T> where
T: fmt::Display + Num + PartialOrd + Clone
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.im < Zero::zero() { if self.im < Zero::zero() {
write!(f, "{}-{}i", self.re, -self.im.clone()) write!(f, "{}-{}i", self.re, T::zero() - self.im.clone())
} else { } else {
write!(f, "{}+{}i", self.re, self.im) write!(f, "{}+{}i", self.re, self.im)
} }
@ -257,9 +256,8 @@ mod test {
use super::{Complex64, Complex}; use super::{Complex64, Complex};
use std::f64; use std::f64;
use std::num::Float;
use {Zero, One}; use {Zero, One, Float};
pub const _0_0i : Complex64 = Complex { re: 0.0, im: 0.0 }; pub const _0_0i : Complex64 = Complex { re: 0.0, im: 0.0 };
pub const _1_0i : Complex64 = Complex { re: 1.0, im: 0.0 }; pub const _1_0i : Complex64 = Complex { re: 1.0, im: 0.0 };

View File

@ -10,12 +10,13 @@
//! Integer trait and functions. //! Integer trait and functions.
use std::ops::{Div, Rem};
use {Num, Signed}; use {Num, Signed};
pub trait Integer: Sized + Num + PartialOrd pub trait Integer
+ Div<Self, Output = Self> + Rem<Self, Output = Self> { : Sized
+ Num
+ PartialOrd + Ord + Eq
{
/// Floored integer division. /// Floored integer division.
/// ///
/// # Examples /// # Examples

View File

@ -10,9 +10,8 @@
//! External iterators for generic mathematics //! External iterators for generic mathematics
use {Integer, Zero, One, CheckedAdd}; use {Integer, Zero, One, CheckedAdd, ToPrimitive};
use std::ops::{Add, Sub}; use std::ops::{Add, Sub};
use std::num::{ToPrimitive, Int};
/// An iterator over the range [start, stop) /// An iterator over the range [start, stop)
#[derive(Clone)] #[derive(Clone)]
@ -260,10 +259,9 @@ impl<A> Iterator for RangeStepInclusive<A>
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::usize; use std::usize;
use std::num::ToPrimitive;
use std::ops::{Add, Mul}; use std::ops::{Add, Mul};
use std::cmp::Ordering; use std::cmp::Ordering;
use One; use {One, ToPrimitive};
#[test] #[test]
fn test_range() { fn test_range() {
@ -328,7 +326,6 @@ mod tests {
// this test is only meaningful when sizeof usize < sizeof u64 // this test is only meaningful when sizeof usize < sizeof u64
assert_eq!(super::range(usize::MAX - 1, usize::MAX).size_hint(), (1, Some(1))); assert_eq!(super::range(usize::MAX - 1, usize::MAX).size_hint(), (1, Some(1)));
assert_eq!(super::range(-10, -1).size_hint(), (9, Some(9))); assert_eq!(super::range(-10, -1).size_hint(), (9, Some(9)));
assert_eq!(super::range(Foo, Foo).size_hint(), (0, None));
} }
#[test] #[test]

View File

@ -43,7 +43,6 @@
//! ``` //! ```
//! //!
//! [newt]: https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method //! [newt]: https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method
#![feature(collections, core, std_misc)]
//#![cfg_attr(test, deny(warnings))] //#![cfg_attr(test, deny(warnings))]
#![cfg_attr(test, feature(hash, test))] #![cfg_attr(test, feature(hash, test))]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
@ -52,7 +51,6 @@
html_playground_url = "http://play.rust-lang.org/")] html_playground_url = "http://play.rust-lang.org/")]
extern crate rustc_serialize; extern crate rustc_serialize;
extern crate core;
extern crate rand; extern crate rand;
pub use bigint::{BigInt, BigUint}; pub use bigint::{BigInt, BigUint};
@ -61,7 +59,8 @@ pub use complex::Complex;
pub use integer::Integer; pub use integer::Integer;
pub use iter::{range, range_inclusive, range_step, range_step_inclusive}; pub use iter::{range, range_inclusive, range_step, range_step_inclusive};
pub use traits::{Num, Zero, One, Signed, Unsigned, Bounded, pub use traits::{Num, Zero, One, Signed, Unsigned, Bounded,
Saturating, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv}; Saturating, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv,
PrimInt, Float, ToPrimitive, FromPrimitive, NumCast};
#[cfg(test)] use std::hash; #[cfg(test)] use std::hash;

View File

@ -17,8 +17,8 @@ use std::error::Error;
use std::fmt; use std::fmt;
use std::ops::{Add, Div, Mul, Neg, Rem, Sub}; use std::ops::{Add, Div, Mul, Neg, Rem, Sub};
use std::str::FromStr; use std::str::FromStr;
use std::num::{FromPrimitive, FromStrRadix, Float};
use traits::{FromPrimitive, Float};
use bigint::{BigInt, BigUint, Sign}; use bigint::{BigInt, BigUint, Sign};
use {Num, Signed, Zero, One}; use {Num, Signed, Zero, One};
@ -38,8 +38,7 @@ pub type Rational64 = Ratio<i64>;
/// Alias for arbitrary precision rationals. /// Alias for arbitrary precision rationals.
pub type BigRational = Ratio<BigInt>; pub type BigRational = Ratio<BigInt>;
impl<T: Clone + Integer + PartialOrd> impl<T: Clone + Integer + PartialOrd> Ratio<T> {
Ratio<T> {
/// Creates a ratio representing the integer `t`. /// Creates a ratio representing the integer `t`.
#[inline] #[inline]
pub fn from_integer(t: T) -> Ratio<T> { pub fn from_integer(t: T) -> Ratio<T> {
@ -99,9 +98,9 @@ impl<T: Clone + Integer + PartialOrd>
self.denom = self.denom.clone() / g; self.denom = self.denom.clone() / g;
// keep denom positive! // keep denom positive!
if self.denom < Zero::zero() { if self.denom < T::zero() {
self.numer = -self.numer.clone(); self.numer = T::zero() - self.numer.clone();
self.denom = -self.denom.clone(); self.denom = T::zero() - self.denom.clone();
} }
} }
@ -143,11 +142,13 @@ impl<T: Clone + Integer + PartialOrd>
/// Rounds to the nearest integer. Rounds half-way cases away from zero. /// Rounds to the nearest integer. Rounds half-way cases away from zero.
#[inline] #[inline]
pub fn round(&self) -> Ratio<T> { pub fn round(&self) -> Ratio<T> {
let zero: Ratio<T> = Zero::zero();
let one: T = One::one(); let one: T = One::one();
let two: T = one.clone() + one.clone(); let two: T = one.clone() + one.clone();
// Find unsigned fractional part of rational number // Find unsigned fractional part of rational number
let fractional = self.fract().abs(); let mut fractional = self.fract();
if fractional < zero { fractional = zero - fractional };
// The algorithm compares the unsigned fractional part with 1/2, that // The algorithm compares the unsigned fractional part with 1/2, that
// is, a/b >= 1/2, or a >= b/2. For odd denominators, we use // is, a/b >= 1/2, or a >= b/2. For odd denominators, we use
@ -216,7 +217,9 @@ macro_rules! cmp_impl {
}; };
// return something other than a Ratio<T> // return something other than a Ratio<T>
(impl $imp:ident, $($method:ident -> $res:ty),*) => { (impl $imp:ident, $($method:ident -> $res:ty),*) => {
impl<T: Clone + Mul<T, Output = T> + $imp> $imp for Ratio<T> { impl<T> $imp for Ratio<T> where
T: Clone + Mul<T, Output = T> + $imp
{
$( $(
#[inline] #[inline]
fn $method(&self, other: &Ratio<T>) -> $res { fn $method(&self, other: &Ratio<T>) -> $res {
@ -247,7 +250,9 @@ macro_rules! forward_val_val_binop {
macro_rules! forward_ref_val_binop { macro_rules! forward_ref_val_binop {
(impl $imp:ident, $method:ident) => { (impl $imp:ident, $method:ident) => {
impl<'a, T: Clone + Integer + PartialOrd> $imp<Ratio<T>> for &'a Ratio<T> { impl<'a, T> $imp<Ratio<T>> for &'a Ratio<T> where
T: Clone + Integer + PartialOrd
{
type Output = Ratio<T>; type Output = Ratio<T>;
#[inline] #[inline]
@ -260,7 +265,9 @@ macro_rules! forward_ref_val_binop {
macro_rules! forward_val_ref_binop { macro_rules! forward_val_ref_binop {
(impl $imp:ident, $method:ident) => { (impl $imp:ident, $method:ident) => {
impl<'a, T: Clone + Integer + PartialOrd> $imp<&'a Ratio<T>> for Ratio<T> { impl<'a, T> $imp<&'a Ratio<T>> for Ratio<T> where
T: Clone + Integer + PartialOrd
{
type Output = Ratio<T>; type Output = Ratio<T>;
#[inline] #[inline]
@ -332,7 +339,7 @@ arith_impl!(impl Sub, sub);
arith_impl!(impl Rem, rem); arith_impl!(impl Rem, rem);
impl<T> Neg for Ratio<T> impl<T> Neg for Ratio<T>
where T: Clone + Integer + PartialOrd where T: Clone + Integer + PartialOrd + Neg<Output = T>
{ {
type Output = Ratio<T>; type Output = Ratio<T>;
@ -341,7 +348,7 @@ impl<T> Neg for Ratio<T>
} }
impl<'a, T> Neg for &'a Ratio<T> impl<'a, T> Neg for &'a Ratio<T>
where T: Clone + Integer + PartialOrd where T: Clone + Integer + PartialOrd + Neg<Output = T>
{ {
type Output = Ratio<T>; type Output = Ratio<T>;
@ -373,11 +380,30 @@ impl<T: Clone + Integer + PartialOrd>
} }
} }
impl<T: Clone + Integer + PartialOrd> impl<T: Clone + Integer + PartialOrd> Num for Ratio<T> {
Num for Ratio<T> {} type FromStrRadixErr = ParseRatioError;
impl<T: Clone + Integer + PartialOrd> /// Parses `numer/denom` where the numbers are in base `radix`.
Signed for Ratio<T> { fn from_str_radix(s: &str, radix: u32) -> Result<Ratio<T>, ParseRatioError> {
let split: Vec<&str> = s.splitn(2, '/').collect();
if split.len() < 2 {
Err(ParseRatioError)
} else {
let a_result: Result<T, _> = T::from_str_radix(
split[0],
radix).map_err(|_| ParseRatioError);
a_result.and_then(|a| {
let b_result: Result<T, _> =
T::from_str_radix(split[1], radix).map_err(|_| ParseRatioError);
b_result.and_then(|b| {
Ok(Ratio::new(a.clone(), b.clone()))
})
})
}
}
}
impl<T: Clone + Integer + PartialOrd + Signed> Signed for Ratio<T> {
#[inline] #[inline]
fn abs(&self) -> Ratio<T> { fn abs(&self) -> Ratio<T> {
if self.is_negative() { -self.clone() } else { self.clone() } if self.is_negative() { -self.clone() } else { self.clone() }
@ -407,7 +433,9 @@ impl<T: Clone + Integer + PartialOrd>
} }
/* String conversions */ /* String conversions */
impl<T: fmt::Display + Eq + One> fmt::Display for Ratio<T> { impl<T> fmt::Display for Ratio<T> where
T: fmt::Display + Eq + One
{
/// Renders as `numer/denom`. If denom=1, renders as numer. /// Renders as `numer/denom`. If denom=1, renders as numer.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.denom == One::one() { if self.denom == One::one() {
@ -418,8 +446,7 @@ impl<T: fmt::Display + Eq + One> fmt::Display for Ratio<T> {
} }
} }
impl<T: FromStr + Clone + Integer + PartialOrd> impl<T: FromStr + Clone + Integer + PartialOrd> FromStr for Ratio<T> {
FromStr for Ratio<T> {
type Err = ParseRatioError; type Err = ParseRatioError;
/// Parses `numer/denom` or just `numer`. /// Parses `numer/denom` or just `numer`.
@ -436,32 +463,8 @@ impl<T: FromStr + Clone + Integer + PartialOrd>
} }
} }
impl<T: FromStrRadix + Clone + Integer + PartialOrd>
FromStrRadix for Ratio<T> {
type Err = ParseRatioError;
/// Parses `numer/denom` where the numbers are in base `radix`.
fn from_str_radix(s: &str, radix: u32) -> Result<Ratio<T>, ParseRatioError> {
let split: Vec<&str> = s.splitn(2, '/').collect();
if split.len() < 2 {
Err(ParseRatioError)
} else {
let a_result: Result<T, _> = FromStrRadix::from_str_radix(
split[0],
radix).map_err(|_| ParseRatioError);
a_result.and_then(|a| {
let b_result: Result<T, _> =
FromStrRadix::from_str_radix(split[1], radix).map_err(|_| ParseRatioError);
b_result.and_then(|b| {
Ok(Ratio::new(a.clone(), b.clone()))
})
})
}
}
}
// FIXME: Bubble up specific errors // FIXME: Bubble up specific errors
#[derive(Copy, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq)]
pub struct ParseRatioError; pub struct ParseRatioError;
impl fmt::Display for ParseRatioError { impl fmt::Display for ParseRatioError {
@ -478,10 +481,9 @@ impl Error for ParseRatioError {
mod test { mod test {
use super::{Ratio, Rational, BigRational}; use super::{Ratio, Rational, BigRational};
use std::num::{FromPrimitive, Float};
use std::str::FromStr; use std::str::FromStr;
use std::i32; use std::i32;
use {Zero, One, Signed}; use {Zero, One, Signed, FromPrimitive, Float};
pub const _0 : Rational = Ratio { numer: 0, denom: 1}; pub const _0 : Rational = Ratio { numer: 0, denom: 1};
pub const _1 : Rational = Ratio { numer: 1, denom: 1}; pub const _1 : Rational = Ratio { numer: 1, denom: 1};

View File

@ -10,27 +10,54 @@
//! Numeric traits for generic mathematics //! Numeric traits for generic mathematics
use std::intrinsics;
use std::ops::{Add, Sub, Mul, Div, Rem, Neg}; use std::ops::{Add, Sub, Mul, Div, Rem, Neg};
use std::ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr}; use std::ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr};
use std::{usize, u8, u16, u32, u64}; use std::{usize, u8, u16, u32, u64};
use std::{isize, i8, i16, i32, i64}; use std::{isize, i8, i16, i32, i64};
use std::{f32, f64}; use std::{f32, f64};
use std::mem::size_of; use std::mem::{self, size_of};
use std::num::FpCategory; use std::num::FpCategory;
/// The base trait for numeric types /// The base trait for numeric types
pub trait Num: PartialEq + Zero + One pub trait Num: PartialEq + Zero + One
+ Neg<Output = Self> + Add<Output = Self> + Sub<Output = Self> + Add<Output = Self> + Sub<Output = Self>
+ Mul<Output = Self> + Div<Output = Self> + Rem<Output = Self> {} + Mul<Output = Self> + Div<Output = Self> + Rem<Output = Self>
{
/// Parse error for `from_str_radix`
type FromStrRadixErr;
macro_rules! trait_impl { /// Convert from a string and radix <= 36.
fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr>;
}
macro_rules! int_trait_impl {
($name:ident for $($t:ty)*) => ($( ($name:ident for $($t:ty)*) => ($(
impl $name for $t {} impl $name for $t {
type FromStrRadixErr = ::std::num::ParseIntError;
fn from_str_radix(s: &str, radix: u32)
-> Result<Self, ::std::num::ParseIntError>
{
<$t>::from_str_radix(s, radix)
}
}
)*) )*)
} }
trait_impl!(Num for usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64); macro_rules! float_trait_impl {
($name:ident for $($t:ty)*) => ($(
impl $name for $t {
type FromStrRadixErr = ::std::num::ParseFloatError;
fn from_str_radix(s: &str, radix: u32)
-> Result<Self, ::std::num::ParseFloatError>
{
<$t>::from_str_radix(s, radix)
}
}
)*)
}
int_trait_impl!(Num for usize u8 u16 u32 u64 isize i8 i16 i32 i64);
float_trait_impl!(Num for f32 f64);
/// Defines an additive identity element for `Self`. /// Defines an additive identity element for `Self`.
/// ///
@ -132,7 +159,6 @@ one_impl!(i64, 1i64);
one_impl!(f32, 1.0f32); one_impl!(f32, 1.0f32);
one_impl!(f64, 1.0f64); one_impl!(f64, 1.0f64);
/// Useful functions for signed numbers (i.e. numbers that can be negative). /// Useful functions for signed numbers (i.e. numbers that can be negative).
pub trait Signed: Num + Neg<Output = Self> { pub trait Signed: Num + Neg<Output = Self> {
/// Computes the absolute value. /// Computes the absolute value.
@ -204,12 +230,12 @@ macro_rules! signed_impl {
signed_impl!(isize i8 i16 i32 i64); signed_impl!(isize i8 i16 i32 i64);
macro_rules! signed_float_impl { macro_rules! signed_float_impl {
($t:ty, $nan:expr, $inf:expr, $neg_inf:expr, $fabs:path, $fcopysign:path, $fdim:ident) => { ($t:ty, $nan:expr, $inf:expr, $neg_inf:expr) => {
impl Signed for $t { impl Signed for $t {
/// Computes the absolute value. Returns `NAN` if the number is `NAN`. /// Computes the absolute value. Returns `NAN` if the number is `NAN`.
#[inline] #[inline]
fn abs(&self) -> $t { fn abs(&self) -> $t {
unsafe { $fabs(*self) } <$t>::abs(*self)
} }
/// The positive difference of two numbers. Returns `0.0` if the number is /// The positive difference of two numbers. Returns `0.0` if the number is
@ -217,8 +243,7 @@ macro_rules! signed_float_impl {
/// and `other` is returned. /// and `other` is returned.
#[inline] #[inline]
fn abs_sub(&self, other: &$t) -> $t { fn abs_sub(&self, other: &$t) -> $t {
extern { fn $fdim(a: $t, b: $t) -> $t; } <$t>::abs_sub(*self, *other)
unsafe { $fdim(*self, *other) }
} }
/// # Returns /// # Returns
@ -228,9 +253,7 @@ macro_rules! signed_float_impl {
/// - `NAN` if the number is NaN /// - `NAN` if the number is NaN
#[inline] #[inline]
fn signum(&self) -> $t { fn signum(&self) -> $t {
if self != self { $nan } else { <$t>::signum(*self)
unsafe { $fcopysign(1.0, *self) }
}
} }
/// Returns `true` if the number is positive, including `+0.0` and `INFINITY` /// Returns `true` if the number is positive, including `+0.0` and `INFINITY`
@ -244,15 +267,19 @@ macro_rules! signed_float_impl {
} }
} }
signed_float_impl!(f32, f32::NAN, f32::INFINITY, f32::NEG_INFINITY, signed_float_impl!(f32, f32::NAN, f32::INFINITY, f32::NEG_INFINITY);
intrinsics::fabsf32, intrinsics::copysignf32, fdimf); signed_float_impl!(f64, f64::NAN, f64::INFINITY, f64::NEG_INFINITY);
signed_float_impl!(f64, f64::NAN, f64::INFINITY, f64::NEG_INFINITY,
intrinsics::fabsf64, intrinsics::copysignf64, fdim);
/// A trait for values which cannot be negative /// A trait for values which cannot be negative
pub trait Unsigned: Num {} pub trait Unsigned: Num {}
trait_impl!(Unsigned for usize u8 u16 u32 u64); macro_rules! empty_trait_impl {
($name:ident for $($t:ty)*) => ($(
impl $name for $t {}
)*)
}
empty_trait_impl!(Unsigned for usize u8 u16 u32 u64);
/// Numbers which have upper and lower bounds /// Numbers which have upper and lower bounds
pub trait Bounded { pub trait Bounded {
@ -336,51 +363,27 @@ pub trait CheckedAdd: Add<Self, Output = Self> {
} }
macro_rules! checked_impl { macro_rules! checked_impl {
($trait_name:ident, $method:ident, $t:ty, $op:path) => { ($trait_name:ident, $method:ident, $t:ty) => {
impl $trait_name for $t { impl $trait_name for $t {
#[inline] #[inline]
fn $method(&self, v: &$t) -> Option<$t> { fn $method(&self, v: &$t) -> Option<$t> {
unsafe { <$t>::$method(*self, *v)
let (x, y) = $op(*self, *v);
if y { None } else { Some(x) }
}
}
}
}
}
macro_rules! checked_cast_impl {
($trait_name:ident, $method:ident, $t:ty, $cast:ty, $op:path) => {
impl $trait_name for $t {
#[inline]
fn $method(&self, v: &$t) -> Option<$t> {
unsafe {
let (x, y) = $op(*self as $cast, *v as $cast);
if y { None } else { Some(x as $t) }
}
} }
} }
} }
} }
#[cfg(target_pointer_width = "32")] checked_impl!(CheckedAdd, checked_add, u8);
checked_cast_impl!(CheckedAdd, checked_add, usize, u32, intrinsics::u32_add_with_overflow); checked_impl!(CheckedAdd, checked_add, u16);
#[cfg(target_pointer_width = "64")] checked_impl!(CheckedAdd, checked_add, u32);
checked_cast_impl!(CheckedAdd, checked_add, usize, u64, intrinsics::u64_add_with_overflow); checked_impl!(CheckedAdd, checked_add, u64);
checked_impl!(CheckedAdd, checked_add, usize);
checked_impl!(CheckedAdd, checked_add, u8, intrinsics::u8_add_with_overflow); checked_impl!(CheckedAdd, checked_add, i8);
checked_impl!(CheckedAdd, checked_add, u16, intrinsics::u16_add_with_overflow); checked_impl!(CheckedAdd, checked_add, i16);
checked_impl!(CheckedAdd, checked_add, u32, intrinsics::u32_add_with_overflow); checked_impl!(CheckedAdd, checked_add, i32);
checked_impl!(CheckedAdd, checked_add, u64, intrinsics::u64_add_with_overflow); checked_impl!(CheckedAdd, checked_add, i64);
checked_impl!(CheckedAdd, checked_add, isize);
#[cfg(target_pointer_width = "32")]
checked_cast_impl!(CheckedAdd, checked_add, isize, i32, intrinsics::i32_add_with_overflow);
#[cfg(target_pointer_width = "64")]
checked_cast_impl!(CheckedAdd, checked_add, isize, i64, intrinsics::i64_add_with_overflow);
checked_impl!(CheckedAdd, checked_add, i8, intrinsics::i8_add_with_overflow);
checked_impl!(CheckedAdd, checked_add, i16, intrinsics::i16_add_with_overflow);
checked_impl!(CheckedAdd, checked_add, i32, intrinsics::i32_add_with_overflow);
checked_impl!(CheckedAdd, checked_add, i64, intrinsics::i64_add_with_overflow);
/// Performs subtraction that returns `None` instead of wrapping around on underflow. /// Performs subtraction that returns `None` instead of wrapping around on underflow.
pub trait CheckedSub: Sub<Self, Output = Self> { pub trait CheckedSub: Sub<Self, Output = Self> {
@ -389,25 +392,17 @@ pub trait CheckedSub: Sub<Self, Output = Self> {
fn checked_sub(&self, v: &Self) -> Option<Self>; fn checked_sub(&self, v: &Self) -> Option<Self>;
} }
#[cfg(target_pointer_width = "32")] checked_impl!(CheckedSub, checked_sub, u8);
checked_cast_impl!(CheckedSub, checked_sub, usize, u32, intrinsics::u32_sub_with_overflow); checked_impl!(CheckedSub, checked_sub, u16);
#[cfg(target_pointer_width = "64")] checked_impl!(CheckedSub, checked_sub, u32);
checked_cast_impl!(CheckedSub, checked_sub, usize, u64, intrinsics::u64_sub_with_overflow); checked_impl!(CheckedSub, checked_sub, u64);
checked_impl!(CheckedSub, checked_sub, usize);
checked_impl!(CheckedSub, checked_sub, u8, intrinsics::u8_sub_with_overflow); checked_impl!(CheckedSub, checked_sub, i8);
checked_impl!(CheckedSub, checked_sub, u16, intrinsics::u16_sub_with_overflow); checked_impl!(CheckedSub, checked_sub, i16);
checked_impl!(CheckedSub, checked_sub, u32, intrinsics::u32_sub_with_overflow); checked_impl!(CheckedSub, checked_sub, i32);
checked_impl!(CheckedSub, checked_sub, u64, intrinsics::u64_sub_with_overflow); checked_impl!(CheckedSub, checked_sub, i64);
checked_impl!(CheckedSub, checked_sub, isize);
#[cfg(target_pointer_width = "32")]
checked_cast_impl!(CheckedSub, checked_sub, isize, i32, intrinsics::i32_sub_with_overflow);
#[cfg(target_pointer_width = "64")]
checked_cast_impl!(CheckedSub, checked_sub, isize, i64, intrinsics::i64_sub_with_overflow);
checked_impl!(CheckedSub, checked_sub, i8, intrinsics::i8_sub_with_overflow);
checked_impl!(CheckedSub, checked_sub, i16, intrinsics::i16_sub_with_overflow);
checked_impl!(CheckedSub, checked_sub, i32, intrinsics::i32_sub_with_overflow);
checked_impl!(CheckedSub, checked_sub, i64, intrinsics::i64_sub_with_overflow);
/// Performs multiplication that returns `None` instead of wrapping around on underflow or /// Performs multiplication that returns `None` instead of wrapping around on underflow or
/// overflow. /// overflow.
@ -417,25 +412,17 @@ pub trait CheckedMul: Mul<Self, Output = Self> {
fn checked_mul(&self, v: &Self) -> Option<Self>; fn checked_mul(&self, v: &Self) -> Option<Self>;
} }
#[cfg(target_pointer_width = "32")] checked_impl!(CheckedMul, checked_mul, u8);
checked_cast_impl!(CheckedMul, checked_mul, usize, u32, intrinsics::u32_mul_with_overflow); checked_impl!(CheckedMul, checked_mul, u16);
#[cfg(target_pointer_width = "64")] checked_impl!(CheckedMul, checked_mul, u32);
checked_cast_impl!(CheckedMul, checked_mul, usize, u64, intrinsics::u64_mul_with_overflow); checked_impl!(CheckedMul, checked_mul, u64);
checked_impl!(CheckedMul, checked_mul, usize);
checked_impl!(CheckedMul, checked_mul, u8, intrinsics::u8_mul_with_overflow); checked_impl!(CheckedMul, checked_mul, i8);
checked_impl!(CheckedMul, checked_mul, u16, intrinsics::u16_mul_with_overflow); checked_impl!(CheckedMul, checked_mul, i16);
checked_impl!(CheckedMul, checked_mul, u32, intrinsics::u32_mul_with_overflow); checked_impl!(CheckedMul, checked_mul, i32);
checked_impl!(CheckedMul, checked_mul, u64, intrinsics::u64_mul_with_overflow); checked_impl!(CheckedMul, checked_mul, i64);
checked_impl!(CheckedMul, checked_mul, isize);
#[cfg(target_pointer_width = "32")]
checked_cast_impl!(CheckedMul, checked_mul, isize, i32, intrinsics::i32_mul_with_overflow);
#[cfg(target_pointer_width = "64")]
checked_cast_impl!(CheckedMul, checked_mul, isize, i64, intrinsics::i64_mul_with_overflow);
checked_impl!(CheckedMul, checked_mul, i8, intrinsics::i8_mul_with_overflow);
checked_impl!(CheckedMul, checked_mul, i16, intrinsics::i16_mul_with_overflow);
checked_impl!(CheckedMul, checked_mul, i32, intrinsics::i32_mul_with_overflow);
checked_impl!(CheckedMul, checked_mul, i64, intrinsics::i64_mul_with_overflow);
/// Performs division that returns `None` instead of panicking on division by zero and instead of /// Performs division that returns `None` instead of panicking on division by zero and instead of
/// wrapping around on underflow and overflow. /// wrapping around on underflow and overflow.
@ -483,12 +470,12 @@ macro_rules! checkeddiv_uint_impl {
checkeddiv_uint_impl!(usize u8 u16 u32 u64); checkeddiv_uint_impl!(usize u8 u16 u32 u64);
pub trait Int pub trait PrimInt
: Num : Sized
+ Clone + Copy
+ NumCast + Num + NumCast
+ PartialOrd + Ord + Bounded
+ Eq + PartialOrd + Ord + Eq
+ Not<Output=Self> + Not<Output=Self>
+ BitAnd<Output=Self> + BitAnd<Output=Self>
+ BitOr<Output=Self> + BitOr<Output=Self>
@ -501,12 +488,6 @@ pub trait Int
+ CheckedDiv<Output=Self> + CheckedDiv<Output=Self>
+ Saturating + Saturating
{ {
/// Returns the smallest value that can be represented by this integer type.
fn min_value() -> Self;
/// Returns the largest value that can be represented by this integer type.
fn max_value() -> Self;
/// Returns the number of ones in the binary representation of `self`. /// Returns the number of ones in the binary representation of `self`.
/// ///
/// # Examples /// # Examples
@ -693,9 +674,9 @@ pub trait Int
fn pow(self, mut exp: u32) -> Self; fn pow(self, mut exp: u32) -> Self;
} }
macro_rules! int_impl { macro_rules! prim_int_impl {
($($T:ty)*) => ($( ($($T:ty)*) => ($(
impl Int for $T { impl PrimInt for $T {
fn min_value() -> Self { fn min_value() -> Self {
<$T>::min_value() <$T>::min_value()
} }
@ -755,8 +736,6 @@ macro_rules! int_impl {
)*) )*)
} }
int_impl!(u8 u16 u32 u64 usize i8 i16 i32 i64 isize);
/// A generic trait for converting a value to a number. /// A generic trait for converting a value to a number.
pub trait ToPrimitive { pub trait ToPrimitive {
/// Converts the value of `self` to an `isize`. /// Converts the value of `self` to an `isize`.
@ -834,8 +813,8 @@ macro_rules! impl_to_primitive_int_to_int {
Some($slf as $DstT) Some($slf as $DstT)
} else { } else {
let n = $slf as i64; let n = $slf as i64;
let min_value: $DstT = Int::min_value(); let min_value: $DstT = Bounded::min_value();
let max_value: $DstT = Int::max_value(); let max_value: $DstT = Bounded::max_value();
if min_value as i64 <= n && n <= max_value as i64 { if min_value as i64 <= n && n <= max_value as i64 {
Some($slf as $DstT) Some($slf as $DstT)
} else { } else {
@ -850,7 +829,7 @@ macro_rules! impl_to_primitive_int_to_uint {
($SrcT:ty, $DstT:ty, $slf:expr) => ( ($SrcT:ty, $DstT:ty, $slf:expr) => (
{ {
let zero: $SrcT = Zero::zero(); let zero: $SrcT = Zero::zero();
let max_value: $DstT = Int::max_value(); let max_value: $DstT = Bounded::max_value();
if zero <= $slf && $slf as u64 <= max_value as u64 { if zero <= $slf && $slf as u64 <= max_value as u64 {
Some($slf as $DstT) Some($slf as $DstT)
} else { } else {
@ -902,7 +881,7 @@ impl_to_primitive_int! { i64 }
macro_rules! impl_to_primitive_uint_to_int { macro_rules! impl_to_primitive_uint_to_int {
($DstT:ty, $slf:expr) => ( ($DstT:ty, $slf:expr) => (
{ {
let max_value: $DstT = Int::max_value(); let max_value: $DstT = Bounded::max_value();
if $slf as u64 <= max_value as u64 { if $slf as u64 <= max_value as u64 {
Some($slf as $DstT) Some($slf as $DstT)
} else { } else {
@ -919,7 +898,7 @@ macro_rules! impl_to_primitive_uint_to_uint {
Some($slf as $DstT) Some($slf as $DstT)
} else { } else {
let zero: $SrcT = Zero::zero(); let zero: $SrcT = Zero::zero();
let max_value: $DstT = Int::max_value(); let max_value: $DstT = Bounded::max_value();
if zero <= $slf && $slf as u64 <= max_value as u64 { if zero <= $slf && $slf as u64 <= max_value as u64 {
Some($slf as $DstT) Some($slf as $DstT)
} else { } else {
@ -1189,9 +1168,10 @@ impl_num_cast! { f64, to_f64 }
pub trait Float pub trait Float
: Num : Num
+ Clone + Copy
+ NumCast + NumCast
+ PartialOrd + PartialOrd
+ Neg<Output = Self>
{ {
/// Returns the `NaN` value. /// Returns the `NaN` value.
/// ///
@ -1671,36 +1651,6 @@ pub trait Float
/// ``` /// ```
fn log10(self) -> Self; fn log10(self) -> Self;
/// Convert radians to degrees.
///
/// ```
/// # #![feature(std_misc, core)]
/// use num::traits::Float;
/// use std::f64::consts;
///
/// let angle = consts::PI;
///
/// let abs_difference = (angle.to_degrees() - 180.0).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
fn to_degrees(self) -> Self;
/// Convert degrees to radians.
///
/// ```
/// # #![feature(std_misc, core)]
/// use num::traits::Float;
/// use std::f64::consts;
///
/// let angle = 180.0;
///
/// let abs_difference = (angle.to_radians() - consts::PI).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
fn to_radians(self) -> Self;
/// Returns the maximum of the two numbers. /// Returns the maximum of the two numbers.
/// ///
/// ``` /// ```
@ -2039,10 +1989,34 @@ pub trait Float
/// assert!(abs_difference < 1.0e-10); /// assert!(abs_difference < 1.0e-10);
/// ``` /// ```
fn atanh(self) -> Self; fn atanh(self) -> Self;
/// Returns the mantissa, base 2 exponent, and sign as integers, respectively.
/// The original number can be recovered by `sign * mantissa * 2 ^ exponent`.
/// The floating point encoding is documented in the [Reference][floating-point].
///
/// ```
/// use num::Float;
///
/// let num = 2.0f32;
///
/// // (8388608, -22, 1)
/// let (mantissa, exponent, sign) = num.integer_decode();
/// let sign_f = sign as f32;
/// let mantissa_f = mantissa as f32;
/// let exponent_f = num.powf(exponent as f32);
///
/// // 1 * 8388608 * 2^(-22) == 2
/// let abs_difference = (sign_f * mantissa_f * exponent_f - num).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
/// [floating-point]: ../../../../../reference.html#machine-types
fn integer_decode(self) -> (u64, i16, i8);
} }
macro_rules! float_impl { macro_rules! float_impl {
($($T:ident)*) => ($( ($T:ident $decode:ident) => (
impl Float for $T { impl Float for $T {
fn nan() -> Self { fn nan() -> Self {
::std::$T::NAN ::std::$T::NAN
@ -2168,14 +2142,6 @@ macro_rules! float_impl {
<$T>::log10(self) <$T>::log10(self)
} }
fn to_degrees(self) -> Self {
<$T>::to_degrees(self)
}
fn to_radians(self) -> Self {
<$T>::to_radians(self)
}
fn max(self, other: Self) -> Self { fn max(self, other: Self) -> Self {
<$T>::max(self, other) <$T>::max(self, other)
} }
@ -2260,8 +2226,40 @@ macro_rules! float_impl {
<$T>::atanh(self) <$T>::atanh(self)
} }
fn integer_decode(self) -> (u64, i16, i8) {
$decode(self)
}
} }
)*) )
} }
float_impl!(f32 f64); fn integer_decode_f32(f: f32) -> (u64, i16, i8) {
let bits: u32 = unsafe { mem::transmute(f) };
let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
let mantissa = if exponent == 0 {
(bits & 0x7fffff) << 1
} else {
(bits & 0x7fffff) | 0x800000
};
// Exponent bias + mantissa shift
exponent -= 127 + 23;
(mantissa as u64, exponent, sign)
}
fn integer_decode_f64(f: f64) -> (u64, i16, i8) {
let bits: u64 = unsafe { mem::transmute(f) };
let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
let mantissa = if exponent == 0 {
(bits & 0xfffffffffffff) << 1
} else {
(bits & 0xfffffffffffff) | 0x10000000000000
};
// Exponent bias + mantissa shift
exponent -= 1023 + 52;
(mantissa, exponent, sign)
}
float_impl!(f32 integer_decode_f32);
float_impl!(f64 integer_decode_f64);