mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-21 17:52:12 +03:00
auto merge of #6471 : gifnksm/rust/reform-rational, r=brson
`std::ratio` module contains `BigRational` type, but the type is not usable by following reasons. * `Ratio::new` requires `T: Copy + Num + Ord`, but `BigInt` is not implicitly copyable, because it contains unique vector. * `BigInt` is not implements `Num` So, I rewrite `Ratio` as follows. * `Ratio` requires `T: Clone + Integer + Ord`. * `Copy` -> `Clone`: to be able to use `BigRational` * `Num` -> `Integer`: It is incorrect that a rational number constructed by two non-integer numbers. * `BigInt` implements `Num` and `Orderable` which are required by `Integer` bound
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
use core::cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater};
|
||||
use core::num::{IntConvertible, Zero, One, ToStrRadix, FromStrRadix};
|
||||
use core::num::{IntConvertible, Zero, One, ToStrRadix, FromStrRadix, Orderable};
|
||||
|
||||
/**
|
||||
A BigDigit is a BigUint's composing element.
|
||||
@@ -144,6 +144,26 @@ fn from_str(s: &str) -> Option<BigUint> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Num for BigUint {}
|
||||
|
||||
impl Orderable for BigUint {
|
||||
#[inline(always)]
|
||||
fn min(&self, other: &BigUint) -> BigUint {
|
||||
if self < other { self.clone() } else { other.clone() }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn max(&self, other: &BigUint) -> BigUint {
|
||||
if self > other { self.clone() } else { other.clone() }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn clamp(&self, mn: &BigUint, mx: &BigUint) -> BigUint {
|
||||
if self > mx { mx.clone() } else
|
||||
if self < mn { mn.clone() } else { self.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Shl<uint, BigUint> for BigUint {
|
||||
#[inline(always)]
|
||||
fn shl(&self, rhs: &uint) -> BigUint {
|
||||
@@ -788,6 +808,26 @@ fn from_str(s: &str) -> Option<BigInt> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Num for BigInt {}
|
||||
|
||||
impl Orderable for BigInt {
|
||||
#[inline(always)]
|
||||
fn min(&self, other: &BigInt) -> BigInt {
|
||||
if self < other { self.clone() } else { other.clone() }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn max(&self, other: &BigInt) -> BigInt {
|
||||
if self > other { self.clone() } else { other.clone() }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn clamp(&self, mn: &BigInt, mx: &BigInt) -> BigInt {
|
||||
if self > mx { mx.clone() } else
|
||||
if self < mn { mn.clone() } else { self.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Shl<uint, BigInt> for BigInt {
|
||||
#[inline(always)]
|
||||
fn shl(&self, rhs: &uint) -> BigInt {
|
||||
|
||||
+85
-83
@@ -30,7 +30,7 @@ pub struct Ratio<T> {
|
||||
/// Alias for arbitrary precision rationals.
|
||||
pub type BigRational = Ratio<BigInt>;
|
||||
|
||||
impl<T: Copy + Num + Ord>
|
||||
impl<T: Clone + Integer + Ord>
|
||||
Ratio<T> {
|
||||
/// Create a ratio representing the integer `t`.
|
||||
#[inline(always)]
|
||||
@@ -57,10 +57,14 @@ pub fn new(numer: T, denom: T) -> Ratio<T> {
|
||||
|
||||
/// Put self into lowest terms, with denom > 0.
|
||||
fn reduce(&mut self) {
|
||||
let g : T = gcd(self.numer, self.denom);
|
||||
let g : T = self.numer.gcd(&self.denom);
|
||||
|
||||
self.numer /= g;
|
||||
self.denom /= g;
|
||||
// FIXME(#6050): overloaded operators force moves with generic types
|
||||
// self.numer /= g;
|
||||
self.numer = self.numer / g;
|
||||
// FIXME(#6050): overloaded operators force moves with generic types
|
||||
// self.denom /= g;
|
||||
self.denom = self.denom / g;
|
||||
|
||||
// keep denom positive!
|
||||
if self.denom < Zero::zero() {
|
||||
@@ -68,42 +72,15 @@ fn reduce(&mut self) {
|
||||
self.denom = -self.denom;
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a `reduce`d copy of self.
|
||||
fn reduced(&self) -> Ratio<T> {
|
||||
let mut ret = copy *self;
|
||||
let mut ret = self.clone();
|
||||
ret.reduce();
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Compute the greatest common divisor of two numbers, via Euclid's algorithm.
|
||||
|
||||
The result can be negative.
|
||||
*/
|
||||
#[inline]
|
||||
pub fn gcd_raw<T: Num>(n: T, m: T) -> T {
|
||||
let mut m = m, n = n;
|
||||
while m != Zero::zero() {
|
||||
let temp = m;
|
||||
m = n % temp;
|
||||
n = temp;
|
||||
}
|
||||
n
|
||||
}
|
||||
|
||||
/**
|
||||
Compute the greatest common divisor of two numbers, via Euclid's algorithm.
|
||||
|
||||
The result is always positive.
|
||||
*/
|
||||
#[inline]
|
||||
pub fn gcd<T: Num + Ord>(n: T, m: T) -> T {
|
||||
let g = gcd_raw(n, m);
|
||||
if g < Zero::zero() { -g }
|
||||
else { g }
|
||||
}
|
||||
|
||||
/* Comparisons */
|
||||
|
||||
// comparing a/b and c/d is the same as comparing a*d and b*c, so we
|
||||
@@ -133,7 +110,7 @@ fn $method(&self, other: &Ratio<T>) -> $res {
|
||||
|
||||
/* Arithmetic */
|
||||
// a/b * c/d = (a*c)/(b*d)
|
||||
impl<T: Copy + Num + Ord>
|
||||
impl<T: Clone + Integer + Ord>
|
||||
Mul<Ratio<T>,Ratio<T>> for Ratio<T> {
|
||||
#[inline]
|
||||
fn mul(&self, rhs: &Ratio<T>) -> Ratio<T> {
|
||||
@@ -142,7 +119,7 @@ fn mul(&self, rhs: &Ratio<T>) -> Ratio<T> {
|
||||
}
|
||||
|
||||
// (a/b) / (c/d) = (a*d)/(b*c)
|
||||
impl<T: Copy + Num + Ord>
|
||||
impl<T: Clone + Integer + Ord>
|
||||
Div<Ratio<T>,Ratio<T>> for Ratio<T> {
|
||||
#[inline]
|
||||
fn div(&self, rhs: &Ratio<T>) -> Ratio<T> {
|
||||
@@ -153,7 +130,7 @@ fn div(&self, rhs: &Ratio<T>) -> Ratio<T> {
|
||||
// Abstracts the a/b `op` c/d = (a*d `op` b*d) / (b*d) pattern
|
||||
macro_rules! arith_impl {
|
||||
(impl $imp:ident, $method:ident) => {
|
||||
impl<T: Copy + Num + Ord>
|
||||
impl<T: Clone + Integer + Ord>
|
||||
$imp<Ratio<T>,Ratio<T>> for Ratio<T> {
|
||||
#[inline]
|
||||
fn $method(&self, rhs: &Ratio<T>) -> Ratio<T> {
|
||||
@@ -173,16 +150,16 @@ fn $method(&self, rhs: &Ratio<T>) -> Ratio<T> {
|
||||
// a/b % c/d = (a*d % b*c)/(b*d)
|
||||
arith_impl!(impl Rem, rem)
|
||||
|
||||
impl<T: Copy + Num + Ord>
|
||||
impl<T: Clone + Integer + Ord>
|
||||
Neg<Ratio<T>> for Ratio<T> {
|
||||
#[inline]
|
||||
fn neg(&self) -> Ratio<T> {
|
||||
Ratio::new_raw(-self.numer, self.denom)
|
||||
Ratio::new_raw(-self.numer, self.denom.clone())
|
||||
}
|
||||
}
|
||||
|
||||
/* Constants */
|
||||
impl<T: Copy + Num + Ord>
|
||||
impl<T: Clone + Integer + Ord>
|
||||
Zero for Ratio<T> {
|
||||
#[inline]
|
||||
fn zero() -> Ratio<T> {
|
||||
@@ -195,7 +172,7 @@ fn is_zero(&self) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Num + Ord>
|
||||
impl<T: Clone + Integer + Ord>
|
||||
One for Ratio<T> {
|
||||
#[inline]
|
||||
fn one() -> Ratio<T> {
|
||||
@@ -203,11 +180,11 @@ fn one() -> Ratio<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Num + Ord>
|
||||
impl<T: Clone + Integer + Ord>
|
||||
Num for Ratio<T> {}
|
||||
|
||||
/* Utils */
|
||||
impl<T: Copy + Num + Ord>
|
||||
impl<T: Clone + Integer + Ord>
|
||||
Round for Ratio<T> {
|
||||
|
||||
fn floor(&self) -> Ratio<T> {
|
||||
@@ -241,14 +218,14 @@ fn trunc(&self) -> Ratio<T> {
|
||||
}
|
||||
|
||||
fn fract(&self) -> Ratio<T> {
|
||||
Ratio::new_raw(self.numer % self.denom, self.denom)
|
||||
Ratio::new_raw(self.numer % self.denom, self.denom.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Num + Ord> Fractional for Ratio<T> {
|
||||
impl<T: Clone + Integer + Ord> Fractional for Ratio<T> {
|
||||
#[inline]
|
||||
fn recip(&self) -> Ratio<T> {
|
||||
Ratio::new_raw(self.denom, self.numer)
|
||||
Ratio::new_raw(self.denom.clone(), self.numer.clone())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +243,7 @@ fn to_str_radix(&self, radix: uint) -> ~str {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FromStr + Copy + Num + Ord>
|
||||
impl<T: FromStr + Clone + Integer + Ord>
|
||||
FromStr for Ratio<T> {
|
||||
/// Parses `numer/denom`.
|
||||
fn from_str(s: &str) -> Option<Ratio<T>> {
|
||||
@@ -276,14 +253,14 @@ fn from_str(s: &str) -> Option<Ratio<T>> {
|
||||
}
|
||||
});
|
||||
if split.len() < 2 { return None; }
|
||||
do FromStr::from_str(split[0]).chain |a| {
|
||||
do FromStr::from_str(split[1]).chain |b| {
|
||||
Some(Ratio::new(a,b))
|
||||
do FromStr::from_str::<T>(split[0]).chain |a| {
|
||||
do FromStr::from_str::<T>(split[1]).chain |b| {
|
||||
Some(Ratio::new(a.clone(), b.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T: FromStrRadix + Copy + Num + Ord>
|
||||
impl<T: FromStrRadix + Clone + Integer + Ord>
|
||||
FromStrRadix for Ratio<T> {
|
||||
/// Parses `numer/denom` where the numbers are in base `radix`.
|
||||
fn from_str_radix(s: &str, radix: uint) -> Option<Ratio<T>> {
|
||||
@@ -294,9 +271,9 @@ fn from_str_radix(s: &str, radix: uint) -> Option<Ratio<T>> {
|
||||
});
|
||||
if split.len() < 2 { None }
|
||||
else {
|
||||
do FromStrRadix::from_str_radix(split[0], radix).chain |a| {
|
||||
do FromStrRadix::from_str_radix(split[1], radix).chain |b| {
|
||||
Some(Ratio::new(a,b))
|
||||
do FromStrRadix::from_str_radix::<T>(split[0], radix).chain |a| {
|
||||
do FromStrRadix::from_str_radix::<T>(split[1], radix).chain |b| {
|
||||
Some(Ratio::new(a.clone(), b.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -306,7 +283,7 @@ fn from_str_radix(s: &str, radix: uint) -> Option<Ratio<T>> {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use core::num::{Zero,One,FromStrRadix};
|
||||
use core::num::{Zero,One,FromStrRadix,IntConvertible};
|
||||
use core::from_str::FromStr;
|
||||
|
||||
pub static _0 : Rational = Ratio { numer: 0, denom: 1};
|
||||
@@ -316,16 +293,11 @@ mod test {
|
||||
pub static _3_2: Rational = Ratio { numer: 3, denom: 2};
|
||||
pub static _neg1_2: Rational = Ratio { numer: -1, denom: 2};
|
||||
|
||||
#[test]
|
||||
fn test_gcd() {
|
||||
assert_eq!(gcd(10,2),2);
|
||||
assert_eq!(gcd(10,3),1);
|
||||
assert_eq!(gcd(0,3),3);
|
||||
assert_eq!(gcd(3,3),3);
|
||||
|
||||
assert_eq!(gcd(3,-3), 3);
|
||||
assert_eq!(gcd(-6,3), 3);
|
||||
assert_eq!(gcd(-4,-2), 2);
|
||||
pub fn to_big(n: Rational) -> BigRational {
|
||||
Ratio::new(
|
||||
IntConvertible::from_int(n.numer),
|
||||
IntConvertible::from_int(n.denom)
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -374,45 +346,75 @@ mod arith {
|
||||
|
||||
#[test]
|
||||
fn test_add() {
|
||||
assert_eq!(_1 + _1_2, _3_2);
|
||||
assert_eq!(_1 + _1, _2);
|
||||
assert_eq!(_1_2 + _3_2, _2);
|
||||
assert_eq!(_1_2 + _neg1_2, _0);
|
||||
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() {
|
||||
assert_eq!(_1 - _1_2, _1_2);
|
||||
assert_eq!(_3_2 - _1_2, _1);
|
||||
assert_eq!(_1 - _neg1_2, _3_2);
|
||||
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() {
|
||||
assert_eq!(_1 * _1_2, _1_2);
|
||||
assert_eq!(_1_2 * _3_2, Ratio::new(3,4));
|
||||
assert_eq!(_1_2 * _neg1_2, Ratio::new(-1, 4));
|
||||
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() {
|
||||
assert_eq!(_1 / _1_2, _2);
|
||||
assert_eq!(_3_2 / _1_2, _1 + _2);
|
||||
assert_eq!(_1 / _neg1_2, _neg1_2 + _neg1_2 + _neg1_2 + _neg1_2);
|
||||
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() {
|
||||
assert_eq!(_3_2 % _1, _1_2);
|
||||
assert_eq!(_2 % _neg1_2, _0);
|
||||
assert_eq!(_1_2 % _2, _1_2);
|
||||
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() {
|
||||
assert_eq!(-_0, _0);
|
||||
assert_eq!(-_1_2, _neg1_2);
|
||||
assert_eq!(-(-_1), _1);
|
||||
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() {
|
||||
|
||||
Reference in New Issue
Block a user