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 #![no_std]
19
20 #[cfg(feature = "bigint")]
21 extern crate num_bigint as bigint;
22 #[cfg(feature = "serde")]
23 extern crate serde;
24
25 extern crate num_integer as integer;
26 extern crate num_traits as traits;
27
28 #[cfg(feature = "std")]
29 #[cfg_attr(test, macro_use)]
30 extern crate std;
31
32 use core::cmp;
33 use core::fmt;
34 use core::hash::{Hash, Hasher};
35 use core::ops::{Add, Div, Mul, Neg, Rem, Sub};
36 use core::str::FromStr;
37 #[cfg(feature = "std")]
38 use std::error::Error;
39
40 #[cfg(feature = "bigint")]
41 use bigint::{BigInt, BigUint, Sign};
42
43 use integer::Integer;
44 use traits::float::FloatCore;
45 use traits::{
46 Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, FromPrimitive, Inv, Num, NumCast, One,
47 Pow, Signed, Zero,
48 };
49
50 /// Represents the ratio between two numbers.
51 #[derive(Copy, Clone, Debug)]
52 #[allow(missing_docs)]
53 pub struct Ratio<T> {
54 /// Numerator.
55 numer: T,
56 /// Denominator.
57 denom: T,
58 }
59
60 /// Alias for a `Ratio` of machine-sized integers.
61 pub type Rational = Ratio<isize>;
62 /// Alias for a `Ratio` of 32-bit-sized integers.
63 pub type Rational32 = Ratio<i32>;
64 /// Alias for a `Ratio` of 64-bit-sized integers.
65 pub type Rational64 = Ratio<i64>;
66
67 #[cfg(feature = "bigint")]
68 /// Alias for arbitrary precision rationals.
69 pub type BigRational = Ratio<BigInt>;
70
71 macro_rules! maybe_const {
72 ($( $(#[$attr:meta])* pub fn $name:ident $args:tt -> $ret:ty $body:block )*) => {$(
73 #[cfg(has_const_fn)]
74 $(#[$attr])* pub const fn $name $args -> $ret $body
75
76 #[cfg(not(has_const_fn))]
77 $(#[$attr])* pub fn $name $args -> $ret $body
78 )*}
79 }
80
81 /// These method are `const` for Rust 1.31 and later.
82 impl<T> Ratio<T> {
83 maybe_const! {
84 /// Creates a `Ratio` without checking for `denom == 0` or reducing.
85 #[inline]
86 pub fn new_raw(numer: T, denom: T) -> Ratio<T> {
87 Ratio {
88 numer: numer,
89 denom: denom,
90 }
91 }
92
93 /// Gets an immutable reference to the numerator.
94 #[inline]
95 pub fn numer(&self) -> &T {
96 &self.numer
97 }
98
99 /// Gets an immutable reference to the denominator.
100 #[inline]
101 pub fn denom(&self) -> &T {
102 &self.denom
103 }
104 }
105 }
106
107 impl<T: Clone + Integer> Ratio<T> {
108 /// Creates a new `Ratio`. Fails if `denom` is zero.
109 #[inline]
new(numer: T, denom: T) -> Ratio<T>110 pub fn new(numer: T, denom: T) -> Ratio<T> {
111 let mut ret = Ratio::new_raw(numer, denom);
112 ret.reduce();
113 ret
114 }
115
116 /// Creates a `Ratio` representing the integer `t`.
117 #[inline]
from_integer(t: T) -> Ratio<T>118 pub fn from_integer(t: T) -> Ratio<T> {
119 Ratio::new_raw(t, One::one())
120 }
121
122 /// Converts to an integer, rounding towards zero.
123 #[inline]
to_integer(&self) -> T124 pub fn to_integer(&self) -> T {
125 self.trunc().numer
126 }
127
128 /// Returns true if the rational number is an integer (denominator is 1).
129 #[inline]
is_integer(&self) -> bool130 pub fn is_integer(&self) -> bool {
131 self.denom.is_one()
132 }
133
134 /// Puts self into lowest terms, with denom > 0.
reduce(&mut self)135 fn reduce(&mut self) {
136 if self.denom.is_zero() {
137 panic!("denominator == 0");
138 }
139 if self.numer.is_zero() {
140 self.denom.set_one();
141 return;
142 }
143 if self.numer == self.denom {
144 self.set_one();
145 return;
146 }
147 let g: T = self.numer.gcd(&self.denom);
148
149 // FIXME(#5992): assignment operator overloads
150 // self.numer /= g;
151 // T: Clone + Integer != T: Clone + NumAssign
152 self.numer = self.numer.clone() / g.clone();
153 // FIXME(#5992): assignment operator overloads
154 // self.denom /= g;
155 // T: Clone + Integer != T: Clone + NumAssign
156 self.denom = self.denom.clone() / g;
157
158 // keep denom positive!
159 if self.denom < T::zero() {
160 self.numer = T::zero() - self.numer.clone();
161 self.denom = T::zero() - self.denom.clone();
162 }
163 }
164
165 /// Returns a reduced copy of self.
166 ///
167 /// In general, it is not necessary to use this method, as the only
168 /// method of procuring a non-reduced fraction is through `new_raw`.
reduced(&self) -> Ratio<T>169 pub fn reduced(&self) -> Ratio<T> {
170 let mut ret = self.clone();
171 ret.reduce();
172 ret
173 }
174
175 /// Returns the reciprocal.
176 ///
177 /// Fails if the `Ratio` is zero.
178 #[inline]
recip(&self) -> Ratio<T>179 pub fn recip(&self) -> Ratio<T> {
180 match self.numer.cmp(&T::zero()) {
181 cmp::Ordering::Equal => panic!("numerator == 0"),
182 cmp::Ordering::Greater => Ratio::new_raw(self.denom.clone(), self.numer.clone()),
183 cmp::Ordering::Less => Ratio::new_raw(
184 T::zero() - self.denom.clone(),
185 T::zero() - self.numer.clone(),
186 ),
187 }
188 }
189
190 /// Rounds towards minus infinity.
191 #[inline]
floor(&self) -> Ratio<T>192 pub fn floor(&self) -> Ratio<T> {
193 if *self < Zero::zero() {
194 let one: T = One::one();
195 Ratio::from_integer(
196 (self.numer.clone() - self.denom.clone() + one) / self.denom.clone(),
197 )
198 } else {
199 Ratio::from_integer(self.numer.clone() / self.denom.clone())
200 }
201 }
202
203 /// Rounds towards plus infinity.
204 #[inline]
ceil(&self) -> Ratio<T>205 pub fn ceil(&self) -> Ratio<T> {
206 if *self < Zero::zero() {
207 Ratio::from_integer(self.numer.clone() / self.denom.clone())
208 } else {
209 let one: T = One::one();
210 Ratio::from_integer(
211 (self.numer.clone() + self.denom.clone() - one) / self.denom.clone(),
212 )
213 }
214 }
215
216 /// Rounds to the nearest integer. Rounds half-way cases away from zero.
217 #[inline]
round(&self) -> Ratio<T>218 pub fn round(&self) -> Ratio<T> {
219 let zero: Ratio<T> = Zero::zero();
220 let one: T = One::one();
221 let two: T = one.clone() + one.clone();
222
223 // Find unsigned fractional part of rational number
224 let mut fractional = self.fract();
225 if fractional < zero {
226 fractional = zero - fractional
227 };
228
229 // The algorithm compares the unsigned fractional part with 1/2, that
230 // is, a/b >= 1/2, or a >= b/2. For odd denominators, we use
231 // a >= (b/2)+1. This avoids overflow issues.
232 let half_or_larger = if fractional.denom().is_even() {
233 *fractional.numer() >= fractional.denom().clone() / two.clone()
234 } else {
235 *fractional.numer() >= (fractional.denom().clone() / two.clone()) + one.clone()
236 };
237
238 if half_or_larger {
239 let one: Ratio<T> = One::one();
240 if *self >= Zero::zero() {
241 self.trunc() + one
242 } else {
243 self.trunc() - one
244 }
245 } else {
246 self.trunc()
247 }
248 }
249
250 /// Rounds towards zero.
251 #[inline]
trunc(&self) -> Ratio<T>252 pub fn trunc(&self) -> Ratio<T> {
253 Ratio::from_integer(self.numer.clone() / self.denom.clone())
254 }
255
256 /// Returns the fractional part of a number, with division rounded towards zero.
257 ///
258 /// Satisfies `self == self.trunc() + self.fract()`.
259 #[inline]
fract(&self) -> Ratio<T>260 pub fn fract(&self) -> Ratio<T> {
261 Ratio::new_raw(self.numer.clone() % self.denom.clone(), self.denom.clone())
262 }
263 }
264
265 impl<T: Clone + Integer + Pow<u32, Output = T>> Ratio<T> {
266 /// Raises the `Ratio` to the power of an exponent.
267 #[inline]
pow(&self, expon: i32) -> Ratio<T>268 pub fn pow(&self, expon: i32) -> Ratio<T> {
269 Pow::pow(self, expon)
270 }
271 }
272
273 macro_rules! pow_impl {
274 ($exp:ty) => {
275 pow_impl!($exp, $exp);
276 };
277 ($exp:ty, $unsigned:ty) => {
278 impl<T: Clone + Integer + Pow<$unsigned, Output = T>> Pow<$exp> for Ratio<T> {
279 type Output = Ratio<T>;
280 #[inline]
281 fn pow(self, expon: $exp) -> Ratio<T> {
282 match expon.cmp(&0) {
283 cmp::Ordering::Equal => One::one(),
284 cmp::Ordering::Less => {
285 let expon = expon.wrapping_abs() as $unsigned;
286 Ratio::new_raw(Pow::pow(self.denom, expon), Pow::pow(self.numer, expon))
287 }
288 cmp::Ordering::Greater => Ratio::new_raw(
289 Pow::pow(self.numer, expon as $unsigned),
290 Pow::pow(self.denom, expon as $unsigned),
291 ),
292 }
293 }
294 }
295 impl<'a, T: Clone + Integer + Pow<$unsigned, Output = T>> Pow<$exp> for &'a Ratio<T> {
296 type Output = Ratio<T>;
297 #[inline]
298 fn pow(self, expon: $exp) -> Ratio<T> {
299 Pow::pow(self.clone(), expon)
300 }
301 }
302 impl<'a, T: Clone + Integer + Pow<$unsigned, Output = T>> Pow<&'a $exp> for Ratio<T> {
303 type Output = Ratio<T>;
304 #[inline]
305 fn pow(self, expon: &'a $exp) -> Ratio<T> {
306 Pow::pow(self, *expon)
307 }
308 }
309 impl<'a, 'b, T: Clone + Integer + Pow<$unsigned, Output = T>> Pow<&'a $exp>
310 for &'b Ratio<T>
311 {
312 type Output = Ratio<T>;
313 #[inline]
314 fn pow(self, expon: &'a $exp) -> Ratio<T> {
315 Pow::pow(self.clone(), *expon)
316 }
317 }
318 };
319 }
320
321 // this is solely to make `pow_impl!` work
322 trait WrappingAbs: Sized {
wrapping_abs(self) -> Self323 fn wrapping_abs(self) -> Self {
324 self
325 }
326 }
327 impl WrappingAbs for u8 {}
328 impl WrappingAbs for u16 {}
329 impl WrappingAbs for u32 {}
330 impl WrappingAbs for u64 {}
331 impl WrappingAbs for usize {}
332
333 pow_impl!(i8, u8);
334 pow_impl!(i16, u16);
335 pow_impl!(i32, u32);
336 pow_impl!(i64, u64);
337 pow_impl!(isize, usize);
338 pow_impl!(u8);
339 pow_impl!(u16);
340 pow_impl!(u32);
341 pow_impl!(u64);
342 pow_impl!(usize);
343
344 // TODO: pow_impl!(BigUint) and pow_impl!(BigInt, BigUint)
345
346 #[cfg(feature = "bigint")]
347 impl Ratio<BigInt> {
348 /// Converts a float into a rational number.
from_float<T: FloatCore>(f: T) -> Option<BigRational>349 pub fn from_float<T: FloatCore>(f: T) -> Option<BigRational> {
350 if !f.is_finite() {
351 return None;
352 }
353 let (mantissa, exponent, sign) = f.integer_decode();
354 let bigint_sign = if sign == 1 { Sign::Plus } else { Sign::Minus };
355 if exponent < 0 {
356 let one: BigInt = One::one();
357 let denom: BigInt = one << ((-exponent) as usize);
358 let numer: BigUint = FromPrimitive::from_u64(mantissa).unwrap();
359 Some(Ratio::new(BigInt::from_biguint(bigint_sign, numer), denom))
360 } else {
361 let mut numer: BigUint = FromPrimitive::from_u64(mantissa).unwrap();
362 numer = numer << (exponent as usize);
363 Some(Ratio::from_integer(BigInt::from_biguint(
364 bigint_sign,
365 numer,
366 )))
367 }
368 }
369 }
370
371 // From integer
372 impl<T> From<T> for Ratio<T>
373 where
374 T: Clone + Integer,
375 {
from(x: T) -> Ratio<T>376 fn from(x: T) -> Ratio<T> {
377 Ratio::from_integer(x)
378 }
379 }
380
381 // From pair (through the `new` constructor)
382 impl<T> From<(T, T)> for Ratio<T>
383 where
384 T: Clone + Integer,
385 {
from(pair: (T, T)) -> Ratio<T>386 fn from(pair: (T, T)) -> Ratio<T> {
387 Ratio::new(pair.0, pair.1)
388 }
389 }
390
391 // Comparisons
392
393 // Mathematically, comparing a/b and c/d is the same as comparing a*d and b*c, but it's very easy
394 // for those multiplications to overflow fixed-size integers, so we need to take care.
395
396 impl<T: Clone + Integer> Ord for Ratio<T> {
397 #[inline]
cmp(&self, other: &Self) -> cmp::Ordering398 fn cmp(&self, other: &Self) -> cmp::Ordering {
399 // With equal denominators, the numerators can be directly compared
400 if self.denom == other.denom {
401 let ord = self.numer.cmp(&other.numer);
402 return if self.denom < T::zero() {
403 ord.reverse()
404 } else {
405 ord
406 };
407 }
408
409 // With equal numerators, the denominators can be inversely compared
410 if self.numer == other.numer {
411 if self.numer.is_zero() {
412 return cmp::Ordering::Equal;
413 }
414 let ord = self.denom.cmp(&other.denom);
415 return if self.numer < T::zero() {
416 ord
417 } else {
418 ord.reverse()
419 };
420 }
421
422 // Unfortunately, we don't have CheckedMul to try. That could sometimes avoid all the
423 // division below, or even always avoid it for BigInt and BigUint.
424 // FIXME- future breaking change to add Checked* to Integer?
425
426 // Compare as floored integers and remainders
427 let (self_int, self_rem) = self.numer.div_mod_floor(&self.denom);
428 let (other_int, other_rem) = other.numer.div_mod_floor(&other.denom);
429 match self_int.cmp(&other_int) {
430 cmp::Ordering::Greater => cmp::Ordering::Greater,
431 cmp::Ordering::Less => cmp::Ordering::Less,
432 cmp::Ordering::Equal => {
433 match (self_rem.is_zero(), other_rem.is_zero()) {
434 (true, true) => cmp::Ordering::Equal,
435 (true, false) => cmp::Ordering::Less,
436 (false, true) => cmp::Ordering::Greater,
437 (false, false) => {
438 // Compare the reciprocals of the remaining fractions in reverse
439 let self_recip = Ratio::new_raw(self.denom.clone(), self_rem);
440 let other_recip = Ratio::new_raw(other.denom.clone(), other_rem);
441 self_recip.cmp(&other_recip).reverse()
442 }
443 }
444 }
445 }
446 }
447 }
448
449 impl<T: Clone + Integer> PartialOrd for Ratio<T> {
450 #[inline]
partial_cmp(&self, other: &Self) -> Option<cmp::Ordering>451 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
452 Some(self.cmp(other))
453 }
454 }
455
456 impl<T: Clone + Integer> PartialEq for Ratio<T> {
457 #[inline]
eq(&self, other: &Self) -> bool458 fn eq(&self, other: &Self) -> bool {
459 self.cmp(other) == cmp::Ordering::Equal
460 }
461 }
462
463 impl<T: Clone + Integer> Eq for Ratio<T> {}
464
465 // NB: We can't just `#[derive(Hash)]`, because it needs to agree
466 // with `Eq` even for non-reduced ratios.
467 impl<T: Clone + Integer + Hash> Hash for Ratio<T> {
hash<H: Hasher>(&self, state: &mut H)468 fn hash<H: Hasher>(&self, state: &mut H) {
469 recurse(&self.numer, &self.denom, state);
470
471 fn recurse<T: Integer + Hash, H: Hasher>(numer: &T, denom: &T, state: &mut H) {
472 if !denom.is_zero() {
473 let (int, rem) = numer.div_mod_floor(denom);
474 int.hash(state);
475 recurse(denom, &rem, state);
476 } else {
477 denom.hash(state);
478 }
479 }
480 }
481 }
482
483 mod iter_sum_product {
484 use core::iter::{Product, Sum};
485 use integer::Integer;
486 use traits::{One, Zero};
487 use Ratio;
488
489 impl<T: Integer + Clone> Sum for Ratio<T> {
sum<I>(iter: I) -> Self where I: Iterator<Item = Ratio<T>>,490 fn sum<I>(iter: I) -> Self
491 where
492 I: Iterator<Item = Ratio<T>>,
493 {
494 iter.fold(Self::zero(), |sum, num| sum + num)
495 }
496 }
497
498 impl<'a, T: Integer + Clone> Sum<&'a Ratio<T>> for Ratio<T> {
sum<I>(iter: I) -> Self where I: Iterator<Item = &'a Ratio<T>>,499 fn sum<I>(iter: I) -> Self
500 where
501 I: Iterator<Item = &'a Ratio<T>>,
502 {
503 iter.fold(Self::zero(), |sum, num| sum + num)
504 }
505 }
506
507 impl<T: Integer + Clone> Product for Ratio<T> {
product<I>(iter: I) -> Self where I: Iterator<Item = Ratio<T>>,508 fn product<I>(iter: I) -> Self
509 where
510 I: Iterator<Item = Ratio<T>>,
511 {
512 iter.fold(Self::one(), |prod, num| prod * num)
513 }
514 }
515
516 impl<'a, T: Integer + Clone> Product<&'a Ratio<T>> for Ratio<T> {
product<I>(iter: I) -> Self where I: Iterator<Item = &'a Ratio<T>>,517 fn product<I>(iter: I) -> Self
518 where
519 I: Iterator<Item = &'a Ratio<T>>,
520 {
521 iter.fold(Self::one(), |prod, num| prod * num)
522 }
523 }
524 }
525
526 mod opassign {
527 use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign};
528
529 use integer::Integer;
530 use traits::NumAssign;
531 use Ratio;
532
533 impl<T: Clone + Integer + NumAssign> AddAssign for Ratio<T> {
add_assign(&mut self, other: Ratio<T>)534 fn add_assign(&mut self, other: Ratio<T>) {
535 if self.denom == other.denom {
536 self.numer += other.numer
537 } else {
538 let lcm = self.denom.lcm(&other.denom);
539 let lhs_numer = self.numer.clone() * (lcm.clone() / self.denom.clone());
540 let rhs_numer = other.numer * (lcm.clone() / other.denom);
541 self.numer = lhs_numer + rhs_numer;
542 self.denom = lcm;
543 }
544 self.reduce();
545 }
546 }
547
548 // (a/b) / (c/d) = (a/gcd_ac)*(d/gcd_bd) / ((c/gcd_ac)*(b/gcd_bd))
549 impl<T: Clone + Integer + NumAssign> DivAssign for Ratio<T> {
div_assign(&mut self, other: Ratio<T>)550 fn div_assign(&mut self, other: Ratio<T>) {
551 let gcd_ac = self.numer.gcd(&other.numer);
552 let gcd_bd = self.denom.gcd(&other.denom);
553 self.numer /= gcd_ac.clone();
554 self.numer *= other.denom / gcd_bd.clone();
555 self.denom /= gcd_bd;
556 self.denom *= other.numer / gcd_ac;
557 self.reduce(); //TODO: remove this line. see #8.
558 }
559 }
560
561 // a/b * c/d = (a/gcd_ad)*(c/gcd_bc) / ((d/gcd_ad)*(b/gcd_bc))
562 impl<T: Clone + Integer + NumAssign> MulAssign for Ratio<T> {
mul_assign(&mut self, other: Ratio<T>)563 fn mul_assign(&mut self, other: Ratio<T>) {
564 let gcd_ad = self.numer.gcd(&other.denom);
565 let gcd_bc = self.denom.gcd(&other.numer);
566 self.numer /= gcd_ad.clone();
567 self.numer *= other.numer / gcd_bc.clone();
568 self.denom /= gcd_bc;
569 self.denom *= other.denom / gcd_ad;
570 self.reduce(); //TODO: remove this line. see #8.
571 }
572 }
573
574 impl<T: Clone + Integer + NumAssign> RemAssign for Ratio<T> {
rem_assign(&mut self, other: Ratio<T>)575 fn rem_assign(&mut self, other: Ratio<T>) {
576 if self.denom == other.denom {
577 self.numer %= other.numer
578 } else {
579 let lcm = self.denom.lcm(&other.denom);
580 let lhs_numer = self.numer.clone() * (lcm.clone() / self.denom.clone());
581 let rhs_numer = other.numer * (lcm.clone() / other.denom);
582 self.numer = lhs_numer % rhs_numer;
583 self.denom = lcm;
584 }
585 self.reduce();
586 }
587 }
588
589 impl<T: Clone + Integer + NumAssign> SubAssign for Ratio<T> {
sub_assign(&mut self, other: Ratio<T>)590 fn sub_assign(&mut self, other: Ratio<T>) {
591 if self.denom == other.denom {
592 self.numer -= other.numer
593 } else {
594 let lcm = self.denom.lcm(&other.denom);
595 let lhs_numer = self.numer.clone() * (lcm.clone() / self.denom.clone());
596 let rhs_numer = other.numer * (lcm.clone() / other.denom);
597 self.numer = lhs_numer - rhs_numer;
598 self.denom = lcm;
599 }
600 self.reduce();
601 }
602 }
603
604 // a/b + c/1 = (a*1 + b*c) / (b*1) = (a + b*c) / b
605 impl<T: Clone + Integer + NumAssign> AddAssign<T> for Ratio<T> {
add_assign(&mut self, other: T)606 fn add_assign(&mut self, other: T) {
607 self.numer += self.denom.clone() * other;
608 self.reduce();
609 }
610 }
611
612 impl<T: Clone + Integer + NumAssign> DivAssign<T> for Ratio<T> {
div_assign(&mut self, other: T)613 fn div_assign(&mut self, other: T) {
614 let gcd = self.numer.gcd(&other);
615 self.numer /= gcd.clone();
616 self.denom *= other / gcd;
617 self.reduce(); //TODO: remove this line. see #8.
618 }
619 }
620
621 impl<T: Clone + Integer + NumAssign> MulAssign<T> for Ratio<T> {
mul_assign(&mut self, other: T)622 fn mul_assign(&mut self, other: T) {
623 let gcd = self.denom.gcd(&other);
624 self.denom /= gcd.clone();
625 self.numer *= other / gcd;
626 self.reduce(); //TODO: remove this line. see #8.
627 }
628 }
629
630 // a/b % c/1 = (a*1 % b*c) / (b*1) = (a % b*c) / b
631 impl<T: Clone + Integer + NumAssign> RemAssign<T> for Ratio<T> {
rem_assign(&mut self, other: T)632 fn rem_assign(&mut self, other: T) {
633 self.numer %= self.denom.clone() * other;
634 self.reduce();
635 }
636 }
637
638 // a/b - c/1 = (a*1 - b*c) / (b*1) = (a - b*c) / b
639 impl<T: Clone + Integer + NumAssign> SubAssign<T> for Ratio<T> {
sub_assign(&mut self, other: T)640 fn sub_assign(&mut self, other: T) {
641 self.numer -= self.denom.clone() * other;
642 self.reduce();
643 }
644 }
645
646 macro_rules! forward_op_assign {
647 (impl $imp:ident, $method:ident) => {
648 impl<'a, T: Clone + Integer + NumAssign> $imp<&'a Ratio<T>> for Ratio<T> {
649 #[inline]
650 fn $method(&mut self, other: &Ratio<T>) {
651 self.$method(other.clone())
652 }
653 }
654 impl<'a, T: Clone + Integer + NumAssign> $imp<&'a T> for Ratio<T> {
655 #[inline]
656 fn $method(&mut self, other: &T) {
657 self.$method(other.clone())
658 }
659 }
660 };
661 }
662
663 forward_op_assign!(impl AddAssign, add_assign);
664 forward_op_assign!(impl DivAssign, div_assign);
665 forward_op_assign!(impl MulAssign, mul_assign);
666 forward_op_assign!(impl RemAssign, rem_assign);
667 forward_op_assign!(impl SubAssign, sub_assign);
668 }
669
670 macro_rules! forward_ref_ref_binop {
671 (impl $imp:ident, $method:ident) => {
672 impl<'a, 'b, T: Clone + Integer> $imp<&'b Ratio<T>> for &'a Ratio<T> {
673 type Output = Ratio<T>;
674
675 #[inline]
676 fn $method(self, other: &'b Ratio<T>) -> Ratio<T> {
677 self.clone().$method(other.clone())
678 }
679 }
680 impl<'a, 'b, T: Clone + Integer> $imp<&'b T> for &'a Ratio<T> {
681 type Output = Ratio<T>;
682
683 #[inline]
684 fn $method(self, other: &'b T) -> Ratio<T> {
685 self.clone().$method(other.clone())
686 }
687 }
688 };
689 }
690
691 macro_rules! forward_ref_val_binop {
692 (impl $imp:ident, $method:ident) => {
693 impl<'a, T> $imp<Ratio<T>> for &'a Ratio<T>
694 where
695 T: Clone + Integer,
696 {
697 type Output = Ratio<T>;
698
699 #[inline]
700 fn $method(self, other: Ratio<T>) -> Ratio<T> {
701 self.clone().$method(other)
702 }
703 }
704 impl<'a, T> $imp<T> for &'a Ratio<T>
705 where
706 T: Clone + Integer,
707 {
708 type Output = Ratio<T>;
709
710 #[inline]
711 fn $method(self, other: T) -> Ratio<T> {
712 self.clone().$method(other)
713 }
714 }
715 };
716 }
717
718 macro_rules! forward_val_ref_binop {
719 (impl $imp:ident, $method:ident) => {
720 impl<'a, T> $imp<&'a Ratio<T>> for Ratio<T>
721 where
722 T: Clone + Integer,
723 {
724 type Output = Ratio<T>;
725
726 #[inline]
727 fn $method(self, other: &Ratio<T>) -> Ratio<T> {
728 self.$method(other.clone())
729 }
730 }
731 impl<'a, T> $imp<&'a T> for Ratio<T>
732 where
733 T: Clone + Integer,
734 {
735 type Output = Ratio<T>;
736
737 #[inline]
738 fn $method(self, other: &T) -> Ratio<T> {
739 self.$method(other.clone())
740 }
741 }
742 };
743 }
744
745 macro_rules! forward_all_binop {
746 (impl $imp:ident, $method:ident) => {
747 forward_ref_ref_binop!(impl $imp, $method);
748 forward_ref_val_binop!(impl $imp, $method);
749 forward_val_ref_binop!(impl $imp, $method);
750 };
751 }
752
753 // Arithmetic
754 forward_all_binop!(impl Mul, mul);
755 // a/b * c/d = (a/gcd_ad)*(c/gcd_bc) / ((d/gcd_ad)*(b/gcd_bc))
756 impl<T> Mul<Ratio<T>> for Ratio<T>
757 where
758 T: Clone + Integer,
759 {
760 type Output = Ratio<T>;
761 #[inline]
mul(self, rhs: Ratio<T>) -> Ratio<T>762 fn mul(self, rhs: Ratio<T>) -> Ratio<T> {
763 let gcd_ad = self.numer.gcd(&rhs.denom);
764 let gcd_bc = self.denom.gcd(&rhs.numer);
765 Ratio::new(
766 self.numer / gcd_ad.clone() * (rhs.numer / gcd_bc.clone()),
767 self.denom / gcd_bc * (rhs.denom / gcd_ad),
768 )
769 }
770 }
771 // a/b * c/1 = (a*c) / (b*1) = (a*c) / b
772 impl<T> Mul<T> for Ratio<T>
773 where
774 T: Clone + Integer,
775 {
776 type Output = Ratio<T>;
777 #[inline]
mul(self, rhs: T) -> Ratio<T>778 fn mul(self, rhs: T) -> Ratio<T> {
779 let gcd = self.denom.gcd(&rhs);
780 Ratio::new(self.numer * (rhs / gcd.clone()), self.denom / gcd)
781 }
782 }
783
784 forward_all_binop!(impl Div, div);
785 // (a/b) / (c/d) = (a/gcd_ac)*(d/gcd_bd) / ((c/gcd_ac)*(b/gcd_bd))
786 impl<T> Div<Ratio<T>> for Ratio<T>
787 where
788 T: Clone + Integer,
789 {
790 type Output = Ratio<T>;
791
792 #[inline]
div(self, rhs: Ratio<T>) -> Ratio<T>793 fn div(self, rhs: Ratio<T>) -> Ratio<T> {
794 let gcd_ac = self.numer.gcd(&rhs.numer);
795 let gcd_bd = self.denom.gcd(&rhs.denom);
796 Ratio::new(
797 self.numer / gcd_ac.clone() * (rhs.denom / gcd_bd.clone()),
798 self.denom / gcd_bd * (rhs.numer / gcd_ac),
799 )
800 }
801 }
802 // (a/b) / (c/1) = (a*1) / (b*c) = a / (b*c)
803 impl<T> Div<T> for Ratio<T>
804 where
805 T: Clone + Integer,
806 {
807 type Output = Ratio<T>;
808
809 #[inline]
div(self, rhs: T) -> Ratio<T>810 fn div(self, rhs: T) -> Ratio<T> {
811 let gcd = self.numer.gcd(&rhs);
812 Ratio::new(self.numer / gcd.clone(), self.denom * (rhs / gcd))
813 }
814 }
815
816 macro_rules! arith_impl {
817 (impl $imp:ident, $method:ident) => {
818 forward_all_binop!(impl $imp, $method);
819 // Abstracts a/b `op` c/d = (a*lcm/b `op` c*lcm/d)/lcm where lcm = lcm(b,d)
820 impl<T: Clone + Integer> $imp<Ratio<T>> for Ratio<T> {
821 type Output = Ratio<T>;
822 #[inline]
823 fn $method(self, rhs: Ratio<T>) -> Ratio<T> {
824 if self.denom == rhs.denom {
825 return Ratio::new(self.numer.$method(rhs.numer), rhs.denom);
826 }
827 let lcm = self.denom.lcm(&rhs.denom);
828 let lhs_numer = self.numer * (lcm.clone() / self.denom);
829 let rhs_numer = rhs.numer * (lcm.clone() / rhs.denom);
830 Ratio::new(lhs_numer.$method(rhs_numer), lcm)
831 }
832 }
833 // Abstracts the a/b `op` c/1 = (a*1 `op` b*c) / (b*1) = (a `op` b*c) / b pattern
834 impl<T: Clone + Integer> $imp<T> for Ratio<T> {
835 type Output = Ratio<T>;
836 #[inline]
837 fn $method(self, rhs: T) -> Ratio<T> {
838 Ratio::new(self.numer.$method(self.denom.clone() * rhs), self.denom)
839 }
840 }
841 };
842 }
843
844 arith_impl!(impl Add, add);
845 arith_impl!(impl Sub, sub);
846 arith_impl!(impl Rem, rem);
847
848 // Like `std::try!` for Option<T>, unwrap the value or early-return None.
849 // Since Rust 1.22 this can be replaced by the `?` operator.
850 macro_rules! otry {
851 ($expr:expr) => {
852 match $expr {
853 Some(val) => val,
854 None => return None,
855 }
856 };
857 }
858
859 // a/b * c/d = (a*c)/(b*d)
860 impl<T> CheckedMul for Ratio<T>
861 where
862 T: Clone + Integer + CheckedMul,
863 {
864 #[inline]
checked_mul(&self, rhs: &Ratio<T>) -> Option<Ratio<T>>865 fn checked_mul(&self, rhs: &Ratio<T>) -> Option<Ratio<T>> {
866 let gcd_ad = self.numer.gcd(&rhs.denom);
867 let gcd_bc = self.denom.gcd(&rhs.numer);
868 Some(Ratio::new(
869 otry!((self.numer.clone() / gcd_ad.clone())
870 .checked_mul(&(rhs.numer.clone() / gcd_bc.clone()))),
871 otry!((self.denom.clone() / gcd_bc).checked_mul(&(rhs.denom.clone() / gcd_ad))),
872 ))
873 }
874 }
875
876 // (a/b) / (c/d) = (a*d)/(b*c)
877 impl<T> CheckedDiv for Ratio<T>
878 where
879 T: Clone + Integer + CheckedMul,
880 {
881 #[inline]
checked_div(&self, rhs: &Ratio<T>) -> Option<Ratio<T>>882 fn checked_div(&self, rhs: &Ratio<T>) -> Option<Ratio<T>> {
883 if rhs.is_zero() {
884 return None;
885 }
886 let (numer, denom) = if self.denom == rhs.denom {
887 (self.numer.clone(), rhs.numer.clone())
888 } else if self.numer == rhs.numer {
889 (rhs.denom.clone(), self.denom.clone())
890 } else {
891 let gcd_ac = self.numer.gcd(&rhs.numer);
892 let gcd_bd = self.denom.gcd(&rhs.denom);
893 let denom = otry!((self.denom.clone() / gcd_bd.clone())
894 .checked_mul(&(rhs.numer.clone() / gcd_ac.clone())));
895 (
896 otry!((self.numer.clone() / gcd_ac).checked_mul(&(rhs.denom.clone() / gcd_bd))),
897 denom,
898 )
899 };
900 // Manual `reduce()`, avoiding sharp edges
901 if denom.is_zero() {
902 None
903 } else if numer.is_zero() {
904 Some(Self::zero())
905 } else if numer == denom {
906 Some(Self::one())
907 } else {
908 let g = numer.gcd(&denom);
909 let numer = numer / g.clone();
910 let denom = denom / g;
911 let raw = if denom < T::zero() {
912 // We need to keep denom positive, but 2's-complement MIN may
913 // overflow negation -- instead we can check multiplying -1.
914 let n1 = T::zero() - T::one();
915 Ratio::new_raw(otry!(numer.checked_mul(&n1)), otry!(denom.checked_mul(&n1)))
916 } else {
917 Ratio::new_raw(numer, denom)
918 };
919 Some(raw)
920 }
921 }
922 }
923
924 // As arith_impl! but for Checked{Add,Sub} traits
925 macro_rules! checked_arith_impl {
926 (impl $imp:ident, $method:ident) => {
927 impl<T: Clone + Integer + CheckedMul + $imp> $imp for Ratio<T> {
928 #[inline]
929 fn $method(&self, rhs: &Ratio<T>) -> Option<Ratio<T>> {
930 let gcd = self.denom.clone().gcd(&rhs.denom);
931 let lcm = otry!((self.denom.clone() / gcd.clone()).checked_mul(&rhs.denom));
932 let lhs_numer = otry!((lcm.clone() / self.denom.clone()).checked_mul(&self.numer));
933 let rhs_numer = otry!((lcm.clone() / rhs.denom.clone()).checked_mul(&rhs.numer));
934 Some(Ratio::new(otry!(lhs_numer.$method(&rhs_numer)), lcm))
935 }
936 }
937 };
938 }
939
940 // a/b + c/d = (lcm/b*a + lcm/d*c)/lcm, where lcm = lcm(b,d)
941 checked_arith_impl!(impl CheckedAdd, checked_add);
942
943 // a/b - c/d = (lcm/b*a - lcm/d*c)/lcm, where lcm = lcm(b,d)
944 checked_arith_impl!(impl CheckedSub, checked_sub);
945
946 impl<T> Neg for Ratio<T>
947 where
948 T: Clone + Integer + Neg<Output = T>,
949 {
950 type Output = Ratio<T>;
951
952 #[inline]
neg(self) -> Ratio<T>953 fn neg(self) -> Ratio<T> {
954 Ratio::new_raw(-self.numer, self.denom)
955 }
956 }
957
958 impl<'a, T> Neg for &'a Ratio<T>
959 where
960 T: Clone + Integer + Neg<Output = T>,
961 {
962 type Output = Ratio<T>;
963
964 #[inline]
neg(self) -> Ratio<T>965 fn neg(self) -> Ratio<T> {
966 -self.clone()
967 }
968 }
969
970 impl<T> Inv for Ratio<T>
971 where
972 T: Clone + Integer,
973 {
974 type Output = Ratio<T>;
975
976 #[inline]
inv(self) -> Ratio<T>977 fn inv(self) -> Ratio<T> {
978 self.recip()
979 }
980 }
981
982 impl<'a, T> Inv for &'a Ratio<T>
983 where
984 T: Clone + Integer,
985 {
986 type Output = Ratio<T>;
987
988 #[inline]
inv(self) -> Ratio<T>989 fn inv(self) -> Ratio<T> {
990 self.recip()
991 }
992 }
993
994 // Constants
995 impl<T: Clone + Integer> Zero for Ratio<T> {
996 #[inline]
zero() -> Ratio<T>997 fn zero() -> Ratio<T> {
998 Ratio::new_raw(Zero::zero(), One::one())
999 }
1000
1001 #[inline]
is_zero(&self) -> bool1002 fn is_zero(&self) -> bool {
1003 self.numer.is_zero()
1004 }
1005
1006 #[inline]
set_zero(&mut self)1007 fn set_zero(&mut self) {
1008 self.numer.set_zero();
1009 self.denom.set_one();
1010 }
1011 }
1012
1013 impl<T: Clone + Integer> One for Ratio<T> {
1014 #[inline]
one() -> Ratio<T>1015 fn one() -> Ratio<T> {
1016 Ratio::new_raw(One::one(), One::one())
1017 }
1018
1019 #[inline]
is_one(&self) -> bool1020 fn is_one(&self) -> bool {
1021 self.numer == self.denom
1022 }
1023
1024 #[inline]
set_one(&mut self)1025 fn set_one(&mut self) {
1026 self.numer.set_one();
1027 self.denom.set_one();
1028 }
1029 }
1030
1031 impl<T: Clone + Integer> Num for Ratio<T> {
1032 type FromStrRadixErr = ParseRatioError;
1033
1034 /// Parses `numer/denom` where the numbers are in base `radix`.
from_str_radix(s: &str, radix: u32) -> Result<Ratio<T>, ParseRatioError>1035 fn from_str_radix(s: &str, radix: u32) -> Result<Ratio<T>, ParseRatioError> {
1036 if s.splitn(2, '/').count() == 2 {
1037 let mut parts = s.splitn(2, '/').map(|ss| {
1038 T::from_str_radix(ss, radix).map_err(|_| ParseRatioError {
1039 kind: RatioErrorKind::ParseError,
1040 })
1041 });
1042 let numer: T = parts.next().unwrap()?;
1043 let denom: T = parts.next().unwrap()?;
1044 if denom.is_zero() {
1045 Err(ParseRatioError {
1046 kind: RatioErrorKind::ZeroDenominator,
1047 })
1048 } else {
1049 Ok(Ratio::new(numer, denom))
1050 }
1051 } else {
1052 Err(ParseRatioError {
1053 kind: RatioErrorKind::ParseError,
1054 })
1055 }
1056 }
1057 }
1058
1059 impl<T: Clone + Integer + Signed> Signed for Ratio<T> {
1060 #[inline]
abs(&self) -> Ratio<T>1061 fn abs(&self) -> Ratio<T> {
1062 if self.is_negative() {
1063 -self.clone()
1064 } else {
1065 self.clone()
1066 }
1067 }
1068
1069 #[inline]
abs_sub(&self, other: &Ratio<T>) -> Ratio<T>1070 fn abs_sub(&self, other: &Ratio<T>) -> Ratio<T> {
1071 if *self <= *other {
1072 Zero::zero()
1073 } else {
1074 self - other
1075 }
1076 }
1077
1078 #[inline]
signum(&self) -> Ratio<T>1079 fn signum(&self) -> Ratio<T> {
1080 if self.is_positive() {
1081 Self::one()
1082 } else if self.is_zero() {
1083 Self::zero()
1084 } else {
1085 -Self::one()
1086 }
1087 }
1088
1089 #[inline]
is_positive(&self) -> bool1090 fn is_positive(&self) -> bool {
1091 (self.numer.is_positive() && self.denom.is_positive())
1092 || (self.numer.is_negative() && self.denom.is_negative())
1093 }
1094
1095 #[inline]
is_negative(&self) -> bool1096 fn is_negative(&self) -> bool {
1097 (self.numer.is_negative() && self.denom.is_positive())
1098 || (self.numer.is_positive() && self.denom.is_negative())
1099 }
1100 }
1101
1102 // String conversions
1103 impl<T> fmt::Display for Ratio<T>
1104 where
1105 T: fmt::Display + Eq + One,
1106 {
1107 /// Renders as `numer/denom`. If denom=1, renders as numer.
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1108 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1109 if self.denom.is_one() {
1110 write!(f, "{}", self.numer)
1111 } else {
1112 write!(f, "{}/{}", self.numer, self.denom)
1113 }
1114 }
1115 }
1116
1117 impl<T: FromStr + Clone + Integer> FromStr for Ratio<T> {
1118 type Err = ParseRatioError;
1119
1120 /// Parses `numer/denom` or just `numer`.
from_str(s: &str) -> Result<Ratio<T>, ParseRatioError>1121 fn from_str(s: &str) -> Result<Ratio<T>, ParseRatioError> {
1122 let mut split = s.splitn(2, '/');
1123
1124 let n = split.next().ok_or(ParseRatioError {
1125 kind: RatioErrorKind::ParseError,
1126 })?;
1127 let num = FromStr::from_str(n).map_err(|_| ParseRatioError {
1128 kind: RatioErrorKind::ParseError,
1129 })?;
1130
1131 let d = split.next().unwrap_or("1");
1132 let den = FromStr::from_str(d).map_err(|_| ParseRatioError {
1133 kind: RatioErrorKind::ParseError,
1134 })?;
1135
1136 if Zero::is_zero(&den) {
1137 Err(ParseRatioError {
1138 kind: RatioErrorKind::ZeroDenominator,
1139 })
1140 } else {
1141 Ok(Ratio::new(num, den))
1142 }
1143 }
1144 }
1145
1146 impl<T> Into<(T, T)> for Ratio<T> {
into(self) -> (T, T)1147 fn into(self) -> (T, T) {
1148 (self.numer, self.denom)
1149 }
1150 }
1151
1152 #[cfg(feature = "serde")]
1153 impl<T> serde::Serialize for Ratio<T>
1154 where
1155 T: serde::Serialize + Clone + Integer + PartialOrd,
1156 {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer,1157 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1158 where
1159 S: serde::Serializer,
1160 {
1161 (self.numer(), self.denom()).serialize(serializer)
1162 }
1163 }
1164
1165 #[cfg(feature = "serde")]
1166 impl<'de, T> serde::Deserialize<'de> for Ratio<T>
1167 where
1168 T: serde::Deserialize<'de> + Clone + Integer + PartialOrd,
1169 {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de>,1170 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1171 where
1172 D: serde::Deserializer<'de>,
1173 {
1174 use serde::de::Error;
1175 use serde::de::Unexpected;
1176 let (numer, denom): (T, T) = try!(serde::Deserialize::deserialize(deserializer));
1177 if denom.is_zero() {
1178 Err(Error::invalid_value(
1179 Unexpected::Signed(0),
1180 &"a ratio with non-zero denominator",
1181 ))
1182 } else {
1183 Ok(Ratio::new_raw(numer, denom))
1184 }
1185 }
1186 }
1187
1188 // FIXME: Bubble up specific errors
1189 #[derive(Copy, Clone, Debug, PartialEq)]
1190 pub struct ParseRatioError {
1191 kind: RatioErrorKind,
1192 }
1193
1194 #[derive(Copy, Clone, Debug, PartialEq)]
1195 enum RatioErrorKind {
1196 ParseError,
1197 ZeroDenominator,
1198 }
1199
1200 impl fmt::Display for ParseRatioError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1201 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1202 self.kind.description().fmt(f)
1203 }
1204 }
1205
1206 #[cfg(feature = "std")]
1207 impl Error for ParseRatioError {
description(&self) -> &str1208 fn description(&self) -> &str {
1209 self.kind.description()
1210 }
1211 }
1212
1213 impl RatioErrorKind {
description(&self) -> &'static str1214 fn description(&self) -> &'static str {
1215 match *self {
1216 RatioErrorKind::ParseError => "failed to parse integer",
1217 RatioErrorKind::ZeroDenominator => "zero value denominator",
1218 }
1219 }
1220 }
1221
1222 #[cfg(feature = "bigint")]
1223 impl FromPrimitive for Ratio<BigInt> {
from_i64(n: i64) -> Option<Self>1224 fn from_i64(n: i64) -> Option<Self> {
1225 Some(Ratio::from_integer(n.into()))
1226 }
1227
1228 #[cfg(has_i128)]
from_i128(n: i128) -> Option<Self>1229 fn from_i128(n: i128) -> Option<Self> {
1230 Some(Ratio::from_integer(n.into()))
1231 }
1232
from_u64(n: u64) -> Option<Self>1233 fn from_u64(n: u64) -> Option<Self> {
1234 Some(Ratio::from_integer(n.into()))
1235 }
1236
1237 #[cfg(has_i128)]
from_u128(n: u128) -> Option<Self>1238 fn from_u128(n: u128) -> Option<Self> {
1239 Some(Ratio::from_integer(n.into()))
1240 }
1241
from_f32(n: f32) -> Option<Self>1242 fn from_f32(n: f32) -> Option<Self> {
1243 Ratio::from_float(n)
1244 }
1245
from_f64(n: f64) -> Option<Self>1246 fn from_f64(n: f64) -> Option<Self> {
1247 Ratio::from_float(n)
1248 }
1249 }
1250
1251 macro_rules! from_primitive_integer {
1252 ($typ:ty, $approx:ident) => {
1253 impl FromPrimitive for Ratio<$typ> {
1254 fn from_i64(n: i64) -> Option<Self> {
1255 <$typ as FromPrimitive>::from_i64(n).map(Ratio::from_integer)
1256 }
1257
1258 #[cfg(has_i128)]
1259 fn from_i128(n: i128) -> Option<Self> {
1260 <$typ as FromPrimitive>::from_i128(n).map(Ratio::from_integer)
1261 }
1262
1263 fn from_u64(n: u64) -> Option<Self> {
1264 <$typ as FromPrimitive>::from_u64(n).map(Ratio::from_integer)
1265 }
1266
1267 #[cfg(has_i128)]
1268 fn from_u128(n: u128) -> Option<Self> {
1269 <$typ as FromPrimitive>::from_u128(n).map(Ratio::from_integer)
1270 }
1271
1272 fn from_f32(n: f32) -> Option<Self> {
1273 $approx(n, 10e-20, 30)
1274 }
1275
1276 fn from_f64(n: f64) -> Option<Self> {
1277 $approx(n, 10e-20, 30)
1278 }
1279 }
1280 };
1281 }
1282
1283 from_primitive_integer!(i8, approximate_float);
1284 from_primitive_integer!(i16, approximate_float);
1285 from_primitive_integer!(i32, approximate_float);
1286 from_primitive_integer!(i64, approximate_float);
1287 #[cfg(has_i128)]
1288 from_primitive_integer!(i128, approximate_float);
1289 from_primitive_integer!(isize, approximate_float);
1290
1291 from_primitive_integer!(u8, approximate_float_unsigned);
1292 from_primitive_integer!(u16, approximate_float_unsigned);
1293 from_primitive_integer!(u32, approximate_float_unsigned);
1294 from_primitive_integer!(u64, approximate_float_unsigned);
1295 #[cfg(has_i128)]
1296 from_primitive_integer!(u128, approximate_float_unsigned);
1297 from_primitive_integer!(usize, approximate_float_unsigned);
1298
1299 impl<T: Integer + Signed + Bounded + NumCast + Clone> Ratio<T> {
approximate_float<F: FloatCore + NumCast>(f: F) -> Option<Ratio<T>>1300 pub fn approximate_float<F: FloatCore + NumCast>(f: F) -> Option<Ratio<T>> {
1301 // 1/10e-20 < 1/2**32 which seems like a good default, and 30 seems
1302 // to work well. Might want to choose something based on the types in the future, e.g.
1303 // T::max().recip() and T::bits() or something similar.
1304 let epsilon = <F as NumCast>::from(10e-20).expect("Can't convert 10e-20");
1305 approximate_float(f, epsilon, 30)
1306 }
1307 }
1308
approximate_float<T, F>(val: F, max_error: F, max_iterations: usize) -> Option<Ratio<T>> where T: Integer + Signed + Bounded + NumCast + Clone, F: FloatCore + NumCast,1309 fn approximate_float<T, F>(val: F, max_error: F, max_iterations: usize) -> Option<Ratio<T>>
1310 where
1311 T: Integer + Signed + Bounded + NumCast + Clone,
1312 F: FloatCore + NumCast,
1313 {
1314 let negative = val.is_sign_negative();
1315 let abs_val = val.abs();
1316
1317 let r = approximate_float_unsigned(abs_val, max_error, max_iterations);
1318
1319 // Make negative again if needed
1320 if negative {
1321 r.map(|r| r.neg())
1322 } else {
1323 r
1324 }
1325 }
1326
1327 // No Unsigned constraint because this also works on positive integers and is called
1328 // 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 + NumCast,1329 fn approximate_float_unsigned<T, F>(val: F, max_error: F, max_iterations: usize) -> Option<Ratio<T>>
1330 where
1331 T: Integer + Bounded + NumCast + Clone,
1332 F: FloatCore + NumCast,
1333 {
1334 // Continued fractions algorithm
1335 // http://mathforum.org/dr.math/faq/faq.fractions.html#decfrac
1336
1337 if val < F::zero() || val.is_nan() {
1338 return None;
1339 }
1340
1341 let mut q = val;
1342 let mut n0 = T::zero();
1343 let mut d0 = T::one();
1344 let mut n1 = T::one();
1345 let mut d1 = T::zero();
1346
1347 let t_max = T::max_value();
1348 let t_max_f = match <F as NumCast>::from(t_max.clone()) {
1349 None => return None,
1350 Some(t_max_f) => t_max_f,
1351 };
1352
1353 // 1/epsilon > T::MAX
1354 let epsilon = t_max_f.recip();
1355
1356 // Overflow
1357 if q > t_max_f {
1358 return None;
1359 }
1360
1361 for _ in 0..max_iterations {
1362 let a = match <T as NumCast>::from(q) {
1363 None => break,
1364 Some(a) => a,
1365 };
1366
1367 let a_f = match <F as NumCast>::from(a.clone()) {
1368 None => break,
1369 Some(a_f) => a_f,
1370 };
1371 let f = q - a_f;
1372
1373 // Prevent overflow
1374 if !a.is_zero()
1375 && (n1 > t_max.clone() / a.clone()
1376 || d1 > t_max.clone() / a.clone()
1377 || a.clone() * n1.clone() > t_max.clone() - n0.clone()
1378 || a.clone() * d1.clone() > t_max.clone() - d0.clone())
1379 {
1380 break;
1381 }
1382
1383 let n = a.clone() * n1.clone() + n0.clone();
1384 let d = a.clone() * d1.clone() + d0.clone();
1385
1386 n0 = n1;
1387 d0 = d1;
1388 n1 = n.clone();
1389 d1 = d.clone();
1390
1391 // Simplify fraction. Doing so here instead of at the end
1392 // allows us to get closer to the target value without overflows
1393 let g = Integer::gcd(&n1, &d1);
1394 if !g.is_zero() {
1395 n1 = n1 / g.clone();
1396 d1 = d1 / g.clone();
1397 }
1398
1399 // Close enough?
1400 let (n_f, d_f) = match (<F as NumCast>::from(n), <F as NumCast>::from(d)) {
1401 (Some(n_f), Some(d_f)) => (n_f, d_f),
1402 _ => break,
1403 };
1404 if (n_f / d_f - val).abs() < max_error {
1405 break;
1406 }
1407
1408 // Prevent division by ~0
1409 if f < epsilon {
1410 break;
1411 }
1412 q = f.recip();
1413 }
1414
1415 // Overflow
1416 if d1.is_zero() {
1417 return None;
1418 }
1419
1420 Some(Ratio::new(n1, d1))
1421 }
1422
1423 #[cfg(test)]
1424 #[cfg(feature = "std")]
hash<T: Hash>(x: &T) -> u641425 fn hash<T: Hash>(x: &T) -> u64 {
1426 use std::collections::hash_map::RandomState;
1427 use std::hash::BuildHasher;
1428 let mut hasher = <RandomState as BuildHasher>::Hasher::new();
1429 x.hash(&mut hasher);
1430 hasher.finish()
1431 }
1432
1433 #[cfg(test)]
1434 mod test {
1435 #[cfg(feature = "bigint")]
1436 use super::BigRational;
1437 use super::{Ratio, Rational, Rational64};
1438
1439 use core::f64;
1440 use core::i32;
1441 use core::isize;
1442 use core::str::FromStr;
1443 use integer::Integer;
1444 use traits::{FromPrimitive, One, Pow, Signed, Zero};
1445
1446 pub const _0: Rational = Ratio { numer: 0, denom: 1 };
1447 pub const _1: Rational = Ratio { numer: 1, denom: 1 };
1448 pub const _2: Rational = Ratio { numer: 2, denom: 1 };
1449 pub const _NEG2: Rational = Ratio {
1450 numer: -2,
1451 denom: 1,
1452 };
1453 pub const _1_2: Rational = Ratio { numer: 1, denom: 2 };
1454 pub const _3_2: Rational = Ratio { numer: 3, denom: 2 };
1455 pub const _5_2: Rational = Ratio { numer: 5, denom: 2 };
1456 pub const _NEG1_2: Rational = Ratio {
1457 numer: -1,
1458 denom: 2,
1459 };
1460 pub const _1_NEG2: Rational = Ratio {
1461 numer: 1,
1462 denom: -2,
1463 };
1464 pub const _NEG1_NEG2: Rational = Ratio {
1465 numer: -1,
1466 denom: -2,
1467 };
1468 pub const _1_3: Rational = Ratio { numer: 1, denom: 3 };
1469 pub const _NEG1_3: Rational = Ratio {
1470 numer: -1,
1471 denom: 3,
1472 };
1473 pub const _2_3: Rational = Ratio { numer: 2, denom: 3 };
1474 pub const _NEG2_3: Rational = Ratio {
1475 numer: -2,
1476 denom: 3,
1477 };
1478 pub const _MIN: Rational = Ratio {
1479 numer: isize::MIN,
1480 denom: 1,
1481 };
1482 pub const _MIN_P1: Rational = Ratio {
1483 numer: isize::MIN + 1,
1484 denom: 1,
1485 };
1486 pub const _MAX: Rational = Ratio {
1487 numer: isize::MAX,
1488 denom: 1,
1489 };
1490 pub const _MAX_M1: Rational = Ratio {
1491 numer: isize::MAX - 1,
1492 denom: 1,
1493 };
1494
1495 #[cfg(feature = "bigint")]
to_big(n: Rational) -> BigRational1496 pub fn to_big(n: Rational) -> BigRational {
1497 Ratio::new(
1498 FromPrimitive::from_isize(n.numer).unwrap(),
1499 FromPrimitive::from_isize(n.denom).unwrap(),
1500 )
1501 }
1502 #[cfg(not(feature = "bigint"))]
to_big(n: Rational) -> Rational1503 pub fn to_big(n: Rational) -> Rational {
1504 Ratio::new(
1505 FromPrimitive::from_isize(n.numer).unwrap(),
1506 FromPrimitive::from_isize(n.denom).unwrap(),
1507 )
1508 }
1509
1510 #[test]
test_test_constants()1511 fn test_test_constants() {
1512 // check our constants are what Ratio::new etc. would make.
1513 assert_eq!(_0, Zero::zero());
1514 assert_eq!(_1, One::one());
1515 assert_eq!(_2, Ratio::from_integer(2));
1516 assert_eq!(_1_2, Ratio::new(1, 2));
1517 assert_eq!(_3_2, Ratio::new(3, 2));
1518 assert_eq!(_NEG1_2, Ratio::new(-1, 2));
1519 assert_eq!(_2, From::from(2));
1520 }
1521
1522 #[test]
test_new_reduce()1523 fn test_new_reduce() {
1524 assert_eq!(Ratio::new(2, 2), One::one());
1525 assert_eq!(Ratio::new(0, i32::MIN), Zero::zero());
1526 assert_eq!(Ratio::new(i32::MIN, i32::MIN), One::one());
1527 }
1528 #[test]
1529 #[should_panic]
test_new_zero()1530 fn test_new_zero() {
1531 let _a = Ratio::new(1, 0);
1532 }
1533
1534 #[test]
test_approximate_float()1535 fn test_approximate_float() {
1536 assert_eq!(Ratio::from_f32(0.5f32), Some(Ratio::new(1i64, 2)));
1537 assert_eq!(Ratio::from_f64(0.5f64), Some(Ratio::new(1i32, 2)));
1538 assert_eq!(Ratio::from_f32(5f32), Some(Ratio::new(5i64, 1)));
1539 assert_eq!(Ratio::from_f64(5f64), Some(Ratio::new(5i32, 1)));
1540 assert_eq!(Ratio::from_f32(29.97f32), Some(Ratio::new(2997i64, 100)));
1541 assert_eq!(Ratio::from_f32(-29.97f32), Some(Ratio::new(-2997i64, 100)));
1542
1543 assert_eq!(Ratio::<i8>::from_f32(63.5f32), Some(Ratio::new(127i8, 2)));
1544 assert_eq!(Ratio::<i8>::from_f32(126.5f32), Some(Ratio::new(126i8, 1)));
1545 assert_eq!(Ratio::<i8>::from_f32(127.0f32), Some(Ratio::new(127i8, 1)));
1546 assert_eq!(Ratio::<i8>::from_f32(127.5f32), None);
1547 assert_eq!(Ratio::<i8>::from_f32(-63.5f32), Some(Ratio::new(-127i8, 2)));
1548 assert_eq!(
1549 Ratio::<i8>::from_f32(-126.5f32),
1550 Some(Ratio::new(-126i8, 1))
1551 );
1552 assert_eq!(
1553 Ratio::<i8>::from_f32(-127.0f32),
1554 Some(Ratio::new(-127i8, 1))
1555 );
1556 assert_eq!(Ratio::<i8>::from_f32(-127.5f32), None);
1557
1558 assert_eq!(Ratio::<u8>::from_f32(-127f32), None);
1559 assert_eq!(Ratio::<u8>::from_f32(127f32), Some(Ratio::new(127u8, 1)));
1560 assert_eq!(Ratio::<u8>::from_f32(127.5f32), Some(Ratio::new(255u8, 2)));
1561 assert_eq!(Ratio::<u8>::from_f32(256f32), None);
1562
1563 assert_eq!(Ratio::<i64>::from_f64(-10e200), None);
1564 assert_eq!(Ratio::<i64>::from_f64(10e200), None);
1565 assert_eq!(Ratio::<i64>::from_f64(f64::INFINITY), None);
1566 assert_eq!(Ratio::<i64>::from_f64(f64::NEG_INFINITY), None);
1567 assert_eq!(Ratio::<i64>::from_f64(f64::NAN), None);
1568 assert_eq!(
1569 Ratio::<i64>::from_f64(f64::EPSILON),
1570 Some(Ratio::new(1, 4503599627370496))
1571 );
1572 assert_eq!(Ratio::<i64>::from_f64(0.0), Some(Ratio::new(0, 1)));
1573 assert_eq!(Ratio::<i64>::from_f64(-0.0), Some(Ratio::new(0, 1)));
1574 }
1575
1576 #[test]
test_cmp()1577 fn test_cmp() {
1578 assert!(_0 == _0 && _1 == _1);
1579 assert!(_0 != _1 && _1 != _0);
1580 assert!(_0 < _1 && !(_1 < _0));
1581 assert!(_1 > _0 && !(_0 > _1));
1582
1583 assert!(_0 <= _0 && _1 <= _1);
1584 assert!(_0 <= _1 && !(_1 <= _0));
1585
1586 assert!(_0 >= _0 && _1 >= _1);
1587 assert!(_1 >= _0 && !(_0 >= _1));
1588
1589 let _0_2: Rational = Ratio::new_raw(0, 2);
1590 assert_eq!(_0, _0_2);
1591 }
1592
1593 #[test]
test_cmp_overflow()1594 fn test_cmp_overflow() {
1595 use core::cmp::Ordering;
1596
1597 // issue #7 example:
1598 let big = Ratio::new(128u8, 1);
1599 let small = big.recip();
1600 assert!(big > small);
1601
1602 // try a few that are closer together
1603 // (some matching numer, some matching denom, some neither)
1604 let ratios = [
1605 Ratio::new(125_i8, 127_i8),
1606 Ratio::new(63_i8, 64_i8),
1607 Ratio::new(124_i8, 125_i8),
1608 Ratio::new(125_i8, 126_i8),
1609 Ratio::new(126_i8, 127_i8),
1610 Ratio::new(127_i8, 126_i8),
1611 ];
1612
1613 fn check_cmp(a: Ratio<i8>, b: Ratio<i8>, ord: Ordering) {
1614 #[cfg(feature = "std")]
1615 println!("comparing {} and {}", a, b);
1616 assert_eq!(a.cmp(&b), ord);
1617 assert_eq!(b.cmp(&a), ord.reverse());
1618 }
1619
1620 for (i, &a) in ratios.iter().enumerate() {
1621 check_cmp(a, a, Ordering::Equal);
1622 check_cmp(-a, a, Ordering::Less);
1623 for &b in &ratios[i + 1..] {
1624 check_cmp(a, b, Ordering::Less);
1625 check_cmp(-a, -b, Ordering::Greater);
1626 check_cmp(a.recip(), b.recip(), Ordering::Greater);
1627 check_cmp(-a.recip(), -b.recip(), Ordering::Less);
1628 }
1629 }
1630 }
1631
1632 #[test]
test_to_integer()1633 fn test_to_integer() {
1634 assert_eq!(_0.to_integer(), 0);
1635 assert_eq!(_1.to_integer(), 1);
1636 assert_eq!(_2.to_integer(), 2);
1637 assert_eq!(_1_2.to_integer(), 0);
1638 assert_eq!(_3_2.to_integer(), 1);
1639 assert_eq!(_NEG1_2.to_integer(), 0);
1640 }
1641
1642 #[test]
test_numer()1643 fn test_numer() {
1644 assert_eq!(_0.numer(), &0);
1645 assert_eq!(_1.numer(), &1);
1646 assert_eq!(_2.numer(), &2);
1647 assert_eq!(_1_2.numer(), &1);
1648 assert_eq!(_3_2.numer(), &3);
1649 assert_eq!(_NEG1_2.numer(), &(-1));
1650 }
1651 #[test]
test_denom()1652 fn test_denom() {
1653 assert_eq!(_0.denom(), &1);
1654 assert_eq!(_1.denom(), &1);
1655 assert_eq!(_2.denom(), &1);
1656 assert_eq!(_1_2.denom(), &2);
1657 assert_eq!(_3_2.denom(), &2);
1658 assert_eq!(_NEG1_2.denom(), &2);
1659 }
1660
1661 #[test]
test_is_integer()1662 fn test_is_integer() {
1663 assert!(_0.is_integer());
1664 assert!(_1.is_integer());
1665 assert!(_2.is_integer());
1666 assert!(!_1_2.is_integer());
1667 assert!(!_3_2.is_integer());
1668 assert!(!_NEG1_2.is_integer());
1669 }
1670
1671 #[test]
1672 #[cfg(feature = "std")]
test_show()1673 fn test_show() {
1674 use std::string::ToString;
1675 assert_eq!(format!("{}", _2), "2".to_string());
1676 assert_eq!(format!("{}", _1_2), "1/2".to_string());
1677 assert_eq!(format!("{}", _0), "0".to_string());
1678 assert_eq!(format!("{}", Ratio::from_integer(-2)), "-2".to_string());
1679 }
1680
1681 mod arith {
1682 use super::super::{Ratio, Rational};
1683 use super::{to_big, _0, _1, _1_2, _2, _3_2, _5_2, _MAX, _MAX_M1, _MIN, _MIN_P1, _NEG1_2};
1684 use core::fmt::Debug;
1685 use integer::Integer;
1686 use traits::{Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, NumAssign};
1687
1688 #[test]
test_add()1689 fn test_add() {
1690 fn test(a: Rational, b: Rational, c: Rational) {
1691 assert_eq!(a + b, c);
1692 assert_eq!(
1693 {
1694 let mut x = a;
1695 x += b;
1696 x
1697 },
1698 c
1699 );
1700 assert_eq!(to_big(a) + to_big(b), to_big(c));
1701 assert_eq!(a.checked_add(&b), Some(c));
1702 assert_eq!(to_big(a).checked_add(&to_big(b)), Some(to_big(c)));
1703 }
1704 fn test_assign(a: Rational, b: isize, c: Rational) {
1705 assert_eq!(a + b, c);
1706 assert_eq!(
1707 {
1708 let mut x = a;
1709 x += b;
1710 x
1711 },
1712 c
1713 );
1714 }
1715
1716 test(_1, _1_2, _3_2);
1717 test(_1, _1, _2);
1718 test(_1_2, _3_2, _2);
1719 test(_1_2, _NEG1_2, _0);
1720 test_assign(_1_2, 1, _3_2);
1721 }
1722
1723 #[test]
test_add_overflow()1724 fn test_add_overflow() {
1725 // compares Ratio(1, T::max_value()) + Ratio(1, T::max_value())
1726 // to Ratio(1+1, T::max_value()) for each integer type.
1727 // Previously, this calculation would overflow.
1728 fn test_add_typed_overflow<T>()
1729 where
1730 T: Integer + Bounded + Clone + Debug + NumAssign,
1731 {
1732 let _1_max = Ratio::new(T::one(), T::max_value());
1733 let _2_max = Ratio::new(T::one() + T::one(), T::max_value());
1734 assert_eq!(_1_max.clone() + _1_max.clone(), _2_max);
1735 assert_eq!(
1736 {
1737 let mut tmp = _1_max.clone();
1738 tmp += _1_max.clone();
1739 tmp
1740 },
1741 _2_max.clone()
1742 );
1743 }
1744 test_add_typed_overflow::<u8>();
1745 test_add_typed_overflow::<u16>();
1746 test_add_typed_overflow::<u32>();
1747 test_add_typed_overflow::<u64>();
1748 test_add_typed_overflow::<usize>();
1749 #[cfg(has_u128)]
1750 test_add_typed_overflow::<u128>();
1751
1752 test_add_typed_overflow::<i8>();
1753 test_add_typed_overflow::<i16>();
1754 test_add_typed_overflow::<i32>();
1755 test_add_typed_overflow::<i64>();
1756 test_add_typed_overflow::<isize>();
1757 #[cfg(has_i128)]
1758 test_add_typed_overflow::<i128>();
1759 }
1760
1761 #[test]
test_sub()1762 fn test_sub() {
1763 fn test(a: Rational, b: Rational, c: Rational) {
1764 assert_eq!(a - b, c);
1765 assert_eq!(
1766 {
1767 let mut x = a;
1768 x -= b;
1769 x
1770 },
1771 c
1772 );
1773 assert_eq!(to_big(a) - to_big(b), to_big(c));
1774 assert_eq!(a.checked_sub(&b), Some(c));
1775 assert_eq!(to_big(a).checked_sub(&to_big(b)), Some(to_big(c)));
1776 }
1777 fn test_assign(a: Rational, b: isize, c: Rational) {
1778 assert_eq!(a - b, c);
1779 assert_eq!(
1780 {
1781 let mut x = a;
1782 x -= b;
1783 x
1784 },
1785 c
1786 );
1787 }
1788
1789 test(_1, _1_2, _1_2);
1790 test(_3_2, _1_2, _1);
1791 test(_1, _NEG1_2, _3_2);
1792 test_assign(_1_2, 1, _NEG1_2);
1793 }
1794
1795 #[test]
test_sub_overflow()1796 fn test_sub_overflow() {
1797 // compares Ratio(1, T::max_value()) - Ratio(1, T::max_value()) to T::zero()
1798 // for each integer type. Previously, this calculation would overflow.
1799 fn test_sub_typed_overflow<T>()
1800 where
1801 T: Integer + Bounded + Clone + Debug + NumAssign,
1802 {
1803 let _1_max: Ratio<T> = Ratio::new(T::one(), T::max_value());
1804 assert!(T::is_zero(&(_1_max.clone() - _1_max.clone()).numer));
1805 {
1806 let mut tmp: Ratio<T> = _1_max.clone();
1807 tmp -= _1_max.clone();
1808 assert!(T::is_zero(&tmp.numer));
1809 }
1810 }
1811 test_sub_typed_overflow::<u8>();
1812 test_sub_typed_overflow::<u16>();
1813 test_sub_typed_overflow::<u32>();
1814 test_sub_typed_overflow::<u64>();
1815 test_sub_typed_overflow::<usize>();
1816 #[cfg(has_u128)]
1817 test_sub_typed_overflow::<u128>();
1818
1819 test_sub_typed_overflow::<i8>();
1820 test_sub_typed_overflow::<i16>();
1821 test_sub_typed_overflow::<i32>();
1822 test_sub_typed_overflow::<i64>();
1823 test_sub_typed_overflow::<isize>();
1824 #[cfg(has_i128)]
1825 test_sub_typed_overflow::<i128>();
1826 }
1827
1828 #[test]
test_mul()1829 fn test_mul() {
1830 fn test(a: Rational, b: Rational, c: Rational) {
1831 assert_eq!(a * b, c);
1832 assert_eq!(
1833 {
1834 let mut x = a;
1835 x *= b;
1836 x
1837 },
1838 c
1839 );
1840 assert_eq!(to_big(a) * to_big(b), to_big(c));
1841 assert_eq!(a.checked_mul(&b), Some(c));
1842 assert_eq!(to_big(a).checked_mul(&to_big(b)), Some(to_big(c)));
1843 }
1844 fn test_assign(a: Rational, b: isize, c: Rational) {
1845 assert_eq!(a * b, c);
1846 assert_eq!(
1847 {
1848 let mut x = a;
1849 x *= b;
1850 x
1851 },
1852 c
1853 );
1854 }
1855
1856 test(_1, _1_2, _1_2);
1857 test(_1_2, _3_2, Ratio::new(3, 4));
1858 test(_1_2, _NEG1_2, Ratio::new(-1, 4));
1859 test_assign(_1_2, 2, _1);
1860 }
1861
1862 #[test]
test_mul_overflow()1863 fn test_mul_overflow() {
1864 fn test_mul_typed_overflow<T>()
1865 where
1866 T: Integer + Bounded + Clone + Debug + NumAssign + CheckedMul,
1867 {
1868 let two = T::one() + T::one();
1869 let _3 = T::one() + T::one() + T::one();
1870
1871 // 1/big * 2/3 = 1/(max/4*3), where big is max/2
1872 // make big = max/2, but also divisible by 2
1873 let big = T::max_value() / two.clone() / two.clone() * two.clone();
1874 let _1_big: Ratio<T> = Ratio::new(T::one(), big.clone());
1875 let _2_3: Ratio<T> = Ratio::new(two.clone(), _3.clone());
1876 assert_eq!(None, big.clone().checked_mul(&_3.clone()));
1877 let expected = Ratio::new(T::one(), big / two.clone() * _3.clone());
1878 assert_eq!(expected.clone(), _1_big.clone() * _2_3.clone());
1879 assert_eq!(
1880 Some(expected.clone()),
1881 _1_big.clone().checked_mul(&_2_3.clone())
1882 );
1883 assert_eq!(expected, {
1884 let mut tmp = _1_big.clone();
1885 tmp *= _2_3;
1886 tmp
1887 });
1888
1889 // big/3 * 3 = big/1
1890 // make big = max/2, but make it indivisible by 3
1891 let big = T::max_value() / two.clone() / _3.clone() * _3.clone() + T::one();
1892 assert_eq!(None, big.clone().checked_mul(&_3.clone()));
1893 let big_3 = Ratio::new(big.clone(), _3.clone());
1894 let expected = Ratio::new(big.clone(), T::one());
1895 assert_eq!(expected, big_3.clone() * _3.clone());
1896 assert_eq!(expected, {
1897 let mut tmp = big_3.clone();
1898 tmp *= _3.clone();
1899 tmp
1900 });
1901 }
1902 test_mul_typed_overflow::<u16>();
1903 test_mul_typed_overflow::<u8>();
1904 test_mul_typed_overflow::<u32>();
1905 test_mul_typed_overflow::<u64>();
1906 test_mul_typed_overflow::<usize>();
1907 #[cfg(has_u128)]
1908 test_mul_typed_overflow::<u128>();
1909
1910 test_mul_typed_overflow::<i8>();
1911 test_mul_typed_overflow::<i16>();
1912 test_mul_typed_overflow::<i32>();
1913 test_mul_typed_overflow::<i64>();
1914 test_mul_typed_overflow::<isize>();
1915 #[cfg(has_i128)]
1916 test_mul_typed_overflow::<i128>();
1917 }
1918
1919 #[test]
test_div()1920 fn test_div() {
1921 fn test(a: Rational, b: Rational, c: Rational) {
1922 assert_eq!(a / b, c);
1923 assert_eq!(
1924 {
1925 let mut x = a;
1926 x /= b;
1927 x
1928 },
1929 c
1930 );
1931 assert_eq!(to_big(a) / to_big(b), to_big(c));
1932 assert_eq!(a.checked_div(&b), Some(c));
1933 assert_eq!(to_big(a).checked_div(&to_big(b)), Some(to_big(c)));
1934 }
1935 fn test_assign(a: Rational, b: isize, c: Rational) {
1936 assert_eq!(a / b, c);
1937 assert_eq!(
1938 {
1939 let mut x = a;
1940 x /= b;
1941 x
1942 },
1943 c
1944 );
1945 }
1946
1947 test(_1, _1_2, _2);
1948 test(_3_2, _1_2, _1 + _2);
1949 test(_1, _NEG1_2, _NEG1_2 + _NEG1_2 + _NEG1_2 + _NEG1_2);
1950 test_assign(_1, 2, _1_2);
1951 }
1952
1953 #[test]
test_div_overflow()1954 fn test_div_overflow() {
1955 fn test_div_typed_overflow<T>()
1956 where
1957 T: Integer + Bounded + Clone + Debug + NumAssign + CheckedMul,
1958 {
1959 let two = T::one() + T::one();
1960 let _3 = T::one() + T::one() + T::one();
1961
1962 // 1/big / 3/2 = 1/(max/4*3), where big is max/2
1963 // big ~ max/2, and big is divisible by 2
1964 let big = T::max_value() / two.clone() / two.clone() * two.clone();
1965 assert_eq!(None, big.clone().checked_mul(&_3.clone()));
1966 let _1_big: Ratio<T> = Ratio::new(T::one(), big.clone());
1967 let _3_two: Ratio<T> = Ratio::new(_3.clone(), two.clone());
1968 let expected = Ratio::new(T::one(), big.clone() / two.clone() * _3.clone());
1969 assert_eq!(expected.clone(), _1_big.clone() / _3_two.clone());
1970 assert_eq!(
1971 Some(expected.clone()),
1972 _1_big.clone().checked_div(&_3_two.clone())
1973 );
1974 assert_eq!(expected, {
1975 let mut tmp = _1_big.clone();
1976 tmp /= _3_two;
1977 tmp
1978 });
1979
1980 // 3/big / 3 = 1/big where big is max/2
1981 // big ~ max/2, and big is not divisible by 3
1982 let big = T::max_value() / two.clone() / _3.clone() * _3.clone() + T::one();
1983 assert_eq!(None, big.clone().checked_mul(&_3.clone()));
1984 let _3_big = Ratio::new(_3.clone(), big.clone());
1985 let expected = Ratio::new(T::one(), big.clone());
1986 assert_eq!(expected, _3_big.clone() / _3.clone());
1987 assert_eq!(expected, {
1988 let mut tmp = _3_big.clone();
1989 tmp /= _3.clone();
1990 tmp
1991 });
1992 }
1993 test_div_typed_overflow::<u8>();
1994 test_div_typed_overflow::<u16>();
1995 test_div_typed_overflow::<u32>();
1996 test_div_typed_overflow::<u64>();
1997 test_div_typed_overflow::<usize>();
1998 #[cfg(has_u128)]
1999 test_div_typed_overflow::<u128>();
2000
2001 test_div_typed_overflow::<i8>();
2002 test_div_typed_overflow::<i16>();
2003 test_div_typed_overflow::<i32>();
2004 test_div_typed_overflow::<i64>();
2005 test_div_typed_overflow::<isize>();
2006 #[cfg(has_i128)]
2007 test_div_typed_overflow::<i128>();
2008 }
2009
2010 #[test]
test_rem()2011 fn test_rem() {
2012 fn test(a: Rational, b: Rational, c: Rational) {
2013 assert_eq!(a % b, c);
2014 assert_eq!(
2015 {
2016 let mut x = a;
2017 x %= b;
2018 x
2019 },
2020 c
2021 );
2022 assert_eq!(to_big(a) % to_big(b), to_big(c))
2023 }
2024 fn test_assign(a: Rational, b: isize, c: Rational) {
2025 assert_eq!(a % b, c);
2026 assert_eq!(
2027 {
2028 let mut x = a;
2029 x %= b;
2030 x
2031 },
2032 c
2033 );
2034 }
2035
2036 test(_3_2, _1, _1_2);
2037 test(_3_2, _1_2, _0);
2038 test(_5_2, _3_2, _1);
2039 test(_2, _NEG1_2, _0);
2040 test(_1_2, _2, _1_2);
2041 test_assign(_3_2, 1, _1_2);
2042 }
2043
2044 #[test]
test_rem_overflow()2045 fn test_rem_overflow() {
2046 // tests that Ratio(1,2) % Ratio(1, T::max_value()) equals 0
2047 // for each integer type. Previously, this calculation would overflow.
2048 fn test_rem_typed_overflow<T>()
2049 where
2050 T: Integer + Bounded + Clone + Debug + NumAssign,
2051 {
2052 let two = T::one() + T::one();
2053 //value near to maximum, but divisible by two
2054 let max_div2 = T::max_value() / two.clone() * two.clone();
2055 let _1_max: Ratio<T> = Ratio::new(T::one(), max_div2.clone());
2056 let _1_two: Ratio<T> = Ratio::new(T::one(), two);
2057 assert!(T::is_zero(&(_1_two.clone() % _1_max.clone()).numer));
2058 {
2059 let mut tmp: Ratio<T> = _1_two.clone();
2060 tmp %= _1_max.clone();
2061 assert!(T::is_zero(&tmp.numer));
2062 }
2063 }
2064 test_rem_typed_overflow::<u8>();
2065 test_rem_typed_overflow::<u16>();
2066 test_rem_typed_overflow::<u32>();
2067 test_rem_typed_overflow::<u64>();
2068 test_rem_typed_overflow::<usize>();
2069 #[cfg(has_u128)]
2070 test_rem_typed_overflow::<u128>();
2071
2072 test_rem_typed_overflow::<i8>();
2073 test_rem_typed_overflow::<i16>();
2074 test_rem_typed_overflow::<i32>();
2075 test_rem_typed_overflow::<i64>();
2076 test_rem_typed_overflow::<isize>();
2077 #[cfg(has_i128)]
2078 test_rem_typed_overflow::<i128>();
2079 }
2080
2081 #[test]
test_neg()2082 fn test_neg() {
2083 fn test(a: Rational, b: Rational) {
2084 assert_eq!(-a, b);
2085 assert_eq!(-to_big(a), to_big(b))
2086 }
2087
2088 test(_0, _0);
2089 test(_1_2, _NEG1_2);
2090 test(-_1, _1);
2091 }
2092 #[test]
test_zero()2093 fn test_zero() {
2094 assert_eq!(_0 + _0, _0);
2095 assert_eq!(_0 * _0, _0);
2096 assert_eq!(_0 * _1, _0);
2097 assert_eq!(_0 / _NEG1_2, _0);
2098 assert_eq!(_0 - _0, _0);
2099 }
2100 #[test]
2101 #[should_panic]
test_div_0()2102 fn test_div_0() {
2103 let _a = _1 / _0;
2104 }
2105
2106 #[test]
test_checked_failures()2107 fn test_checked_failures() {
2108 let big = Ratio::new(128u8, 1);
2109 let small = Ratio::new(1, 128u8);
2110 assert_eq!(big.checked_add(&big), None);
2111 assert_eq!(small.checked_sub(&big), None);
2112 assert_eq!(big.checked_mul(&big), None);
2113 assert_eq!(small.checked_div(&big), None);
2114 assert_eq!(_1.checked_div(&_0), None);
2115 }
2116
2117 #[test]
test_checked_zeros()2118 fn test_checked_zeros() {
2119 assert_eq!(_0.checked_add(&_0), Some(_0));
2120 assert_eq!(_0.checked_sub(&_0), Some(_0));
2121 assert_eq!(_0.checked_mul(&_0), Some(_0));
2122 assert_eq!(_0.checked_div(&_0), None);
2123 }
2124
2125 #[test]
test_checked_min()2126 fn test_checked_min() {
2127 assert_eq!(_MIN.checked_add(&_MIN), None);
2128 assert_eq!(_MIN.checked_sub(&_MIN), Some(_0));
2129 assert_eq!(_MIN.checked_mul(&_MIN), None);
2130 assert_eq!(_MIN.checked_div(&_MIN), Some(_1));
2131 assert_eq!(_0.checked_add(&_MIN), Some(_MIN));
2132 assert_eq!(_0.checked_sub(&_MIN), None);
2133 assert_eq!(_0.checked_mul(&_MIN), Some(_0));
2134 assert_eq!(_0.checked_div(&_MIN), Some(_0));
2135 assert_eq!(_1.checked_add(&_MIN), Some(_MIN_P1));
2136 assert_eq!(_1.checked_sub(&_MIN), None);
2137 assert_eq!(_1.checked_mul(&_MIN), Some(_MIN));
2138 assert_eq!(_1.checked_div(&_MIN), None);
2139 assert_eq!(_MIN.checked_add(&_0), Some(_MIN));
2140 assert_eq!(_MIN.checked_sub(&_0), Some(_MIN));
2141 assert_eq!(_MIN.checked_mul(&_0), Some(_0));
2142 assert_eq!(_MIN.checked_div(&_0), None);
2143 assert_eq!(_MIN.checked_add(&_1), Some(_MIN_P1));
2144 assert_eq!(_MIN.checked_sub(&_1), None);
2145 assert_eq!(_MIN.checked_mul(&_1), Some(_MIN));
2146 assert_eq!(_MIN.checked_div(&_1), Some(_MIN));
2147 }
2148
2149 #[test]
test_checked_max()2150 fn test_checked_max() {
2151 assert_eq!(_MAX.checked_add(&_MAX), None);
2152 assert_eq!(_MAX.checked_sub(&_MAX), Some(_0));
2153 assert_eq!(_MAX.checked_mul(&_MAX), None);
2154 assert_eq!(_MAX.checked_div(&_MAX), Some(_1));
2155 assert_eq!(_0.checked_add(&_MAX), Some(_MAX));
2156 assert_eq!(_0.checked_sub(&_MAX), Some(_MIN_P1));
2157 assert_eq!(_0.checked_mul(&_MAX), Some(_0));
2158 assert_eq!(_0.checked_div(&_MAX), Some(_0));
2159 assert_eq!(_1.checked_add(&_MAX), None);
2160 assert_eq!(_1.checked_sub(&_MAX), Some(-_MAX_M1));
2161 assert_eq!(_1.checked_mul(&_MAX), Some(_MAX));
2162 assert_eq!(_1.checked_div(&_MAX), Some(_MAX.recip()));
2163 assert_eq!(_MAX.checked_add(&_0), Some(_MAX));
2164 assert_eq!(_MAX.checked_sub(&_0), Some(_MAX));
2165 assert_eq!(_MAX.checked_mul(&_0), Some(_0));
2166 assert_eq!(_MAX.checked_div(&_0), None);
2167 assert_eq!(_MAX.checked_add(&_1), None);
2168 assert_eq!(_MAX.checked_sub(&_1), Some(_MAX_M1));
2169 assert_eq!(_MAX.checked_mul(&_1), Some(_MAX));
2170 assert_eq!(_MAX.checked_div(&_1), Some(_MAX));
2171 }
2172
2173 #[test]
test_checked_min_max()2174 fn test_checked_min_max() {
2175 assert_eq!(_MIN.checked_add(&_MAX), Some(-_1));
2176 assert_eq!(_MIN.checked_sub(&_MAX), None);
2177 assert_eq!(_MIN.checked_mul(&_MAX), None);
2178 assert_eq!(
2179 _MIN.checked_div(&_MAX),
2180 Some(Ratio::new(_MIN.numer, _MAX.numer))
2181 );
2182 assert_eq!(_MAX.checked_add(&_MIN), Some(-_1));
2183 assert_eq!(_MAX.checked_sub(&_MIN), None);
2184 assert_eq!(_MAX.checked_mul(&_MIN), None);
2185 assert_eq!(_MAX.checked_div(&_MIN), None);
2186 }
2187 }
2188
2189 #[test]
test_round()2190 fn test_round() {
2191 assert_eq!(_1_3.ceil(), _1);
2192 assert_eq!(_1_3.floor(), _0);
2193 assert_eq!(_1_3.round(), _0);
2194 assert_eq!(_1_3.trunc(), _0);
2195
2196 assert_eq!(_NEG1_3.ceil(), _0);
2197 assert_eq!(_NEG1_3.floor(), -_1);
2198 assert_eq!(_NEG1_3.round(), _0);
2199 assert_eq!(_NEG1_3.trunc(), _0);
2200
2201 assert_eq!(_2_3.ceil(), _1);
2202 assert_eq!(_2_3.floor(), _0);
2203 assert_eq!(_2_3.round(), _1);
2204 assert_eq!(_2_3.trunc(), _0);
2205
2206 assert_eq!(_NEG2_3.ceil(), _0);
2207 assert_eq!(_NEG2_3.floor(), -_1);
2208 assert_eq!(_NEG2_3.round(), -_1);
2209 assert_eq!(_NEG2_3.trunc(), _0);
2210
2211 assert_eq!(_1_2.ceil(), _1);
2212 assert_eq!(_1_2.floor(), _0);
2213 assert_eq!(_1_2.round(), _1);
2214 assert_eq!(_1_2.trunc(), _0);
2215
2216 assert_eq!(_NEG1_2.ceil(), _0);
2217 assert_eq!(_NEG1_2.floor(), -_1);
2218 assert_eq!(_NEG1_2.round(), -_1);
2219 assert_eq!(_NEG1_2.trunc(), _0);
2220
2221 assert_eq!(_1.ceil(), _1);
2222 assert_eq!(_1.floor(), _1);
2223 assert_eq!(_1.round(), _1);
2224 assert_eq!(_1.trunc(), _1);
2225
2226 // Overflow checks
2227
2228 let _neg1 = Ratio::from_integer(-1);
2229 let _large_rat1 = Ratio::new(i32::MAX, i32::MAX - 1);
2230 let _large_rat2 = Ratio::new(i32::MAX - 1, i32::MAX);
2231 let _large_rat3 = Ratio::new(i32::MIN + 2, i32::MIN + 1);
2232 let _large_rat4 = Ratio::new(i32::MIN + 1, i32::MIN + 2);
2233 let _large_rat5 = Ratio::new(i32::MIN + 2, i32::MAX);
2234 let _large_rat6 = Ratio::new(i32::MAX, i32::MIN + 2);
2235 let _large_rat7 = Ratio::new(1, i32::MIN + 1);
2236 let _large_rat8 = Ratio::new(1, i32::MAX);
2237
2238 assert_eq!(_large_rat1.round(), One::one());
2239 assert_eq!(_large_rat2.round(), One::one());
2240 assert_eq!(_large_rat3.round(), One::one());
2241 assert_eq!(_large_rat4.round(), One::one());
2242 assert_eq!(_large_rat5.round(), _neg1);
2243 assert_eq!(_large_rat6.round(), _neg1);
2244 assert_eq!(_large_rat7.round(), Zero::zero());
2245 assert_eq!(_large_rat8.round(), Zero::zero());
2246 }
2247
2248 #[test]
test_fract()2249 fn test_fract() {
2250 assert_eq!(_1.fract(), _0);
2251 assert_eq!(_NEG1_2.fract(), _NEG1_2);
2252 assert_eq!(_1_2.fract(), _1_2);
2253 assert_eq!(_3_2.fract(), _1_2);
2254 }
2255
2256 #[test]
test_recip()2257 fn test_recip() {
2258 assert_eq!(_1 * _1.recip(), _1);
2259 assert_eq!(_2 * _2.recip(), _1);
2260 assert_eq!(_1_2 * _1_2.recip(), _1);
2261 assert_eq!(_3_2 * _3_2.recip(), _1);
2262 assert_eq!(_NEG1_2 * _NEG1_2.recip(), _1);
2263
2264 assert_eq!(_3_2.recip(), _2_3);
2265 assert_eq!(_NEG1_2.recip(), _NEG2);
2266 assert_eq!(_NEG1_2.recip().denom(), &1);
2267 }
2268
2269 #[test]
2270 #[should_panic(expected = "== 0")]
test_recip_fail()2271 fn test_recip_fail() {
2272 let _a = Ratio::new(0, 1).recip();
2273 }
2274
2275 #[test]
test_pow()2276 fn test_pow() {
2277 fn test(r: Rational, e: i32, expected: Rational) {
2278 assert_eq!(r.pow(e), expected);
2279 assert_eq!(Pow::pow(r, e), expected);
2280 assert_eq!(Pow::pow(r, &e), expected);
2281 assert_eq!(Pow::pow(&r, e), expected);
2282 assert_eq!(Pow::pow(&r, &e), expected);
2283 }
2284
2285 test(_1_2, 2, Ratio::new(1, 4));
2286 test(_1_2, -2, Ratio::new(4, 1));
2287 test(_1, 1, _1);
2288 test(_1, i32::MAX, _1);
2289 test(_1, i32::MIN, _1);
2290 test(_NEG1_2, 2, _1_2.pow(2i32));
2291 test(_NEG1_2, 3, -_1_2.pow(3i32));
2292 test(_3_2, 0, _1);
2293 test(_3_2, -1, _3_2.recip());
2294 test(_3_2, 3, Ratio::new(27, 8));
2295 }
2296
2297 #[test]
2298 #[cfg(feature = "std")]
test_to_from_str()2299 fn test_to_from_str() {
2300 use std::string::{String, ToString};
2301 fn test(r: Rational, s: String) {
2302 assert_eq!(FromStr::from_str(&s), Ok(r));
2303 assert_eq!(r.to_string(), s);
2304 }
2305 test(_1, "1".to_string());
2306 test(_0, "0".to_string());
2307 test(_1_2, "1/2".to_string());
2308 test(_3_2, "3/2".to_string());
2309 test(_2, "2".to_string());
2310 test(_NEG1_2, "-1/2".to_string());
2311 }
2312 #[test]
test_from_str_fail()2313 fn test_from_str_fail() {
2314 fn test(s: &str) {
2315 let rational: Result<Rational, _> = FromStr::from_str(s);
2316 assert!(rational.is_err());
2317 }
2318
2319 let xs = ["0 /1", "abc", "", "1/", "--1/2", "3/2/1", "1/0"];
2320 for &s in xs.iter() {
2321 test(s);
2322 }
2323 }
2324
2325 #[cfg(feature = "bigint")]
2326 #[test]
test_from_float()2327 fn test_from_float() {
2328 use traits::float::FloatCore;
2329 fn test<T: FloatCore>(given: T, (numer, denom): (&str, &str)) {
2330 let ratio: BigRational = Ratio::from_float(given).unwrap();
2331 assert_eq!(
2332 ratio,
2333 Ratio::new(
2334 FromStr::from_str(numer).unwrap(),
2335 FromStr::from_str(denom).unwrap()
2336 )
2337 );
2338 }
2339
2340 // f32
2341 test(3.14159265359f32, ("13176795", "4194304"));
2342 test(2f32.powf(100.), ("1267650600228229401496703205376", "1"));
2343 test(-2f32.powf(100.), ("-1267650600228229401496703205376", "1"));
2344 test(
2345 1.0 / 2f32.powf(100.),
2346 ("1", "1267650600228229401496703205376"),
2347 );
2348 test(684729.48391f32, ("1369459", "2"));
2349 test(-8573.5918555f32, ("-4389679", "512"));
2350
2351 // f64
2352 test(3.14159265359f64, ("3537118876014453", "1125899906842624"));
2353 test(2f64.powf(100.), ("1267650600228229401496703205376", "1"));
2354 test(-2f64.powf(100.), ("-1267650600228229401496703205376", "1"));
2355 test(684729.48391f64, ("367611342500051", "536870912"));
2356 test(-8573.5918555f64, ("-4713381968463931", "549755813888"));
2357 test(
2358 1.0 / 2f64.powf(100.),
2359 ("1", "1267650600228229401496703205376"),
2360 );
2361 }
2362
2363 #[cfg(feature = "bigint")]
2364 #[test]
test_from_float_fail()2365 fn test_from_float_fail() {
2366 use core::{f32, f64};
2367
2368 assert_eq!(Ratio::from_float(f32::NAN), None);
2369 assert_eq!(Ratio::from_float(f32::INFINITY), None);
2370 assert_eq!(Ratio::from_float(f32::NEG_INFINITY), None);
2371 assert_eq!(Ratio::from_float(f64::NAN), None);
2372 assert_eq!(Ratio::from_float(f64::INFINITY), None);
2373 assert_eq!(Ratio::from_float(f64::NEG_INFINITY), None);
2374 }
2375
2376 #[test]
test_signed()2377 fn test_signed() {
2378 assert_eq!(_NEG1_2.abs(), _1_2);
2379 assert_eq!(_3_2.abs_sub(&_1_2), _1);
2380 assert_eq!(_1_2.abs_sub(&_3_2), Zero::zero());
2381 assert_eq!(_1_2.signum(), One::one());
2382 assert_eq!(_NEG1_2.signum(), -<Ratio<isize>>::one());
2383 assert_eq!(_0.signum(), Zero::zero());
2384 assert!(_NEG1_2.is_negative());
2385 assert!(_1_NEG2.is_negative());
2386 assert!(!_NEG1_2.is_positive());
2387 assert!(!_1_NEG2.is_positive());
2388 assert!(_1_2.is_positive());
2389 assert!(_NEG1_NEG2.is_positive());
2390 assert!(!_1_2.is_negative());
2391 assert!(!_NEG1_NEG2.is_negative());
2392 assert!(!_0.is_positive());
2393 assert!(!_0.is_negative());
2394 }
2395
2396 #[test]
2397 #[cfg(feature = "std")]
test_hash()2398 fn test_hash() {
2399 assert!(::hash(&_0) != ::hash(&_1));
2400 assert!(::hash(&_0) != ::hash(&_3_2));
2401
2402 // a == b -> hash(a) == hash(b)
2403 let a = Rational::new_raw(4, 2);
2404 let b = Rational::new_raw(6, 3);
2405 assert_eq!(a, b);
2406 assert_eq!(::hash(&a), ::hash(&b));
2407
2408 let a = Rational::new_raw(123456789, 1000);
2409 let b = Rational::new_raw(123456789 * 5, 5000);
2410 assert_eq!(a, b);
2411 assert_eq!(::hash(&a), ::hash(&b));
2412 }
2413
2414 #[test]
test_into_pair()2415 fn test_into_pair() {
2416 assert_eq!((0, 1), _0.into());
2417 assert_eq!((-2, 1), _NEG2.into());
2418 assert_eq!((1, -2), _1_NEG2.into());
2419 }
2420
2421 #[test]
test_from_pair()2422 fn test_from_pair() {
2423 assert_eq!(_0, Ratio::from((0, 1)));
2424 assert_eq!(_1, Ratio::from((1, 1)));
2425 assert_eq!(_NEG2, Ratio::from((-2, 1)));
2426 assert_eq!(_1_NEG2, Ratio::from((1, -2)));
2427 }
2428
2429 #[test]
ratio_iter_sum()2430 fn ratio_iter_sum() {
2431 // generic function to assure the iter method can be called
2432 // for any Iterator with Item = Ratio<impl Integer> or Ratio<&impl Integer>
2433 fn iter_sums<T: Integer + Clone>(slice: &[Ratio<T>]) -> [Ratio<T>; 3] {
2434 let mut manual_sum = Ratio::new(T::zero(), T::one());
2435 for ratio in slice {
2436 manual_sum = manual_sum + ratio;
2437 }
2438 [manual_sum, slice.iter().sum(), slice.iter().cloned().sum()]
2439 }
2440 // collect into array so test works on no_std
2441 let mut nums = [Ratio::new(0, 1); 1000];
2442 for (i, r) in (0..1000).map(|n| Ratio::new(n, 500)).enumerate() {
2443 nums[i] = r;
2444 }
2445 let sums = iter_sums(&nums[..]);
2446 assert_eq!(sums[0], sums[1]);
2447 assert_eq!(sums[0], sums[2]);
2448 }
2449
2450 #[test]
ratio_iter_product()2451 fn ratio_iter_product() {
2452 // generic function to assure the iter method can be called
2453 // for any Iterator with Item = Ratio<impl Integer> or Ratio<&impl Integer>
2454 fn iter_products<T: Integer + Clone>(slice: &[Ratio<T>]) -> [Ratio<T>; 3] {
2455 let mut manual_prod = Ratio::new(T::one(), T::one());
2456 for ratio in slice {
2457 manual_prod = manual_prod * ratio;
2458 }
2459 [
2460 manual_prod,
2461 slice.iter().product(),
2462 slice.iter().cloned().product(),
2463 ]
2464 }
2465
2466 // collect into array so test works on no_std
2467 let mut nums = [Ratio::new(0, 1); 1000];
2468 for (i, r) in (0..1000).map(|n| Ratio::new(n, 500)).enumerate() {
2469 nums[i] = r;
2470 }
2471 let products = iter_products(&nums[..]);
2472 assert_eq!(products[0], products[1]);
2473 assert_eq!(products[0], products[2]);
2474 }
2475
2476 #[test]
test_num_zero()2477 fn test_num_zero() {
2478 let zero = Rational64::zero();
2479 assert!(zero.is_zero());
2480
2481 let mut r = Rational64::new(123, 456);
2482 assert!(!r.is_zero());
2483 assert_eq!(&r + &zero, r);
2484
2485 r.set_zero();
2486 assert!(r.is_zero());
2487 }
2488
2489 #[test]
test_num_one()2490 fn test_num_one() {
2491 let one = Rational64::one();
2492 assert!(one.is_one());
2493
2494 let mut r = Rational64::new(123, 456);
2495 assert!(!r.is_one());
2496 assert_eq!(&r * &one, r);
2497
2498 r.set_one();
2499 assert!(r.is_one());
2500 }
2501
2502 #[cfg(has_const_fn)]
2503 #[test]
test_const()2504 fn test_const() {
2505 const N: Ratio<i32> = Ratio::new_raw(123, 456);
2506 const N_NUMER: &i32 = N.numer();
2507 const N_DENOM: &i32 = N.denom();
2508
2509 assert_eq!(N_NUMER, &123);
2510 assert_eq!(N_DENOM, &456);
2511
2512 let r = N.reduced();
2513 assert_eq!(r.numer(), &(123 / 3));
2514 assert_eq!(r.denom(), &(456 / 3));
2515 }
2516 }
2517