From 54685c46a1973e86f70d8eccc9dc0ebb3a251c17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Jan=20Niemier?= Date: Fri, 4 Mar 2016 12:32:44 +0100 Subject: [PATCH] Extract rational --- .travis.yml | 7 +- .travis/test_features.sh | 2 - Cargo.toml | 10 +- Makefile | 14 + bigint/Cargo.toml | 5 +- bigint/src/lib.rs | 74 +-- integer/src/lib.rs | 20 +- rational/Cargo.toml | 24 + rational/src/lib.rs | 1091 ++++++++++++++++++++++++++++++++++++++ src/lib.rs | 29 +- traits/src/cast.rs | 3 +- traits/src/float.rs | 108 ++-- traits/src/int.rs | 32 +- 13 files changed, 1277 insertions(+), 142 deletions(-) create mode 100644 Makefile create mode 100644 rational/Cargo.toml create mode 100644 rational/src/lib.rs diff --git a/.travis.yml b/.travis.yml index fa2027b..beadc77 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,12 +5,9 @@ rust: - nightly sudo: false script: - - cargo build --verbose - - cargo test --verbose - - .travis/test_features.sh + - make test - | - [ $TRAVIS_RUST_VERSION != nightly ] || - .travis/test_nightly.sh + [ $TRAVIS_RUST_VERSION != nightly ] || .travis/test_nightly.sh - cargo doc after_success: | [ $TRAVIS_BRANCH = master ] && diff --git a/.travis/test_features.sh b/.travis/test_features.sh index 150ac41..5ff01c0 100755 --- a/.travis/test_features.sh +++ b/.travis/test_features.sh @@ -3,7 +3,5 @@ set -ex for feature in '' bigint rational complex; do - cargo build --verbose --no-default-features --features="$feature" cargo test --verbose --no-default-features --features="$feature" done - diff --git a/Cargo.toml b/Cargo.toml index 378484a..d833beb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,12 +19,16 @@ name = "shootout-pidigits" [dependencies] [dependencies.num-bigint] -optional = false +optional = true path = "bigint" [dependencies.num-integer] path = "./integer" +[dependencies.num-rational] +optional = true +path = "rational" + [dependencies.num-traits] path = "./traits" @@ -46,7 +50,7 @@ version = "^0.7.0" version = "0.3.8" [features] -bigint = [] +bigint = ["num-bigint"] complex = [] default = ["bigint", "complex", "rand", "rational", "rustc-serialize"] -rational = [] +rational = ["num-rational"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..74a3a93 --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +CARGO_CMD ?= cargo + +packages = bigint integer rational traits + +test: + $(MAKE) run-all TASK="test --no-fail-fast" + +run-all: $(packages) + $(CARGO_CMD) $(TASK) + +$(packages): + $(CARGO_CMD) $(TASK) --manifest-path $@/Cargo.toml + +.PHONY: $(packages) test diff --git a/bigint/Cargo.toml b/bigint/Cargo.toml index 729e5cc..657e511 100644 --- a/bigint/Cargo.toml +++ b/bigint/Cargo.toml @@ -6,11 +6,9 @@ version = "0.1.0" [dependencies] [dependencies.num-integer] -optional = false path = "../integer" [dependencies.num-traits] -optional = false path = "../traits" [dependencies.rand] @@ -20,3 +18,6 @@ version = "0.3.14" [dependencies.serde] optional = true version = "0.7.0" + +[features] +default = ["rand"] diff --git a/bigint/src/lib.rs b/bigint/src/lib.rs index 7bb3cc5..4f5b0a3 100644 --- a/bigint/src/lib.rs +++ b/bigint/src/lib.rs @@ -18,8 +18,9 @@ //! //! ## Example //! -//! ```rust -//! use num::{BigUint, Zero, One}; +//! ```rust,ignore +//! use num_bigint::BigUint; +//! use num_traits::{Zero, One}; //! use std::mem::replace; //! //! // Calculate large fibonacci numbers. @@ -42,11 +43,11 @@ //! //! ```rust //! extern crate rand; -//! extern crate num; +//! extern crate num_bigint as bigint; //! //! # #[cfg(feature = "rand")] //! # fn main() { -//! use num::bigint::{ToBigInt, RandBigInt}; +//! use bigint::{ToBigInt, RandBigInt}; //! //! let mut rng = rand::thread_rng(); //! let a = rng.gen_bigint(1000); @@ -64,6 +65,9 @@ //! # } //! ``` +#[cfg(any(feature = "rand", test))] +extern crate rand; + extern crate num_integer as integer; extern crate num_traits as traits; @@ -75,6 +79,7 @@ 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::fmt; +use std::hash; use std::cmp::Ordering::{self, Less, Greater, Equal}; use std::{f32, f64}; use std::{u8, i64, u64}; @@ -1655,7 +1660,7 @@ impl BigUint { /// # Examples /// /// ``` - /// use num::bigint::BigUint; + /// use num_bigint::BigUint; /// /// assert_eq!(BigUint::from_bytes_be(b"A"), /// BigUint::parse_bytes(b"65", 10).unwrap()); @@ -1694,7 +1699,7 @@ impl BigUint { /// # Examples /// /// ``` - /// use num::bigint::BigUint; + /// use num_bigint::BigUint; /// /// let i = BigUint::parse_bytes(b"1125", 10).unwrap(); /// assert_eq!(i.to_bytes_le(), vec![101, 4]); @@ -1713,7 +1718,7 @@ impl BigUint { /// # Examples /// /// ``` - /// use num::bigint::BigUint; + /// use num_bigint::BigUint; /// /// let i = BigUint::parse_bytes(b"1125", 10).unwrap(); /// assert_eq!(i.to_bytes_be(), vec![4, 101]); @@ -1731,7 +1736,7 @@ impl BigUint { /// # Examples /// /// ``` - /// use num::bigint::BigUint; + /// use num_bigint::BigUint; /// /// let i = BigUint::parse_bytes(b"ff", 16).unwrap(); /// assert_eq!(i.to_str_radix(16), "ff"); @@ -1748,7 +1753,7 @@ impl BigUint { /// # Examples /// /// ``` - /// use num::bigint::{BigUint, ToBigUint}; + /// use num_bigint::{BigUint, ToBigUint}; /// /// assert_eq!(BigUint::parse_bytes(b"1234", 10), ToBigUint::to_biguint(&1234)); /// assert_eq!(BigUint::parse_bytes(b"ABCD", 16), ToBigUint::to_biguint(&0xABCD)); @@ -2764,7 +2769,7 @@ impl BigInt { /// # Examples /// /// ``` - /// use num::bigint::{BigInt, Sign}; + /// use num_bigint::{BigInt, Sign}; /// /// assert_eq!(BigInt::from_bytes_be(Sign::Plus, b"A"), /// BigInt::parse_bytes(b"65", 10).unwrap()); @@ -2793,7 +2798,7 @@ impl BigInt { /// # Examples /// /// ``` - /// use num::bigint::{ToBigInt, Sign}; + /// use num_bigint::{ToBigInt, Sign}; /// /// let i = -1125.to_bigint().unwrap(); /// assert_eq!(i.to_bytes_le(), (Sign::Minus, vec![101, 4])); @@ -2808,7 +2813,7 @@ impl BigInt { /// # Examples /// /// ``` - /// use num::bigint::{ToBigInt, Sign}; + /// use num_bigint::{ToBigInt, Sign}; /// /// let i = -1125.to_bigint().unwrap(); /// assert_eq!(i.to_bytes_be(), (Sign::Minus, vec![4, 101])); @@ -2824,7 +2829,7 @@ impl BigInt { /// # Examples /// /// ``` - /// use num::bigint::BigInt; + /// use num_bigint::BigInt; /// /// let i = BigInt::parse_bytes(b"ff", 16).unwrap(); /// assert_eq!(i.to_str_radix(16), "ff"); @@ -2846,7 +2851,7 @@ impl BigInt { /// # Examples /// /// ``` - /// use num::bigint::{ToBigInt, Sign}; + /// use num_bigint::{ToBigInt, Sign}; /// /// assert_eq!(ToBigInt::to_bigint(&1234).unwrap().sign(), Sign::Plus); /// assert_eq!(ToBigInt::to_bigint(&-4321).unwrap().sign(), Sign::Minus); @@ -2862,7 +2867,7 @@ impl BigInt { /// # Examples /// /// ``` - /// use num::bigint::{BigInt, ToBigInt}; + /// use num_bigint::{BigInt, ToBigInt}; /// /// assert_eq!(BigInt::parse_bytes(b"1234", 10), ToBigInt::to_bigint(&1234)); /// assert_eq!(BigInt::parse_bytes(b"ABCD", 16), ToBigInt::to_bigint(&0xABCD)); @@ -2935,9 +2940,17 @@ impl From for ParseBigIntError { } } +#[cfg(test)] +fn hash(x: &T) -> u64 { + use std::hash::Hasher; + let mut hasher = hash::SipHasher::new(); + x.hash(&mut hasher); + hasher.finish() +} + #[cfg(test)] mod biguint_tests { - use Integer; + use integer::Integer; use super::{BigDigit, BigUint, ToBigUint, big_digit}; use super::{BigInt, RandBigInt, ToBigInt}; use super::Sign::Plus; @@ -2950,9 +2963,9 @@ mod biguint_tests { use std::{u8, u16, u32, u64, usize}; use rand::thread_rng; - use {Num, Zero, One, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv}; - use {ToPrimitive, FromPrimitive}; - use Float; + use traits::{Num, Zero, One, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, ToPrimitive, + FromPrimitive, Float}; + /// Assert that an op works for all val/ref combinations macro_rules! assert_op { @@ -3083,10 +3096,10 @@ mod biguint_tests { let c = BigUint::new(vec![1]); let d = BigUint::new(vec![1, 0, 0, 0, 0, 0]); let e = BigUint::new(vec![0, 0, 0, 0, 0, 1]); - assert!(::hash(&a) == ::hash(&b)); - assert!(::hash(&b) != ::hash(&c)); - assert!(::hash(&c) == ::hash(&d)); - assert!(::hash(&d) != ::hash(&e)); + assert!(super::hash(&a) == super::hash(&b)); + assert!(super::hash(&b) != super::hash(&c)); + assert!(super::hash(&c) == super::hash(&d)); + assert!(super::hash(&d) != super::hash(&e)); } const BIT_TESTS: &'static [(&'static [BigDigit], @@ -4173,7 +4186,6 @@ mod biguint_tests { #[cfg(test)] mod bigint_tests { - use Integer; use super::{BigDigit, BigUint, ToBigUint}; use super::{Sign, BigInt, RandBigInt, ToBigInt, big_digit}; use super::Sign::{Minus, NoSign, Plus}; @@ -4187,8 +4199,8 @@ mod bigint_tests { use rand::thread_rng; - use {Zero, One, Signed, ToPrimitive, FromPrimitive, Num}; - use Float; + use integer::Integer; + use traits::{Zero, One, Signed, ToPrimitive, FromPrimitive, Num, Float}; /// Assert that an op works for all val/ref combinations macro_rules! assert_op { @@ -4334,11 +4346,11 @@ mod bigint_tests { let d = BigInt::new(Plus, vec![1, 0, 0, 0, 0, 0]); let e = BigInt::new(Plus, vec![0, 0, 0, 0, 0, 1]); let f = BigInt::new(Minus, vec![1]); - assert!(::hash(&a) == ::hash(&b)); - assert!(::hash(&b) != ::hash(&c)); - assert!(::hash(&c) == ::hash(&d)); - assert!(::hash(&d) != ::hash(&e)); - assert!(::hash(&c) != ::hash(&f)); + assert!(super::hash(&a) == super::hash(&b)); + assert!(super::hash(&b) != super::hash(&c)); + assert!(super::hash(&c) == super::hash(&d)); + assert!(super::hash(&d) != super::hash(&e)); + assert!(super::hash(&c) != super::hash(&f)); } #[test] diff --git a/integer/src/lib.rs b/integer/src/lib.rs index 6059133..eee4ba2 100644 --- a/integer/src/lib.rs +++ b/integer/src/lib.rs @@ -20,7 +20,7 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq { /// # Examples /// /// ~~~ - /// # use num::Integer; + /// # use num_integer::Integer; /// assert!(( 8).div_floor(& 3) == 2); /// assert!(( 8).div_floor(&-3) == -3); /// assert!((-8).div_floor(& 3) == -3); @@ -36,7 +36,7 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq { /// Floored integer modulo, satisfying: /// /// ~~~ - /// # use num::Integer; + /// # use num_integer::Integer; /// # let n = 1; let d = 1; /// assert!(n.div_floor(&d) * d + n.mod_floor(&d) == n) /// ~~~ @@ -44,7 +44,7 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq { /// # Examples /// /// ~~~ - /// # use num::Integer; + /// # use num_integer::Integer; /// assert!(( 8).mod_floor(& 3) == 2); /// assert!(( 8).mod_floor(&-3) == -1); /// assert!((-8).mod_floor(& 3) == 1); @@ -62,7 +62,7 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq { /// # Examples /// /// ~~~ - /// # use num::Integer; + /// # use num_integer::Integer; /// assert_eq!(6.gcd(&8), 2); /// assert_eq!(7.gcd(&3), 1); /// ~~~ @@ -73,7 +73,7 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq { /// # Examples /// /// ~~~ - /// # use num::Integer; + /// # use num_integer::Integer; /// assert_eq!(7.lcm(&3), 21); /// assert_eq!(2.lcm(&4), 4); /// ~~~ @@ -87,7 +87,7 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq { /// # Examples /// /// ~~~ - /// # use num::Integer; + /// # use num_integer::Integer; /// assert_eq!(9.is_multiple_of(&3), true); /// assert_eq!(3.is_multiple_of(&9), false); /// ~~~ @@ -98,7 +98,7 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq { /// # Examples /// /// ~~~ - /// # use num::Integer; + /// # use num_integer::Integer; /// assert_eq!(3.is_even(), false); /// assert_eq!(4.is_even(), true); /// ~~~ @@ -109,7 +109,7 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq { /// # Examples /// /// ~~~ - /// # use num::Integer; + /// # use num_integer::Integer; /// assert_eq!(3.is_odd(), true); /// assert_eq!(4.is_odd(), false); /// ~~~ @@ -121,7 +121,7 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq { /// # Examples /// /// ~~~ - /// # use num::Integer; + /// # use num_integer::Integer; /// assert_eq!(( 8).div_rem( &3), ( 2, 2)); /// assert_eq!(( 8).div_rem(&-3), (-2, 2)); /// assert_eq!((-8).div_rem( &3), (-2, -2)); @@ -141,7 +141,7 @@ pub trait Integer: Sized + Num + PartialOrd + Ord + Eq { /// # Examples /// /// ~~~ - /// # use num::Integer; + /// # use num_integer::Integer; /// assert_eq!(( 8).div_mod_floor( &3), ( 2, 2)); /// assert_eq!(( 8).div_mod_floor(&-3), (-3, -1)); /// assert_eq!((-8).div_mod_floor( &3), (-3, 1)); diff --git a/rational/Cargo.toml b/rational/Cargo.toml new file mode 100644 index 0000000..5524742 --- /dev/null +++ b/rational/Cargo.toml @@ -0,0 +1,24 @@ +[package] +authors = ["Ɓukasz Jan Niemier "] +name = "num-rational" +version = "0.1.0" + +[dependencies] + +[dependencies.num-bigint] +optional = true +path = "../bigint" + +[dependencies.num-integer] +path = "../integer" + +[dependencies.num-traits] +path = "../traits" + +[dependencies.serde] +optional = true +version = "0.7.0" + +[features] +default = ["bigint"] +bigint = ["num-bigint"] diff --git a/rational/src/lib.rs b/rational/src/lib.rs new file mode 100644 index 0000000..09ecafb --- /dev/null +++ b/rational/src/lib.rs @@ -0,0 +1,1091 @@ +// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Rational numbers + +#[cfg(feature = "serde")] +extern crate serde; +#[cfg(feature = "num-bigint")] +extern crate num_bigint as bigint; + +extern crate num_traits as traits; +extern crate num_integer as integer; + +use std::cmp; +use std::error::Error; +use std::fmt; +use std::hash; +use std::ops::{Add, Div, Mul, Neg, Rem, Sub}; +use std::str::FromStr; + +#[cfg(feature = "serde")] +use serde; + +#[cfg(feature = "num-bigint")] +use bigint::{BigInt, BigUint, Sign}; + +use integer::Integer; +use traits::{FromPrimitive, Float, PrimInt, Num, Signed, Zero, One}; + +/// Represents the ratio between 2 numbers. +#[derive(Copy, Clone, Hash, Debug)] +#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] +#[allow(missing_docs)] +pub struct Ratio { + numer: T, + denom: T, +} + +/// Alias for a `Ratio` of machine-sized integers. +pub type Rational = Ratio; +pub type Rational32 = Ratio; +pub type Rational64 = Ratio; + +#[cfg(feature = "num-bigint")] +/// Alias for arbitrary precision rationals. +pub type BigRational = Ratio; + +impl Ratio { + /// Creates a ratio representing the integer `t`. + #[inline] + pub fn from_integer(t: T) -> Ratio { + Ratio::new_raw(t, One::one()) + } + + /// Creates a ratio without checking for `denom == 0` or reducing. + #[inline] + pub fn new_raw(numer: T, denom: T) -> Ratio { + Ratio { + numer: numer, + denom: denom, + } + } + + /// Create a new Ratio. Fails if `denom == 0`. + #[inline] + pub fn new(numer: T, denom: T) -> Ratio { + if denom == Zero::zero() { + panic!("denominator == 0"); + } + let mut ret = Ratio::new_raw(numer, denom); + ret.reduce(); + ret + } + + /// Converts to an integer. + #[inline] + pub fn to_integer(&self) -> T { + self.trunc().numer + } + + /// Gets an immutable reference to the numerator. + #[inline] + pub fn numer<'a>(&'a self) -> &'a T { + &self.numer + } + + /// Gets an immutable reference to the denominator. + #[inline] + pub fn denom<'a>(&'a self) -> &'a T { + &self.denom + } + + /// Returns true if the rational number is an integer (denominator is 1). + #[inline] + pub fn is_integer(&self) -> bool { + self.denom == One::one() + } + + /// Put self into lowest terms, with denom > 0. + fn reduce(&mut self) { + let g: T = self.numer.gcd(&self.denom); + + // FIXME(#5992): assignment operator overloads + // self.numer /= g; + self.numer = self.numer.clone() / g.clone(); + // FIXME(#5992): assignment operator overloads + // self.denom /= g; + self.denom = self.denom.clone() / g; + + // keep denom positive! + if self.denom < T::zero() { + self.numer = T::zero() - self.numer.clone(); + self.denom = T::zero() - self.denom.clone(); + } + } + + /// Returns a `reduce`d copy of self. + pub fn reduced(&self) -> Ratio { + let mut ret = self.clone(); + ret.reduce(); + ret + } + + /// Returns the reciprocal. + #[inline] + pub fn recip(&self) -> Ratio { + Ratio::new_raw(self.denom.clone(), self.numer.clone()) + } + + /// Rounds towards minus infinity. + #[inline] + pub fn floor(&self) -> Ratio { + if *self < Zero::zero() { + let one: T = One::one(); + Ratio::from_integer((self.numer.clone() - self.denom.clone() + one) / + self.denom.clone()) + } else { + Ratio::from_integer(self.numer.clone() / self.denom.clone()) + } + } + + /// Rounds towards plus infinity. + #[inline] + pub fn ceil(&self) -> Ratio { + if *self < Zero::zero() { + Ratio::from_integer(self.numer.clone() / self.denom.clone()) + } else { + let one: T = One::one(); + Ratio::from_integer((self.numer.clone() + self.denom.clone() - one) / + self.denom.clone()) + } + } + + /// 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 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 + // a >= (b/2)+1. This avoids overflow issues. + let half_or_larger = if fractional.denom().is_even() { + *fractional.numer() >= fractional.denom().clone() / two.clone() + } else { + *fractional.numer() >= (fractional.denom().clone() / two.clone()) + one.clone() + }; + + if half_or_larger { + let one: Ratio = One::one(); + if *self >= Zero::zero() { + self.trunc() + one + } else { + self.trunc() - one + } + } else { + self.trunc() + } + } + + /// Rounds towards zero. + #[inline] + pub fn trunc(&self) -> Ratio { + Ratio::from_integer(self.numer.clone() / self.denom.clone()) + } + + /// Returns the fractional part of a number. + #[inline] + pub fn fract(&self) -> Ratio { + Ratio::new_raw(self.numer.clone() % self.denom.clone(), self.denom.clone()) + } +} + +impl Ratio { + /// Raises the ratio to the power of an exponent + #[inline] + pub fn pow(&self, expon: i32) -> Ratio { + match expon.cmp(&0) { + cmp::Ordering::Equal => One::one(), + cmp::Ordering::Less => self.recip().pow(-expon), + cmp::Ordering::Greater => { + Ratio::new_raw(self.numer.pow(expon as u32), self.denom.pow(expon as u32)) + } + } + } +} + +#[cfg(feature = "num-bigint")] +impl Ratio { + /// Converts a float into a rational number. + pub fn from_float(f: T) -> Option { + if !f.is_finite() { + return None; + } + let (mantissa, exponent, sign) = f.integer_decode(); + let bigint_sign = if sign == 1 { + Sign::Plus + } else { + Sign::Minus + }; + if exponent < 0 { + let one: BigInt = One::one(); + let denom: BigInt = one << ((-exponent) as usize); + let numer: BigUint = FromPrimitive::from_u64(mantissa).unwrap(); + Some(Ratio::new(BigInt::from_biguint(bigint_sign, numer), denom)) + } else { + let mut numer: BigUint = FromPrimitive::from_u64(mantissa).unwrap(); + numer = numer << (exponent as usize); + Some(Ratio::from_integer(BigInt::from_biguint(bigint_sign, numer))) + } + } +} + +// Comparisons + +// Mathematically, comparing a/b and c/d is the same as comparing a*d and b*c, but it's very easy +// for those multiplications to overflow fixed-size integers, so we need to take care. + +impl Ord for Ratio { + #[inline] + fn cmp(&self, other: &Self) -> cmp::Ordering { + // With equal denominators, the numerators can be directly compared + if self.denom == other.denom { + let ord = self.numer.cmp(&other.numer); + return if self.denom < T::zero() { + ord.reverse() + } else { + ord + }; + } + + // With equal numerators, the denominators can be inversely compared + if self.numer == other.numer { + let ord = self.denom.cmp(&other.denom); + return if self.numer < T::zero() { + ord + } else { + ord.reverse() + }; + } + + // Unfortunately, we don't have CheckedMul to try. That could sometimes avoid all the + // division below, or even always avoid it for BigInt and BigUint. + // FIXME- future breaking change to add Checked* to Integer? + + // Compare as floored integers and remainders + let (self_int, self_rem) = self.numer.div_mod_floor(&self.denom); + let (other_int, other_rem) = other.numer.div_mod_floor(&other.denom); + match self_int.cmp(&other_int) { + cmp::Ordering::Greater => cmp::Ordering::Greater, + cmp::Ordering::Less => cmp::Ordering::Less, + cmp::Ordering::Equal => { + match (self_rem.is_zero(), other_rem.is_zero()) { + (true, true) => cmp::Ordering::Equal, + (true, false) => cmp::Ordering::Less, + (false, true) => cmp::Ordering::Greater, + (false, false) => { + // Compare the reciprocals of the remaining fractions in reverse + let self_recip = Ratio::new_raw(self.denom.clone(), self_rem); + let other_recip = Ratio::new_raw(other.denom.clone(), other_rem); + self_recip.cmp(&other_recip).reverse() + } + } + } + } + } +} + +impl PartialOrd for Ratio { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl PartialEq for Ratio { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.cmp(other) == cmp::Ordering::Equal + } +} + +impl Eq for Ratio {} + + +macro_rules! forward_val_val_binop { + (impl $imp:ident, $method:ident) => { + impl $imp> for Ratio { + type Output = Ratio; + + #[inline] + fn $method(self, other: Ratio) -> Ratio { + (&self).$method(&other) + } + } + } +} + +macro_rules! forward_ref_val_binop { + (impl $imp:ident, $method:ident) => { + impl<'a, T> $imp> for &'a Ratio where + T: Clone + Integer + { + type Output = Ratio; + + #[inline] + fn $method(self, other: Ratio) -> Ratio { + self.$method(&other) + } + } + } +} + +macro_rules! forward_val_ref_binop { + (impl $imp:ident, $method:ident) => { + impl<'a, T> $imp<&'a Ratio> for Ratio where + T: Clone + Integer + { + type Output = Ratio; + + #[inline] + fn $method(self, other: &Ratio) -> Ratio { + (&self).$method(other) + } + } + } +} + +macro_rules! forward_all_binop { + (impl $imp:ident, $method:ident) => { + forward_val_val_binop!(impl $imp, $method); + forward_ref_val_binop!(impl $imp, $method); + forward_val_ref_binop!(impl $imp, $method); + }; +} + +// Arithmetic +forward_all_binop!(impl Mul, mul); +// a/b * c/d = (a*c)/(b*d) +impl<'a, 'b, T> Mul<&'b Ratio> for &'a Ratio + where T: Clone + Integer +{ + type Output = Ratio; + #[inline] + fn mul(self, rhs: &Ratio) -> Ratio { + Ratio::new(self.numer.clone() * rhs.numer.clone(), + self.denom.clone() * rhs.denom.clone()) + } +} + +forward_all_binop!(impl Div, div); +// (a/b) / (c/d) = (a*d)/(b*c) +impl<'a, 'b, T> Div<&'b Ratio> for &'a Ratio + where T: Clone + Integer +{ + type Output = Ratio; + + #[inline] + fn div(self, rhs: &Ratio) -> Ratio { + Ratio::new(self.numer.clone() * rhs.denom.clone(), + self.denom.clone() * rhs.numer.clone()) + } +} + +// Abstracts the a/b `op` c/d = (a*d `op` b*d) / (b*d) pattern +macro_rules! arith_impl { + (impl $imp:ident, $method:ident) => { + forward_all_binop!(impl $imp, $method); + impl<'a, 'b, T: Clone + Integer> + $imp<&'b Ratio> for &'a Ratio { + type Output = Ratio; + #[inline] + fn $method(self, rhs: &Ratio) -> Ratio { + Ratio::new((self.numer.clone() * rhs.denom.clone()).$method(self.denom.clone() * rhs.numer.clone()), + self.denom.clone() * rhs.denom.clone()) + } + } + } +} + +// a/b + c/d = (a*d + b*c)/(b*d) +arith_impl!(impl Add, add); + +// a/b - c/d = (a*d - b*c)/(b*d) +arith_impl!(impl Sub, sub); + +// a/b % c/d = (a*d % b*c)/(b*d) +arith_impl!(impl Rem, rem); + +impl Neg for Ratio + where T: Clone + Integer + Neg +{ + type Output = Ratio; + + #[inline] + fn neg(self) -> Ratio { + Ratio::new_raw(-self.numer, self.denom) + } +} + +impl<'a, T> Neg for &'a Ratio + where T: Clone + Integer + Neg +{ + type Output = Ratio; + + #[inline] + fn neg(self) -> Ratio { + -self.clone() + } +} + +// Constants +impl Zero for Ratio { + #[inline] + fn zero() -> Ratio { + Ratio::new_raw(Zero::zero(), One::one()) + } + + #[inline] + fn is_zero(&self) -> bool { + self.numer.is_zero() + } +} + +impl One for Ratio { + #[inline] + fn one() -> Ratio { + Ratio::new_raw(One::one(), One::one()) + } +} + +impl Num for Ratio { + type FromStrRadixErr = 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 { kind: RatioErrorKind::ParseError }) + } else { + let a_result: Result = T::from_str_radix(split[0], radix).map_err(|_| { + ParseRatioError { kind: RatioErrorKind::ParseError } + }); + a_result.and_then(|a| { + let b_result: Result = T::from_str_radix(split[1], radix).map_err(|_| { + ParseRatioError { kind: RatioErrorKind::ParseError } + }); + b_result.and_then(|b| { + if b.is_zero() { + Err(ParseRatioError { kind: RatioErrorKind::ZeroDenominator }) + } else { + 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() + } + } + + #[inline] + fn abs_sub(&self, other: &Ratio) -> Ratio { + if *self <= *other { + Zero::zero() + } else { + self - other + } + } + + #[inline] + fn signum(&self) -> Ratio { + if self.is_positive() { + Self::one() + } else if self.is_zero() { + Self::zero() + } else { + -Self::one() + } + } + + #[inline] + fn is_positive(&self) -> bool { + !self.is_negative() + } + + #[inline] + fn is_negative(&self) -> bool { + self.numer.is_negative() ^ self.denom.is_negative() + } +} + +// String conversions +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() { + write!(f, "{}", self.numer) + } else { + write!(f, "{}/{}", self.numer, self.denom) + } + } +} + +impl FromStr for Ratio { + type Err = ParseRatioError; + + /// Parses `numer/denom` or just `numer`. + fn from_str(s: &str) -> Result, ParseRatioError> { + let mut split = s.splitn(2, '/'); + + let n = try!(split.next().ok_or(ParseRatioError { kind: RatioErrorKind::ParseError })); + let num = try!(FromStr::from_str(n) + .map_err(|_| ParseRatioError { kind: RatioErrorKind::ParseError })); + + let d = split.next().unwrap_or("1"); + let den = try!(FromStr::from_str(d) + .map_err(|_| ParseRatioError { kind: RatioErrorKind::ParseError })); + + if Zero::is_zero(&den) { + Err(ParseRatioError { kind: RatioErrorKind::ZeroDenominator }) + } else { + Ok(Ratio::new(num, den)) + } + } +} + +#[cfg(feature = "serde")] +impl serde::Serialize for Ratio + where T: serde::Serialize + Clone + Integer + PartialOrd +{ + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> + where S: serde::Serializer + { + (self.numer(), self.denom()).serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl serde::Deserialize for Ratio + where T: serde::Deserialize + Clone + Integer + PartialOrd +{ + fn deserialize(deserializer: &mut D) -> Result + where D: serde::Deserializer + { + let (numer, denom) = try!(serde::Deserialize::deserialize(deserializer)); + if denom == Zero::zero() { + Err(serde::de::Error::invalid_value("denominator is zero")) + } else { + Ok(Ratio::new_raw(numer, denom)) + } + } +} + +// FIXME: Bubble up specific errors +#[derive(Copy, Clone, Debug, PartialEq)] +pub struct ParseRatioError { + kind: RatioErrorKind, +} + +#[derive(Copy, Clone, Debug, PartialEq)] +enum RatioErrorKind { + ParseError, + ZeroDenominator, +} + +impl fmt::Display for ParseRatioError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.description().fmt(f) + } +} + +impl Error for ParseRatioError { + fn description(&self) -> &str { + self.kind.description() + } +} + +impl RatioErrorKind { + fn description(&self) -> &'static str { + match *self { + RatioErrorKind::ParseError => "failed to parse integer", + RatioErrorKind::ZeroDenominator => "zero value denominator", + } + } +} + +#[cfg(test)] +fn hash(x: &T) -> u64 { + use std::hash::Hasher; + let mut hasher = hash::SipHasher::new(); + x.hash(&mut hasher); + hasher.finish() +} + +#[cfg(test)] +mod test { + use super::{Ratio, Rational}; + #[cfg(feature = "num-bigint")] + use super::BigRational; + + use std::str::FromStr; + use std::i32; + use traits::{Zero, One, Signed, FromPrimitive, Float}; + + pub const _0: Rational = Ratio { + numer: 0, + denom: 1, + }; + pub const _1: Rational = Ratio { + numer: 1, + denom: 1, + }; + pub const _2: Rational = Ratio { + numer: 2, + denom: 1, + }; + pub const _1_2: Rational = Ratio { + numer: 1, + denom: 2, + }; + pub const _3_2: Rational = Ratio { + numer: 3, + denom: 2, + }; + pub const _NEG1_2: Rational = Ratio { + numer: -1, + denom: 2, + }; + pub const _1_3: Rational = Ratio { + numer: 1, + denom: 3, + }; + pub const _NEG1_3: Rational = Ratio { + numer: -1, + denom: 3, + }; + pub const _2_3: Rational = Ratio { + numer: 2, + denom: 3, + }; + pub const _NEG2_3: Rational = Ratio { + numer: -2, + denom: 3, + }; + + #[cfg(feature = "num-bigint")] + pub fn to_big(n: Rational) -> BigRational { + Ratio::new(FromPrimitive::from_isize(n.numer).unwrap(), + FromPrimitive::from_isize(n.denom).unwrap()) + } + #[cfg(not(feature = "num-bigint"))] + pub fn to_big(n: Rational) -> Rational { + Ratio::new(FromPrimitive::from_isize(n.numer).unwrap(), + FromPrimitive::from_isize(n.denom).unwrap()) + } + + #[test] + fn test_test_constants() { + // check our constants are what Ratio::new etc. would make. + assert_eq!(_0, Zero::zero()); + assert_eq!(_1, One::one()); + assert_eq!(_2, Ratio::from_integer(2)); + assert_eq!(_1_2, Ratio::new(1, 2)); + assert_eq!(_3_2, Ratio::new(3, 2)); + assert_eq!(_NEG1_2, Ratio::new(-1, 2)); + } + + #[test] + fn test_new_reduce() { + let one22 = Ratio::new(2, 2); + + assert_eq!(one22, One::one()); + } + #[test] + #[should_panic] + fn test_new_zero() { + let _a = Ratio::new(1, 0); + } + + + #[test] + fn test_cmp() { + assert!(_0 == _0 && _1 == _1); + assert!(_0 != _1 && _1 != _0); + assert!(_0 < _1 && !(_1 < _0)); + assert!(_1 > _0 && !(_0 > _1)); + + assert!(_0 <= _0 && _1 <= _1); + assert!(_0 <= _1 && !(_1 <= _0)); + + assert!(_0 >= _0 && _1 >= _1); + assert!(_1 >= _0 && !(_0 >= _1)); + } + + #[test] + fn test_cmp_overflow() { + use std::cmp::Ordering; + + // issue #7 example: + let big = Ratio::new(128u8, 1); + let small = big.recip(); + assert!(big > small); + + // try a few that are closer together + // (some matching numer, some matching denom, some neither) + let ratios = vec![ + Ratio::new(125_i8, 127_i8), + Ratio::new(63_i8, 64_i8), + Ratio::new(124_i8, 125_i8), + Ratio::new(125_i8, 126_i8), + Ratio::new(126_i8, 127_i8), + Ratio::new(127_i8, 126_i8), + ]; + + fn check_cmp(a: Ratio, b: Ratio, ord: Ordering) { + println!("comparing {} and {}", a, b); + assert_eq!(a.cmp(&b), ord); + assert_eq!(b.cmp(&a), ord.reverse()); + } + + for (i, &a) in ratios.iter().enumerate() { + check_cmp(a, a, Ordering::Equal); + check_cmp(-a, a, Ordering::Less); + for &b in &ratios[i + 1..] { + check_cmp(a, b, Ordering::Less); + check_cmp(-a, -b, Ordering::Greater); + check_cmp(a.recip(), b.recip(), Ordering::Greater); + check_cmp(-a.recip(), -b.recip(), Ordering::Less); + } + } + } + + #[test] + fn test_to_integer() { + assert_eq!(_0.to_integer(), 0); + assert_eq!(_1.to_integer(), 1); + assert_eq!(_2.to_integer(), 2); + assert_eq!(_1_2.to_integer(), 0); + assert_eq!(_3_2.to_integer(), 1); + assert_eq!(_NEG1_2.to_integer(), 0); + } + + + #[test] + fn test_numer() { + assert_eq!(_0.numer(), &0); + assert_eq!(_1.numer(), &1); + assert_eq!(_2.numer(), &2); + assert_eq!(_1_2.numer(), &1); + assert_eq!(_3_2.numer(), &3); + assert_eq!(_NEG1_2.numer(), &(-1)); + } + #[test] + fn test_denom() { + assert_eq!(_0.denom(), &1); + assert_eq!(_1.denom(), &1); + assert_eq!(_2.denom(), &1); + assert_eq!(_1_2.denom(), &2); + assert_eq!(_3_2.denom(), &2); + assert_eq!(_NEG1_2.denom(), &2); + } + + + #[test] + fn test_is_integer() { + assert!(_0.is_integer()); + assert!(_1.is_integer()); + assert!(_2.is_integer()); + assert!(!_1_2.is_integer()); + assert!(!_3_2.is_integer()); + assert!(!_NEG1_2.is_integer()); + } + + #[test] + fn test_show() { + assert_eq!(format!("{}", _2), "2".to_string()); + assert_eq!(format!("{}", _1_2), "1/2".to_string()); + assert_eq!(format!("{}", _0), "0".to_string()); + assert_eq!(format!("{}", Ratio::from_integer(-2)), "-2".to_string()); + } + + mod arith { + use super::{_0, _1, _2, _1_2, _3_2, _NEG1_2, to_big}; + use super::super::{Ratio, Rational}; + + #[test] + fn test_add() { + fn test(a: Rational, b: Rational, c: Rational) { + assert_eq!(a + b, c); + assert_eq!(to_big(a) + to_big(b), to_big(c)); + } + + test(_1, _1_2, _3_2); + test(_1, _1, _2); + test(_1_2, _3_2, _2); + test(_1_2, _NEG1_2, _0); + } + + #[test] + fn test_sub() { + fn test(a: Rational, b: Rational, c: Rational) { + assert_eq!(a - b, c); + assert_eq!(to_big(a) - to_big(b), to_big(c)) + } + + test(_1, _1_2, _1_2); + test(_3_2, _1_2, _1); + test(_1, _NEG1_2, _3_2); + } + + #[test] + fn test_mul() { + fn test(a: Rational, b: Rational, c: Rational) { + assert_eq!(a * b, c); + assert_eq!(to_big(a) * to_big(b), to_big(c)) + } + + test(_1, _1_2, _1_2); + test(_1_2, _3_2, Ratio::new(3, 4)); + test(_1_2, _NEG1_2, Ratio::new(-1, 4)); + } + + #[test] + fn test_div() { + fn test(a: Rational, b: Rational, c: Rational) { + assert_eq!(a / b, c); + assert_eq!(to_big(a) / to_big(b), to_big(c)) + } + + test(_1, _1_2, _2); + test(_3_2, _1_2, _1 + _2); + test(_1, _NEG1_2, _NEG1_2 + _NEG1_2 + _NEG1_2 + _NEG1_2); + } + + #[test] + fn test_rem() { + fn test(a: Rational, b: Rational, c: Rational) { + assert_eq!(a % b, c); + assert_eq!(to_big(a) % to_big(b), to_big(c)) + } + + test(_3_2, _1, _1_2); + test(_2, _NEG1_2, _0); + test(_1_2, _2, _1_2); + } + + #[test] + fn test_neg() { + fn test(a: Rational, b: Rational) { + assert_eq!(-a, b); + assert_eq!(-to_big(a), to_big(b)) + } + + test(_0, _0); + test(_1_2, _NEG1_2); + test(-_1, _1); + } + #[test] + fn test_zero() { + assert_eq!(_0 + _0, _0); + assert_eq!(_0 * _0, _0); + assert_eq!(_0 * _1, _0); + assert_eq!(_0 / _NEG1_2, _0); + assert_eq!(_0 - _0, _0); + } + #[test] + #[should_panic] + fn test_div_0() { + let _a = _1 / _0; + } + } + + #[test] + fn test_round() { + assert_eq!(_1_3.ceil(), _1); + assert_eq!(_1_3.floor(), _0); + assert_eq!(_1_3.round(), _0); + assert_eq!(_1_3.trunc(), _0); + + assert_eq!(_NEG1_3.ceil(), _0); + assert_eq!(_NEG1_3.floor(), -_1); + assert_eq!(_NEG1_3.round(), _0); + assert_eq!(_NEG1_3.trunc(), _0); + + assert_eq!(_2_3.ceil(), _1); + assert_eq!(_2_3.floor(), _0); + assert_eq!(_2_3.round(), _1); + assert_eq!(_2_3.trunc(), _0); + + assert_eq!(_NEG2_3.ceil(), _0); + assert_eq!(_NEG2_3.floor(), -_1); + assert_eq!(_NEG2_3.round(), -_1); + assert_eq!(_NEG2_3.trunc(), _0); + + assert_eq!(_1_2.ceil(), _1); + assert_eq!(_1_2.floor(), _0); + assert_eq!(_1_2.round(), _1); + assert_eq!(_1_2.trunc(), _0); + + assert_eq!(_NEG1_2.ceil(), _0); + assert_eq!(_NEG1_2.floor(), -_1); + assert_eq!(_NEG1_2.round(), -_1); + assert_eq!(_NEG1_2.trunc(), _0); + + assert_eq!(_1.ceil(), _1); + assert_eq!(_1.floor(), _1); + assert_eq!(_1.round(), _1); + assert_eq!(_1.trunc(), _1); + + // Overflow checks + + let _neg1 = Ratio::from_integer(-1); + let _large_rat1 = Ratio::new(i32::MAX, i32::MAX - 1); + let _large_rat2 = Ratio::new(i32::MAX - 1, i32::MAX); + let _large_rat3 = Ratio::new(i32::MIN + 2, i32::MIN + 1); + let _large_rat4 = Ratio::new(i32::MIN + 1, i32::MIN + 2); + let _large_rat5 = Ratio::new(i32::MIN + 2, i32::MAX); + let _large_rat6 = Ratio::new(i32::MAX, i32::MIN + 2); + let _large_rat7 = Ratio::new(1, i32::MIN + 1); + let _large_rat8 = Ratio::new(1, i32::MAX); + + assert_eq!(_large_rat1.round(), One::one()); + assert_eq!(_large_rat2.round(), One::one()); + assert_eq!(_large_rat3.round(), One::one()); + assert_eq!(_large_rat4.round(), One::one()); + assert_eq!(_large_rat5.round(), _neg1); + assert_eq!(_large_rat6.round(), _neg1); + assert_eq!(_large_rat7.round(), Zero::zero()); + assert_eq!(_large_rat8.round(), Zero::zero()); + } + + #[test] + fn test_fract() { + assert_eq!(_1.fract(), _0); + assert_eq!(_NEG1_2.fract(), _NEG1_2); + assert_eq!(_1_2.fract(), _1_2); + assert_eq!(_3_2.fract(), _1_2); + } + + #[test] + fn test_recip() { + assert_eq!(_1 * _1.recip(), _1); + assert_eq!(_2 * _2.recip(), _1); + assert_eq!(_1_2 * _1_2.recip(), _1); + assert_eq!(_3_2 * _3_2.recip(), _1); + assert_eq!(_NEG1_2 * _NEG1_2.recip(), _1); + } + + #[test] + fn test_pow() { + assert_eq!(_1_2.pow(2), Ratio::new(1, 4)); + assert_eq!(_1_2.pow(-2), Ratio::new(4, 1)); + assert_eq!(_1.pow(1), _1); + assert_eq!(_NEG1_2.pow(2), _1_2.pow(2)); + assert_eq!(_NEG1_2.pow(3), -_1_2.pow(3)); + assert_eq!(_3_2.pow(0), _1); + assert_eq!(_3_2.pow(-1), _3_2.recip()); + assert_eq!(_3_2.pow(3), Ratio::new(27, 8)); + } + + #[test] + fn test_to_from_str() { + fn test(r: Rational, s: String) { + assert_eq!(FromStr::from_str(&s), Ok(r)); + assert_eq!(r.to_string(), s); + } + test(_1, "1".to_string()); + test(_0, "0".to_string()); + test(_1_2, "1/2".to_string()); + test(_3_2, "3/2".to_string()); + test(_2, "2".to_string()); + test(_NEG1_2, "-1/2".to_string()); + } + #[test] + fn test_from_str_fail() { + fn test(s: &str) { + let rational: Result = FromStr::from_str(s); + assert!(rational.is_err()); + } + + let xs = ["0 /1", "abc", "", "1/", "--1/2", "3/2/1", "1/0"]; + for &s in xs.iter() { + test(s); + } + } + + #[cfg(feature = "num-bigint")] + #[test] + fn test_from_float() { + fn test(given: T, (numer, denom): (&str, &str)) { + let ratio: BigRational = Ratio::from_float(given).unwrap(); + assert_eq!(ratio, + Ratio::new(FromStr::from_str(numer).unwrap(), + FromStr::from_str(denom).unwrap())); + } + + // f32 + test(3.14159265359f32, ("13176795", "4194304")); + test(2f32.powf(100.), ("1267650600228229401496703205376", "1")); + test(-2f32.powf(100.), ("-1267650600228229401496703205376", "1")); + test(1.0 / 2f32.powf(100.), + ("1", "1267650600228229401496703205376")); + test(684729.48391f32, ("1369459", "2")); + test(-8573.5918555f32, ("-4389679", "512")); + + // f64 + test(3.14159265359f64, ("3537118876014453", "1125899906842624")); + test(2f64.powf(100.), ("1267650600228229401496703205376", "1")); + test(-2f64.powf(100.), ("-1267650600228229401496703205376", "1")); + test(684729.48391f64, ("367611342500051", "536870912")); + test(-8573.5918555f64, ("-4713381968463931", "549755813888")); + test(1.0 / 2f64.powf(100.), + ("1", "1267650600228229401496703205376")); + } + + #[cfg(feature = "num-bigint")] + #[test] + fn test_from_float_fail() { + use std::{f32, f64}; + + assert_eq!(Ratio::from_float(f32::NAN), None); + assert_eq!(Ratio::from_float(f32::INFINITY), None); + assert_eq!(Ratio::from_float(f32::NEG_INFINITY), None); + assert_eq!(Ratio::from_float(f64::NAN), None); + assert_eq!(Ratio::from_float(f64::INFINITY), None); + assert_eq!(Ratio::from_float(f64::NEG_INFINITY), None); + } + + #[test] + fn test_signed() { + assert_eq!(_NEG1_2.abs(), _1_2); + assert_eq!(_3_2.abs_sub(&_1_2), _1); + assert_eq!(_1_2.abs_sub(&_3_2), Zero::zero()); + assert_eq!(_1_2.signum(), One::one()); + assert_eq!(_NEG1_2.signum(), ->::one()); + assert!(_NEG1_2.is_negative()); + assert!(!_NEG1_2.is_positive()); + assert!(!_1_2.is_negative()); + } + + #[test] + fn test_hash() { + assert!(::hash(&_0) != ::hash(&_1)); + assert!(::hash(&_0) != ::hash(&_3_2)); + } +} diff --git a/src/lib.rs b/src/lib.rs index a44bb9b..4fce75d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -59,7 +59,10 @@ extern crate num_traits; extern crate num_integer; +#[cfg(feature = "num-bigint")] extern crate num_bigint; +#[cfg(feature = "num-rational")] +extern crate num_rational; #[cfg(feature = "rustc-serialize")] extern crate rustc_serialize; @@ -73,11 +76,11 @@ extern crate rand; #[cfg(feature = "serde")] extern crate serde; -#[cfg(feature = "bigint")] +#[cfg(feature = "num-bigint")] pub use bigint::{BigInt, BigUint}; -#[cfg(feature = "rational")] +#[cfg(feature = "num-rational")] pub use rational::Rational; -#[cfg(all(feature = "rational", feature="bigint"))] +#[cfg(all(feature = "num-rational", feature="num-bigint"))] pub use rational::BigRational; #[cfg(feature = "complex")] pub use complex::Complex; @@ -91,14 +94,14 @@ pub use traits::{Num, Zero, One, Signed, Unsigned, Bounded, use std::ops::{Mul}; -#[cfg(feature = "bigint")] -pub mod bigint { pub use num_bigint::*; } +#[cfg(feature = "num-bigint")] +pub use num_bigint as bigint; pub mod complex; -pub mod integer { pub use num_integer::*; } +pub use num_integer as integers; pub mod iter; -pub mod traits { pub use num_traits::*; } -#[cfg(feature = "rational")] -pub mod rational; +pub use num_traits as traits; +#[cfg(feature = "num-rational")] +pub use num_rational as rational; /// Returns the additive identity, `0`. #[inline(always)] pub fn zero() -> T { Zero::zero() } @@ -210,11 +213,3 @@ pub fn checked_pow(mut base: T, mut exp: usize) -> } Some(acc) } - -#[cfg(test)] -fn hash(x: &T) -> u64 { - use std::hash::Hasher; - let mut hasher = hash::SipHasher::new(); - x.hash(&mut hasher); - hasher.finish() -} diff --git a/traits/src/cast.rs b/traits/src/cast.rs index 90b99ef..cefa7ff 100644 --- a/traits/src/cast.rs +++ b/traits/src/cast.rs @@ -388,8 +388,7 @@ impl_from_primitive!(f64, to_f64); /// # Examples /// /// ``` -/// use num; -/// +/// # use num_traits as num; /// let twenty: f32 = num::cast(0x14).unwrap(); /// assert_eq!(twenty, 20f32); /// ``` diff --git a/traits/src/float.rs b/traits/src/float.rs index 5d1f0e0..f8c19ae 100644 --- a/traits/src/float.rs +++ b/traits/src/float.rs @@ -14,7 +14,7 @@ pub trait Float /// Returns the `NaN` value. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// /// let nan: f32 = Float::nan(); /// @@ -24,7 +24,7 @@ pub trait Float /// Returns the infinite value. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// use std::f32; /// /// let infinity: f32 = Float::infinity(); @@ -37,7 +37,7 @@ pub trait Float /// Returns the negative infinite value. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// use std::f32; /// /// let neg_infinity: f32 = Float::neg_infinity(); @@ -50,7 +50,7 @@ pub trait Float /// Returns `-0.0`. /// /// ``` - /// use num::traits::{Zero, Float}; + /// use num_traits::{Zero, Float}; /// /// let inf: f32 = Float::infinity(); /// let zero: f32 = Zero::zero(); @@ -65,7 +65,7 @@ pub trait Float /// Returns the smallest finite value that this type can represent. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// use std::f64; /// /// let x: f64 = Float::min_value(); @@ -77,7 +77,7 @@ pub trait Float /// Returns the smallest positive, normalized value that this type can represent. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// use std::f64; /// /// let x: f64 = Float::min_positive_value(); @@ -89,7 +89,7 @@ pub trait Float /// Returns the largest finite value that this type can represent. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// use std::f64; /// /// let x: f64 = Float::max_value(); @@ -100,7 +100,7 @@ pub trait Float /// Returns `true` if this value is `NaN` and false otherwise. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// use std::f64; /// /// let nan = f64::NAN; @@ -115,7 +115,7 @@ pub trait Float /// false otherwise. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// use std::f32; /// /// let f = 7.0f32; @@ -134,7 +134,7 @@ pub trait Float /// Returns `true` if this number is neither infinite nor `NaN`. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// use std::f32; /// /// let f = 7.0f32; @@ -154,7 +154,7 @@ pub trait Float /// [subnormal][subnormal], or `NaN`. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// use std::f32; /// /// let min = f32::MIN_POSITIVE; // 1.17549435e-38f32 @@ -179,7 +179,7 @@ pub trait Float /// predicate instead. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// use std::num::FpCategory; /// use std::f32; /// @@ -194,7 +194,7 @@ pub trait Float /// Returns the largest integer less than or equal to a number. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// /// let f = 3.99; /// let g = 3.0; @@ -207,7 +207,7 @@ pub trait Float /// Returns the smallest integer greater than or equal to a number. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// /// let f = 3.01; /// let g = 4.0; @@ -221,7 +221,7 @@ pub trait Float /// `0.0`. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// /// let f = 3.3; /// let g = -3.3; @@ -234,7 +234,7 @@ pub trait Float /// Return the integer part of a number. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// /// let f = 3.3; /// let g = -3.7; @@ -247,7 +247,7 @@ pub trait Float /// Returns the fractional part of a number. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// /// let x = 3.5; /// let y = -3.5; @@ -263,7 +263,7 @@ pub trait Float /// number is `Float::nan()`. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// use std::f64; /// /// let x = 3.5; @@ -286,7 +286,7 @@ pub trait Float /// - `Float::nan()` if the number is `Float::nan()` /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// use std::f64; /// /// let f = 3.5; @@ -302,7 +302,7 @@ pub trait Float /// `Float::infinity()`. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// use std::f64; /// /// let nan: f64 = f64::NAN; @@ -321,7 +321,7 @@ pub trait Float /// `Float::neg_infinity()`. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// use std::f64; /// /// let nan = f64::NAN; @@ -341,7 +341,7 @@ pub trait Float /// a separate multiplication operation followed by an add. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// /// let m = 10.0; /// let x = 4.0; @@ -356,7 +356,7 @@ pub trait Float /// Take the reciprocal (inverse) of a number, `1/x`. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// /// let x = 2.0; /// let abs_difference = (x.recip() - (1.0/x)).abs(); @@ -370,7 +370,7 @@ pub trait Float /// Using this function is generally faster than using `powf` /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// /// let x = 2.0; /// let abs_difference = (x.powi(2) - x*x).abs(); @@ -382,7 +382,7 @@ pub trait Float /// Raise a number to a floating point power. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// /// let x = 2.0; /// let abs_difference = (x.powf(2.0) - x*x).abs(); @@ -396,7 +396,7 @@ pub trait Float /// Returns NaN if `self` is a negative number. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// /// let positive = 4.0; /// let negative = -4.0; @@ -411,7 +411,7 @@ pub trait Float /// Returns `e^(self)`, (the exponential function). /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// /// let one = 1.0; /// // e^1 @@ -427,7 +427,7 @@ pub trait Float /// Returns `2^(self)`. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// /// let f = 2.0; /// @@ -441,7 +441,7 @@ pub trait Float /// Returns the natural logarithm of the number. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// /// let one = 1.0; /// // e^1 @@ -457,7 +457,7 @@ pub trait Float /// Returns the logarithm of the number with respect to an arbitrary base. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// /// let ten = 10.0; /// let two = 2.0; @@ -476,7 +476,7 @@ pub trait Float /// Returns the base 2 logarithm of the number. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// /// let two = 2.0; /// @@ -490,7 +490,7 @@ pub trait Float /// Returns the base 10 logarithm of the number. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// /// let ten = 10.0; /// @@ -504,7 +504,7 @@ pub trait Float /// Returns the maximum of the two numbers. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// /// let x = 1.0; /// let y = 2.0; @@ -516,7 +516,7 @@ pub trait Float /// Returns the minimum of the two numbers. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// /// let x = 1.0; /// let y = 2.0; @@ -531,7 +531,7 @@ pub trait Float /// * Else: `self - other` /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// /// let x = 3.0; /// let y = -3.0; @@ -547,7 +547,7 @@ pub trait Float /// Take the cubic root of a number. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// /// let x = 8.0; /// @@ -562,7 +562,7 @@ pub trait Float /// legs of length `x` and `y`. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// /// let x = 2.0; /// let y = 3.0; @@ -577,7 +577,7 @@ pub trait Float /// Computes the sine of a number (in radians). /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// use std::f64; /// /// let x = f64::consts::PI/2.0; @@ -591,7 +591,7 @@ pub trait Float /// Computes the cosine of a number (in radians). /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// use std::f64; /// /// let x = 2.0*f64::consts::PI; @@ -605,7 +605,7 @@ pub trait Float /// Computes the tangent of a number (in radians). /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// use std::f64; /// /// let x = f64::consts::PI/4.0; @@ -620,7 +620,7 @@ pub trait Float /// [-1, 1]. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// use std::f64; /// /// let f = f64::consts::PI / 2.0; @@ -637,7 +637,7 @@ pub trait Float /// [-1, 1]. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// use std::f64; /// /// let f = f64::consts::PI / 4.0; @@ -653,7 +653,7 @@ pub trait Float /// range [-pi/2, pi/2]; /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// /// let f = 1.0; /// @@ -672,7 +672,7 @@ pub trait Float /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)` /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// use std::f64; /// /// let pi = f64::consts::PI; @@ -697,7 +697,7 @@ pub trait Float /// `(sin(x), cos(x))`. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// use std::f64; /// /// let x = f64::consts::PI/4.0; @@ -715,7 +715,7 @@ pub trait Float /// number is close to zero. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// /// let x = 7.0; /// @@ -730,7 +730,7 @@ pub trait Float /// the operations were performed separately. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// use std::f64; /// /// let x = f64::consts::E - 1.0; @@ -745,7 +745,7 @@ pub trait Float /// Hyperbolic sine function. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// use std::f64; /// /// let e = f64::consts::E; @@ -763,7 +763,7 @@ pub trait Float /// Hyperbolic cosine function. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// use std::f64; /// /// let e = f64::consts::E; @@ -781,7 +781,7 @@ pub trait Float /// Hyperbolic tangent function. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// use std::f64; /// /// let e = f64::consts::E; @@ -799,7 +799,7 @@ pub trait Float /// Inverse hyperbolic sine function. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// /// let x = 1.0; /// let f = x.sinh().asinh(); @@ -813,7 +813,7 @@ pub trait Float /// Inverse hyperbolic cosine function. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// /// let x = 1.0; /// let f = x.cosh().acosh(); @@ -827,7 +827,7 @@ pub trait Float /// Inverse hyperbolic tangent function. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// use std::f64; /// /// let e = f64::consts::E; @@ -845,7 +845,7 @@ pub trait Float /// The floating point encoding is documented in the [Reference][floating-point]. /// /// ``` - /// use num::traits::Float; + /// use num_traits::Float; /// /// let num = 2.0f32; /// diff --git a/traits/src/int.rs b/traits/src/int.rs index 071df7f..6cc90ca 100644 --- a/traits/src/int.rs +++ b/traits/src/int.rs @@ -28,7 +28,7 @@ pub trait PrimInt /// # Examples /// /// ``` - /// use num::traits::PrimInt; + /// use num_traits::PrimInt; /// /// let n = 0b01001100u8; /// @@ -41,7 +41,7 @@ pub trait PrimInt /// # Examples /// /// ``` - /// use num::traits::PrimInt; + /// use num_traits::PrimInt; /// /// let n = 0b01001100u8; /// @@ -55,7 +55,7 @@ pub trait PrimInt /// # Examples /// /// ``` - /// use num::traits::PrimInt; + /// use num_traits::PrimInt; /// /// let n = 0b0101000u16; /// @@ -69,7 +69,7 @@ pub trait PrimInt /// # Examples /// /// ``` - /// use num::traits::PrimInt; + /// use num_traits::PrimInt; /// /// let n = 0b0101000u16; /// @@ -83,7 +83,7 @@ pub trait PrimInt /// # Examples /// /// ``` - /// use num::traits::PrimInt; + /// use num_traits::PrimInt; /// /// let n = 0x0123456789ABCDEFu64; /// let m = 0x3456789ABCDEF012u64; @@ -98,7 +98,7 @@ pub trait PrimInt /// # Examples /// /// ``` - /// use num::traits::PrimInt; + /// use num_traits::PrimInt; /// /// let n = 0x0123456789ABCDEFu64; /// let m = 0xDEF0123456789ABCu64; @@ -115,7 +115,7 @@ pub trait PrimInt /// # Examples /// /// ``` - /// use num::traits::PrimInt; + /// use num_traits::PrimInt; /// /// let n = 0x0123456789ABCDEFu64; /// let m = 0x3456789ABCDEF000u64; @@ -132,7 +132,7 @@ pub trait PrimInt /// # Examples /// /// ``` - /// use num::traits::PrimInt; + /// use num_traits::PrimInt; /// /// let n = 0xFEDCBA9876543210u64; /// let m = 0xFFFFEDCBA9876543u64; @@ -149,7 +149,7 @@ pub trait PrimInt /// # Examples /// /// ``` - /// use num::traits::PrimInt; + /// use num_traits::PrimInt; /// /// let n = 0x0123456789ABCDEFi64; /// let m = 0x3456789ABCDEF000i64; @@ -166,7 +166,7 @@ pub trait PrimInt /// # Examples /// /// ``` - /// use num::traits::PrimInt; + /// use num_traits::PrimInt; /// /// let n = 0xFEDCBA9876543210i64; /// let m = 0x000FEDCBA9876543i64; @@ -180,7 +180,7 @@ pub trait PrimInt /// # Examples /// /// ``` - /// use num::traits::PrimInt; + /// use num_traits::PrimInt; /// /// let n = 0x0123456789ABCDEFu64; /// let m = 0xEFCDAB8967452301u64; @@ -196,7 +196,7 @@ pub trait PrimInt /// # Examples /// /// ``` - /// use num::traits::PrimInt; + /// use num_traits::PrimInt; /// /// let n = 0x0123456789ABCDEFu64; /// @@ -215,7 +215,7 @@ pub trait PrimInt /// # Examples /// /// ``` - /// use num::traits::PrimInt; + /// use num_traits::PrimInt; /// /// let n = 0x0123456789ABCDEFu64; /// @@ -234,7 +234,7 @@ pub trait PrimInt /// # Examples /// /// ``` - /// use num::traits::PrimInt; + /// use num_traits::PrimInt; /// /// let n = 0x0123456789ABCDEFu64; /// @@ -253,7 +253,7 @@ pub trait PrimInt /// # Examples /// /// ``` - /// use num::traits::PrimInt; + /// use num_traits::PrimInt; /// /// let n = 0x0123456789ABCDEFu64; /// @@ -270,7 +270,7 @@ pub trait PrimInt /// # Examples /// /// ``` - /// use num::traits::PrimInt; + /// use num_traits::PrimInt; /// /// assert_eq!(2i32.pow(4), 16); /// ```