From 63c7a25ed9007298228a3cddda003103ec961480 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 2 Apr 2015 23:29:17 -0700 Subject: [PATCH] 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). --- src/bigint.rs | 374 +++++++++++++++++++++++++++--------------------- src/complex.rs | 32 ++--- src/integer.rs | 9 +- src/iter.rs | 7 +- src/lib.rs | 5 +- src/rational.rs | 94 ++++++------ src/traits.rs | 308 ++++++++++++++++++++------------------- 7 files changed, 435 insertions(+), 394 deletions(-) diff --git a/src/bigint.rs b/src/bigint.rs index bfc74a0..d79745a 100644 --- a/src/bigint.rs +++ b/src/bigint.rs @@ -62,12 +62,10 @@ extern crate rustc_serialize; use Integer; -use core::num::ParseIntError; - use std::default::Default; use std::error::Error; 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::str::{self, FromStr}; use std::{cmp, fmt, hash, mem}; @@ -77,6 +75,8 @@ use std::{i64, u64}; use rand::Rng; use rustc_serialize::hex::ToHex; +use traits::{ToPrimitive, FromPrimitive, cast}; + use {Num, Unsigned, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, Signed, Zero, One}; use self::Sign::{Minus, NoSign, Plus}; @@ -99,7 +99,7 @@ pub mod big_digit { pub const BITS: usize = 32; pub const BASE: DoubleBigDigit = 1 << BITS; - const LO_MASK: DoubleBigDigit = (-1 as DoubleBigDigit) >> BITS; + const LO_MASK: DoubleBigDigit = (-1i32 as DoubleBigDigit) >> BITS; #[inline] fn get_hi(n: DoubleBigDigit) -> BigDigit { (n >> BITS) as BigDigit } @@ -190,11 +190,47 @@ impl FromStr for BigUint { #[inline] fn from_str(s: &str) -> Result { - 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 { + 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 = 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 { (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 ored = a.data.iter().zip(b.data.iter().chain(zeros)).map( |(ai, bi)| *ai | *bi - ).collect(); + ).collect(); 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 xored = a.data.iter().zip(b.data.iter().chain(zeros)).map( |(ai, bi)| *ai ^ *bi - ).collect(); + ).collect(); return BigUint::new(xored); } } @@ -373,11 +409,11 @@ impl<'a, 'b> Sub<&'b BigUint> for &'a BigUint { + (*ai as DoubleBigDigit) - (*bi as DoubleBigDigit) - (borrow as DoubleBigDigit) - ); + ); /* hi * (base) + lo == 1*(base) + ai - bi - borrow => ai - bi - borrow < 0 <=> hi == 0 - */ + */ borrow = if hi == 0 { 1 } else { 0 }; lo }).collect(); @@ -433,7 +469,7 @@ impl<'a, 'b> Mul<&'b BigUint> for &'a BigUint { let mut prod: Vec = a.data.iter().map(|ai| { let (hi, lo) = big_digit::from_doublebigdigit( (*ai as DoubleBigDigit) * (n as DoubleBigDigit) + (carry as DoubleBigDigit) - ); + ); carry = hi; lo }).collect(); @@ -605,33 +641,33 @@ impl Integer for BigUint { fn div_estimate(a: &BigUint, b: &BigUint, n: usize) - -> (BigUint, BigUint, BigUint) { - if a.data.len() < n { - return (Zero::zero(), Zero::zero(), (*a).clone()); - } + -> (BigUint, BigUint, BigUint) { + if a.data.len() < n { + return (Zero::zero(), Zero::zero(), (*a).clone()); + } - let an = &a.data[a.data.len() - n ..]; - let bn = *b.data.last().unwrap(); - let mut d = Vec::with_capacity(an.len()); - let mut carry = 0; - for elt in an.iter().rev() { - let ai = big_digit::to_doublebigdigit(carry, *elt); - let di = ai / (bn as DoubleBigDigit); - assert!(di < big_digit::BASE); - carry = (ai % (bn as DoubleBigDigit)) as BigDigit; - d.push(di as BigDigit) - } - d.reverse(); + let an = &a.data[a.data.len() - n ..]; + let bn = *b.data.last().unwrap(); + let mut d = Vec::with_capacity(an.len()); + let mut carry = 0; + for elt in an.iter().rev() { + let ai = big_digit::to_doublebigdigit(carry, *elt); + let di = ai / (bn as DoubleBigDigit); + assert!(di < big_digit::BASE); + carry = (ai % (bn as DoubleBigDigit)) as BigDigit; + d.push(di as BigDigit) + } + d.reverse(); - let shift = (a.data.len() - an.len()) - (b.data.len() - 1); - if shift == 0 { - return (BigUint::new(d), One::one(), (*b).clone()); - } - let one: BigUint = One::one(); - return (BigUint::new(d).shl_unit(shift), - one.shl_unit(shift), - b.shl_unit(shift)); - } + let shift = (a.data.len() - an.len()) - (b.data.len() - 1); + if shift == 0 { + return (BigUint::new(d), One::one(), (*b).clone()); + } + let one: BigUint = One::one(); + return (BigUint::new(d).shl_unit(shift), + one.shl_unit(shift), + b.shl_unit(shift)); + } } /// 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!(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 { assert!(1 < radix && radix <= 16, "The radix must be within (1, 16]"); 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); 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.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 { - 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 = 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 { /// Creates and initializes a `BigUint`. /// @@ -961,7 +1011,7 @@ impl BigUint { /// ``` #[inline] pub fn parse_bytes(buf: &[u8], radix: u32) -> Option { - 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] @@ -969,7 +1019,7 @@ impl BigUint { if n_unit == 0 || self.is_zero() { return (*self).clone(); } let mut v = repeat(ZERO_BIG_DIGIT).take(n_unit).collect::>(); - v.push_all(&self.data); + v.extend(self.data.iter().cloned()); BigUint::new(v) } @@ -1119,11 +1169,27 @@ impl FromStr for BigInt { #[inline] fn from_str(s: &str) -> Result { - 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 { + 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 for 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!(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 { - 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 { /// Generate a random `BigUint` of the given bit size. fn gen_biguint(&mut self, bit_size: usize) -> BigUint; @@ -1712,7 +1760,7 @@ impl BigInt { /// ``` #[inline] pub fn parse_bytes(buf: &[u8], radix: u32) -> Option { - 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::i64; use std::iter::repeat; - use std::num::FromStrRadix; - use std::num::{ToPrimitive, FromPrimitive}; use std::str::FromStr; use std::u64; use rand::thread_rng; - use {Zero, One, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv}; + use {Num, Zero, One, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv}; + use {ToPrimitive, FromPrimitive}; #[test] fn test_from_slice() { @@ -1803,7 +1850,7 @@ mod biguint_tests { check(&[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(&[-1], &[-1]); + check(&[-1i32 as BigDigit], &[-1i32 as BigDigit]); } #[test] @@ -1833,7 +1880,7 @@ mod biguint_tests { assert_eq!(b.to_bytes_be(), [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]); } @@ -1864,7 +1911,7 @@ mod biguint_tests { assert_eq!(b.to_bytes_le(), [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]); } @@ -1963,7 +2010,7 @@ mod biguint_tests { #[test] fn test_shl() { fn check(s: &str, shift: usize, ans: &str) { - let opt_biguint: Option = 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); assert_eq!(bu, ans); } @@ -2084,8 +2131,7 @@ mod biguint_tests { #[test] fn test_shr() { fn check(s: &str, shift: usize, ans: &str) { - let opt_biguint: Option = - 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); assert_eq!(bu, ans); } @@ -2199,6 +2245,9 @@ mod biguint_tests { "88887777666655554444333322221111"); } + const N1: BigDigit = -1i32 as BigDigit; + const N2: BigDigit = -2i32 as BigDigit; + // `DoubleBigDigit` size dependent #[test] fn test_convert_i64() { @@ -2214,14 +2263,14 @@ mod biguint_tests { check(BigUint::new(vec!( )), 0); 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!(-1, -1 >> 1)), i64::MAX); + check(BigUint::new(vec!(N1, N1 >> 1)), i64::MAX); 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!(-1, -1, -1)).to_i64(), None); + assert_eq!(BigUint::new(vec!(N1, N1, N1)).to_i64(), None); } // `DoubleBigDigit` size dependent @@ -2240,12 +2289,12 @@ mod biguint_tests { check(BigUint::new(vec!( )), 0); 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!(-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!(-1, -1, -1)).to_u64(), None); + assert_eq!(BigUint::new(vec!(N1, N1, N1)).to_u64(), None); } #[test] @@ -2266,11 +2315,11 @@ mod biguint_tests { (&[], &[ 1], &[ 1]), (&[ 1], &[ 1], &[ 2]), (&[ 1], &[ 1, 1], &[ 2, 1]), - (&[ 1], &[-1], &[ 0, 1]), - (&[ 1], &[-1, -1], &[ 0, 0, 1]), - (&[-1, -1], &[-1, -1], &[-2, -1, 1]), - (&[ 1, 1, 1], &[-1, -1], &[ 0, 1, 2]), - (&[ 2, 2, 1], &[-1, -2], &[ 1, 1, 2]) + (&[ 1], &[N1], &[ 0, 1]), + (&[ 1], &[N1, N1], &[ 0, 0, 1]), + (&[N1, N1], &[N1, N1], &[N2, N1, 1]), + (&[ 1, 1, 1], &[N1, N1], &[ 0, 1, 2]), + (&[ 2, 2, 1], &[N1, N2], &[ 1, 1, 2]) ]; #[test] @@ -2317,18 +2366,18 @@ mod biguint_tests { (&[ 2], &[ 3], &[ 6]), (&[ 1], &[ 1, 1, 1], &[1, 1, 1]), (&[ 1, 2, 3], &[ 3], &[ 3, 6, 9]), - (&[ 1, 1, 1], &[-1], &[-1, -1, -1]), - (&[ 1, 2, 3], &[-1], &[-1, -2, -2, 2]), - (&[ 1, 2, 3, 4], &[-1], &[-1, -2, -2, -2, 3]), - (&[-1], &[-1], &[ 1, -2]), - (&[-1, -1], &[-1], &[ 1, -1, -2]), - (&[-1, -1, -1], &[-1], &[ 1, -1, -1, -2]), - (&[-1, -1, -1, -1], &[-1], &[ 1, -1, -1, -1, -2]), + (&[ 1, 1, 1], &[N1], &[N1, N1, N1]), + (&[ 1, 2, 3], &[N1], &[N1, N2, N2, 2]), + (&[ 1, 2, 3, 4], &[N1], &[N1, N2, N2, N2, 3]), + (&[N1], &[N1], &[ 1, N2]), + (&[N1, N1], &[N1], &[ 1, N1, N2]), + (&[N1, N1, N1], &[N1], &[ 1, N1, N1, N2]), + (&[N1, N1, N1, N1], &[N1], &[ 1, N1, N1, N1, N2]), (&[ M/2 + 1], &[ 2], &[ 0, 1]), (&[0, M/2 + 1], &[ 2], &[ 0, 0, 1]), (&[ 1, 2], &[ 1, 2, 3], &[1, 4, 7, 6]), - (&[-1, -1], &[-1, -1, -1], &[1, 0, -1, -2, -1]), - (&[-1, -1, -1], &[-1, -1, -1, -1], &[1, 0, 0, -1, -2, -1, -1]), + (&[N1, N1], &[N1, N1, N1], &[1, 0, N1, N2, N1]), + (&[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], &[ 0, 0, 0, 1], &[0, 0, 0, 0, 0, 1]) ]; @@ -2341,8 +2390,8 @@ mod biguint_tests { (&[ 1], &[ 2], &[], &[1]), (&[ 1, 1], &[ 2], &[ M/2+1], &[1]), (&[ 1, 1, 1], &[ 2], &[ M/2+1, M/2+1], &[1]), - (&[ 0, 1], &[-1], &[1], &[1]), - (&[-1, -1], &[-2], &[2, 1], &[3]) + (&[ 0, 1], &[N1], &[1], &[1]), + (&[N1, N1], &[N2], &[2, 1], &[3]) ]; #[test] @@ -2600,17 +2649,15 @@ mod biguint_tests { for str_pair in rs.iter() { let &(ref radix, ref str) = str_pair; assert_eq!(n, - &FromStrRadix::from_str_radix(str, - *radix).unwrap()); + &BigUint::from_str_radix(str, *radix).unwrap()); } } - let zed: Option = FromStrRadix::from_str_radix("Z", 10).ok(); + let zed = BigUint::from_str_radix("Z", 10).ok(); assert_eq!(zed, None); - let blank: Option = FromStrRadix::from_str_radix("_", 2).ok(); + let blank = BigUint::from_str_radix("_", 2).ok(); assert_eq!(blank, None); - let minus_one: Option = FromStrRadix::from_str_radix("-1", - 10).ok(); + let minus_one = BigUint::from_str_radix("-1", 10).ok(); assert_eq!(minus_one, None); } @@ -2629,7 +2676,7 @@ mod biguint_tests { fn check(n: usize, s: &str) { 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!() }; assert_eq!(n, ans); @@ -2650,7 +2697,7 @@ mod biguint_tests { assert_eq!(n.bits(), 1); let n: BigUint = FromPrimitive::from_usize(3).unwrap(); 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); let one: BigUint = One::one(); assert_eq!((one << 426).bits(), 427); @@ -2713,14 +2760,12 @@ mod bigint_tests { use std::cmp::Ordering::{Less, Equal, Greater}; use std::i64; use std::iter::repeat; - use std::num::FromStrRadix; - use std::num::{ToPrimitive, FromPrimitive}; use std::u64; use std::ops::{Neg}; use rand::thread_rng; - use {Zero, One, Signed}; + use {Zero, One, Signed, ToPrimitive, FromPrimitive, Num}; #[test] fn test_from_biguint() { @@ -2764,7 +2809,7 @@ mod bigint_tests { assert_eq!(b.to_bytes_be(), (NoSign, vec![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])); } @@ -2797,7 +2842,7 @@ mod bigint_tests { assert_eq!(b.to_bytes_le(), (NoSign, vec![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])); } @@ -2929,6 +2974,9 @@ mod bigint_tests { assert_eq!(negative.to_biguint(), None); } + const N1: BigDigit = -1i32 as BigDigit; + const N2: BigDigit = -2i32 as BigDigit; + const SUM_TRIPLES: &'static [(&'static [BigDigit], &'static [BigDigit], &'static [BigDigit])] = &[ @@ -2936,11 +2984,11 @@ mod bigint_tests { (&[], &[ 1], &[ 1]), (&[ 1], &[ 1], &[ 2]), (&[ 1], &[ 1, 1], &[ 2, 1]), - (&[ 1], &[-1], &[ 0, 1]), - (&[ 1], &[-1, -1], &[ 0, 0, 1]), - (&[-1, -1], &[-1, -1], &[-2, -1, 1]), - (&[ 1, 1, 1], &[-1, -1], &[ 0, 1, 2]), - (&[ 2, 2, 1], &[-1, -2], &[ 1, 1, 2]) + (&[ 1], &[N1], &[ 0, 1]), + (&[ 1], &[N1, N1], &[ 0, 0, 1]), + (&[N1, N1], &[N1, N1], &[N2, N1, 1]), + (&[ 1, 1, 1], &[N1, N1], &[ 0, 1, 2]), + (&[ 2, 2, 1], &[N1, N2], &[ 1, 1, 2]) ]; #[test] @@ -2992,18 +3040,18 @@ mod bigint_tests { (&[ 2], &[ 3], &[ 6]), (&[ 1], &[ 1, 1, 1], &[1, 1, 1]), (&[ 1, 2, 3], &[ 3], &[ 3, 6, 9]), - (&[ 1, 1, 1], &[-1], &[-1, -1, -1]), - (&[ 1, 2, 3], &[-1], &[-1, -2, -2, 2]), - (&[ 1, 2, 3, 4], &[-1], &[-1, -2, -2, -2, 3]), - (&[-1], &[-1], &[ 1, -2]), - (&[-1, -1], &[-1], &[ 1, -1, -2]), - (&[-1, -1, -1], &[-1], &[ 1, -1, -1, -2]), - (&[-1, -1, -1, -1], &[-1], &[ 1, -1, -1, -1, -2]), + (&[ 1, 1, 1], &[N1], &[N1, N1, N1]), + (&[ 1, 2, 3], &[N1], &[N1, N2, N2, 2]), + (&[ 1, 2, 3, 4], &[N1], &[N1, N2, N2, N2, 3]), + (&[N1], &[N1], &[ 1, N2]), + (&[N1, N1], &[N1], &[ 1, N1, N2]), + (&[N1, N1, N1], &[N1], &[ 1, N1, N1, N2]), + (&[N1, N1, N1, N1], &[N1], &[ 1, N1, N1, N1, N2]), (&[ M/2 + 1], &[ 2], &[ 0, 1]), (&[0, M/2 + 1], &[ 2], &[ 0, 0, 1]), (&[ 1, 2], &[ 1, 2, 3], &[1, 4, 7, 6]), - (&[-1, -1], &[-1, -1, -1], &[1, 0, -1, -2, -1]), - (&[-1, -1, -1], &[-1, -1, -1, -1], &[1, 0, 0, -1, -2, -1, -1]), + (&[N1, N1], &[N1, N1, N1], &[1, 0, N1, N2, N1]), + (&[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], &[ 0, 0, 0, 1], &[0, 0, 0, 0, 0, 1]) ]; @@ -3016,8 +3064,8 @@ mod bigint_tests { (&[ 1], &[ 2], &[], &[1]), (&[ 1, 1], &[ 2], &[ M/2+1], &[1]), (&[ 1, 1, 1], &[ 2], &[ M/2+1, M/2+1], &[1]), - (&[ 0, 1], &[-1], &[1], &[1]), - (&[-1, -1], &[-2], &[2, 1], &[3]) + (&[ 0, 1], &[N1], &[1], &[1]), + (&[N1, N1], &[N2], &[2, 1], &[3]) ]; #[test] @@ -3292,7 +3340,7 @@ mod bigint_tests { let x: BigInt = FromPrimitive::from_isize(n).unwrap(); 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("1", Some(1)); @@ -3374,15 +3422,13 @@ mod bench { extern crate test; use self::test::Bencher; use super::BigUint; - use std::iter; use std::mem::replace; - use std::num::FromPrimitive; - use {Zero, One}; + use {Zero, One, FromPrimitive}; fn factorial(n: usize) -> BigUint { 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(); f = f * bu; } diff --git a/src/complex.rs b/src/complex.rs index 9b23952..e8c7557 100644 --- a/src/complex.rs +++ b/src/complex.rs @@ -12,10 +12,9 @@ //! Complex numbers. use std::fmt; -use std::num::Float; 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 // probably doesn't map to C's _Complex correctly. @@ -46,14 +45,6 @@ impl Complex { 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 { - Complex::new(self.re.clone(), -self.im.clone()) - } - - /// Multiplies `self` by the scalar `t`. #[inline] pub fn scale(&self, t: T) -> Complex { @@ -66,12 +57,18 @@ impl Complex { 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 { + Complex::new(self.re.clone(), T::zero() - self.im.clone()) + } + /// Returns `1/self` #[inline] pub fn inv(&self) -> Complex { let norm_sqr = self.norm_sqr(); 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> for &'a Complex { } } -impl Neg for Complex { +impl> Neg for Complex { type Output = Complex; #[inline] fn neg(self) -> Complex { -&self } } -impl<'a, T: Clone + Num> Neg for &'a Complex { +impl<'a, T: Clone + Num + Neg> Neg for &'a Complex { type Output = Complex; #[inline] @@ -241,10 +238,12 @@ impl One for Complex { } /* string conversions */ -impl fmt::Display for Complex { +impl fmt::Display for Complex where + T: fmt::Display + Num + PartialOrd + Clone +{ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if self.im < Zero::zero() { - write!(f, "{}-{}i", self.re, -self.im.clone()) + write!(f, "{}-{}i", self.re, T::zero() - self.im.clone()) } else { write!(f, "{}+{}i", self.re, self.im) } @@ -257,9 +256,8 @@ mod test { use super::{Complex64, Complex}; 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 _1_0i : Complex64 = Complex { re: 1.0, im: 0.0 }; diff --git a/src/integer.rs b/src/integer.rs index 8f1b7f5..b5e094b 100644 --- a/src/integer.rs +++ b/src/integer.rs @@ -10,12 +10,13 @@ //! Integer trait and functions. -use std::ops::{Div, Rem}; - use {Num, Signed}; -pub trait Integer: Sized + Num + PartialOrd - + Div + Rem { +pub trait Integer + : Sized + + Num + + PartialOrd + Ord + Eq +{ /// Floored integer division. /// /// # Examples diff --git a/src/iter.rs b/src/iter.rs index 41c6aec..917e614 100644 --- a/src/iter.rs +++ b/src/iter.rs @@ -10,9 +10,8 @@ //! External iterators for generic mathematics -use {Integer, Zero, One, CheckedAdd}; +use {Integer, Zero, One, CheckedAdd, ToPrimitive}; use std::ops::{Add, Sub}; -use std::num::{ToPrimitive, Int}; /// An iterator over the range [start, stop) #[derive(Clone)] @@ -260,10 +259,9 @@ impl Iterator for RangeStepInclusive #[cfg(test)] mod tests { use std::usize; - use std::num::ToPrimitive; use std::ops::{Add, Mul}; use std::cmp::Ordering; - use One; + use {One, ToPrimitive}; #[test] fn test_range() { @@ -328,7 +326,6 @@ mod tests { // 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(-10, -1).size_hint(), (9, Some(9))); - assert_eq!(super::range(Foo, Foo).size_hint(), (0, None)); } #[test] diff --git a/src/lib.rs b/src/lib.rs index e1ef089..a1ac396 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,7 +43,6 @@ //! ``` //! //! [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, feature(hash, test))] #![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/")] extern crate rustc_serialize; -extern crate core; extern crate rand; pub use bigint::{BigInt, BigUint}; @@ -61,7 +59,8 @@ pub use complex::Complex; pub use integer::Integer; pub use iter::{range, range_inclusive, range_step, range_step_inclusive}; 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; diff --git a/src/rational.rs b/src/rational.rs index 753bde1..97d0a83 100644 --- a/src/rational.rs +++ b/src/rational.rs @@ -17,8 +17,8 @@ use std::error::Error; use std::fmt; use std::ops::{Add, Div, Mul, Neg, Rem, Sub}; use std::str::FromStr; -use std::num::{FromPrimitive, FromStrRadix, Float}; +use traits::{FromPrimitive, Float}; use bigint::{BigInt, BigUint, Sign}; use {Num, Signed, Zero, One}; @@ -38,8 +38,7 @@ pub type Rational64 = Ratio; /// Alias for arbitrary precision rationals. pub type BigRational = Ratio; -impl - Ratio { +impl Ratio { /// Creates a ratio representing the integer `t`. #[inline] pub fn from_integer(t: T) -> Ratio { @@ -99,9 +98,9 @@ impl self.denom = self.denom.clone() / g; // keep denom positive! - if self.denom < Zero::zero() { - self.numer = -self.numer.clone(); - self.denom = -self.denom.clone(); + if self.denom < T::zero() { + self.numer = T::zero() - self.numer.clone(); + self.denom = T::zero() - self.denom.clone(); } } @@ -143,11 +142,13 @@ impl /// Rounds to the nearest integer. Rounds half-way cases away from zero. #[inline] pub fn round(&self) -> Ratio { + let zero: Ratio = Zero::zero(); let one: T = One::one(); let two: T = one.clone() + one.clone(); // 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 // 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 (impl $imp:ident, $($method:ident -> $res:ty),*) => { - impl + $imp> $imp for Ratio { + impl $imp for Ratio where + T: Clone + Mul + $imp + { $( #[inline] fn $method(&self, other: &Ratio) -> $res { @@ -247,7 +250,9 @@ macro_rules! forward_val_val_binop { macro_rules! forward_ref_val_binop { (impl $imp:ident, $method:ident) => { - impl<'a, T: Clone + Integer + PartialOrd> $imp> for &'a Ratio { + impl<'a, T> $imp> for &'a Ratio where + T: Clone + Integer + PartialOrd + { type Output = Ratio; #[inline] @@ -260,7 +265,9 @@ macro_rules! forward_ref_val_binop { macro_rules! forward_val_ref_binop { (impl $imp:ident, $method:ident) => { - impl<'a, T: Clone + Integer + PartialOrd> $imp<&'a Ratio> for Ratio { + impl<'a, T> $imp<&'a Ratio> for Ratio where + T: Clone + Integer + PartialOrd + { type Output = Ratio; #[inline] @@ -332,7 +339,7 @@ arith_impl!(impl Sub, sub); arith_impl!(impl Rem, rem); impl Neg for Ratio - where T: Clone + Integer + PartialOrd + where T: Clone + Integer + PartialOrd + Neg { type Output = Ratio; @@ -341,7 +348,7 @@ impl Neg for Ratio } impl<'a, T> Neg for &'a Ratio - where T: Clone + Integer + PartialOrd + where T: Clone + Integer + PartialOrd + Neg { type Output = Ratio; @@ -373,11 +380,30 @@ impl } } -impl - Num for Ratio {} +impl Num for Ratio { + type FromStrRadixErr = ParseRatioError; -impl - Signed for Ratio { + /// Parses `numer/denom` where the numbers are in base `radix`. + fn from_str_radix(s: &str, radix: u32) -> Result, ParseRatioError> { + let split: Vec<&str> = s.splitn(2, '/').collect(); + if split.len() < 2 { + Err(ParseRatioError) + } else { + let a_result: Result = T::from_str_radix( + split[0], + radix).map_err(|_| ParseRatioError); + a_result.and_then(|a| { + let b_result: Result = + T::from_str_radix(split[1], radix).map_err(|_| ParseRatioError); + b_result.and_then(|b| { + Ok(Ratio::new(a.clone(), b.clone())) + }) + }) + } + } +} + +impl Signed for Ratio { #[inline] fn abs(&self) -> Ratio { if self.is_negative() { -self.clone() } else { self.clone() } @@ -407,7 +433,9 @@ impl } /* String conversions */ -impl fmt::Display for Ratio { +impl fmt::Display for Ratio where + T: fmt::Display + Eq + One +{ /// Renders as `numer/denom`. If denom=1, renders as numer. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if self.denom == One::one() { @@ -418,8 +446,7 @@ impl fmt::Display for Ratio { } } -impl - FromStr for Ratio { +impl FromStr for Ratio { type Err = ParseRatioError; /// Parses `numer/denom` or just `numer`. @@ -436,32 +463,8 @@ impl } } -impl - FromStrRadix for Ratio { - type Err = ParseRatioError; - - /// Parses `numer/denom` where the numbers are in base `radix`. - fn from_str_radix(s: &str, radix: u32) -> Result, ParseRatioError> { - let split: Vec<&str> = s.splitn(2, '/').collect(); - if split.len() < 2 { - Err(ParseRatioError) - } else { - let a_result: Result = FromStrRadix::from_str_radix( - split[0], - radix).map_err(|_| ParseRatioError); - a_result.and_then(|a| { - let b_result: Result = - 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 -#[derive(Copy, Debug, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq)] pub struct ParseRatioError; impl fmt::Display for ParseRatioError { @@ -478,10 +481,9 @@ impl Error for ParseRatioError { mod test { use super::{Ratio, Rational, BigRational}; - use std::num::{FromPrimitive, Float}; use std::str::FromStr; use std::i32; - use {Zero, One, Signed}; + use {Zero, One, Signed, FromPrimitive, Float}; pub const _0 : Rational = Ratio { numer: 0, denom: 1}; pub const _1 : Rational = Ratio { numer: 1, denom: 1}; diff --git a/src/traits.rs b/src/traits.rs index 39e4ecb..8000fda 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -10,27 +10,54 @@ //! Numeric traits for generic mathematics -use std::intrinsics; use std::ops::{Add, Sub, Mul, Div, Rem, Neg}; use std::ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr}; use std::{usize, u8, u16, u32, u64}; use std::{isize, i8, i16, i32, i64}; use std::{f32, f64}; -use std::mem::size_of; +use std::mem::{self, size_of}; use std::num::FpCategory; /// The base trait for numeric types pub trait Num: PartialEq + Zero + One - + Neg + Add + Sub - + Mul + Div + Rem {} + + Add + Sub + + Mul + Div + Rem +{ + /// 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; +} + +macro_rules! int_trait_impl { ($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 + { + <$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 + { + <$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`. /// @@ -132,7 +159,6 @@ one_impl!(i64, 1i64); one_impl!(f32, 1.0f32); one_impl!(f64, 1.0f64); - /// Useful functions for signed numbers (i.e. numbers that can be negative). pub trait Signed: Num + Neg { /// Computes the absolute value. @@ -204,12 +230,12 @@ macro_rules! signed_impl { signed_impl!(isize i8 i16 i32 i64); 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 { /// Computes the absolute value. Returns `NAN` if the number is `NAN`. #[inline] fn abs(&self) -> $t { - unsafe { $fabs(*self) } + <$t>::abs(*self) } /// 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. #[inline] fn abs_sub(&self, other: &$t) -> $t { - extern { fn $fdim(a: $t, b: $t) -> $t; } - unsafe { $fdim(*self, *other) } + <$t>::abs_sub(*self, *other) } /// # Returns @@ -228,9 +253,7 @@ macro_rules! signed_float_impl { /// - `NAN` if the number is NaN #[inline] fn signum(&self) -> $t { - if self != self { $nan } else { - unsafe { $fcopysign(1.0, *self) } - } + <$t>::signum(*self) } /// 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, - intrinsics::fabsf32, intrinsics::copysignf32, fdimf); -signed_float_impl!(f64, f64::NAN, f64::INFINITY, f64::NEG_INFINITY, - intrinsics::fabsf64, intrinsics::copysignf64, fdim); +signed_float_impl!(f32, f32::NAN, f32::INFINITY, f32::NEG_INFINITY); +signed_float_impl!(f64, f64::NAN, f64::INFINITY, f64::NEG_INFINITY); /// A trait for values which cannot be negative 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 pub trait Bounded { @@ -336,51 +363,27 @@ pub trait CheckedAdd: Add { } 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 { #[inline] fn $method(&self, v: &$t) -> Option<$t> { - unsafe { - 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) } - } + <$t>::$method(*self, *v) } } } } -#[cfg(target_pointer_width = "32")] -checked_cast_impl!(CheckedAdd, checked_add, usize, u32, intrinsics::u32_add_with_overflow); -#[cfg(target_pointer_width = "64")] -checked_cast_impl!(CheckedAdd, checked_add, usize, u64, intrinsics::u64_add_with_overflow); +checked_impl!(CheckedAdd, checked_add, u8); +checked_impl!(CheckedAdd, checked_add, u16); +checked_impl!(CheckedAdd, checked_add, u32); +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, u16, intrinsics::u16_add_with_overflow); -checked_impl!(CheckedAdd, checked_add, u32, intrinsics::u32_add_with_overflow); -checked_impl!(CheckedAdd, checked_add, u64, intrinsics::u64_add_with_overflow); - -#[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); +checked_impl!(CheckedAdd, checked_add, i8); +checked_impl!(CheckedAdd, checked_add, i16); +checked_impl!(CheckedAdd, checked_add, i32); +checked_impl!(CheckedAdd, checked_add, i64); +checked_impl!(CheckedAdd, checked_add, isize); /// Performs subtraction that returns `None` instead of wrapping around on underflow. pub trait CheckedSub: Sub { @@ -389,25 +392,17 @@ pub trait CheckedSub: Sub { fn checked_sub(&self, v: &Self) -> Option; } -#[cfg(target_pointer_width = "32")] -checked_cast_impl!(CheckedSub, checked_sub, usize, u32, intrinsics::u32_sub_with_overflow); -#[cfg(target_pointer_width = "64")] -checked_cast_impl!(CheckedSub, checked_sub, usize, u64, intrinsics::u64_sub_with_overflow); +checked_impl!(CheckedSub, checked_sub, u8); +checked_impl!(CheckedSub, checked_sub, u16); +checked_impl!(CheckedSub, checked_sub, u32); +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, u16, intrinsics::u16_sub_with_overflow); -checked_impl!(CheckedSub, checked_sub, u32, intrinsics::u32_sub_with_overflow); -checked_impl!(CheckedSub, checked_sub, u64, intrinsics::u64_sub_with_overflow); - -#[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); +checked_impl!(CheckedSub, checked_sub, i8); +checked_impl!(CheckedSub, checked_sub, i16); +checked_impl!(CheckedSub, checked_sub, i32); +checked_impl!(CheckedSub, checked_sub, i64); +checked_impl!(CheckedSub, checked_sub, isize); /// Performs multiplication that returns `None` instead of wrapping around on underflow or /// overflow. @@ -417,25 +412,17 @@ pub trait CheckedMul: Mul { fn checked_mul(&self, v: &Self) -> Option; } -#[cfg(target_pointer_width = "32")] -checked_cast_impl!(CheckedMul, checked_mul, usize, u32, intrinsics::u32_mul_with_overflow); -#[cfg(target_pointer_width = "64")] -checked_cast_impl!(CheckedMul, checked_mul, usize, u64, intrinsics::u64_mul_with_overflow); +checked_impl!(CheckedMul, checked_mul, u8); +checked_impl!(CheckedMul, checked_mul, u16); +checked_impl!(CheckedMul, checked_mul, u32); +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, u16, intrinsics::u16_mul_with_overflow); -checked_impl!(CheckedMul, checked_mul, u32, intrinsics::u32_mul_with_overflow); -checked_impl!(CheckedMul, checked_mul, u64, intrinsics::u64_mul_with_overflow); - -#[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); +checked_impl!(CheckedMul, checked_mul, i8); +checked_impl!(CheckedMul, checked_mul, i16); +checked_impl!(CheckedMul, checked_mul, i32); +checked_impl!(CheckedMul, checked_mul, i64); +checked_impl!(CheckedMul, checked_mul, isize); /// Performs division that returns `None` instead of panicking on division by zero and instead of /// wrapping around on underflow and overflow. @@ -483,12 +470,12 @@ macro_rules! checkeddiv_uint_impl { checkeddiv_uint_impl!(usize u8 u16 u32 u64); -pub trait Int - : Num - + Clone - + NumCast - + PartialOrd + Ord - + Eq +pub trait PrimInt + : Sized + + Copy + + Num + NumCast + + Bounded + + PartialOrd + Ord + Eq + Not + BitAnd + BitOr @@ -501,12 +488,6 @@ pub trait Int + CheckedDiv + 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`. /// /// # Examples @@ -693,9 +674,9 @@ pub trait Int fn pow(self, mut exp: u32) -> Self; } -macro_rules! int_impl { +macro_rules! prim_int_impl { ($($T:ty)*) => ($( - impl Int for $T { + impl PrimInt for $T { fn min_value() -> Self { <$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. pub trait ToPrimitive { /// Converts the value of `self` to an `isize`. @@ -834,8 +813,8 @@ macro_rules! impl_to_primitive_int_to_int { Some($slf as $DstT) } else { let n = $slf as i64; - let min_value: $DstT = Int::min_value(); - let max_value: $DstT = Int::max_value(); + let min_value: $DstT = Bounded::min_value(); + let max_value: $DstT = Bounded::max_value(); if min_value as i64 <= n && n <= max_value as i64 { Some($slf as $DstT) } else { @@ -850,7 +829,7 @@ macro_rules! impl_to_primitive_int_to_uint { ($SrcT:ty, $DstT:ty, $slf:expr) => ( { 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 { Some($slf as $DstT) } else { @@ -902,7 +881,7 @@ impl_to_primitive_int! { i64 } macro_rules! impl_to_primitive_uint_to_int { ($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 { Some($slf as $DstT) } else { @@ -919,7 +898,7 @@ macro_rules! impl_to_primitive_uint_to_uint { Some($slf as $DstT) } else { 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 { Some($slf as $DstT) } else { @@ -1189,9 +1168,10 @@ impl_num_cast! { f64, to_f64 } pub trait Float : Num - + Clone + + Copy + NumCast + PartialOrd + + Neg { /// Returns the `NaN` value. /// @@ -1671,36 +1651,6 @@ pub trait Float /// ``` 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. /// /// ``` @@ -2039,10 +1989,34 @@ pub trait Float /// assert!(abs_difference < 1.0e-10); /// ``` 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 { - ($($T:ident)*) => ($( + ($T:ident $decode:ident) => ( impl Float for $T { fn nan() -> Self { ::std::$T::NAN @@ -2168,14 +2142,6 @@ macro_rules! float_impl { <$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 { <$T>::max(self, other) } @@ -2260,8 +2226,40 @@ macro_rules! float_impl { <$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);