Skip to content

Commit c30414f

Browse files
committed
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
2 parents 043d022 + da9c1fb commit c30414f

File tree

2 files changed

+126
-84
lines changed

2 files changed

+126
-84
lines changed

src/libstd/num/bigint.rs

+41-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ A BigInt is a combination of BigUint and Sign.
1717
*/
1818

1919
use core::cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater};
20-
use core::num::{IntConvertible, Zero, One, ToStrRadix, FromStrRadix};
20+
use core::num::{IntConvertible, Zero, One, ToStrRadix, FromStrRadix, Orderable};
2121

2222
/**
2323
A BigDigit is a BigUint's composing element.
@@ -144,6 +144,26 @@ impl FromStr for BigUint {
144144
}
145145
}
146146

147+
impl Num for BigUint {}
148+
149+
impl Orderable for BigUint {
150+
#[inline(always)]
151+
fn min(&self, other: &BigUint) -> BigUint {
152+
if self < other { self.clone() } else { other.clone() }
153+
}
154+
155+
#[inline(always)]
156+
fn max(&self, other: &BigUint) -> BigUint {
157+
if self > other { self.clone() } else { other.clone() }
158+
}
159+
160+
#[inline(always)]
161+
fn clamp(&self, mn: &BigUint, mx: &BigUint) -> BigUint {
162+
if self > mx { mx.clone() } else
163+
if self < mn { mn.clone() } else { self.clone() }
164+
}
165+
}
166+
147167
impl Shl<uint, BigUint> for BigUint {
148168
#[inline(always)]
149169
fn shl(&self, rhs: &uint) -> BigUint {
@@ -788,6 +808,26 @@ impl FromStr for BigInt {
788808
}
789809
}
790810

811+
impl Num for BigInt {}
812+
813+
impl Orderable for BigInt {
814+
#[inline(always)]
815+
fn min(&self, other: &BigInt) -> BigInt {
816+
if self < other { self.clone() } else { other.clone() }
817+
}
818+
819+
#[inline(always)]
820+
fn max(&self, other: &BigInt) -> BigInt {
821+
if self > other { self.clone() } else { other.clone() }
822+
}
823+
824+
#[inline(always)]
825+
fn clamp(&self, mn: &BigInt, mx: &BigInt) -> BigInt {
826+
if self > mx { mx.clone() } else
827+
if self < mn { mn.clone() } else { self.clone() }
828+
}
829+
}
830+
791831
impl Shl<uint, BigInt> for BigInt {
792832
#[inline(always)]
793833
fn shl(&self, rhs: &uint) -> BigInt {

src/libstd/num/rational.rs

+85-83
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ pub type Rational64 = Ratio<i64>;
3030
/// Alias for arbitrary precision rationals.
3131
pub type BigRational = Ratio<BigInt>;
3232

33-
impl<T: Copy + Num + Ord>
33+
impl<T: Clone + Integer + Ord>
3434
Ratio<T> {
3535
/// Create a ratio representing the integer `t`.
3636
#[inline(always)]
@@ -57,53 +57,30 @@ impl<T: Copy + Num + Ord>
5757

5858
/// Put self into lowest terms, with denom > 0.
5959
fn reduce(&mut self) {
60-
let g : T = gcd(self.numer, self.denom);
60+
let g : T = self.numer.gcd(&self.denom);
6161

62-
self.numer /= g;
63-
self.denom /= g;
62+
// FIXME(#6050): overloaded operators force moves with generic types
63+
// self.numer /= g;
64+
self.numer = self.numer / g;
65+
// FIXME(#6050): overloaded operators force moves with generic types
66+
// self.denom /= g;
67+
self.denom = self.denom / g;
6468

6569
// keep denom positive!
6670
if self.denom < Zero::zero() {
6771
self.numer = -self.numer;
6872
self.denom = -self.denom;
6973
}
7074
}
75+
7176
/// Return a `reduce`d copy of self.
7277
fn reduced(&self) -> Ratio<T> {
73-
let mut ret = copy *self;
78+
let mut ret = self.clone();
7479
ret.reduce();
7580
ret
7681
}
7782
}
7883

79-
/**
80-
Compute the greatest common divisor of two numbers, via Euclid's algorithm.
81-
82-
The result can be negative.
83-
*/
84-
#[inline]
85-
pub fn gcd_raw<T: Num>(n: T, m: T) -> T {
86-
let mut m = m, n = n;
87-
while m != Zero::zero() {
88-
let temp = m;
89-
m = n % temp;
90-
n = temp;
91-
}
92-
n
93-
}
94-
95-
/**
96-
Compute the greatest common divisor of two numbers, via Euclid's algorithm.
97-
98-
The result is always positive.
99-
*/
100-
#[inline]
101-
pub fn gcd<T: Num + Ord>(n: T, m: T) -> T {
102-
let g = gcd_raw(n, m);
103-
if g < Zero::zero() { -g }
104-
else { g }
105-
}
106-
10784
/* Comparisons */
10885

10986
// comparing a/b and c/d is the same as comparing a*d and b*c, so we
@@ -133,7 +110,7 @@ cmp_impl!(impl TotalOrd, cmp -> cmp::Ordering)
133110

134111
/* Arithmetic */
135112
// a/b * c/d = (a*c)/(b*d)
136-
impl<T: Copy + Num + Ord>
113+
impl<T: Clone + Integer + Ord>
137114
Mul<Ratio<T>,Ratio<T>> for Ratio<T> {
138115
#[inline]
139116
fn mul(&self, rhs: &Ratio<T>) -> Ratio<T> {
@@ -142,7 +119,7 @@ impl<T: Copy + Num + Ord>
142119
}
143120

144121
// (a/b) / (c/d) = (a*d)/(b*c)
145-
impl<T: Copy + Num + Ord>
122+
impl<T: Clone + Integer + Ord>
146123
Div<Ratio<T>,Ratio<T>> for Ratio<T> {
147124
#[inline]
148125
fn div(&self, rhs: &Ratio<T>) -> Ratio<T> {
@@ -153,7 +130,7 @@ impl<T: Copy + Num + Ord>
153130
// Abstracts the a/b `op` c/d = (a*d `op` b*d) / (b*d) pattern
154131
macro_rules! arith_impl {
155132
(impl $imp:ident, $method:ident) => {
156-
impl<T: Copy + Num + Ord>
133+
impl<T: Clone + Integer + Ord>
157134
$imp<Ratio<T>,Ratio<T>> for Ratio<T> {
158135
#[inline]
159136
fn $method(&self, rhs: &Ratio<T>) -> Ratio<T> {
@@ -173,16 +150,16 @@ arith_impl!(impl Sub, sub)
173150
// a/b % c/d = (a*d % b*c)/(b*d)
174151
arith_impl!(impl Rem, rem)
175152

176-
impl<T: Copy + Num + Ord>
153+
impl<T: Clone + Integer + Ord>
177154
Neg<Ratio<T>> for Ratio<T> {
178155
#[inline]
179156
fn neg(&self) -> Ratio<T> {
180-
Ratio::new_raw(-self.numer, self.denom)
157+
Ratio::new_raw(-self.numer, self.denom.clone())
181158
}
182159
}
183160

184161
/* Constants */
185-
impl<T: Copy + Num + Ord>
162+
impl<T: Clone + Integer + Ord>
186163
Zero for Ratio<T> {
187164
#[inline]
188165
fn zero() -> Ratio<T> {
@@ -195,19 +172,19 @@ impl<T: Copy + Num + Ord>
195172
}
196173
}
197174

198-
impl<T: Copy + Num + Ord>
175+
impl<T: Clone + Integer + Ord>
199176
One for Ratio<T> {
200177
#[inline]
201178
fn one() -> Ratio<T> {
202179
Ratio::new_raw(One::one(), One::one())
203180
}
204181
}
205182

206-
impl<T: Copy + Num + Ord>
183+
impl<T: Clone + Integer + Ord>
207184
Num for Ratio<T> {}
208185

209186
/* Utils */
210-
impl<T: Copy + Num + Ord>
187+
impl<T: Clone + Integer + Ord>
211188
Round for Ratio<T> {
212189

213190
fn floor(&self) -> Ratio<T> {
@@ -241,14 +218,14 @@ impl<T: Copy + Num + Ord>
241218
}
242219

243220
fn fract(&self) -> Ratio<T> {
244-
Ratio::new_raw(self.numer % self.denom, self.denom)
221+
Ratio::new_raw(self.numer % self.denom, self.denom.clone())
245222
}
246223
}
247224

248-
impl<T: Copy + Num + Ord> Fractional for Ratio<T> {
225+
impl<T: Clone + Integer + Ord> Fractional for Ratio<T> {
249226
#[inline]
250227
fn recip(&self) -> Ratio<T> {
251-
Ratio::new_raw(self.denom, self.numer)
228+
Ratio::new_raw(self.denom.clone(), self.numer.clone())
252229
}
253230
}
254231

@@ -266,7 +243,7 @@ impl<T: ToStrRadix> ToStrRadix for Ratio<T> {
266243
}
267244
}
268245

269-
impl<T: FromStr + Copy + Num + Ord>
246+
impl<T: FromStr + Clone + Integer + Ord>
270247
FromStr for Ratio<T> {
271248
/// Parses `numer/denom`.
272249
fn from_str(s: &str) -> Option<Ratio<T>> {
@@ -276,14 +253,14 @@ impl<T: FromStr + Copy + Num + Ord>
276253
}
277254
});
278255
if split.len() < 2 { return None; }
279-
do FromStr::from_str(split[0]).chain |a| {
280-
do FromStr::from_str(split[1]).chain |b| {
281-
Some(Ratio::new(a,b))
256+
do FromStr::from_str::<T>(split[0]).chain |a| {
257+
do FromStr::from_str::<T>(split[1]).chain |b| {
258+
Some(Ratio::new(a.clone(), b.clone()))
282259
}
283260
}
284261
}
285262
}
286-
impl<T: FromStrRadix + Copy + Num + Ord>
263+
impl<T: FromStrRadix + Clone + Integer + Ord>
287264
FromStrRadix for Ratio<T> {
288265
/// Parses `numer/denom` where the numbers are in base `radix`.
289266
fn from_str_radix(s: &str, radix: uint) -> Option<Ratio<T>> {
@@ -294,9 +271,9 @@ impl<T: FromStrRadix + Copy + Num + Ord>
294271
});
295272
if split.len() < 2 { None }
296273
else {
297-
do FromStrRadix::from_str_radix(split[0], radix).chain |a| {
298-
do FromStrRadix::from_str_radix(split[1], radix).chain |b| {
299-
Some(Ratio::new(a,b))
274+
do FromStrRadix::from_str_radix::<T>(split[0], radix).chain |a| {
275+
do FromStrRadix::from_str_radix::<T>(split[1], radix).chain |b| {
276+
Some(Ratio::new(a.clone(), b.clone()))
300277
}
301278
}
302279
}
@@ -306,7 +283,7 @@ impl<T: FromStrRadix + Copy + Num + Ord>
306283
#[cfg(test)]
307284
mod test {
308285
use super::*;
309-
use core::num::{Zero,One,FromStrRadix};
286+
use core::num::{Zero,One,FromStrRadix,IntConvertible};
310287
use core::from_str::FromStr;
311288

312289
pub static _0 : Rational = Ratio { numer: 0, denom: 1};
@@ -316,16 +293,11 @@ mod test {
316293
pub static _3_2: Rational = Ratio { numer: 3, denom: 2};
317294
pub static _neg1_2: Rational = Ratio { numer: -1, denom: 2};
318295

319-
#[test]
320-
fn test_gcd() {
321-
assert_eq!(gcd(10,2),2);
322-
assert_eq!(gcd(10,3),1);
323-
assert_eq!(gcd(0,3),3);
324-
assert_eq!(gcd(3,3),3);
325-
326-
assert_eq!(gcd(3,-3), 3);
327-
assert_eq!(gcd(-6,3), 3);
328-
assert_eq!(gcd(-4,-2), 2);
296+
pub fn to_big(n: Rational) -> BigRational {
297+
Ratio::new(
298+
IntConvertible::from_int(n.numer),
299+
IntConvertible::from_int(n.denom)
300+
)
329301
}
330302

331303
#[test]
@@ -374,45 +346,75 @@ mod test {
374346

375347
#[test]
376348
fn test_add() {
377-
assert_eq!(_1 + _1_2, _3_2);
378-
assert_eq!(_1 + _1, _2);
379-
assert_eq!(_1_2 + _3_2, _2);
380-
assert_eq!(_1_2 + _neg1_2, _0);
349+
fn test(a: Rational, b: Rational, c: Rational) {
350+
assert_eq!(a + b, c);
351+
assert_eq!(to_big(a) + to_big(b), to_big(c));
352+
}
353+
354+
test(_1, _1_2, _3_2);
355+
test(_1, _1, _2);
356+
test(_1_2, _3_2, _2);
357+
test(_1_2, _neg1_2, _0);
381358
}
382359

383360
#[test]
384361
fn test_sub() {
385-
assert_eq!(_1 - _1_2, _1_2);
386-
assert_eq!(_3_2 - _1_2, _1);
387-
assert_eq!(_1 - _neg1_2, _3_2);
362+
fn test(a: Rational, b: Rational, c: Rational) {
363+
assert_eq!(a - b, c);
364+
assert_eq!(to_big(a) - to_big(b), to_big(c))
365+
}
366+
367+
test(_1, _1_2, _1_2);
368+
test(_3_2, _1_2, _1);
369+
test(_1, _neg1_2, _3_2);
388370
}
389371

390372
#[test]
391373
fn test_mul() {
392-
assert_eq!(_1 * _1_2, _1_2);
393-
assert_eq!(_1_2 * _3_2, Ratio::new(3,4));
394-
assert_eq!(_1_2 * _neg1_2, Ratio::new(-1, 4));
374+
fn test(a: Rational, b: Rational, c: Rational) {
375+
assert_eq!(a * b, c);
376+
assert_eq!(to_big(a) * to_big(b), to_big(c))
377+
}
378+
379+
test(_1, _1_2, _1_2);
380+
test(_1_2, _3_2, Ratio::new(3,4));
381+
test(_1_2, _neg1_2, Ratio::new(-1, 4));
395382
}
396383

397384
#[test]
398385
fn test_div() {
399-
assert_eq!(_1 / _1_2, _2);
400-
assert_eq!(_3_2 / _1_2, _1 + _2);
401-
assert_eq!(_1 / _neg1_2, _neg1_2 + _neg1_2 + _neg1_2 + _neg1_2);
386+
fn test(a: Rational, b: Rational, c: Rational) {
387+
assert_eq!(a / b, c);
388+
assert_eq!(to_big(a) / to_big(b), to_big(c))
389+
}
390+
391+
test(_1, _1_2, _2);
392+
test(_3_2, _1_2, _1 + _2);
393+
test(_1, _neg1_2, _neg1_2 + _neg1_2 + _neg1_2 + _neg1_2);
402394
}
403395

404396
#[test]
405397
fn test_rem() {
406-
assert_eq!(_3_2 % _1, _1_2);
407-
assert_eq!(_2 % _neg1_2, _0);
408-
assert_eq!(_1_2 % _2, _1_2);
398+
fn test(a: Rational, b: Rational, c: Rational) {
399+
assert_eq!(a % b, c);
400+
assert_eq!(to_big(a) % to_big(b), to_big(c))
401+
}
402+
403+
test(_3_2, _1, _1_2);
404+
test(_2, _neg1_2, _0);
405+
test(_1_2, _2, _1_2);
409406
}
410407

411408
#[test]
412409
fn test_neg() {
413-
assert_eq!(-_0, _0);
414-
assert_eq!(-_1_2, _neg1_2);
415-
assert_eq!(-(-_1), _1);
410+
fn test(a: Rational, b: Rational) {
411+
assert_eq!(-a, b);
412+
assert_eq!(-to_big(a), to_big(b))
413+
}
414+
415+
test(_0, _0);
416+
test(_1_2, _neg1_2);
417+
test(-_1, _1);
416418
}
417419
#[test]
418420
fn test_zero() {

0 commit comments

Comments
 (0)