1 // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
17 use std::from_str::FromStr;
18 use std::num::{Zero,One,ToStrRadix,FromStrRadix,Round};
19 use bigint::{BigInt, BigUint, Sign, Plus, Minus};
21 /// Represents the ratio between 2 numbers.
29 /// Alias for a `Ratio` of machine-sized integers.
30 pub type Rational = Ratio<int>;
31 pub type Rational32 = Ratio<i32>;
32 pub type Rational64 = Ratio<i64>;
34 /// Alias for arbitrary precision rationals.
35 pub type BigRational = Ratio<BigInt>;
37 impl<T: Clone + Integer + Ord>
39 /// Create a ratio representing the integer `t`.
41 pub fn from_integer(t: T) -> Ratio<T> {
42 Ratio::new_raw(t, One::one())
45 /// Create a ratio without checking for `denom == 0` or reducing.
47 pub fn new_raw(numer: T, denom: T) -> Ratio<T> {
48 Ratio { numer: numer, denom: denom }
51 /// Create a new Ratio. Fails if `denom == 0`.
53 pub fn new(numer: T, denom: T) -> Ratio<T> {
54 if denom == Zero::zero() {
55 fail!("denominator == 0");
57 let mut ret = Ratio::new_raw(numer, denom);
62 /// Convert to an integer.
64 pub fn to_integer(&self) -> T {
68 /// Gets an immutable reference to the numerator.
70 pub fn numer<'a>(&'a self) -> &'a T {
74 /// Gets an immutable reference to the denominator.
76 pub fn denom<'a>(&'a self) -> &'a T {
80 /// Return true if the rational number is an integer (denominator is 1).
82 pub fn is_integer(&self) -> bool {
83 self.denom == One::one()
86 /// Put self into lowest terms, with denom > 0.
87 fn reduce(&mut self) {
88 let g : T = self.numer.gcd(&self.denom);
90 // FIXME(#5992): assignment operator overloads
92 self.numer = self.numer / g;
93 // FIXME(#5992): assignment operator overloads
95 self.denom = self.denom / g;
97 // keep denom positive!
98 if self.denom < Zero::zero() {
99 self.numer = -self.numer;
100 self.denom = -self.denom;
104 /// Return a `reduce`d copy of self.
105 pub fn reduced(&self) -> Ratio<T> {
106 let mut ret = self.clone();
111 /// Return the reciprocal
113 pub fn recip(&self) -> Ratio<T> {
114 Ratio::new_raw(self.denom.clone(), self.numer.clone())
119 /// Converts a float into a rational number
120 pub fn from_float<T: Float>(f: T) -> Option<BigRational> {
124 let (mantissa, exponent, sign) = f.integer_decode();
125 let bigint_sign: Sign = if sign == 1 { Plus } else { Minus };
127 let one: BigInt = One::one();
128 let denom: BigInt = one << ((-exponent) as uint);
129 let numer: BigUint = FromPrimitive::from_u64(mantissa).unwrap();
130 Some(Ratio::new(BigInt::from_biguint(bigint_sign, numer), denom))
132 let mut numer: BigUint = FromPrimitive::from_u64(mantissa).unwrap();
133 numer = numer << (exponent as uint);
134 Some(Ratio::from_integer(BigInt::from_biguint(bigint_sign, numer)))
141 // comparing a/b and c/d is the same as comparing a*d and b*c, so we
142 // abstract that pattern. The following macro takes a trait and either
143 // a comma-separated list of "method name -> return value" or just
144 // "method name" (return value is bool in that case)
145 macro_rules! cmp_impl {
146 (impl $imp:ident, $($method:ident),+) => {
147 cmp_impl!(impl $imp, $($method -> bool),+)
149 // return something other than a Ratio<T>
150 (impl $imp:ident, $($method:ident -> $res:ty),*) => {
151 impl<T: Mul<T,T> + $imp> $imp for Ratio<T> {
154 fn $method(&self, other: &Ratio<T>) -> $res {
155 (self.numer * other.denom). $method (&(self.denom*other.numer))
161 cmp_impl!(impl Eq, eq, ne)
162 cmp_impl!(impl Ord, lt, gt, le, ge)
163 cmp_impl!(impl TotalEq, )
164 cmp_impl!(impl TotalOrd, cmp -> cmp::Ordering)
167 // a/b * c/d = (a*c)/(b*d)
168 impl<T: Clone + Integer + Ord>
169 Mul<Ratio<T>,Ratio<T>> for Ratio<T> {
171 fn mul(&self, rhs: &Ratio<T>) -> Ratio<T> {
172 Ratio::new(self.numer * rhs.numer, self.denom * rhs.denom)
176 // (a/b) / (c/d) = (a*d)/(b*c)
177 impl<T: Clone + Integer + Ord>
178 Div<Ratio<T>,Ratio<T>> for Ratio<T> {
180 fn div(&self, rhs: &Ratio<T>) -> Ratio<T> {
181 Ratio::new(self.numer * rhs.denom, self.denom * rhs.numer)
185 // Abstracts the a/b `op` c/d = (a*d `op` b*d) / (b*d) pattern
186 macro_rules! arith_impl {
187 (impl $imp:ident, $method:ident) => {
188 impl<T: Clone + Integer + Ord>
189 $imp<Ratio<T>,Ratio<T>> for Ratio<T> {
191 fn $method(&self, rhs: &Ratio<T>) -> Ratio<T> {
192 Ratio::new((self.numer * rhs.denom).$method(&(self.denom * rhs.numer)),
193 self.denom * rhs.denom)
199 // a/b + c/d = (a*d + b*c)/(b*d
200 arith_impl!(impl Add, add)
202 // a/b - c/d = (a*d - b*c)/(b*d)
203 arith_impl!(impl Sub, sub)
205 // a/b % c/d = (a*d % b*c)/(b*d)
206 arith_impl!(impl Rem, rem)
208 impl<T: Clone + Integer + Ord>
209 Neg<Ratio<T>> for Ratio<T> {
211 fn neg(&self) -> Ratio<T> {
212 Ratio::new_raw(-self.numer, self.denom.clone())
217 impl<T: Clone + Integer + Ord>
220 fn zero() -> Ratio<T> {
221 Ratio::new_raw(Zero::zero(), One::one())
225 fn is_zero(&self) -> bool {
226 *self == Zero::zero()
230 impl<T: Clone + Integer + Ord>
233 fn one() -> Ratio<T> {
234 Ratio::new_raw(One::one(), One::one())
238 impl<T: Clone + Integer + Ord>
242 impl<T: Clone + Integer + Ord>
245 fn floor(&self) -> Ratio<T> {
246 if *self < Zero::zero() {
247 Ratio::from_integer((self.numer - self.denom + One::one()) / self.denom)
249 Ratio::from_integer(self.numer / self.denom)
253 fn ceil(&self) -> Ratio<T> {
254 if *self < Zero::zero() {
255 Ratio::from_integer(self.numer / self.denom)
257 Ratio::from_integer((self.numer + self.denom - One::one()) / self.denom)
262 fn round(&self) -> Ratio<T> {
263 if *self < Zero::zero() {
264 Ratio::from_integer((self.numer - self.denom + One::one()) / self.denom)
266 Ratio::from_integer((self.numer + self.denom - One::one()) / self.denom)
271 fn trunc(&self) -> Ratio<T> {
272 Ratio::from_integer(self.numer / self.denom)
275 fn fract(&self) -> Ratio<T> {
276 Ratio::new_raw(self.numer % self.denom, self.denom.clone())
280 /* String conversions */
281 impl<T: fmt::Show> fmt::Show for Ratio<T> {
282 /// Renders as `numer/denom`.
283 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
284 write!(f.buf, "{}/{}", self.numer, self.denom)
287 impl<T: ToStrRadix> ToStrRadix for Ratio<T> {
288 /// Renders as `numer/denom` where the numbers are in base `radix`.
289 fn to_str_radix(&self, radix: uint) -> ~str {
290 format!("{}/{}", self.numer.to_str_radix(radix), self.denom.to_str_radix(radix))
294 impl<T: FromStr + Clone + Integer + Ord>
295 FromStr for Ratio<T> {
296 /// Parses `numer/denom`.
297 fn from_str(s: &str) -> Option<Ratio<T>> {
298 let split: Vec<&str> = s.splitn('/', 1).collect();
302 let a_option: Option<T> = FromStr::from_str(*split.get(0));
303 a_option.and_then(|a| {
304 let b_option: Option<T> = FromStr::from_str(*split.get(1));
305 b_option.and_then(|b| {
306 Some(Ratio::new(a.clone(), b.clone()))
311 impl<T: FromStrRadix + Clone + Integer + Ord>
312 FromStrRadix for Ratio<T> {
313 /// Parses `numer/denom` where the numbers are in base `radix`.
314 fn from_str_radix(s: &str, radix: uint) -> Option<Ratio<T>> {
315 let split: Vec<&str> = s.splitn('/', 1).collect();
319 let a_option: Option<T> = FromStrRadix::from_str_radix(
322 a_option.and_then(|a| {
323 let b_option: Option<T> =
324 FromStrRadix::from_str_radix(*split.get(1), radix);
325 b_option.and_then(|b| {
326 Some(Ratio::new(a.clone(), b.clone()))
336 use super::{Ratio, Rational, BigRational};
337 use std::num::{Zero, One, FromStrRadix, FromPrimitive, ToStrRadix};
338 use std::from_str::FromStr;
340 pub static _0 : Rational = Ratio { numer: 0, denom: 1};
341 pub static _1 : Rational = Ratio { numer: 1, denom: 1};
342 pub static _2: Rational = Ratio { numer: 2, denom: 1};
343 pub static _1_2: Rational = Ratio { numer: 1, denom: 2};
344 pub static _3_2: Rational = Ratio { numer: 3, denom: 2};
345 pub static _neg1_2: Rational = Ratio { numer: -1, denom: 2};
347 pub fn to_big(n: Rational) -> BigRational {
349 FromPrimitive::from_int(n.numer).unwrap(),
350 FromPrimitive::from_int(n.denom).unwrap()
355 fn test_test_constants() {
356 // check our constants are what Ratio::new etc. would make.
357 assert_eq!(_0, Zero::zero());
358 assert_eq!(_1, One::one());
359 assert_eq!(_2, Ratio::from_integer(2));
360 assert_eq!(_1_2, Ratio::new(1,2));
361 assert_eq!(_3_2, Ratio::new(3,2));
362 assert_eq!(_neg1_2, Ratio::new(-1,2));
366 fn test_new_reduce() {
367 let one22 = Ratio::new(2i,2);
369 assert_eq!(one22, One::one());
374 let _a = Ratio::new(1,0);
380 assert!(_0 == _0 && _1 == _1);
381 assert!(_0 != _1 && _1 != _0);
382 assert!(_0 < _1 && !(_1 < _0));
383 assert!(_1 > _0 && !(_0 > _1));
385 assert!(_0 <= _0 && _1 <= _1);
386 assert!(_0 <= _1 && !(_1 <= _0));
388 assert!(_0 >= _0 && _1 >= _1);
389 assert!(_1 >= _0 && !(_0 >= _1));
394 fn test_to_integer() {
395 assert_eq!(_0.to_integer(), 0);
396 assert_eq!(_1.to_integer(), 1);
397 assert_eq!(_2.to_integer(), 2);
398 assert_eq!(_1_2.to_integer(), 0);
399 assert_eq!(_3_2.to_integer(), 1);
400 assert_eq!(_neg1_2.to_integer(), 0);
406 assert_eq!(_0.numer(), &0);
407 assert_eq!(_1.numer(), &1);
408 assert_eq!(_2.numer(), &2);
409 assert_eq!(_1_2.numer(), &1);
410 assert_eq!(_3_2.numer(), &3);
411 assert_eq!(_neg1_2.numer(), &(-1));
415 assert_eq!(_0.denom(), &1);
416 assert_eq!(_1.denom(), &1);
417 assert_eq!(_2.denom(), &1);
418 assert_eq!(_1_2.denom(), &2);
419 assert_eq!(_3_2.denom(), &2);
420 assert_eq!(_neg1_2.denom(), &2);
425 fn test_is_integer() {
426 assert!(_0.is_integer());
427 assert!(_1.is_integer());
428 assert!(_2.is_integer());
429 assert!(!_1_2.is_integer());
430 assert!(!_3_2.is_integer());
431 assert!(!_neg1_2.is_integer());
436 use super::{_0, _1, _2, _1_2, _3_2, _neg1_2, to_big};
437 use super::super::{Ratio, Rational};
441 fn test(a: Rational, b: Rational, c: Rational) {
442 assert_eq!(a + b, c);
443 assert_eq!(to_big(a) + to_big(b), to_big(c));
446 test(_1, _1_2, _3_2);
448 test(_1_2, _3_2, _2);
449 test(_1_2, _neg1_2, _0);
454 fn test(a: Rational, b: Rational, c: Rational) {
455 assert_eq!(a - b, c);
456 assert_eq!(to_big(a) - to_big(b), to_big(c))
459 test(_1, _1_2, _1_2);
460 test(_3_2, _1_2, _1);
461 test(_1, _neg1_2, _3_2);
466 fn test(a: Rational, b: Rational, c: Rational) {
467 assert_eq!(a * b, c);
468 assert_eq!(to_big(a) * to_big(b), to_big(c))
471 test(_1, _1_2, _1_2);
472 test(_1_2, _3_2, Ratio::new(3,4));
473 test(_1_2, _neg1_2, Ratio::new(-1, 4));
478 fn test(a: Rational, b: Rational, c: Rational) {
479 assert_eq!(a / b, c);
480 assert_eq!(to_big(a) / to_big(b), to_big(c))
484 test(_3_2, _1_2, _1 + _2);
485 test(_1, _neg1_2, _neg1_2 + _neg1_2 + _neg1_2 + _neg1_2);
490 fn test(a: Rational, b: Rational, c: Rational) {
491 assert_eq!(a % b, c);
492 assert_eq!(to_big(a) % to_big(b), to_big(c))
495 test(_3_2, _1, _1_2);
496 test(_2, _neg1_2, _0);
497 test(_1_2, _2, _1_2);
502 fn test(a: Rational, b: Rational) {
504 assert_eq!(-to_big(a), to_big(b))
513 assert_eq!(_0 + _0, _0);
514 assert_eq!(_0 * _0, _0);
515 assert_eq!(_0 * _1, _0);
516 assert_eq!(_0 / _neg1_2, _0);
517 assert_eq!(_0 - _0, _0);
528 assert_eq!(_1_2.ceil(), _1);
529 assert_eq!(_1_2.floor(), _0);
530 assert_eq!(_1_2.round(), _1);
531 assert_eq!(_1_2.trunc(), _0);
533 assert_eq!(_neg1_2.ceil(), _0);
534 assert_eq!(_neg1_2.floor(), -_1);
535 assert_eq!(_neg1_2.round(), -_1);
536 assert_eq!(_neg1_2.trunc(), _0);
538 assert_eq!(_1.ceil(), _1);
539 assert_eq!(_1.floor(), _1);
540 assert_eq!(_1.round(), _1);
541 assert_eq!(_1.trunc(), _1);
546 assert_eq!(_1.fract(), _0);
547 assert_eq!(_neg1_2.fract(), _neg1_2);
548 assert_eq!(_1_2.fract(), _1_2);
549 assert_eq!(_3_2.fract(), _1_2);
554 assert_eq!(_1 * _1.recip(), _1);
555 assert_eq!(_2 * _2.recip(), _1);
556 assert_eq!(_1_2 * _1_2.recip(), _1);
557 assert_eq!(_3_2 * _3_2.recip(), _1);
558 assert_eq!(_neg1_2 * _neg1_2.recip(), _1);
562 fn test_to_from_str() {
563 fn test(r: Rational, s: ~str) {
564 assert_eq!(FromStr::from_str(s), Some(r));
565 assert_eq!(r.to_str(), s);
572 test(_neg1_2, ~"-1/2");
575 fn test_from_str_fail() {
577 let rational: Option<Rational> = FromStr::from_str(s);
578 assert_eq!(rational, None);
581 let xs = ["0 /1", "abc", "", "1/", "--1/2","3/2/1"];
582 for &s in xs.iter() {
588 fn test_to_from_str_radix() {
589 fn test(r: Rational, s: ~str, n: uint) {
590 assert_eq!(FromStrRadix::from_str_radix(s, n), Some(r));
591 assert_eq!(r.to_str_radix(n), s);
593 fn test3(r: Rational, s: ~str) { test(r, s, 3) }
594 fn test16(r: Rational, s: ~str) { test(r, s, 16) }
599 test3(_3_2, ~"10/2");
601 test3(_neg1_2, ~"-1/2");
602 test3(_neg1_2 / _2, ~"-1/11");
606 test16(_1_2, ~"1/2");
607 test16(_3_2, ~"3/2");
609 test16(_neg1_2, ~"-1/2");
610 test16(_neg1_2 / _2, ~"-1/4");
611 test16(Ratio::new(13,15), ~"d/f");
612 test16(_1_2*_1_2*_1_2*_1_2, ~"1/10");
616 fn test_from_str_radix_fail() {
618 let radix: Option<Rational> = FromStrRadix::from_str_radix(s, 3);
619 assert_eq!(radix, None);
622 let xs = ["0 /1", "abc", "", "1/", "--1/2","3/2/1", "3/2"];
623 for &s in xs.iter() {
629 fn test_from_float() {
630 fn test<T: Float>(given: T, (numer, denom): (&str, &str)) {
631 let ratio: BigRational = Ratio::from_float(given).unwrap();
632 assert_eq!(ratio, Ratio::new(
633 FromStr::from_str(numer).unwrap(),
634 FromStr::from_str(denom).unwrap()));
638 test(3.14159265359f32, ("13176795", "4194304"));
639 test(2f32.powf(&100.), ("1267650600228229401496703205376", "1"));
640 test(-2f32.powf(&100.), ("-1267650600228229401496703205376", "1"));
641 test(1.0 / 2f32.powf(&100.), ("1", "1267650600228229401496703205376"));
642 test(684729.48391f32, ("1369459", "2"));
643 test(-8573.5918555f32, ("-4389679", "512"));
646 test(3.14159265359f64, ("3537118876014453", "1125899906842624"));
647 test(2f64.powf(&100.), ("1267650600228229401496703205376", "1"));
648 test(-2f64.powf(&100.), ("-1267650600228229401496703205376", "1"));
649 test(684729.48391f64, ("367611342500051", "536870912"));
650 test(-8573.5918555, ("-4713381968463931", "549755813888"));
651 test(1.0 / 2f64.powf(&100.), ("1", "1267650600228229401496703205376"));
655 fn test_from_float_fail() {
658 assert_eq!(Ratio::from_float(f32::NAN), None);
659 assert_eq!(Ratio::from_float(f32::INFINITY), None);
660 assert_eq!(Ratio::from_float(f32::NEG_INFINITY), None);
661 assert_eq!(Ratio::from_float(f64::NAN), None);
662 assert_eq!(Ratio::from_float(f64::INFINITY), None);
663 assert_eq!(Ratio::from_float(f64::NEG_INFINITY), None);