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.
4 //
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.
10
11 //! Rational numbers
12 //!
13 //! ## Compatibility
14 //!
15 //! The `num-rational` crate is tested for rustc 1.15 and greater.
16
17 #![doc(html_root_url = "https://docs.rs/num-rational/0.2")]
18
19 #![no_std]
20
21 #[cfg(feature = "serde")]
22 extern crate serde;
23 #[cfg(feature = "bigint")]
24 extern crate num_bigint as bigint;
25
26 extern crate num_traits as traits;
27 extern crate num_integer as integer;
28
29 #[cfg(feature = "std")]
30 #[cfg_attr(test, macro_use)]
31 extern crate std;
32
33 use core::cmp;
34 #[cfg(feature = "std")]
35 use std::error::Error;
36 use core::fmt;
37 use core::hash::{Hash, Hasher};
38 use core::ops::{Add, Div, Mul, Neg, Rem, Sub};
39 use core::str::FromStr;
40
41 #[cfg(feature = "bigint")]
42 use bigint::{BigInt, BigUint, Sign};
43
44 use integer::Integer;
45 use traits::float::FloatCore;
46 use traits::{Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, FromPrimitive, Inv, Num,
47 NumCast, One, Pow, Signed, Zero};
48
49 /// Represents the ratio between two numbers.
50 #[derive(Copy, Clone, Debug)]
51 #[allow(missing_docs)]
52 pub struct Ratio<T> {
53 /// Numerator.
54 numer: T,
55 /// Denominator.
56 denom: T,
57 }
58
59 /// Alias for a `Ratio` of machine-sized integers.
60 pub type Rational = Ratio<isize>;
61 /// Alias for a `Ratio` of 32-bit-sized integers.
62 pub type Rational32 = Ratio<i32>;
63 /// Alias for a `Ratio` of 64-bit-sized integers.
64 pub type Rational64 = Ratio<i64>;
65
66 #[cfg(feature = "bigint")]
67 /// Alias for arbitrary precision rationals.
68 pub type BigRational = Ratio<BigInt>;
69
70 impl<T: Clone + Integer> Ratio<T> {
71 /// Creates a new `Ratio`. Fails if `denom` is zero.
72 #[inline]
new(numer: T, denom: T) -> Ratio<T>73 pub fn new(numer: T, denom: T) -> Ratio<T> {
74 if denom.is_zero() {
75 panic!("denominator == 0");
76 }
77 let mut ret = Ratio::new_raw(numer, denom);
78 ret.reduce();
79 ret
80 }
81
82 /// Creates a `Ratio` representing the integer `t`.
83 #[inline]
from_integer(t: T) -> Ratio<T>84 pub fn from_integer(t: T) -> Ratio<T> {
85 Ratio::new_raw(t, One::one())
86 }
87
88 /// Creates a `Ratio` without checking for `denom == 0` or reducing.
89 #[inline]
new_raw(numer: T, denom: T) -> Ratio<T>90 pub fn new_raw(numer: T, denom: T) -> Ratio<T> {
91 Ratio {
92 numer: numer,
93 denom: denom,
94 }
95 }
96
97 /// Converts to an integer, rounding towards zero.
98 #[inline]
to_integer(&self) -> T99 pub fn to_integer(&self) -> T {
100 self.trunc().numer
101 }
102
103 /// Gets an immutable reference to the numerator.
104 #[inline]
numer<'a>(&'a self) -> &'a T105 pub fn numer<'a>(&'a self) -> &'a T {
106 &self.numer
107 }
108
109 /// Gets an immutable reference to the denominator.
110 #[inline]
denom<'a>(&'a self) -> &'a T111 pub fn denom<'a>(&'a self) -> &'a T {
112 &self.denom
113 }
114
115 /// Returns true if the rational number is an integer (denominator is 1).
116 #[inline]
is_integer(&self) -> bool117 pub fn is_integer(&self) -> bool {
118 self.denom.is_one()
119 }
120
121 /// Puts self into lowest terms, with denom > 0.
reduce(&mut self)122 fn reduce(&mut self) {
123 let g: T = self.numer.gcd(&self.denom);
124
125 // FIXME(#5992): assignment operator overloads
126 // self.numer /= g;
127 // T: Clone + Integer != T: Clone + NumAssign
128 self.numer = self.numer.clone() / g.clone();
129 // FIXME(#5992): assignment operator overloads
130 // self.denom /= g;
131 // T: Clone + Integer != T: Clone + NumAssign
132 self.denom = self.denom.clone() / g;
133
134 // keep denom positive!
135 if self.denom < T::zero() {
136 self.numer = T::zero() - self.numer.clone();
137 self.denom = T::zero() - self.denom.clone();
138 }
139 }
140
141 /// Returns a reduced copy of self.
142 ///
143 /// In general, it is not necessary to use this method, as the only
144 /// method of procuring a non-reduced fraction is through `new_raw`.
reduced(&self) -> Ratio<T>145 pub fn reduced(&self) -> Ratio<T> {
146 let mut ret = self.clone();
147 ret.reduce();
148 ret
149 }
150
151 /// Returns the reciprocal.
152 ///
153 /// Fails if the `Ratio` is zero.
154 #[inline]
recip(&self) -> Ratio<T>155 pub fn recip(&self) -> Ratio<T> {
156 match self.numer.cmp(&T::zero()) {
157 cmp::Ordering::Equal => panic!("numerator == 0"),
158 cmp::Ordering::Greater => Ratio::new_raw(self.denom.clone(), self.numer.clone()),
159 cmp::Ordering::Less => Ratio::new_raw(T::zero() - self.denom.clone(),
160 T::zero() - self.numer.clone())
161 }
162 }
163
164 /// Rounds towards minus infinity.
165 #[inline]
floor(&self) -> Ratio<T>166 pub fn floor(&self) -> Ratio<T> {
167 if *self < Zero::zero() {
168 let one: T = One::one();
169 Ratio::from_integer((self.numer.clone() - self.denom.clone() + one) /
170 self.denom.clone())
171 } else {
172 Ratio::from_integer(self.numer.clone() / self.denom.clone())
173 }
174 }
175
176 /// Rounds towards plus infinity.
177 #[inline]
ceil(&self) -> Ratio<T>178 pub fn ceil(&self) -> Ratio<T> {
179 if *self < Zero::zero() {
180 Ratio::from_integer(self.numer.clone() / self.denom.clone())
181 } else {
182 let one: T = One::one();
183 Ratio::from_integer((self.numer.clone() + self.denom.clone() - one) /
184 self.denom.clone())
185 }
186 }
187
188 /// Rounds to the nearest integer. Rounds half-way cases away from zero.
189 #[inline]
round(&self) -> Ratio<T>190 pub fn round(&self) -> Ratio<T> {
191 let zero: Ratio<T> = Zero::zero();
192 let one: T = One::one();
193 let two: T = one.clone() + one.clone();
194
195 // Find unsigned fractional part of rational number
196 let mut fractional = self.fract();
197 if fractional < zero {
198 fractional = zero - fractional
199 };
200
201 // The algorithm compares the unsigned fractional part with 1/2, that
202 // is, a/b >= 1/2, or a >= b/2. For odd denominators, we use
203 // a >= (b/2)+1. This avoids overflow issues.
204 let half_or_larger = if fractional.denom().is_even() {
205 *fractional.numer() >= fractional.denom().clone() / two.clone()
206 } else {
207 *fractional.numer() >= (fractional.denom().clone() / two.clone()) + one.clone()
208 };
209
210 if half_or_larger {
211 let one: Ratio<T> = One::one();
212 if *self >= Zero::zero() {
213 self.trunc() + one
214 } else {
215 self.trunc() - one
216 }
217 } else {
218 self.trunc()
219 }
220 }
221
222 /// Rounds towards zero.
223 #[inline]
trunc(&self) -> Ratio<T>224 pub fn trunc(&self) -> Ratio<T> {
225 Ratio::from_integer(self.numer.clone() / self.denom.clone())
226 }
227
228 /// Returns the fractional part of a number, with division rounded towards zero.
229 ///
230 /// Satisfies `self == self.trunc() + self.fract()`.
231 #[inline]
fract(&self) -> Ratio<T>232 pub fn fract(&self) -> Ratio<T> {
233 Ratio::new_raw(self.numer.clone() % self.denom.clone(), self.denom.clone())
234 }
235 }
236
237 impl<T: Clone + Integer + Pow<u32, Output = T>> Ratio<T> {
238 /// Raises the `Ratio` to the power of an exponent.
239 #[inline]
pow(&self, expon: i32) -> Ratio<T>240 pub fn pow(&self, expon: i32) -> Ratio<T> {
241 Pow::pow(self, expon)
242 }
243 }
244
245 macro_rules! pow_impl {
246 ($exp: ty) => {
247 pow_impl!($exp, $exp);
248 };
249 ($exp: ty, $unsigned: ty) => {
250 impl<T: Clone + Integer + Pow<$unsigned, Output = T>> Pow<$exp> for Ratio<T> {
251 type Output = Ratio<T>;
252 #[inline]
253 fn pow(self, expon: $exp) -> Ratio<T> {
254 match expon.cmp(&0) {
255 cmp::Ordering::Equal => One::one(),
256 cmp::Ordering::Less => {
257 let expon = expon.wrapping_abs() as $unsigned;
258 Ratio::new_raw(
259 Pow::pow(self.denom, expon),
260 Pow::pow(self.numer, expon),
261 )
262 },
263 cmp::Ordering::Greater => {
264 Ratio::new_raw(
265 Pow::pow(self.numer, expon as $unsigned),
266 Pow::pow(self.denom, expon as $unsigned),
267 )
268 }
269 }
270 }
271 }
272 impl<'a, T: Clone + Integer + Pow<$unsigned, Output = T>> Pow<$exp> for &'a Ratio<T> {
273 type Output = Ratio<T>;
274 #[inline]
275 fn pow(self, expon: $exp) -> Ratio<T> {
276 Pow::pow(self.clone(), expon)
277 }
278 }
279 impl<'a, T: Clone + Integer + Pow<$unsigned, Output = T>> Pow<&'a $exp> for Ratio<T> {
280 type Output = Ratio<T>;
281 #[inline]
282 fn pow(self, expon: &'a $exp) -> Ratio<T> {
283 Pow::pow(self, *expon)
284 }
285 }
286 impl<'a, 'b, T: Clone + Integer + Pow<$unsigned, Output = T>> Pow<&'a $exp> for &'b Ratio<T> {
287 type Output = Ratio<T>;
288 #[inline]
289 fn pow(self, expon: &'a $exp) -> Ratio<T> {
290 Pow::pow(self.clone(), *expon)
291 }
292 }
293 };
294 }
295
296 // this is solely to make `pow_impl!` work
297 trait WrappingAbs: Sized {
wrapping_abs(self) -> Self298 fn wrapping_abs(self) -> Self {
299 self
300 }
301 }
302 impl WrappingAbs for u8 {}
303 impl WrappingAbs for u16 {}
304 impl WrappingAbs for u32 {}
305 impl WrappingAbs for u64 {}
306 impl WrappingAbs for usize {}
307
308 pow_impl!(i8, u8);
309 pow_impl!(i16, u16);
310 pow_impl!(i32, u32);
311 pow_impl!(i64, u64);
312 pow_impl!(isize, usize);
313 pow_impl!(u8);
314 pow_impl!(u16);
315 pow_impl!(u32);
316 pow_impl!(u64);
317 pow_impl!(usize);
318
319 // TODO: pow_impl!(BigUint) and pow_impl!(BigInt, BigUint)
320
321 #[cfg(feature = "bigint")]
322 impl Ratio<BigInt> {
323 /// Converts a float into a rational number.
from_float<T: FloatCore>(f: T) -> Option<BigRational>324 pub fn from_float<T: FloatCore>(f: T) -> Option<BigRational> {
325 if !f.is_finite() {
326 return None;
327 }
328 let (mantissa, exponent, sign) = f.integer_decode();
329 let bigint_sign = if sign == 1 {
330 Sign::Plus
331 } else {
332 Sign::Minus
333 };
334 if exponent < 0 {
335 let one: BigInt = One::one();
336 let denom: BigInt = one << ((-exponent) as usize);
337 let numer: BigUint = FromPrimitive::from_u64(mantissa).unwrap();
338 Some(Ratio::new(BigInt::from_biguint(bigint_sign, numer), denom))
339 } else {
340 let mut numer: BigUint = FromPrimitive::from_u64(mantissa).unwrap();
341 numer = numer << (exponent as usize);
342 Some(Ratio::from_integer(BigInt::from_biguint(bigint_sign, numer)))
343 }
344 }
345 }
346
347 // From integer
348 impl<T> From<T> for Ratio<T> where T: Clone + Integer {
from(x: T) -> Ratio<T>349 fn from(x: T) -> Ratio<T> {
350 Ratio::from_integer(x)
351 }
352 }
353
354 // From pair (through the `new` constructor)
355 impl<T> From<(T, T)> for Ratio<T> where T: Clone + Integer {
from(pair: (T, T)) -> Ratio<T>356 fn from(pair: (T, T)) -> Ratio<T> {
357 Ratio::new(pair.0, pair.1)
358 }
359 }
360
361 // Comparisons
362
363 // Mathematically, comparing a/b and c/d is the same as comparing a*d and b*c, but it's very easy
364 // for those multiplications to overflow fixed-size integers, so we need to take care.
365
366 impl<T: Clone + Integer> Ord for Ratio<T> {
367 #[inline]
cmp(&self, other: &Self) -> cmp::Ordering368 fn cmp(&self, other: &Self) -> cmp::Ordering {
369 // With equal denominators, the numerators can be directly compared
370 if self.denom == other.denom {
371 let ord = self.numer.cmp(&other.numer);
372 return if self.denom < T::zero() {
373 ord.reverse()
374 } else {
375 ord
376 };
377 }
378
379 // With equal numerators, the denominators can be inversely compared
380 if self.numer == other.numer {
381 let ord = self.denom.cmp(&other.denom);
382 return if self.numer < T::zero() {
383 ord
384 } else {
385 ord.reverse()
386 };
387 }
388
389 // Unfortunately, we don't have CheckedMul to try. That could sometimes avoid all the
390 // division below, or even always avoid it for BigInt and BigUint.
391 // FIXME- future breaking change to add Checked* to Integer?
392
393 // Compare as floored integers and remainders
394 let (self_int, self_rem) = self.numer.div_mod_floor(&self.denom);
395 let (other_int, other_rem) = other.numer.div_mod_floor(&other.denom);
396 match self_int.cmp(&other_int) {
397 cmp::Ordering::Greater => cmp::Ordering::Greater,
398 cmp::Ordering::Less => cmp::Ordering::Less,
399 cmp::Ordering::Equal => {
400 match (self_rem.is_zero(), other_rem.is_zero()) {
401 (true, true) => cmp::Ordering::Equal,
402 (true, false) => cmp::Ordering::Less,
403 (false, true) => cmp::Ordering::Greater,
404 (false, false) => {
405 // Compare the reciprocals of the remaining fractions in reverse
406 let self_recip = Ratio::new_raw(self.denom.clone(), self_rem);
407 let other_recip = Ratio::new_raw(other.denom.clone(), other_rem);
408 self_recip.cmp(&other_recip).reverse()
409 }
410 }
411 }
412 }
413 }
414 }
415
416 impl<T: Clone + Integer> PartialOrd for Ratio<T> {
417 #[inline]
partial_cmp(&self, other: &Self) -> Option<cmp::Ordering>418 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
419 Some(self.cmp(other))
420 }
421 }
422
423 impl<T: Clone + Integer> PartialEq for Ratio<T> {
424 #[inline]
eq(&self, other: &Self) -> bool425 fn eq(&self, other: &Self) -> bool {
426 self.cmp(other) == cmp::Ordering::Equal
427 }
428 }
429
430 impl<T: Clone + Integer> Eq for Ratio<T> {}
431
432 // NB: We can't just `#[derive(Hash)]`, because it needs to agree
433 // with `Eq` even for non-reduced ratios.
434 impl<T: Clone + Integer + Hash> Hash for Ratio<T> {
hash<H: Hasher>(&self, state: &mut H)435 fn hash<H: Hasher>(&self, state: &mut H) {
436 recurse(&self.numer, &self.denom, state);
437
438 fn recurse<T: Integer + Hash, H: Hasher>(numer: &T, denom: &T, state: &mut H) {
439 if !denom.is_zero() {
440 let (int, rem) = numer.div_mod_floor(denom);
441 int.hash(state);
442 recurse(denom, &rem, state);
443 } else {
444 denom.hash(state);
445 }
446 }
447 }
448 }
449
450 mod iter_sum_product {
451 use ::core::iter::{Sum, Product};
452 use Ratio;
453 use integer::Integer;
454 use traits::{Zero, One};
455
456 impl<T: Integer + Clone> Sum for Ratio<T> {
sum<I>(iter: I) -> Self where I: Iterator<Item = Ratio<T>>457 fn sum<I>(iter: I) -> Self
458 where
459 I: Iterator<Item = Ratio<T>>
460 {
461 iter.fold(Self::zero(), |sum, num| sum + num)
462 }
463 }
464
465 impl<'a, T: Integer + Clone> Sum<&'a Ratio<T>> for Ratio<T> {
sum<I>(iter: I) -> Self where I: Iterator<Item = &'a Ratio<T>>466 fn sum<I>(iter: I) -> Self
467 where
468 I: Iterator<Item = &'a Ratio<T>>
469 {
470 iter.fold(Self::zero(), |sum, num| sum + num)
471 }
472 }
473
474 impl<T: Integer + Clone> Product for Ratio<T> {
product<I>(iter: I) -> Self where I: Iterator<Item = Ratio<T>>475 fn product<I>(iter: I) -> Self
476 where
477 I: Iterator<Item = Ratio<T>>
478 {
479 iter.fold(Self::one(), |prod, num| prod * num)
480 }
481 }
482
483 impl<'a, T: Integer + Clone> Product<&'a Ratio<T>> for Ratio<T> {
product<I>(iter: I) -> Self where I: Iterator<Item = &'a Ratio<T>>484 fn product<I>(iter: I) -> Self
485 where
486 I: Iterator<Item = &'a Ratio<T>>
487 {
488 iter.fold(Self::one(), |prod, num| prod * num)
489 }
490 }
491 }
492
493 mod opassign {
494 use core::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign};
495
496 use Ratio;
497 use integer::Integer;
498 use traits::NumAssign;
499
500 impl<T: Clone + Integer + NumAssign> AddAssign for Ratio<T> {
add_assign(&mut self, other: Ratio<T>)501 fn add_assign(&mut self, other: Ratio<T>) {
502 self.numer *= other.denom.clone();
503 self.numer += self.denom.clone() * other.numer;
504 self.denom *= other.denom;
505 self.reduce();
506 }
507 }
508
509 impl<T: Clone + Integer + NumAssign> DivAssign for Ratio<T> {
div_assign(&mut self, other: Ratio<T>)510 fn div_assign(&mut self, other: Ratio<T>) {
511 self.numer *= other.denom;
512 self.denom *= other.numer;
513 self.reduce();
514 }
515 }
516
517 impl<T: Clone + Integer + NumAssign> MulAssign for Ratio<T> {
mul_assign(&mut self, other: Ratio<T>)518 fn mul_assign(&mut self, other: Ratio<T>) {
519 self.numer *= other.numer;
520 self.denom *= other.denom;
521 self.reduce();
522 }
523 }
524
525 impl<T: Clone + Integer + NumAssign> RemAssign for Ratio<T> {
rem_assign(&mut self, other: Ratio<T>)526 fn rem_assign(&mut self, other: Ratio<T>) {
527 self.numer *= other.denom.clone();
528 self.numer %= self.denom.clone() * other.numer;
529 self.denom *= other.denom;
530 self.reduce();
531 }
532 }
533
534 impl<T: Clone + Integer + NumAssign> SubAssign for Ratio<T> {
sub_assign(&mut self, other: Ratio<T>)535 fn sub_assign(&mut self, other: Ratio<T>) {
536 self.numer *= other.denom.clone();
537 self.numer -= self.denom.clone() * other.numer;
538 self.denom *= other.denom;
539 self.reduce();
540 }
541 }
542
543 // a/b + c/1 = (a*1 + b*c) / (b*1) = (a + b*c) / b
544 impl<T: Clone + Integer + NumAssign> AddAssign<T> for Ratio<T> {
add_assign(&mut self, other: T)545 fn add_assign(&mut self, other: T) {
546 self.numer += self.denom.clone() * other;
547 self.reduce();
548 }
549 }
550
551 impl<T: Clone + Integer + NumAssign> DivAssign<T> for Ratio<T> {
div_assign(&mut self, other: T)552 fn div_assign(&mut self, other: T) {
553 self.denom *= other;
554 self.reduce();
555 }
556 }
557
558 impl<T: Clone + Integer + NumAssign> MulAssign<T> for Ratio<T> {
mul_assign(&mut self, other: T)559 fn mul_assign(&mut self, other: T) {
560 self.numer *= other;
561 self.reduce();
562 }
563 }
564
565 // a/b % c/1 = (a*1 % b*c) / (b*1) = (a % b*c) / b
566 impl<T: Clone + Integer + NumAssign> RemAssign<T> for Ratio<T> {
rem_assign(&mut self, other: T)567 fn rem_assign(&mut self, other: T) {
568 self.numer %= self.denom.clone() * other;
569 self.reduce();
570 }
571 }
572
573 // a/b - c/1 = (a*1 - b*c) / (b*1) = (a - b*c) / b
574 impl<T: Clone + Integer + NumAssign> SubAssign<T> for Ratio<T> {
sub_assign(&mut self, other: T)575 fn sub_assign(&mut self, other: T) {
576 self.numer -= self.denom.clone() * other;
577 self.reduce();
578 }
579 }
580
581 macro_rules! forward_op_assign {
582 (impl $imp:ident, $method:ident) => {
583 impl<'a, T: Clone + Integer + NumAssign> $imp<&'a Ratio<T>> for Ratio<T> {
584 #[inline]
585 fn $method(&mut self, other: &Ratio<T>) {
586 self.$method(other.clone())
587 }
588 }
589 impl<'a, T: Clone + Integer + NumAssign> $imp<&'a T> for Ratio<T> {
590 #[inline]
591 fn $method(&mut self, other: &T) {
592 self.$method(other.clone())
593 }
594 }
595 }
596 }
597
598 forward_op_assign!(impl AddAssign, add_assign);
599 forward_op_assign!(impl DivAssign, div_assign);
600 forward_op_assign!(impl MulAssign, mul_assign);
601 forward_op_assign!(impl RemAssign, rem_assign);
602 forward_op_assign!(impl SubAssign, sub_assign);
603 }
604
605 macro_rules! forward_ref_ref_binop {
606 (impl $imp:ident, $method:ident) => {
607 impl<'a, 'b, T: Clone + Integer> $imp<&'b Ratio<T>> for &'a Ratio<T> {
608 type Output = Ratio<T>;
609
610 #[inline]
611 fn $method(self, other: &'b Ratio<T>) -> Ratio<T> {
612 self.clone().$method(other.clone())
613 }
614 }
615 impl<'a, 'b, T: Clone + Integer> $imp<&'b T> for &'a Ratio<T> {
616 type Output = Ratio<T>;
617
618 #[inline]
619 fn $method(self, other: &'b T) -> Ratio<T> {
620 self.clone().$method(other.clone())
621 }
622 }
623 }
624 }
625
626 macro_rules! forward_ref_val_binop {
627 (impl $imp:ident, $method:ident) => {
628 impl<'a, T> $imp<Ratio<T>> for &'a Ratio<T> where
629 T: Clone + Integer
630 {
631 type Output = Ratio<T>;
632
633 #[inline]
634 fn $method(self, other: Ratio<T>) -> Ratio<T> {
635 self.clone().$method(other)
636 }
637 }
638 impl<'a, T> $imp<T> for &'a Ratio<T> where
639 T: Clone + Integer
640 {
641 type Output = Ratio<T>;
642
643 #[inline]
644 fn $method(self, other: T) -> Ratio<T> {
645 self.clone().$method(other)
646 }
647 }
648 }
649 }
650
651 macro_rules! forward_val_ref_binop {
652 (impl $imp:ident, $method:ident) => {
653 impl<'a, T> $imp<&'a Ratio<T>> for Ratio<T> where
654 T: Clone + Integer
655 {
656 type Output = Ratio<T>;
657
658 #[inline]
659 fn $method(self, other: &Ratio<T>) -> Ratio<T> {
660 self.$method(other.clone())
661 }
662 }
663 impl<'a, T> $imp<&'a T> for Ratio<T> where
664 T: Clone + Integer
665 {
666 type Output = Ratio<T>;
667
668 #[inline]
669 fn $method(self, other: &T) -> Ratio<T> {
670 self.$method(other.clone())
671 }
672 }
673 }
674 }
675
676 macro_rules! forward_all_binop {
677 (impl $imp:ident, $method:ident) => {
678 forward_ref_ref_binop!(impl $imp, $method);
679 forward_ref_val_binop!(impl $imp, $method);
680 forward_val_ref_binop!(impl $imp, $method);
681 };
682 }
683
684 // Arithmetic
685 forward_all_binop!(impl Mul, mul);
686 // a/b * c/d = (a*c)/(b*d)
687 impl<T> Mul<Ratio<T>> for Ratio<T>
688 where T: Clone + Integer
689 {
690 type Output = Ratio<T>;
691 #[inline]
mul(self, rhs: Ratio<T>) -> Ratio<T>692 fn mul(self, rhs: Ratio<T>) -> Ratio<T> {
693 Ratio::new(self.numer * rhs.numer,
694 self.denom * rhs.denom)
695 }
696 }
697 // a/b * c/1 = (a*c) / (b*1) = (a*c) / b
698 impl<T> Mul<T> for Ratio<T>
699 where T: Clone + Integer
700 {
701 type Output = Ratio<T>;
702 #[inline]
mul(self, rhs: T) -> Ratio<T>703 fn mul(self, rhs: T) -> Ratio<T> {
704 Ratio::new(self.numer * rhs,
705 self.denom)
706 }
707 }
708
709 forward_all_binop!(impl Div, div);
710 // (a/b) / (c/d) = (a*d) / (b*c)
711 impl<T> Div<Ratio<T>> for Ratio<T>
712 where T: Clone + Integer
713 {
714 type Output = Ratio<T>;
715
716 #[inline]
div(self, rhs: Ratio<T>) -> Ratio<T>717 fn div(self, rhs: Ratio<T>) -> Ratio<T> {
718 Ratio::new(self.numer * rhs.denom,
719 self.denom * rhs.numer)
720 }
721 }
722 // (a/b) / (c/1) = (a*1) / (b*c) = a / (b*c)
723 impl<T> Div<T> for Ratio<T>
724 where T: Clone + Integer
725 {
726 type Output = Ratio<T>;
727
728 #[inline]
div(self, rhs: T) -> Ratio<T>729 fn div(self, rhs: T) -> Ratio<T> {
730 Ratio::new(self.numer,
731 self.denom * rhs)
732 }
733 }
734
735 macro_rules! arith_impl {
736 (impl $imp:ident, $method:ident) => {
737 forward_all_binop!(impl $imp, $method);
738 // Abstracts the a/b `op` c/d = (a*d `op` b*c) / (b*d) pattern
739 impl<T: Clone + Integer> $imp<Ratio<T>> for Ratio<T> {
740 type Output = Ratio<T>;
741 #[inline]
742 fn $method(self, rhs: Ratio<T>) -> Ratio<T> {
743 Ratio::new((self.numer * rhs.denom.clone()).$method(self.denom.clone() * rhs.numer),
744 self.denom * rhs.denom)
745 }
746 }
747 // Abstracts the a/b `op` c/1 = (a*1 `op` b*c) / (b*1) = (a `op` b*c) / b pattern
748 impl<T: Clone + Integer> $imp<T> for Ratio<T> {
749 type Output = Ratio<T>;
750 #[inline]
751 fn $method(self, rhs: T) -> Ratio<T> {
752 Ratio::new(self.numer.$method(self.denom.clone() * rhs),
753 self.denom)
754 }
755 }
756 }
757 }
758
759 arith_impl!(impl Add, add);
760 arith_impl!(impl Sub, sub);
761 arith_impl!(impl Rem, rem);
762
763 // Like `std::try!` for Option<T>, unwrap the value or early-return None.
764 // Since Rust 1.22 this can be replaced by the `?` operator.
765 macro_rules! otry {
766 ($expr:expr) => (match $expr {
767 Some(val) => val,
768 None => return None,
769 })
770 }
771
772 // a/b * c/d = (a*c)/(b*d)
773 impl<T> CheckedMul for Ratio<T>
774 where T: Clone + Integer + CheckedMul
775 {
776 #[inline]
checked_mul(&self, rhs: &Ratio<T>) -> Option<Ratio<T>>777 fn checked_mul(&self, rhs: &Ratio<T>) -> Option<Ratio<T>> {
778 Some(Ratio::new(otry!(self.numer.checked_mul(&rhs.numer)),
779 otry!(self.denom.checked_mul(&rhs.denom))))
780 }
781 }
782
783 // (a/b) / (c/d) = (a*d)/(b*c)
784 impl<T> CheckedDiv for Ratio<T>
785 where T: Clone + Integer + CheckedMul
786 {
787 #[inline]
checked_div(&self, rhs: &Ratio<T>) -> Option<Ratio<T>>788 fn checked_div(&self, rhs: &Ratio<T>) -> Option<Ratio<T>> {
789 let bc = otry!(self.denom.checked_mul(&rhs.numer));
790 if bc.is_zero() {
791 None
792 } else {
793 Some(Ratio::new(otry!(self.numer.checked_mul(&rhs.denom)), bc))
794 }
795 }
796 }
797
798 // As arith_impl! but for Checked{Add,Sub} traits
799 macro_rules! checked_arith_impl {
800 (impl $imp:ident, $method:ident) => {
801 impl<T: Clone + Integer + CheckedMul + $imp> $imp for Ratio<T> {
802 #[inline]
803 fn $method(&self, rhs: &Ratio<T>) -> Option<Ratio<T>> {
804 let ad = otry!(self.numer.checked_mul(&rhs.denom));
805 let bc = otry!(self.denom.checked_mul(&rhs.numer));
806 let bd = otry!(self.denom.checked_mul(&rhs.denom));
807 Some(Ratio::new(otry!(ad.$method(&bc)), bd))
808 }
809 }
810 }
811 }
812
813 // a/b + c/d = (a*d + b*c)/(b*d)
814 checked_arith_impl!(impl CheckedAdd, checked_add);
815
816 // a/b - c/d = (a*d - b*c)/(b*d)
817 checked_arith_impl!(impl CheckedSub, checked_sub);
818
819 impl<T> Neg for Ratio<T>
820 where T: Clone + Integer + Neg<Output = T>
821 {
822 type Output = Ratio<T>;
823
824 #[inline]
neg(self) -> Ratio<T>825 fn neg(self) -> Ratio<T> {
826 Ratio::new_raw(-self.numer, self.denom)
827 }
828 }
829
830 impl<'a, T> Neg for &'a Ratio<T>
831 where T: Clone + Integer + Neg<Output = T>
832 {
833 type Output = Ratio<T>;
834
835 #[inline]
neg(self) -> Ratio<T>836 fn neg(self) -> Ratio<T> {
837 -self.clone()
838 }
839 }
840
841 impl<T> Inv for Ratio<T>
842 where T: Clone + Integer
843 {
844 type Output = Ratio<T>;
845
846 #[inline]
inv(self) -> Ratio<T>847 fn inv(self) -> Ratio<T> {
848 self.recip()
849 }
850 }
851
852 impl<'a, T> Inv for &'a Ratio<T>
853 where T: Clone + Integer
854 {
855 type Output = Ratio<T>;
856
857 #[inline]
inv(self) -> Ratio<T>858 fn inv(self) -> Ratio<T> {
859 self.recip()
860 }
861 }
862
863 // Constants
864 impl<T: Clone + Integer> Zero for Ratio<T> {
865 #[inline]
zero() -> Ratio<T>866 fn zero() -> Ratio<T> {
867 Ratio::new_raw(Zero::zero(), One::one())
868 }
869
870 #[inline]
is_zero(&self) -> bool871 fn is_zero(&self) -> bool {
872 self.numer.is_zero()
873 }
874 }
875
876 impl<T: Clone + Integer> One for Ratio<T> {
877 #[inline]
one() -> Ratio<T>878 fn one() -> Ratio<T> {
879 Ratio::new_raw(One::one(), One::one())
880 }
881
882 #[inline]
is_one(&self) -> bool883 fn is_one(&self) -> bool {
884 self.numer == self.denom
885 }
886 }
887
888 impl<T: Clone + Integer> Num for Ratio<T> {
889 type FromStrRadixErr = ParseRatioError;
890
891 /// Parses `numer/denom` where the numbers are in base `radix`.
from_str_radix(s: &str, radix: u32) -> Result<Ratio<T>, ParseRatioError>892 fn from_str_radix(s: &str, radix: u32) -> Result<Ratio<T>, ParseRatioError> {
893 if s.splitn(2, '/').count() == 2 {
894 let mut parts = s.splitn(2, '/').map(|ss| T::from_str_radix(ss, radix).map_err(|_| {
895 ParseRatioError { kind: RatioErrorKind::ParseError }
896 }));
897 let numer: T = parts.next().unwrap()?;
898 let denom: T = parts.next().unwrap()?;
899 if denom.is_zero() {
900 Err(ParseRatioError { kind: RatioErrorKind::ZeroDenominator })
901 } else {
902 Ok(Ratio::new(numer, denom))
903 }
904 } else {
905 Err(ParseRatioError { kind: RatioErrorKind::ParseError })
906 }
907 }
908 }
909
910 impl<T: Clone + Integer + Signed> Signed for Ratio<T> {
911 #[inline]
abs(&self) -> Ratio<T>912 fn abs(&self) -> Ratio<T> {
913 if self.is_negative() {
914 -self.clone()
915 } else {
916 self.clone()
917 }
918 }
919
920 #[inline]
abs_sub(&self, other: &Ratio<T>) -> Ratio<T>921 fn abs_sub(&self, other: &Ratio<T>) -> Ratio<T> {
922 if *self <= *other {
923 Zero::zero()
924 } else {
925 self - other
926 }
927 }
928
929 #[inline]
signum(&self) -> Ratio<T>930 fn signum(&self) -> Ratio<T> {
931 if self.is_positive() {
932 Self::one()
933 } else if self.is_zero() {
934 Self::zero()
935 } else {
936 -Self::one()
937 }
938 }
939
940 #[inline]
is_positive(&self) -> bool941 fn is_positive(&self) -> bool {
942 (self.numer.is_positive() && self.denom.is_positive()) ||
943 (self.numer.is_negative() && self.denom.is_negative())
944 }
945
946 #[inline]
is_negative(&self) -> bool947 fn is_negative(&self) -> bool {
948 (self.numer.is_negative() && self.denom.is_positive()) ||
949 (self.numer.is_positive() && self.denom.is_negative())
950 }
951 }
952
953 // String conversions
954 impl<T> fmt::Display for Ratio<T>
955 where T: fmt::Display + Eq + One
956 {
957 /// Renders as `numer/denom`. If denom=1, renders as numer.
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result958 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
959 if self.denom.is_one() {
960 write!(f, "{}", self.numer)
961 } else {
962 write!(f, "{}/{}", self.numer, self.denom)
963 }
964 }
965 }
966
967 impl<T: FromStr + Clone + Integer> FromStr for Ratio<T> {
968 type Err = ParseRatioError;
969
970 /// Parses `numer/denom` or just `numer`.
from_str(s: &str) -> Result<Ratio<T>, ParseRatioError>971 fn from_str(s: &str) -> Result<Ratio<T>, ParseRatioError> {
972 let mut split = s.splitn(2, '/');
973
974 let n = try!(split.next().ok_or(ParseRatioError { kind: RatioErrorKind::ParseError }));
975 let num = try!(FromStr::from_str(n)
976 .map_err(|_| ParseRatioError { kind: RatioErrorKind::ParseError }));
977
978 let d = split.next().unwrap_or("1");
979 let den = try!(FromStr::from_str(d)
980 .map_err(|_| ParseRatioError { kind: RatioErrorKind::ParseError }));
981
982 if Zero::is_zero(&den) {
983 Err(ParseRatioError { kind: RatioErrorKind::ZeroDenominator })
984 } else {
985 Ok(Ratio::new(num, den))
986 }
987 }
988 }
989
990 impl<T> Into<(T, T)> for Ratio<T> {
into(self) -> (T, T)991 fn into(self) -> (T, T) {
992 (self.numer, self.denom)
993 }
994 }
995
996 #[cfg(feature = "serde")]
997 impl<T> serde::Serialize for Ratio<T>
998 where T: serde::Serialize + Clone + Integer + PartialOrd
999 {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer1000 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1001 where S: serde::Serializer
1002 {
1003 (self.numer(), self.denom()).serialize(serializer)
1004 }
1005 }
1006
1007 #[cfg(feature = "serde")]
1008 impl<'de, T> serde::Deserialize<'de> for Ratio<T>
1009 where T: serde::Deserialize<'de> + Clone + Integer + PartialOrd
1010 {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de>1011 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1012 where D: serde::Deserializer<'de>
1013 {
1014 use serde::de::Unexpected;
1015 use serde::de::Error;
1016 let (numer, denom): (T,T) = try!(serde::Deserialize::deserialize(deserializer));
1017 if denom.is_zero() {
1018 Err(Error::invalid_value(Unexpected::Signed(0), &"a ratio with non-zero denominator"))
1019 } else {
1020 Ok(Ratio::new_raw(numer, denom))
1021 }
1022 }
1023 }
1024
1025 // FIXME: Bubble up specific errors
1026 #[derive(Copy, Clone, Debug, PartialEq)]
1027 pub struct ParseRatioError {
1028 kind: RatioErrorKind,
1029 }
1030
1031 #[derive(Copy, Clone, Debug, PartialEq)]
1032 enum RatioErrorKind {
1033 ParseError,
1034 ZeroDenominator,
1035 }
1036
1037 impl fmt::Display for ParseRatioError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1038 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1039 self.kind.description().fmt(f)
1040 }
1041 }
1042
1043 #[cfg(feature = "std")]
1044 impl Error for ParseRatioError {
description(&self) -> &str1045 fn description(&self) -> &str {
1046 self.kind.description()
1047 }
1048 }
1049
1050 impl RatioErrorKind {
description(&self) -> &'static str1051 fn description(&self) -> &'static str {
1052 match *self {
1053 RatioErrorKind::ParseError => "failed to parse integer",
1054 RatioErrorKind::ZeroDenominator => "zero value denominator",
1055 }
1056 }
1057 }
1058
1059 #[cfg(feature = "bigint")]
1060 impl FromPrimitive for Ratio<BigInt> {
from_i64(n: i64) -> Option<Self>1061 fn from_i64(n: i64) -> Option<Self> {
1062 Some(Ratio::from_integer(n.into()))
1063 }
1064
1065 #[cfg(has_i128)]
from_i128(n: i128) -> Option<Self>1066 fn from_i128(n: i128) -> Option<Self> {
1067 Some(Ratio::from_integer(n.into()))
1068 }
1069
from_u64(n: u64) -> Option<Self>1070 fn from_u64(n: u64) -> Option<Self> {
1071 Some(Ratio::from_integer(n.into()))
1072 }
1073
1074 #[cfg(has_i128)]
from_u128(n: u128) -> Option<Self>1075 fn from_u128(n: u128) -> Option<Self> {
1076 Some(Ratio::from_integer(n.into()))
1077 }
1078
from_f32(n: f32) -> Option<Self>1079 fn from_f32(n: f32) -> Option<Self> {
1080 Ratio::from_float(n)
1081 }
1082
from_f64(n: f64) -> Option<Self>1083 fn from_f64(n: f64) -> Option<Self> {
1084 Ratio::from_float(n)
1085 }
1086 }
1087
1088 macro_rules! from_primitive_integer {
1089 ($typ:ty, $approx:ident) => {
1090 impl FromPrimitive for Ratio<$typ> {
1091 fn from_i64(n: i64) -> Option<Self> {
1092 <$typ as FromPrimitive>::from_i64(n).map(Ratio::from_integer)
1093 }
1094
1095 #[cfg(has_i128)]
1096 fn from_i128(n: i128) -> Option<Self> {
1097 <$typ as FromPrimitive>::from_i128(n).map(Ratio::from_integer)
1098 }
1099
1100 fn from_u64(n: u64) -> Option<Self> {
1101 <$typ as FromPrimitive>::from_u64(n).map(Ratio::from_integer)
1102 }
1103
1104 #[cfg(has_i128)]
1105 fn from_u128(n: u128) -> Option<Self> {
1106 <$typ as FromPrimitive>::from_u128(n).map(Ratio::from_integer)
1107 }
1108
1109 fn from_f32(n: f32) -> Option<Self> {
1110 $approx(n, 10e-20, 30)
1111 }
1112
1113 fn from_f64(n: f64) -> Option<Self> {
1114 $approx(n, 10e-20, 30)
1115 }
1116 }
1117 }
1118 }
1119
1120 from_primitive_integer!(i8, approximate_float);
1121 from_primitive_integer!(i16, approximate_float);
1122 from_primitive_integer!(i32, approximate_float);
1123 from_primitive_integer!(i64, approximate_float);
1124 #[cfg(has_i128)]
1125 from_primitive_integer!(i128, approximate_float);
1126 from_primitive_integer!(isize, approximate_float);
1127
1128 from_primitive_integer!(u8, approximate_float_unsigned);
1129 from_primitive_integer!(u16, approximate_float_unsigned);
1130 from_primitive_integer!(u32, approximate_float_unsigned);
1131 from_primitive_integer!(u64, approximate_float_unsigned);
1132 #[cfg(has_i128)]
1133 from_primitive_integer!(u128, approximate_float_unsigned);
1134 from_primitive_integer!(usize, approximate_float_unsigned);
1135
1136 impl<T: Integer + Signed + Bounded + NumCast + Clone> Ratio<T> {
approximate_float<F: FloatCore + NumCast>(f: F) -> Option<Ratio<T>>1137 pub fn approximate_float<F: FloatCore + NumCast>(f: F) -> Option<Ratio<T>> {
1138 // 1/10e-20 < 1/2**32 which seems like a good default, and 30 seems
1139 // to work well. Might want to choose something based on the types in the future, e.g.
1140 // T::max().recip() and T::bits() or something similar.
1141 let epsilon = <F as NumCast>::from(10e-20).expect("Can't convert 10e-20");
1142 approximate_float(f, epsilon, 30)
1143 }
1144 }
1145
approximate_float<T, F>(val: F, max_error: F, max_iterations: usize) -> Option<Ratio<T>> where T: Integer + Signed + Bounded + NumCast + Clone, F: FloatCore + NumCast1146 fn approximate_float<T, F>(val: F, max_error: F, max_iterations: usize) -> Option<Ratio<T>>
1147 where T: Integer + Signed + Bounded + NumCast + Clone,
1148 F: FloatCore + NumCast
1149 {
1150 let negative = val.is_sign_negative();
1151 let abs_val = val.abs();
1152
1153 let r = approximate_float_unsigned(abs_val, max_error, max_iterations);
1154
1155 // Make negative again if needed
1156 if negative {
1157 r.map(|r| r.neg())
1158 } else {
1159 r
1160 }
1161 }
1162
1163 // No Unsigned constraint because this also works on positive integers and is called
1164 // like that, see above
approximate_float_unsigned<T, F>(val: F, max_error: F, max_iterations: usize) -> Option<Ratio<T>> where T: Integer + Bounded + NumCast + Clone, F: FloatCore + NumCast1165 fn approximate_float_unsigned<T, F>(val: F, max_error: F, max_iterations: usize) -> Option<Ratio<T>>
1166 where T: Integer + Bounded + NumCast + Clone,
1167 F: FloatCore + NumCast
1168 {
1169 // Continued fractions algorithm
1170 // http://mathforum.org/dr.math/faq/faq.fractions.html#decfrac
1171
1172 if val < F::zero() || val.is_nan() {
1173 return None;
1174 }
1175
1176 let mut q = val;
1177 let mut n0 = T::zero();
1178 let mut d0 = T::one();
1179 let mut n1 = T::one();
1180 let mut d1 = T::zero();
1181
1182 let t_max = T::max_value();
1183 let t_max_f = match <F as NumCast>::from(t_max.clone()) {
1184 None => return None,
1185 Some(t_max_f) => t_max_f,
1186 };
1187
1188 // 1/epsilon > T::MAX
1189 let epsilon = t_max_f.recip();
1190
1191 // Overflow
1192 if q > t_max_f {
1193 return None;
1194 }
1195
1196 for _ in 0..max_iterations {
1197 let a = match <T as NumCast>::from(q) {
1198 None => break,
1199 Some(a) => a,
1200 };
1201
1202 let a_f = match <F as NumCast>::from(a.clone()) {
1203 None => break,
1204 Some(a_f) => a_f,
1205 };
1206 let f = q - a_f;
1207
1208 // Prevent overflow
1209 if !a.is_zero() &&
1210 (n1 > t_max.clone() / a.clone() ||
1211 d1 > t_max.clone() / a.clone() ||
1212 a.clone() * n1.clone() > t_max.clone() - n0.clone() ||
1213 a.clone() * d1.clone() > t_max.clone() - d0.clone()) {
1214 break;
1215 }
1216
1217 let n = a.clone() * n1.clone() + n0.clone();
1218 let d = a.clone() * d1.clone() + d0.clone();
1219
1220 n0 = n1;
1221 d0 = d1;
1222 n1 = n.clone();
1223 d1 = d.clone();
1224
1225 // Simplify fraction. Doing so here instead of at the end
1226 // allows us to get closer to the target value without overflows
1227 let g = Integer::gcd(&n1, &d1);
1228 if !g.is_zero() {
1229 n1 = n1 / g.clone();
1230 d1 = d1 / g.clone();
1231 }
1232
1233 // Close enough?
1234 let (n_f, d_f) = match (<F as NumCast>::from(n), <F as NumCast>::from(d)) {
1235 (Some(n_f), Some(d_f)) => (n_f, d_f),
1236 _ => break,
1237 };
1238 if (n_f / d_f - val).abs() < max_error {
1239 break;
1240 }
1241
1242 // Prevent division by ~0
1243 if f < epsilon {
1244 break;
1245 }
1246 q = f.recip();
1247 }
1248
1249 // Overflow
1250 if d1.is_zero() {
1251 return None;
1252 }
1253
1254 Some(Ratio::new(n1, d1))
1255 }
1256
1257 #[cfg(test)]
1258 #[cfg(feature = "std")]
hash<T: Hash>(x: &T) -> u641259 fn hash<T: Hash>(x: &T) -> u64 {
1260 use std::hash::BuildHasher;
1261 use std::collections::hash_map::RandomState;
1262 let mut hasher = <RandomState as BuildHasher>::Hasher::new();
1263 x.hash(&mut hasher);
1264 hasher.finish()
1265 }
1266
1267 #[cfg(test)]
1268 mod test {
1269 use super::{Ratio, Rational};
1270 #[cfg(feature = "bigint")]
1271 use super::BigRational;
1272
1273 use core::str::FromStr;
1274 use core::i32;
1275 use core::f64;
1276 use traits::{Zero, One, Signed, FromPrimitive, Pow};
1277 use integer::Integer;
1278
1279 pub const _0: Rational = Ratio {
1280 numer: 0,
1281 denom: 1,
1282 };
1283 pub const _1: Rational = Ratio {
1284 numer: 1,
1285 denom: 1,
1286 };
1287 pub const _2: Rational = Ratio {
1288 numer: 2,
1289 denom: 1,
1290 };
1291 pub const _NEG2: Rational = Ratio {
1292 numer: -2,
1293 denom: 1,
1294 };
1295 pub const _1_2: Rational = Ratio {
1296 numer: 1,
1297 denom: 2,
1298 };
1299 pub const _3_2: Rational = Ratio {
1300 numer: 3,
1301 denom: 2,
1302 };
1303 pub const _NEG1_2: Rational = Ratio {
1304 numer: -1,
1305 denom: 2,
1306 };
1307 pub const _1_NEG2: Rational = Ratio {
1308 numer: 1,
1309 denom: -2,
1310 };
1311 pub const _NEG1_NEG2: Rational = Ratio {
1312 numer: -1,
1313 denom: -2,
1314 };
1315 pub const _1_3: Rational = Ratio {
1316 numer: 1,
1317 denom: 3,
1318 };
1319 pub const _NEG1_3: Rational = Ratio {
1320 numer: -1,
1321 denom: 3,
1322 };
1323 pub const _2_3: Rational = Ratio {
1324 numer: 2,
1325 denom: 3,
1326 };
1327 pub const _NEG2_3: Rational = Ratio {
1328 numer: -2,
1329 denom: 3,
1330 };
1331
1332 #[cfg(feature = "bigint")]
to_big(n: Rational) -> BigRational1333 pub fn to_big(n: Rational) -> BigRational {
1334 Ratio::new(FromPrimitive::from_isize(n.numer).unwrap(),
1335 FromPrimitive::from_isize(n.denom).unwrap())
1336 }
1337 #[cfg(not(feature = "bigint"))]
to_big(n: Rational) -> Rational1338 pub fn to_big(n: Rational) -> Rational {
1339 Ratio::new(FromPrimitive::from_isize(n.numer).unwrap(),
1340 FromPrimitive::from_isize(n.denom).unwrap())
1341 }
1342
1343 #[test]
test_test_constants()1344 fn test_test_constants() {
1345 // check our constants are what Ratio::new etc. would make.
1346 assert_eq!(_0, Zero::zero());
1347 assert_eq!(_1, One::one());
1348 assert_eq!(_2, Ratio::from_integer(2));
1349 assert_eq!(_1_2, Ratio::new(1, 2));
1350 assert_eq!(_3_2, Ratio::new(3, 2));
1351 assert_eq!(_NEG1_2, Ratio::new(-1, 2));
1352 assert_eq!(_2, From::from(2));
1353 }
1354
1355 #[test]
test_new_reduce()1356 fn test_new_reduce() {
1357 let one22 = Ratio::new(2, 2);
1358
1359 assert_eq!(one22, One::one());
1360 }
1361 #[test]
1362 #[should_panic]
test_new_zero()1363 fn test_new_zero() {
1364 let _a = Ratio::new(1, 0);
1365 }
1366
1367 #[test]
test_approximate_float()1368 fn test_approximate_float() {
1369 assert_eq!(Ratio::from_f32(0.5f32), Some(Ratio::new(1i64, 2)));
1370 assert_eq!(Ratio::from_f64(0.5f64), Some(Ratio::new(1i32, 2)));
1371 assert_eq!(Ratio::from_f32(5f32), Some(Ratio::new(5i64, 1)));
1372 assert_eq!(Ratio::from_f64(5f64), Some(Ratio::new(5i32, 1)));
1373 assert_eq!(Ratio::from_f32(29.97f32), Some(Ratio::new(2997i64, 100)));
1374 assert_eq!(Ratio::from_f32(-29.97f32), Some(Ratio::new(-2997i64, 100)));
1375
1376 assert_eq!(Ratio::<i8>::from_f32(63.5f32), Some(Ratio::new(127i8, 2)));
1377 assert_eq!(Ratio::<i8>::from_f32(126.5f32), Some(Ratio::new(126i8, 1)));
1378 assert_eq!(Ratio::<i8>::from_f32(127.0f32), Some(Ratio::new(127i8, 1)));
1379 assert_eq!(Ratio::<i8>::from_f32(127.5f32), None);
1380 assert_eq!(Ratio::<i8>::from_f32(-63.5f32), Some(Ratio::new(-127i8, 2)));
1381 assert_eq!(Ratio::<i8>::from_f32(-126.5f32), Some(Ratio::new(-126i8, 1)));
1382 assert_eq!(Ratio::<i8>::from_f32(-127.0f32), Some(Ratio::new(-127i8, 1)));
1383 assert_eq!(Ratio::<i8>::from_f32(-127.5f32), None);
1384
1385 assert_eq!(Ratio::<u8>::from_f32(-127f32), None);
1386 assert_eq!(Ratio::<u8>::from_f32(127f32), Some(Ratio::new(127u8, 1)));
1387 assert_eq!(Ratio::<u8>::from_f32(127.5f32), Some(Ratio::new(255u8, 2)));
1388 assert_eq!(Ratio::<u8>::from_f32(256f32), None);
1389
1390 assert_eq!(Ratio::<i64>::from_f64(-10e200), None);
1391 assert_eq!(Ratio::<i64>::from_f64(10e200), None);
1392 assert_eq!(Ratio::<i64>::from_f64(f64::INFINITY), None);
1393 assert_eq!(Ratio::<i64>::from_f64(f64::NEG_INFINITY), None);
1394 assert_eq!(Ratio::<i64>::from_f64(f64::NAN), None);
1395 assert_eq!(Ratio::<i64>::from_f64(f64::EPSILON), Some(Ratio::new(1, 4503599627370496)));
1396 assert_eq!(Ratio::<i64>::from_f64(0.0), Some(Ratio::new(0, 1)));
1397 assert_eq!(Ratio::<i64>::from_f64(-0.0), Some(Ratio::new(0, 1)));
1398 }
1399
1400 #[test]
test_cmp()1401 fn test_cmp() {
1402 assert!(_0 == _0 && _1 == _1);
1403 assert!(_0 != _1 && _1 != _0);
1404 assert!(_0 < _1 && !(_1 < _0));
1405 assert!(_1 > _0 && !(_0 > _1));
1406
1407 assert!(_0 <= _0 && _1 <= _1);
1408 assert!(_0 <= _1 && !(_1 <= _0));
1409
1410 assert!(_0 >= _0 && _1 >= _1);
1411 assert!(_1 >= _0 && !(_0 >= _1));
1412 }
1413
1414 #[test]
test_cmp_overflow()1415 fn test_cmp_overflow() {
1416 use core::cmp::Ordering;
1417
1418 // issue #7 example:
1419 let big = Ratio::new(128u8, 1);
1420 let small = big.recip();
1421 assert!(big > small);
1422
1423 // try a few that are closer together
1424 // (some matching numer, some matching denom, some neither)
1425 let ratios = [
1426 Ratio::new(125_i8, 127_i8),
1427 Ratio::new(63_i8, 64_i8),
1428 Ratio::new(124_i8, 125_i8),
1429 Ratio::new(125_i8, 126_i8),
1430 Ratio::new(126_i8, 127_i8),
1431 Ratio::new(127_i8, 126_i8),
1432 ];
1433
1434 fn check_cmp(a: Ratio<i8>, b: Ratio<i8>, ord: Ordering) {
1435 #[cfg(feature = "std")]
1436 println!("comparing {} and {}", a, b);
1437 assert_eq!(a.cmp(&b), ord);
1438 assert_eq!(b.cmp(&a), ord.reverse());
1439 }
1440
1441 for (i, &a) in ratios.iter().enumerate() {
1442 check_cmp(a, a, Ordering::Equal);
1443 check_cmp(-a, a, Ordering::Less);
1444 for &b in &ratios[i + 1..] {
1445 check_cmp(a, b, Ordering::Less);
1446 check_cmp(-a, -b, Ordering::Greater);
1447 check_cmp(a.recip(), b.recip(), Ordering::Greater);
1448 check_cmp(-a.recip(), -b.recip(), Ordering::Less);
1449 }
1450 }
1451 }
1452
1453 #[test]
test_to_integer()1454 fn test_to_integer() {
1455 assert_eq!(_0.to_integer(), 0);
1456 assert_eq!(_1.to_integer(), 1);
1457 assert_eq!(_2.to_integer(), 2);
1458 assert_eq!(_1_2.to_integer(), 0);
1459 assert_eq!(_3_2.to_integer(), 1);
1460 assert_eq!(_NEG1_2.to_integer(), 0);
1461 }
1462
1463
1464 #[test]
test_numer()1465 fn test_numer() {
1466 assert_eq!(_0.numer(), &0);
1467 assert_eq!(_1.numer(), &1);
1468 assert_eq!(_2.numer(), &2);
1469 assert_eq!(_1_2.numer(), &1);
1470 assert_eq!(_3_2.numer(), &3);
1471 assert_eq!(_NEG1_2.numer(), &(-1));
1472 }
1473 #[test]
test_denom()1474 fn test_denom() {
1475 assert_eq!(_0.denom(), &1);
1476 assert_eq!(_1.denom(), &1);
1477 assert_eq!(_2.denom(), &1);
1478 assert_eq!(_1_2.denom(), &2);
1479 assert_eq!(_3_2.denom(), &2);
1480 assert_eq!(_NEG1_2.denom(), &2);
1481 }
1482
1483
1484 #[test]
test_is_integer()1485 fn test_is_integer() {
1486 assert!(_0.is_integer());
1487 assert!(_1.is_integer());
1488 assert!(_2.is_integer());
1489 assert!(!_1_2.is_integer());
1490 assert!(!_3_2.is_integer());
1491 assert!(!_NEG1_2.is_integer());
1492 }
1493
1494 #[test]
1495 #[cfg(feature = "std")]
test_show()1496 fn test_show() {
1497 use std::string::ToString;
1498 assert_eq!(format!("{}", _2), "2".to_string());
1499 assert_eq!(format!("{}", _1_2), "1/2".to_string());
1500 assert_eq!(format!("{}", _0), "0".to_string());
1501 assert_eq!(format!("{}", Ratio::from_integer(-2)), "-2".to_string());
1502 }
1503
1504 mod arith {
1505 use super::{_0, _1, _2, _1_2, _3_2, _NEG1_2, to_big};
1506 use super::super::{Ratio, Rational};
1507 use traits::{CheckedAdd, CheckedSub, CheckedMul, CheckedDiv};
1508
1509 #[test]
test_add()1510 fn test_add() {
1511 fn test(a: Rational, b: Rational, c: Rational) {
1512 assert_eq!(a + b, c);
1513 assert_eq!({ let mut x = a; x += b; x}, c);
1514 assert_eq!(to_big(a) + to_big(b), to_big(c));
1515 assert_eq!(a.checked_add(&b), Some(c));
1516 assert_eq!(to_big(a).checked_add(&to_big(b)), Some(to_big(c)));
1517 }
1518 fn test_assign(a: Rational, b: isize, c: Rational) {
1519 assert_eq!(a + b, c);
1520 assert_eq!({ let mut x = a; x += b; x}, c);
1521 }
1522
1523 test(_1, _1_2, _3_2);
1524 test(_1, _1, _2);
1525 test(_1_2, _3_2, _2);
1526 test(_1_2, _NEG1_2, _0);
1527 test_assign(_1_2, 1, _3_2);
1528 }
1529
1530 #[test]
test_sub()1531 fn test_sub() {
1532 fn test(a: Rational, b: Rational, c: Rational) {
1533 assert_eq!(a - b, c);
1534 assert_eq!({ let mut x = a; x -= b; x}, c);
1535 assert_eq!(to_big(a) - to_big(b), to_big(c));
1536 assert_eq!(a.checked_sub(&b), Some(c));
1537 assert_eq!(to_big(a).checked_sub(&to_big(b)), Some(to_big(c)));
1538 }
1539 fn test_assign(a: Rational, b: isize, c: Rational) {
1540 assert_eq!(a - b, c);
1541 assert_eq!({ let mut x = a; x -= b; x}, c);
1542 }
1543
1544 test(_1, _1_2, _1_2);
1545 test(_3_2, _1_2, _1);
1546 test(_1, _NEG1_2, _3_2);
1547 test_assign(_1_2, 1, _NEG1_2);
1548 }
1549
1550 #[test]
test_mul()1551 fn test_mul() {
1552 fn test(a: Rational, b: Rational, c: Rational) {
1553 assert_eq!(a * b, c);
1554 assert_eq!({ let mut x = a; x *= b; x}, c);
1555 assert_eq!(to_big(a) * to_big(b), to_big(c));
1556 assert_eq!(a.checked_mul(&b), Some(c));
1557 assert_eq!(to_big(a).checked_mul(&to_big(b)), Some(to_big(c)));
1558 }
1559 fn test_assign(a: Rational, b: isize, c: Rational) {
1560 assert_eq!(a * b, c);
1561 assert_eq!({ let mut x = a; x *= b; x}, c);
1562 }
1563
1564 test(_1, _1_2, _1_2);
1565 test(_1_2, _3_2, Ratio::new(3, 4));
1566 test(_1_2, _NEG1_2, Ratio::new(-1, 4));
1567 test_assign(_1_2, 2, _1);
1568 }
1569
1570 #[test]
test_div()1571 fn test_div() {
1572 fn test(a: Rational, b: Rational, c: Rational) {
1573 assert_eq!(a / b, c);
1574 assert_eq!({ let mut x = a; x /= b; x}, c);
1575 assert_eq!(to_big(a) / to_big(b), to_big(c));
1576 assert_eq!(a.checked_div(&b), Some(c));
1577 assert_eq!(to_big(a).checked_div(&to_big(b)), Some(to_big(c)));
1578 }
1579 fn test_assign(a: Rational, b: isize, c: Rational) {
1580 assert_eq!(a / b, c);
1581 assert_eq!({ let mut x = a; x /= b; x}, c);
1582 }
1583
1584 test(_1, _1_2, _2);
1585 test(_3_2, _1_2, _1 + _2);
1586 test(_1, _NEG1_2, _NEG1_2 + _NEG1_2 + _NEG1_2 + _NEG1_2);
1587 test_assign(_1, 2, _1_2);
1588 }
1589
1590 #[test]
test_rem()1591 fn test_rem() {
1592 fn test(a: Rational, b: Rational, c: Rational) {
1593 assert_eq!(a % b, c);
1594 assert_eq!({ let mut x = a; x %= b; x}, c);
1595 assert_eq!(to_big(a) % to_big(b), to_big(c))
1596 }
1597 fn test_assign(a: Rational, b: isize, c: Rational) {
1598 assert_eq!(a % b, c);
1599 assert_eq!({ let mut x = a; x %= b; x}, c);
1600 }
1601
1602 test(_3_2, _1, _1_2);
1603 test(_2, _NEG1_2, _0);
1604 test(_1_2, _2, _1_2);
1605 test_assign(_3_2, 1, _1_2);
1606 }
1607
1608 #[test]
test_neg()1609 fn test_neg() {
1610 fn test(a: Rational, b: Rational) {
1611 assert_eq!(-a, b);
1612 assert_eq!(-to_big(a), to_big(b))
1613 }
1614
1615 test(_0, _0);
1616 test(_1_2, _NEG1_2);
1617 test(-_1, _1);
1618 }
1619 #[test]
test_zero()1620 fn test_zero() {
1621 assert_eq!(_0 + _0, _0);
1622 assert_eq!(_0 * _0, _0);
1623 assert_eq!(_0 * _1, _0);
1624 assert_eq!(_0 / _NEG1_2, _0);
1625 assert_eq!(_0 - _0, _0);
1626 }
1627 #[test]
1628 #[should_panic]
test_div_0()1629 fn test_div_0() {
1630 let _a = _1 / _0;
1631 }
1632
1633 #[test]
test_checked_failures()1634 fn test_checked_failures() {
1635 let big = Ratio::new(128u8, 1);
1636 let small = Ratio::new(1, 128u8);
1637 assert_eq!(big.checked_add(&big), None);
1638 assert_eq!(small.checked_sub(&big), None);
1639 assert_eq!(big.checked_mul(&big), None);
1640 assert_eq!(small.checked_div(&big), None);
1641 assert_eq!(_1.checked_div(&_0), None);
1642 }
1643 }
1644
1645 #[test]
test_round()1646 fn test_round() {
1647 assert_eq!(_1_3.ceil(), _1);
1648 assert_eq!(_1_3.floor(), _0);
1649 assert_eq!(_1_3.round(), _0);
1650 assert_eq!(_1_3.trunc(), _0);
1651
1652 assert_eq!(_NEG1_3.ceil(), _0);
1653 assert_eq!(_NEG1_3.floor(), -_1);
1654 assert_eq!(_NEG1_3.round(), _0);
1655 assert_eq!(_NEG1_3.trunc(), _0);
1656
1657 assert_eq!(_2_3.ceil(), _1);
1658 assert_eq!(_2_3.floor(), _0);
1659 assert_eq!(_2_3.round(), _1);
1660 assert_eq!(_2_3.trunc(), _0);
1661
1662 assert_eq!(_NEG2_3.ceil(), _0);
1663 assert_eq!(_NEG2_3.floor(), -_1);
1664 assert_eq!(_NEG2_3.round(), -_1);
1665 assert_eq!(_NEG2_3.trunc(), _0);
1666
1667 assert_eq!(_1_2.ceil(), _1);
1668 assert_eq!(_1_2.floor(), _0);
1669 assert_eq!(_1_2.round(), _1);
1670 assert_eq!(_1_2.trunc(), _0);
1671
1672 assert_eq!(_NEG1_2.ceil(), _0);
1673 assert_eq!(_NEG1_2.floor(), -_1);
1674 assert_eq!(_NEG1_2.round(), -_1);
1675 assert_eq!(_NEG1_2.trunc(), _0);
1676
1677 assert_eq!(_1.ceil(), _1);
1678 assert_eq!(_1.floor(), _1);
1679 assert_eq!(_1.round(), _1);
1680 assert_eq!(_1.trunc(), _1);
1681
1682 // Overflow checks
1683
1684 let _neg1 = Ratio::from_integer(-1);
1685 let _large_rat1 = Ratio::new(i32::MAX, i32::MAX - 1);
1686 let _large_rat2 = Ratio::new(i32::MAX - 1, i32::MAX);
1687 let _large_rat3 = Ratio::new(i32::MIN + 2, i32::MIN + 1);
1688 let _large_rat4 = Ratio::new(i32::MIN + 1, i32::MIN + 2);
1689 let _large_rat5 = Ratio::new(i32::MIN + 2, i32::MAX);
1690 let _large_rat6 = Ratio::new(i32::MAX, i32::MIN + 2);
1691 let _large_rat7 = Ratio::new(1, i32::MIN + 1);
1692 let _large_rat8 = Ratio::new(1, i32::MAX);
1693
1694 assert_eq!(_large_rat1.round(), One::one());
1695 assert_eq!(_large_rat2.round(), One::one());
1696 assert_eq!(_large_rat3.round(), One::one());
1697 assert_eq!(_large_rat4.round(), One::one());
1698 assert_eq!(_large_rat5.round(), _neg1);
1699 assert_eq!(_large_rat6.round(), _neg1);
1700 assert_eq!(_large_rat7.round(), Zero::zero());
1701 assert_eq!(_large_rat8.round(), Zero::zero());
1702 }
1703
1704 #[test]
test_fract()1705 fn test_fract() {
1706 assert_eq!(_1.fract(), _0);
1707 assert_eq!(_NEG1_2.fract(), _NEG1_2);
1708 assert_eq!(_1_2.fract(), _1_2);
1709 assert_eq!(_3_2.fract(), _1_2);
1710 }
1711
1712 #[test]
test_recip()1713 fn test_recip() {
1714 assert_eq!(_1 * _1.recip(), _1);
1715 assert_eq!(_2 * _2.recip(), _1);
1716 assert_eq!(_1_2 * _1_2.recip(), _1);
1717 assert_eq!(_3_2 * _3_2.recip(), _1);
1718 assert_eq!(_NEG1_2 * _NEG1_2.recip(), _1);
1719
1720 assert_eq!(_3_2.recip(), _2_3);
1721 assert_eq!(_NEG1_2.recip(), _NEG2);
1722 assert_eq!(_NEG1_2.recip().denom(), &1);
1723 }
1724
1725 #[test]
1726 #[should_panic(expected = "== 0")]
test_recip_fail()1727 fn test_recip_fail() {
1728 let _a = Ratio::new(0, 1).recip();
1729 }
1730
1731 #[test]
test_pow()1732 fn test_pow() {
1733 fn test(r: Rational, e: i32, expected: Rational) {
1734 assert_eq!(r.pow(e), expected);
1735 assert_eq!(Pow::pow(r, e), expected);
1736 assert_eq!(Pow::pow(r, &e), expected);
1737 assert_eq!(Pow::pow(&r, e), expected);
1738 assert_eq!(Pow::pow(&r, &e), expected);
1739 }
1740
1741 test(_1_2, 2, Ratio::new(1, 4));
1742 test(_1_2, -2, Ratio::new(4, 1));
1743 test(_1, 1, _1);
1744 test(_1, i32::MAX, _1);
1745 test(_1, i32::MIN, _1);
1746 test(_NEG1_2, 2, _1_2.pow(2i32));
1747 test(_NEG1_2, 3, -_1_2.pow(3i32));
1748 test(_3_2, 0, _1);
1749 test(_3_2, -1, _3_2.recip());
1750 test(_3_2, 3, Ratio::new(27, 8));
1751 }
1752
1753 #[test]
1754 #[cfg(feature = "std")]
test_to_from_str()1755 fn test_to_from_str() {
1756 use std::string::{String, ToString};
1757 fn test(r: Rational, s: String) {
1758 assert_eq!(FromStr::from_str(&s), Ok(r));
1759 assert_eq!(r.to_string(), s);
1760 }
1761 test(_1, "1".to_string());
1762 test(_0, "0".to_string());
1763 test(_1_2, "1/2".to_string());
1764 test(_3_2, "3/2".to_string());
1765 test(_2, "2".to_string());
1766 test(_NEG1_2, "-1/2".to_string());
1767 }
1768 #[test]
test_from_str_fail()1769 fn test_from_str_fail() {
1770 fn test(s: &str) {
1771 let rational: Result<Rational, _> = FromStr::from_str(s);
1772 assert!(rational.is_err());
1773 }
1774
1775 let xs = ["0 /1", "abc", "", "1/", "--1/2", "3/2/1", "1/0"];
1776 for &s in xs.iter() {
1777 test(s);
1778 }
1779 }
1780
1781 #[cfg(feature = "bigint")]
1782 #[test]
test_from_float()1783 fn test_from_float() {
1784 use traits::float::FloatCore;
1785 fn test<T: FloatCore>(given: T, (numer, denom): (&str, &str)) {
1786 let ratio: BigRational = Ratio::from_float(given).unwrap();
1787 assert_eq!(ratio,
1788 Ratio::new(FromStr::from_str(numer).unwrap(),
1789 FromStr::from_str(denom).unwrap()));
1790 }
1791
1792 // f32
1793 test(3.14159265359f32, ("13176795", "4194304"));
1794 test(2f32.powf(100.), ("1267650600228229401496703205376", "1"));
1795 test(-2f32.powf(100.), ("-1267650600228229401496703205376", "1"));
1796 test(1.0 / 2f32.powf(100.),
1797 ("1", "1267650600228229401496703205376"));
1798 test(684729.48391f32, ("1369459", "2"));
1799 test(-8573.5918555f32, ("-4389679", "512"));
1800
1801 // f64
1802 test(3.14159265359f64, ("3537118876014453", "1125899906842624"));
1803 test(2f64.powf(100.), ("1267650600228229401496703205376", "1"));
1804 test(-2f64.powf(100.), ("-1267650600228229401496703205376", "1"));
1805 test(684729.48391f64, ("367611342500051", "536870912"));
1806 test(-8573.5918555f64, ("-4713381968463931", "549755813888"));
1807 test(1.0 / 2f64.powf(100.),
1808 ("1", "1267650600228229401496703205376"));
1809 }
1810
1811 #[cfg(feature = "bigint")]
1812 #[test]
test_from_float_fail()1813 fn test_from_float_fail() {
1814 use core::{f32, f64};
1815
1816 assert_eq!(Ratio::from_float(f32::NAN), None);
1817 assert_eq!(Ratio::from_float(f32::INFINITY), None);
1818 assert_eq!(Ratio::from_float(f32::NEG_INFINITY), None);
1819 assert_eq!(Ratio::from_float(f64::NAN), None);
1820 assert_eq!(Ratio::from_float(f64::INFINITY), None);
1821 assert_eq!(Ratio::from_float(f64::NEG_INFINITY), None);
1822 }
1823
1824 #[test]
test_signed()1825 fn test_signed() {
1826 assert_eq!(_NEG1_2.abs(), _1_2);
1827 assert_eq!(_3_2.abs_sub(&_1_2), _1);
1828 assert_eq!(_1_2.abs_sub(&_3_2), Zero::zero());
1829 assert_eq!(_1_2.signum(), One::one());
1830 assert_eq!(_NEG1_2.signum(), -<Ratio<isize>>::one());
1831 assert_eq!(_0.signum(), Zero::zero());
1832 assert!(_NEG1_2.is_negative());
1833 assert!(_1_NEG2.is_negative());
1834 assert!(!_NEG1_2.is_positive());
1835 assert!(!_1_NEG2.is_positive());
1836 assert!(_1_2.is_positive());
1837 assert!(_NEG1_NEG2.is_positive());
1838 assert!(!_1_2.is_negative());
1839 assert!(!_NEG1_NEG2.is_negative());
1840 assert!(!_0.is_positive());
1841 assert!(!_0.is_negative());
1842 }
1843
1844 #[test]
1845 #[cfg(feature = "std")]
test_hash()1846 fn test_hash() {
1847 assert!(::hash(&_0) != ::hash(&_1));
1848 assert!(::hash(&_0) != ::hash(&_3_2));
1849
1850 // a == b -> hash(a) == hash(b)
1851 let a = Rational::new_raw(4, 2);
1852 let b = Rational::new_raw(6, 3);
1853 assert_eq!(a, b);
1854 assert_eq!(::hash(&a), ::hash(&b));
1855
1856 let a = Rational::new_raw(123456789, 1000);
1857 let b = Rational::new_raw(123456789 * 5, 5000);
1858 assert_eq!(a, b);
1859 assert_eq!(::hash(&a), ::hash(&b));
1860 }
1861
1862 #[test]
test_into_pair()1863 fn test_into_pair() {
1864 assert_eq! ((0, 1), _0.into());
1865 assert_eq! ((-2, 1), _NEG2.into());
1866 assert_eq! ((1, -2), _1_NEG2.into());
1867 }
1868
1869 #[test]
test_from_pair()1870 fn test_from_pair() {
1871 assert_eq! (_0, Ratio::from ((0, 1)));
1872 assert_eq! (_1, Ratio::from ((1, 1)));
1873 assert_eq! (_NEG2, Ratio::from ((-2, 1)));
1874 assert_eq! (_1_NEG2, Ratio::from ((1, -2)));
1875 }
1876
1877 #[test]
ratio_iter_sum()1878 fn ratio_iter_sum() {
1879 // generic function to assure the iter method can be called
1880 // for any Iterator with Item = Ratio<impl Integer> or Ratio<&impl Integer>
1881 fn iter_sums<T: Integer + Clone>(slice: &[Ratio<T>]) -> [Ratio<T>; 3] {
1882 let mut manual_sum = Ratio::new(T::zero(), T::one());
1883 for ratio in slice {
1884 manual_sum = manual_sum + ratio;
1885 }
1886 [
1887 manual_sum,
1888 slice.iter().sum(),
1889 slice.iter().cloned().sum()
1890 ]
1891 }
1892 // collect into array so test works on no_std
1893 let mut nums = [Ratio::new(0,1); 1000];
1894 for (i, r) in (0..1000).map(|n| Ratio::new(n, 500)).enumerate() {
1895 nums[i] = r;
1896 }
1897 let sums = iter_sums(&nums[..]);
1898 assert_eq!(sums[0], sums[1]);
1899 assert_eq!(sums[0], sums[2]);
1900 }
1901
1902 #[test]
ratio_iter_product()1903 fn ratio_iter_product() {
1904 // generic function to assure the iter method can be called
1905 // for any Iterator with Item = Ratio<impl Integer> or Ratio<&impl Integer>
1906 fn iter_products<T: Integer + Clone>(slice: &[Ratio<T>]) -> [Ratio<T>; 3] {
1907 let mut manual_prod = Ratio::new(T::one(), T::one());
1908 for ratio in slice {
1909 manual_prod = manual_prod * ratio;
1910 }
1911 [
1912 manual_prod,
1913 slice.iter().product(),
1914 slice.iter().cloned().product()
1915 ]
1916 }
1917
1918 // collect into array so test works on no_std
1919 let mut nums = [Ratio::new(0,1); 1000];
1920 for (i, r) in (0..1000).map(|n| Ratio::new(n, 500)).enumerate() {
1921 nums[i] = r;
1922 }
1923 let products = iter_products(&nums[..]);
1924 assert_eq!(products[0], products[1]);
1925 assert_eq!(products[0], products[2]);
1926 }
1927 }
1928