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.31 and greater.
16
17 #![doc(html_root_url = "https://docs.rs/num-rational/0.3")]
18 #![no_std]
19 // Ratio ops often use other "suspicious" ops
20 #![allow(clippy::suspicious_arithmetic_impl)]
21 #![allow(clippy::suspicious_op_assign_impl)]
22
23 #[cfg(feature = "std")]
24 #[macro_use]
25 extern crate std;
26
27 use core::cmp;
28 use core::fmt;
29 use core::fmt::{Binary, Display, Formatter, LowerExp, LowerHex, Octal, UpperExp, UpperHex};
30 use core::hash::{Hash, Hasher};
31 use core::ops::{Add, Div, Mul, Neg, Rem, ShlAssign, Sub};
32 use core::str::FromStr;
33 #[cfg(feature = "std")]
34 use std::error::Error;
35
36 #[cfg(feature = "num-bigint")]
37 use num_bigint::{BigInt, BigUint, Sign, ToBigInt};
38
39 use num_integer::Integer;
40 use num_traits::float::FloatCore;
41 use num_traits::ToPrimitive;
42 use num_traits::{
43 Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, FromPrimitive, Inv, Num, NumCast, One,
44 Pow, Signed, Zero,
45 };
46
47 mod pow;
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 = "num-bigint")]
67 /// Alias for arbitrary precision rationals.
68 pub type BigRational = Ratio<BigInt>;
69
70 /// These method are `const` for Rust 1.31 and later.
71 impl<T> Ratio<T> {
72 /// Creates a `Ratio` without checking for `denom == 0` or reducing.
73 ///
74 /// **There are several methods that will panic if used on a `Ratio` with
75 /// `denom == 0`.**
76 #[inline]
new_raw(numer: T, denom: T) -> Ratio<T>77 pub const fn new_raw(numer: T, denom: T) -> Ratio<T> {
78 Ratio { numer, denom }
79 }
80
81 /// Gets an immutable reference to the numerator.
82 #[inline]
numer(&self) -> &T83 pub const fn numer(&self) -> &T {
84 &self.numer
85 }
86
87 /// Gets an immutable reference to the denominator.
88 #[inline]
denom(&self) -> &T89 pub const fn denom(&self) -> &T {
90 &self.denom
91 }
92 }
93
94 impl<T: Clone + Integer> Ratio<T> {
95 /// Creates a new `Ratio`.
96 ///
97 /// **Panics if `denom` is zero.**
98 #[inline]
new(numer: T, denom: T) -> Ratio<T>99 pub fn new(numer: T, denom: T) -> Ratio<T> {
100 let mut ret = Ratio::new_raw(numer, denom);
101 ret.reduce();
102 ret
103 }
104
105 /// Creates a `Ratio` representing the integer `t`.
106 #[inline]
from_integer(t: T) -> Ratio<T>107 pub fn from_integer(t: T) -> Ratio<T> {
108 Ratio::new_raw(t, One::one())
109 }
110
111 /// Converts to an integer, rounding towards zero.
112 #[inline]
to_integer(&self) -> T113 pub fn to_integer(&self) -> T {
114 self.trunc().numer
115 }
116
117 /// Returns true if the rational number is an integer (denominator is 1).
118 #[inline]
is_integer(&self) -> bool119 pub fn is_integer(&self) -> bool {
120 self.denom.is_one()
121 }
122
123 /// Puts self into lowest terms, with `denom` > 0.
124 ///
125 /// **Panics if `denom` is zero.**
reduce(&mut self)126 fn reduce(&mut self) {
127 if self.denom.is_zero() {
128 panic!("denominator == 0");
129 }
130 if self.numer.is_zero() {
131 self.denom.set_one();
132 return;
133 }
134 if self.numer == self.denom {
135 self.set_one();
136 return;
137 }
138 let g: T = self.numer.gcd(&self.denom);
139
140 // FIXME(#5992): assignment operator overloads
141 // self.numer /= g;
142 // T: Clone + Integer != T: Clone + NumAssign
143 self.numer = self.numer.clone() / g.clone();
144 // FIXME(#5992): assignment operator overloads
145 // self.denom /= g;
146 // T: Clone + Integer != T: Clone + NumAssign
147 self.denom = self.denom.clone() / g;
148
149 // keep denom positive!
150 if self.denom < T::zero() {
151 self.numer = T::zero() - self.numer.clone();
152 self.denom = T::zero() - self.denom.clone();
153 }
154 }
155
156 /// Returns a reduced copy of self.
157 ///
158 /// In general, it is not necessary to use this method, as the only
159 /// method of procuring a non-reduced fraction is through `new_raw`.
160 ///
161 /// **Panics if `denom` is zero.**
reduced(&self) -> Ratio<T>162 pub fn reduced(&self) -> Ratio<T> {
163 let mut ret = self.clone();
164 ret.reduce();
165 ret
166 }
167
168 /// Returns the reciprocal.
169 ///
170 /// **Panics if the `Ratio` is zero.**
171 #[inline]
recip(&self) -> Ratio<T>172 pub fn recip(&self) -> Ratio<T> {
173 self.clone().into_recip()
174 }
175
176 #[inline]
into_recip(self) -> Ratio<T>177 fn into_recip(self) -> Ratio<T> {
178 match self.numer.cmp(&T::zero()) {
179 cmp::Ordering::Equal => panic!("division by zero"),
180 cmp::Ordering::Greater => Ratio::new_raw(self.denom, self.numer),
181 cmp::Ordering::Less => Ratio::new_raw(T::zero() - self.denom, T::zero() - self.numer),
182 }
183 }
184
185 /// Rounds towards minus infinity.
186 #[inline]
floor(&self) -> Ratio<T>187 pub fn floor(&self) -> Ratio<T> {
188 if *self < Zero::zero() {
189 let one: T = One::one();
190 Ratio::from_integer(
191 (self.numer.clone() - self.denom.clone() + one) / self.denom.clone(),
192 )
193 } else {
194 Ratio::from_integer(self.numer.clone() / self.denom.clone())
195 }
196 }
197
198 /// Rounds towards plus infinity.
199 #[inline]
ceil(&self) -> Ratio<T>200 pub fn ceil(&self) -> Ratio<T> {
201 if *self < Zero::zero() {
202 Ratio::from_integer(self.numer.clone() / self.denom.clone())
203 } else {
204 let one: T = One::one();
205 Ratio::from_integer(
206 (self.numer.clone() + self.denom.clone() - one) / self.denom.clone(),
207 )
208 }
209 }
210
211 /// Rounds to the nearest integer. Rounds half-way cases away from zero.
212 #[inline]
round(&self) -> Ratio<T>213 pub fn round(&self) -> Ratio<T> {
214 let zero: Ratio<T> = Zero::zero();
215 let one: T = One::one();
216 let two: T = one.clone() + one.clone();
217
218 // Find unsigned fractional part of rational number
219 let mut fractional = self.fract();
220 if fractional < zero {
221 fractional = zero - fractional
222 };
223
224 // The algorithm compares the unsigned fractional part with 1/2, that
225 // is, a/b >= 1/2, or a >= b/2. For odd denominators, we use
226 // a >= (b/2)+1. This avoids overflow issues.
227 let half_or_larger = if fractional.denom.is_even() {
228 fractional.numer >= fractional.denom / two
229 } else {
230 fractional.numer >= (fractional.denom / two) + one
231 };
232
233 if half_or_larger {
234 let one: Ratio<T> = One::one();
235 if *self >= Zero::zero() {
236 self.trunc() + one
237 } else {
238 self.trunc() - one
239 }
240 } else {
241 self.trunc()
242 }
243 }
244
245 /// Rounds towards zero.
246 #[inline]
trunc(&self) -> Ratio<T>247 pub fn trunc(&self) -> Ratio<T> {
248 Ratio::from_integer(self.numer.clone() / self.denom.clone())
249 }
250
251 /// Returns the fractional part of a number, with division rounded towards zero.
252 ///
253 /// Satisfies `self == self.trunc() + self.fract()`.
254 #[inline]
fract(&self) -> Ratio<T>255 pub fn fract(&self) -> Ratio<T> {
256 Ratio::new_raw(self.numer.clone() % self.denom.clone(), self.denom.clone())
257 }
258
259 /// Raises the `Ratio` to the power of an exponent.
260 #[inline]
pow(&self, expon: i32) -> Ratio<T> where for<'a> &'a T: Pow<u32, Output = T>,261 pub fn pow(&self, expon: i32) -> Ratio<T>
262 where
263 for<'a> &'a T: Pow<u32, Output = T>,
264 {
265 Pow::pow(self, expon)
266 }
267 }
268
269 #[cfg(feature = "num-bigint")]
270 impl Ratio<BigInt> {
271 /// Converts a float into a rational number.
from_float<T: FloatCore>(f: T) -> Option<BigRational>272 pub fn from_float<T: FloatCore>(f: T) -> Option<BigRational> {
273 if !f.is_finite() {
274 return None;
275 }
276 let (mantissa, exponent, sign) = f.integer_decode();
277 let bigint_sign = if sign == 1 { Sign::Plus } else { Sign::Minus };
278 if exponent < 0 {
279 let one: BigInt = One::one();
280 let denom: BigInt = one << ((-exponent) as usize);
281 let numer: BigUint = FromPrimitive::from_u64(mantissa).unwrap();
282 Some(Ratio::new(BigInt::from_biguint(bigint_sign, numer), denom))
283 } else {
284 let mut numer: BigUint = FromPrimitive::from_u64(mantissa).unwrap();
285 numer <<= exponent as usize;
286 Some(Ratio::from_integer(BigInt::from_biguint(
287 bigint_sign,
288 numer,
289 )))
290 }
291 }
292 }
293
294 // From integer
295 impl<T> From<T> for Ratio<T>
296 where
297 T: Clone + Integer,
298 {
from(x: T) -> Ratio<T>299 fn from(x: T) -> Ratio<T> {
300 Ratio::from_integer(x)
301 }
302 }
303
304 // From pair (through the `new` constructor)
305 impl<T> From<(T, T)> for Ratio<T>
306 where
307 T: Clone + Integer,
308 {
from(pair: (T, T)) -> Ratio<T>309 fn from(pair: (T, T)) -> Ratio<T> {
310 Ratio::new(pair.0, pair.1)
311 }
312 }
313
314 // Comparisons
315
316 // Mathematically, comparing a/b and c/d is the same as comparing a*d and b*c, but it's very easy
317 // for those multiplications to overflow fixed-size integers, so we need to take care.
318
319 impl<T: Clone + Integer> Ord for Ratio<T> {
320 #[inline]
cmp(&self, other: &Self) -> cmp::Ordering321 fn cmp(&self, other: &Self) -> cmp::Ordering {
322 // With equal denominators, the numerators can be directly compared
323 if self.denom == other.denom {
324 let ord = self.numer.cmp(&other.numer);
325 return if self.denom < T::zero() {
326 ord.reverse()
327 } else {
328 ord
329 };
330 }
331
332 // With equal numerators, the denominators can be inversely compared
333 if self.numer == other.numer {
334 if self.numer.is_zero() {
335 return cmp::Ordering::Equal;
336 }
337 let ord = self.denom.cmp(&other.denom);
338 return if self.numer < T::zero() {
339 ord
340 } else {
341 ord.reverse()
342 };
343 }
344
345 // Unfortunately, we don't have CheckedMul to try. That could sometimes avoid all the
346 // division below, or even always avoid it for BigInt and BigUint.
347 // FIXME- future breaking change to add Checked* to Integer?
348
349 // Compare as floored integers and remainders
350 let (self_int, self_rem) = self.numer.div_mod_floor(&self.denom);
351 let (other_int, other_rem) = other.numer.div_mod_floor(&other.denom);
352 match self_int.cmp(&other_int) {
353 cmp::Ordering::Greater => cmp::Ordering::Greater,
354 cmp::Ordering::Less => cmp::Ordering::Less,
355 cmp::Ordering::Equal => {
356 match (self_rem.is_zero(), other_rem.is_zero()) {
357 (true, true) => cmp::Ordering::Equal,
358 (true, false) => cmp::Ordering::Less,
359 (false, true) => cmp::Ordering::Greater,
360 (false, false) => {
361 // Compare the reciprocals of the remaining fractions in reverse
362 let self_recip = Ratio::new_raw(self.denom.clone(), self_rem);
363 let other_recip = Ratio::new_raw(other.denom.clone(), other_rem);
364 self_recip.cmp(&other_recip).reverse()
365 }
366 }
367 }
368 }
369 }
370 }
371
372 impl<T: Clone + Integer> PartialOrd for Ratio<T> {
373 #[inline]
partial_cmp(&self, other: &Self) -> Option<cmp::Ordering>374 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
375 Some(self.cmp(other))
376 }
377 }
378
379 impl<T: Clone + Integer> PartialEq for Ratio<T> {
380 #[inline]
eq(&self, other: &Self) -> bool381 fn eq(&self, other: &Self) -> bool {
382 self.cmp(other) == cmp::Ordering::Equal
383 }
384 }
385
386 impl<T: Clone + Integer> Eq for Ratio<T> {}
387
388 // NB: We can't just `#[derive(Hash)]`, because it needs to agree
389 // with `Eq` even for non-reduced ratios.
390 impl<T: Clone + Integer + Hash> Hash for Ratio<T> {
hash<H: Hasher>(&self, state: &mut H)391 fn hash<H: Hasher>(&self, state: &mut H) {
392 recurse(&self.numer, &self.denom, state);
393
394 fn recurse<T: Integer + Hash, H: Hasher>(numer: &T, denom: &T, state: &mut H) {
395 if !denom.is_zero() {
396 let (int, rem) = numer.div_mod_floor(denom);
397 int.hash(state);
398 recurse(denom, &rem, state);
399 } else {
400 denom.hash(state);
401 }
402 }
403 }
404 }
405
406 mod iter_sum_product {
407 use crate::Ratio;
408 use core::iter::{Product, Sum};
409 use num_integer::Integer;
410 use num_traits::{One, Zero};
411
412 impl<T: Integer + Clone> Sum for Ratio<T> {
sum<I>(iter: I) -> Self where I: Iterator<Item = Ratio<T>>,413 fn sum<I>(iter: I) -> Self
414 where
415 I: Iterator<Item = Ratio<T>>,
416 {
417 iter.fold(Self::zero(), |sum, num| sum + num)
418 }
419 }
420
421 impl<'a, T: Integer + Clone> Sum<&'a Ratio<T>> for Ratio<T> {
sum<I>(iter: I) -> Self where I: Iterator<Item = &'a Ratio<T>>,422 fn sum<I>(iter: I) -> Self
423 where
424 I: Iterator<Item = &'a Ratio<T>>,
425 {
426 iter.fold(Self::zero(), |sum, num| sum + num)
427 }
428 }
429
430 impl<T: Integer + Clone> Product for Ratio<T> {
product<I>(iter: I) -> Self where I: Iterator<Item = Ratio<T>>,431 fn product<I>(iter: I) -> Self
432 where
433 I: Iterator<Item = Ratio<T>>,
434 {
435 iter.fold(Self::one(), |prod, num| prod * num)
436 }
437 }
438
439 impl<'a, T: Integer + Clone> Product<&'a Ratio<T>> for Ratio<T> {
product<I>(iter: I) -> Self where I: Iterator<Item = &'a Ratio<T>>,440 fn product<I>(iter: I) -> Self
441 where
442 I: Iterator<Item = &'a Ratio<T>>,
443 {
444 iter.fold(Self::one(), |prod, num| prod * num)
445 }
446 }
447 }
448
449 mod opassign {
450 use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign};
451
452 use crate::Ratio;
453 use num_integer::Integer;
454 use num_traits::NumAssign;
455
456 impl<T: Clone + Integer + NumAssign> AddAssign for Ratio<T> {
add_assign(&mut self, other: Ratio<T>)457 fn add_assign(&mut self, other: Ratio<T>) {
458 if self.denom == other.denom {
459 self.numer += other.numer
460 } else {
461 let lcm = self.denom.lcm(&other.denom);
462 let lhs_numer = self.numer.clone() * (lcm.clone() / self.denom.clone());
463 let rhs_numer = other.numer * (lcm.clone() / other.denom);
464 self.numer = lhs_numer + rhs_numer;
465 self.denom = lcm;
466 }
467 self.reduce();
468 }
469 }
470
471 // (a/b) / (c/d) = (a/gcd_ac)*(d/gcd_bd) / ((c/gcd_ac)*(b/gcd_bd))
472 impl<T: Clone + Integer + NumAssign> DivAssign for Ratio<T> {
div_assign(&mut self, other: Ratio<T>)473 fn div_assign(&mut self, other: Ratio<T>) {
474 let gcd_ac = self.numer.gcd(&other.numer);
475 let gcd_bd = self.denom.gcd(&other.denom);
476 self.numer /= gcd_ac.clone();
477 self.numer *= other.denom / gcd_bd.clone();
478 self.denom /= gcd_bd;
479 self.denom *= other.numer / gcd_ac;
480 self.reduce(); // TODO: remove this line. see #8.
481 }
482 }
483
484 // a/b * c/d = (a/gcd_ad)*(c/gcd_bc) / ((d/gcd_ad)*(b/gcd_bc))
485 impl<T: Clone + Integer + NumAssign> MulAssign for Ratio<T> {
mul_assign(&mut self, other: Ratio<T>)486 fn mul_assign(&mut self, other: Ratio<T>) {
487 let gcd_ad = self.numer.gcd(&other.denom);
488 let gcd_bc = self.denom.gcd(&other.numer);
489 self.numer /= gcd_ad.clone();
490 self.numer *= other.numer / gcd_bc.clone();
491 self.denom /= gcd_bc;
492 self.denom *= other.denom / gcd_ad;
493 self.reduce(); // TODO: remove this line. see #8.
494 }
495 }
496
497 impl<T: Clone + Integer + NumAssign> RemAssign for Ratio<T> {
rem_assign(&mut self, other: Ratio<T>)498 fn rem_assign(&mut self, other: Ratio<T>) {
499 if self.denom == other.denom {
500 self.numer %= other.numer
501 } else {
502 let lcm = self.denom.lcm(&other.denom);
503 let lhs_numer = self.numer.clone() * (lcm.clone() / self.denom.clone());
504 let rhs_numer = other.numer * (lcm.clone() / other.denom);
505 self.numer = lhs_numer % rhs_numer;
506 self.denom = lcm;
507 }
508 self.reduce();
509 }
510 }
511
512 impl<T: Clone + Integer + NumAssign> SubAssign for Ratio<T> {
sub_assign(&mut self, other: Ratio<T>)513 fn sub_assign(&mut self, other: Ratio<T>) {
514 if self.denom == other.denom {
515 self.numer -= other.numer
516 } else {
517 let lcm = self.denom.lcm(&other.denom);
518 let lhs_numer = self.numer.clone() * (lcm.clone() / self.denom.clone());
519 let rhs_numer = other.numer * (lcm.clone() / other.denom);
520 self.numer = lhs_numer - rhs_numer;
521 self.denom = lcm;
522 }
523 self.reduce();
524 }
525 }
526
527 // a/b + c/1 = (a*1 + b*c) / (b*1) = (a + b*c) / b
528 impl<T: Clone + Integer + NumAssign> AddAssign<T> for Ratio<T> {
add_assign(&mut self, other: T)529 fn add_assign(&mut self, other: T) {
530 self.numer += self.denom.clone() * other;
531 self.reduce();
532 }
533 }
534
535 impl<T: Clone + Integer + NumAssign> DivAssign<T> for Ratio<T> {
div_assign(&mut self, other: T)536 fn div_assign(&mut self, other: T) {
537 let gcd = self.numer.gcd(&other);
538 self.numer /= gcd.clone();
539 self.denom *= other / gcd;
540 self.reduce(); // TODO: remove this line. see #8.
541 }
542 }
543
544 impl<T: Clone + Integer + NumAssign> MulAssign<T> for Ratio<T> {
mul_assign(&mut self, other: T)545 fn mul_assign(&mut self, other: T) {
546 let gcd = self.denom.gcd(&other);
547 self.denom /= gcd.clone();
548 self.numer *= other / gcd;
549 self.reduce(); // TODO: remove this line. see #8.
550 }
551 }
552
553 // a/b % c/1 = (a*1 % b*c) / (b*1) = (a % b*c) / b
554 impl<T: Clone + Integer + NumAssign> RemAssign<T> for Ratio<T> {
rem_assign(&mut self, other: T)555 fn rem_assign(&mut self, other: T) {
556 self.numer %= self.denom.clone() * other;
557 self.reduce();
558 }
559 }
560
561 // a/b - c/1 = (a*1 - b*c) / (b*1) = (a - b*c) / b
562 impl<T: Clone + Integer + NumAssign> SubAssign<T> for Ratio<T> {
sub_assign(&mut self, other: T)563 fn sub_assign(&mut self, other: T) {
564 self.numer -= self.denom.clone() * other;
565 self.reduce();
566 }
567 }
568
569 macro_rules! forward_op_assign {
570 (impl $imp:ident, $method:ident) => {
571 impl<'a, T: Clone + Integer + NumAssign> $imp<&'a Ratio<T>> for Ratio<T> {
572 #[inline]
573 fn $method(&mut self, other: &Ratio<T>) {
574 self.$method(other.clone())
575 }
576 }
577 impl<'a, T: Clone + Integer + NumAssign> $imp<&'a T> for Ratio<T> {
578 #[inline]
579 fn $method(&mut self, other: &T) {
580 self.$method(other.clone())
581 }
582 }
583 };
584 }
585
586 forward_op_assign!(impl AddAssign, add_assign);
587 forward_op_assign!(impl DivAssign, div_assign);
588 forward_op_assign!(impl MulAssign, mul_assign);
589 forward_op_assign!(impl RemAssign, rem_assign);
590 forward_op_assign!(impl SubAssign, sub_assign);
591 }
592
593 macro_rules! forward_ref_ref_binop {
594 (impl $imp:ident, $method:ident) => {
595 impl<'a, 'b, T: Clone + Integer> $imp<&'b Ratio<T>> for &'a Ratio<T> {
596 type Output = Ratio<T>;
597
598 #[inline]
599 fn $method(self, other: &'b Ratio<T>) -> Ratio<T> {
600 self.clone().$method(other.clone())
601 }
602 }
603 impl<'a, 'b, T: Clone + Integer> $imp<&'b T> for &'a Ratio<T> {
604 type Output = Ratio<T>;
605
606 #[inline]
607 fn $method(self, other: &'b T) -> Ratio<T> {
608 self.clone().$method(other.clone())
609 }
610 }
611 };
612 }
613
614 macro_rules! forward_ref_val_binop {
615 (impl $imp:ident, $method:ident) => {
616 impl<'a, T> $imp<Ratio<T>> for &'a Ratio<T>
617 where
618 T: Clone + Integer,
619 {
620 type Output = Ratio<T>;
621
622 #[inline]
623 fn $method(self, other: Ratio<T>) -> Ratio<T> {
624 self.clone().$method(other)
625 }
626 }
627 impl<'a, T> $imp<T> for &'a Ratio<T>
628 where
629 T: Clone + Integer,
630 {
631 type Output = Ratio<T>;
632
633 #[inline]
634 fn $method(self, other: T) -> Ratio<T> {
635 self.clone().$method(other)
636 }
637 }
638 };
639 }
640
641 macro_rules! forward_val_ref_binop {
642 (impl $imp:ident, $method:ident) => {
643 impl<'a, T> $imp<&'a Ratio<T>> for Ratio<T>
644 where
645 T: Clone + Integer,
646 {
647 type Output = Ratio<T>;
648
649 #[inline]
650 fn $method(self, other: &Ratio<T>) -> Ratio<T> {
651 self.$method(other.clone())
652 }
653 }
654 impl<'a, T> $imp<&'a T> for Ratio<T>
655 where
656 T: Clone + Integer,
657 {
658 type Output = Ratio<T>;
659
660 #[inline]
661 fn $method(self, other: &T) -> Ratio<T> {
662 self.$method(other.clone())
663 }
664 }
665 };
666 }
667
668 macro_rules! forward_all_binop {
669 (impl $imp:ident, $method:ident) => {
670 forward_ref_ref_binop!(impl $imp, $method);
671 forward_ref_val_binop!(impl $imp, $method);
672 forward_val_ref_binop!(impl $imp, $method);
673 };
674 }
675
676 // Arithmetic
677 forward_all_binop!(impl Mul, mul);
678 // a/b * c/d = (a/gcd_ad)*(c/gcd_bc) / ((d/gcd_ad)*(b/gcd_bc))
679 impl<T> Mul<Ratio<T>> for Ratio<T>
680 where
681 T: Clone + Integer,
682 {
683 type Output = Ratio<T>;
684 #[inline]
mul(self, rhs: Ratio<T>) -> Ratio<T>685 fn mul(self, rhs: Ratio<T>) -> Ratio<T> {
686 let gcd_ad = self.numer.gcd(&rhs.denom);
687 let gcd_bc = self.denom.gcd(&rhs.numer);
688 Ratio::new(
689 self.numer / gcd_ad.clone() * (rhs.numer / gcd_bc.clone()),
690 self.denom / gcd_bc * (rhs.denom / gcd_ad),
691 )
692 }
693 }
694 // a/b * c/1 = (a*c) / (b*1) = (a*c) / b
695 impl<T> Mul<T> for Ratio<T>
696 where
697 T: Clone + Integer,
698 {
699 type Output = Ratio<T>;
700 #[inline]
mul(self, rhs: T) -> Ratio<T>701 fn mul(self, rhs: T) -> Ratio<T> {
702 let gcd = self.denom.gcd(&rhs);
703 Ratio::new(self.numer * (rhs / gcd.clone()), self.denom / gcd)
704 }
705 }
706
707 forward_all_binop!(impl Div, div);
708 // (a/b) / (c/d) = (a/gcd_ac)*(d/gcd_bd) / ((c/gcd_ac)*(b/gcd_bd))
709 impl<T> Div<Ratio<T>> for Ratio<T>
710 where
711 T: Clone + Integer,
712 {
713 type Output = Ratio<T>;
714
715 #[inline]
div(self, rhs: Ratio<T>) -> Ratio<T>716 fn div(self, rhs: Ratio<T>) -> Ratio<T> {
717 let gcd_ac = self.numer.gcd(&rhs.numer);
718 let gcd_bd = self.denom.gcd(&rhs.denom);
719 Ratio::new(
720 self.numer / gcd_ac.clone() * (rhs.denom / gcd_bd.clone()),
721 self.denom / gcd_bd * (rhs.numer / gcd_ac),
722 )
723 }
724 }
725 // (a/b) / (c/1) = (a*1) / (b*c) = a / (b*c)
726 impl<T> Div<T> for Ratio<T>
727 where
728 T: Clone + Integer,
729 {
730 type Output = Ratio<T>;
731
732 #[inline]
div(self, rhs: T) -> Ratio<T>733 fn div(self, rhs: T) -> Ratio<T> {
734 let gcd = self.numer.gcd(&rhs);
735 Ratio::new(self.numer / gcd.clone(), self.denom * (rhs / gcd))
736 }
737 }
738
739 macro_rules! arith_impl {
740 (impl $imp:ident, $method:ident) => {
741 forward_all_binop!(impl $imp, $method);
742 // Abstracts a/b `op` c/d = (a*lcm/b `op` c*lcm/d)/lcm where lcm = lcm(b,d)
743 impl<T: Clone + Integer> $imp<Ratio<T>> for Ratio<T> {
744 type Output = Ratio<T>;
745 #[inline]
746 fn $method(self, rhs: Ratio<T>) -> Ratio<T> {
747 if self.denom == rhs.denom {
748 return Ratio::new(self.numer.$method(rhs.numer), rhs.denom);
749 }
750 let lcm = self.denom.lcm(&rhs.denom);
751 let lhs_numer = self.numer * (lcm.clone() / self.denom);
752 let rhs_numer = rhs.numer * (lcm.clone() / rhs.denom);
753 Ratio::new(lhs_numer.$method(rhs_numer), lcm)
754 }
755 }
756 // Abstracts the a/b `op` c/1 = (a*1 `op` b*c) / (b*1) = (a `op` b*c) / b pattern
757 impl<T: Clone + Integer> $imp<T> for Ratio<T> {
758 type Output = Ratio<T>;
759 #[inline]
760 fn $method(self, rhs: T) -> Ratio<T> {
761 Ratio::new(self.numer.$method(self.denom.clone() * rhs), self.denom)
762 }
763 }
764 };
765 }
766
767 arith_impl!(impl Add, add);
768 arith_impl!(impl Sub, sub);
769 arith_impl!(impl Rem, rem);
770
771 // a/b * c/d = (a*c)/(b*d)
772 impl<T> CheckedMul for Ratio<T>
773 where
774 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 let gcd_ad = self.numer.gcd(&rhs.denom);
779 let gcd_bc = self.denom.gcd(&rhs.numer);
780 Some(Ratio::new(
781 (self.numer.clone() / gcd_ad.clone())
782 .checked_mul(&(rhs.numer.clone() / gcd_bc.clone()))?,
783 (self.denom.clone() / gcd_bc).checked_mul(&(rhs.denom.clone() / gcd_ad))?,
784 ))
785 }
786 }
787
788 // (a/b) / (c/d) = (a*d)/(b*c)
789 impl<T> CheckedDiv for Ratio<T>
790 where
791 T: Clone + Integer + CheckedMul,
792 {
793 #[inline]
checked_div(&self, rhs: &Ratio<T>) -> Option<Ratio<T>>794 fn checked_div(&self, rhs: &Ratio<T>) -> Option<Ratio<T>> {
795 if rhs.is_zero() {
796 return None;
797 }
798 let (numer, denom) = if self.denom == rhs.denom {
799 (self.numer.clone(), rhs.numer.clone())
800 } else if self.numer == rhs.numer {
801 (rhs.denom.clone(), self.denom.clone())
802 } else {
803 let gcd_ac = self.numer.gcd(&rhs.numer);
804 let gcd_bd = self.denom.gcd(&rhs.denom);
805 (
806 (self.numer.clone() / gcd_ac.clone())
807 .checked_mul(&(rhs.denom.clone() / gcd_bd.clone()))?,
808 (self.denom.clone() / gcd_bd).checked_mul(&(rhs.numer.clone() / gcd_ac))?,
809 )
810 };
811 // Manual `reduce()`, avoiding sharp edges
812 if denom.is_zero() {
813 None
814 } else if numer.is_zero() {
815 Some(Self::zero())
816 } else if numer == denom {
817 Some(Self::one())
818 } else {
819 let g = numer.gcd(&denom);
820 let numer = numer / g.clone();
821 let denom = denom / g;
822 let raw = if denom < T::zero() {
823 // We need to keep denom positive, but 2's-complement MIN may
824 // overflow negation -- instead we can check multiplying -1.
825 let n1 = T::zero() - T::one();
826 Ratio::new_raw(numer.checked_mul(&n1)?, denom.checked_mul(&n1)?)
827 } else {
828 Ratio::new_raw(numer, denom)
829 };
830 Some(raw)
831 }
832 }
833 }
834
835 // As arith_impl! but for Checked{Add,Sub} traits
836 macro_rules! checked_arith_impl {
837 (impl $imp:ident, $method:ident) => {
838 impl<T: Clone + Integer + CheckedMul + $imp> $imp for Ratio<T> {
839 #[inline]
840 fn $method(&self, rhs: &Ratio<T>) -> Option<Ratio<T>> {
841 let gcd = self.denom.clone().gcd(&rhs.denom);
842 let lcm = (self.denom.clone() / gcd.clone()).checked_mul(&rhs.denom)?;
843 let lhs_numer = (lcm.clone() / self.denom.clone()).checked_mul(&self.numer)?;
844 let rhs_numer = (lcm.clone() / rhs.denom.clone()).checked_mul(&rhs.numer)?;
845 Some(Ratio::new(lhs_numer.$method(&rhs_numer)?, lcm))
846 }
847 }
848 };
849 }
850
851 // a/b + c/d = (lcm/b*a + lcm/d*c)/lcm, where lcm = lcm(b,d)
852 checked_arith_impl!(impl CheckedAdd, checked_add);
853
854 // a/b - c/d = (lcm/b*a - lcm/d*c)/lcm, where lcm = lcm(b,d)
855 checked_arith_impl!(impl CheckedSub, checked_sub);
856
857 impl<T> Neg for Ratio<T>
858 where
859 T: Clone + Integer + Neg<Output = T>,
860 {
861 type Output = Ratio<T>;
862
863 #[inline]
neg(self) -> Ratio<T>864 fn neg(self) -> Ratio<T> {
865 Ratio::new_raw(-self.numer, self.denom)
866 }
867 }
868
869 impl<'a, T> Neg for &'a Ratio<T>
870 where
871 T: Clone + Integer + Neg<Output = T>,
872 {
873 type Output = Ratio<T>;
874
875 #[inline]
neg(self) -> Ratio<T>876 fn neg(self) -> Ratio<T> {
877 -self.clone()
878 }
879 }
880
881 impl<T> Inv for Ratio<T>
882 where
883 T: Clone + Integer,
884 {
885 type Output = Ratio<T>;
886
887 #[inline]
inv(self) -> Ratio<T>888 fn inv(self) -> Ratio<T> {
889 self.recip()
890 }
891 }
892
893 impl<'a, T> Inv for &'a Ratio<T>
894 where
895 T: Clone + Integer,
896 {
897 type Output = Ratio<T>;
898
899 #[inline]
inv(self) -> Ratio<T>900 fn inv(self) -> Ratio<T> {
901 self.recip()
902 }
903 }
904
905 // Constants
906 impl<T: Clone + Integer> Zero for Ratio<T> {
907 #[inline]
zero() -> Ratio<T>908 fn zero() -> Ratio<T> {
909 Ratio::new_raw(Zero::zero(), One::one())
910 }
911
912 #[inline]
is_zero(&self) -> bool913 fn is_zero(&self) -> bool {
914 self.numer.is_zero()
915 }
916
917 #[inline]
set_zero(&mut self)918 fn set_zero(&mut self) {
919 self.numer.set_zero();
920 self.denom.set_one();
921 }
922 }
923
924 impl<T: Clone + Integer> One for Ratio<T> {
925 #[inline]
one() -> Ratio<T>926 fn one() -> Ratio<T> {
927 Ratio::new_raw(One::one(), One::one())
928 }
929
930 #[inline]
is_one(&self) -> bool931 fn is_one(&self) -> bool {
932 self.numer == self.denom
933 }
934
935 #[inline]
set_one(&mut self)936 fn set_one(&mut self) {
937 self.numer.set_one();
938 self.denom.set_one();
939 }
940 }
941
942 impl<T: Clone + Integer> Num for Ratio<T> {
943 type FromStrRadixErr = ParseRatioError;
944
945 /// Parses `numer/denom` where the numbers are in base `radix`.
from_str_radix(s: &str, radix: u32) -> Result<Ratio<T>, ParseRatioError>946 fn from_str_radix(s: &str, radix: u32) -> Result<Ratio<T>, ParseRatioError> {
947 if s.splitn(2, '/').count() == 2 {
948 let mut parts = s.splitn(2, '/').map(|ss| {
949 T::from_str_radix(ss, radix).map_err(|_| ParseRatioError {
950 kind: RatioErrorKind::ParseError,
951 })
952 });
953 let numer: T = parts.next().unwrap()?;
954 let denom: T = parts.next().unwrap()?;
955 if denom.is_zero() {
956 Err(ParseRatioError {
957 kind: RatioErrorKind::ZeroDenominator,
958 })
959 } else {
960 Ok(Ratio::new(numer, denom))
961 }
962 } else {
963 Err(ParseRatioError {
964 kind: RatioErrorKind::ParseError,
965 })
966 }
967 }
968 }
969
970 impl<T: Clone + Integer + Signed> Signed for Ratio<T> {
971 #[inline]
abs(&self) -> Ratio<T>972 fn abs(&self) -> Ratio<T> {
973 if self.is_negative() {
974 -self.clone()
975 } else {
976 self.clone()
977 }
978 }
979
980 #[inline]
abs_sub(&self, other: &Ratio<T>) -> Ratio<T>981 fn abs_sub(&self, other: &Ratio<T>) -> Ratio<T> {
982 if *self <= *other {
983 Zero::zero()
984 } else {
985 self - other
986 }
987 }
988
989 #[inline]
signum(&self) -> Ratio<T>990 fn signum(&self) -> Ratio<T> {
991 if self.is_positive() {
992 Self::one()
993 } else if self.is_zero() {
994 Self::zero()
995 } else {
996 -Self::one()
997 }
998 }
999
1000 #[inline]
is_positive(&self) -> bool1001 fn is_positive(&self) -> bool {
1002 (self.numer.is_positive() && self.denom.is_positive())
1003 || (self.numer.is_negative() && self.denom.is_negative())
1004 }
1005
1006 #[inline]
is_negative(&self) -> bool1007 fn is_negative(&self) -> bool {
1008 (self.numer.is_negative() && self.denom.is_positive())
1009 || (self.numer.is_positive() && self.denom.is_negative())
1010 }
1011 }
1012
1013 // String conversions
1014 macro_rules! impl_formatting {
1015 ($fmt_trait:ident, $prefix:expr, $fmt_str:expr, $fmt_alt:expr) => {
1016 impl<T: $fmt_trait + Clone + Integer> $fmt_trait for Ratio<T> {
1017 #[cfg(feature = "std")]
1018 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1019 let pre_pad = if self.denom.is_one() {
1020 format!($fmt_str, self.numer)
1021 } else {
1022 if f.alternate() {
1023 format!(concat!($fmt_str, "/", $fmt_alt), self.numer, self.denom)
1024 } else {
1025 format!(concat!($fmt_str, "/", $fmt_str), self.numer, self.denom)
1026 }
1027 };
1028 // TODO: replace with strip_prefix, when stabalized
1029 let (pre_pad, non_negative) = {
1030 if pre_pad.starts_with("-") {
1031 (&pre_pad[1..], false)
1032 } else {
1033 (&pre_pad[..], true)
1034 }
1035 };
1036 f.pad_integral(non_negative, $prefix, pre_pad)
1037 }
1038 #[cfg(not(feature = "std"))]
1039 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1040 let plus = if f.sign_plus() && self.numer >= T::zero() {
1041 "+"
1042 } else {
1043 ""
1044 };
1045 if self.denom.is_one() {
1046 if f.alternate() {
1047 write!(f, concat!("{}", $fmt_alt), plus, self.numer)
1048 } else {
1049 write!(f, concat!("{}", $fmt_str), plus, self.numer)
1050 }
1051 } else {
1052 if f.alternate() {
1053 write!(
1054 f,
1055 concat!("{}", $fmt_alt, "/", $fmt_alt),
1056 plus, self.numer, self.denom
1057 )
1058 } else {
1059 write!(
1060 f,
1061 concat!("{}", $fmt_str, "/", $fmt_str),
1062 plus, self.numer, self.denom
1063 )
1064 }
1065 }
1066 }
1067 }
1068 };
1069 }
1070
1071 impl_formatting!(Display, "", "{}", "{:#}");
1072 impl_formatting!(Octal, "0o", "{:o}", "{:#o}");
1073 impl_formatting!(Binary, "0b", "{:b}", "{:#b}");
1074 impl_formatting!(LowerHex, "0x", "{:x}", "{:#x}");
1075 impl_formatting!(UpperHex, "0x", "{:X}", "{:#X}");
1076 impl_formatting!(LowerExp, "", "{:e}", "{:#e}");
1077 impl_formatting!(UpperExp, "", "{:E}", "{:#E}");
1078
1079 impl<T: FromStr + Clone + Integer> FromStr for Ratio<T> {
1080 type Err = ParseRatioError;
1081
1082 /// Parses `numer/denom` or just `numer`.
from_str(s: &str) -> Result<Ratio<T>, ParseRatioError>1083 fn from_str(s: &str) -> Result<Ratio<T>, ParseRatioError> {
1084 let mut split = s.splitn(2, '/');
1085
1086 let n = split.next().ok_or(ParseRatioError {
1087 kind: RatioErrorKind::ParseError,
1088 })?;
1089 let num = FromStr::from_str(n).map_err(|_| ParseRatioError {
1090 kind: RatioErrorKind::ParseError,
1091 })?;
1092
1093 let d = split.next().unwrap_or("1");
1094 let den = FromStr::from_str(d).map_err(|_| ParseRatioError {
1095 kind: RatioErrorKind::ParseError,
1096 })?;
1097
1098 if Zero::is_zero(&den) {
1099 Err(ParseRatioError {
1100 kind: RatioErrorKind::ZeroDenominator,
1101 })
1102 } else {
1103 Ok(Ratio::new(num, den))
1104 }
1105 }
1106 }
1107
1108 impl<T> Into<(T, T)> for Ratio<T> {
into(self) -> (T, T)1109 fn into(self) -> (T, T) {
1110 (self.numer, self.denom)
1111 }
1112 }
1113
1114 #[cfg(feature = "serde")]
1115 impl<T> serde::Serialize for Ratio<T>
1116 where
1117 T: serde::Serialize + Clone + Integer + PartialOrd,
1118 {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer,1119 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1120 where
1121 S: serde::Serializer,
1122 {
1123 (self.numer(), self.denom()).serialize(serializer)
1124 }
1125 }
1126
1127 #[cfg(feature = "serde")]
1128 impl<'de, T> serde::Deserialize<'de> for Ratio<T>
1129 where
1130 T: serde::Deserialize<'de> + Clone + Integer + PartialOrd,
1131 {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de>,1132 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1133 where
1134 D: serde::Deserializer<'de>,
1135 {
1136 use serde::de::Error;
1137 use serde::de::Unexpected;
1138 let (numer, denom): (T, T) = serde::Deserialize::deserialize(deserializer)?;
1139 if denom.is_zero() {
1140 Err(Error::invalid_value(
1141 Unexpected::Signed(0),
1142 &"a ratio with non-zero denominator",
1143 ))
1144 } else {
1145 Ok(Ratio::new_raw(numer, denom))
1146 }
1147 }
1148 }
1149
1150 // FIXME: Bubble up specific errors
1151 #[derive(Copy, Clone, Debug, PartialEq)]
1152 pub struct ParseRatioError {
1153 kind: RatioErrorKind,
1154 }
1155
1156 #[derive(Copy, Clone, Debug, PartialEq)]
1157 enum RatioErrorKind {
1158 ParseError,
1159 ZeroDenominator,
1160 }
1161
1162 impl fmt::Display for ParseRatioError {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1163 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1164 self.kind.description().fmt(f)
1165 }
1166 }
1167
1168 #[cfg(feature = "std")]
1169 impl Error for ParseRatioError {
1170 #[allow(deprecated)]
description(&self) -> &str1171 fn description(&self) -> &str {
1172 self.kind.description()
1173 }
1174 }
1175
1176 impl RatioErrorKind {
description(&self) -> &'static str1177 fn description(&self) -> &'static str {
1178 match *self {
1179 RatioErrorKind::ParseError => "failed to parse integer",
1180 RatioErrorKind::ZeroDenominator => "zero value denominator",
1181 }
1182 }
1183 }
1184
1185 #[cfg(feature = "num-bigint")]
1186 impl FromPrimitive for Ratio<BigInt> {
from_i64(n: i64) -> Option<Self>1187 fn from_i64(n: i64) -> Option<Self> {
1188 Some(Ratio::from_integer(n.into()))
1189 }
1190
from_i128(n: i128) -> Option<Self>1191 fn from_i128(n: i128) -> Option<Self> {
1192 Some(Ratio::from_integer(n.into()))
1193 }
1194
from_u64(n: u64) -> Option<Self>1195 fn from_u64(n: u64) -> Option<Self> {
1196 Some(Ratio::from_integer(n.into()))
1197 }
1198
from_u128(n: u128) -> Option<Self>1199 fn from_u128(n: u128) -> Option<Self> {
1200 Some(Ratio::from_integer(n.into()))
1201 }
1202
from_f32(n: f32) -> Option<Self>1203 fn from_f32(n: f32) -> Option<Self> {
1204 Ratio::from_float(n)
1205 }
1206
from_f64(n: f64) -> Option<Self>1207 fn from_f64(n: f64) -> Option<Self> {
1208 Ratio::from_float(n)
1209 }
1210 }
1211
1212 macro_rules! from_primitive_integer {
1213 ($typ:ty, $approx:ident) => {
1214 impl FromPrimitive for Ratio<$typ> {
1215 fn from_i64(n: i64) -> Option<Self> {
1216 <$typ as FromPrimitive>::from_i64(n).map(Ratio::from_integer)
1217 }
1218
1219 fn from_i128(n: i128) -> Option<Self> {
1220 <$typ as FromPrimitive>::from_i128(n).map(Ratio::from_integer)
1221 }
1222
1223 fn from_u64(n: u64) -> Option<Self> {
1224 <$typ as FromPrimitive>::from_u64(n).map(Ratio::from_integer)
1225 }
1226
1227 fn from_u128(n: u128) -> Option<Self> {
1228 <$typ as FromPrimitive>::from_u128(n).map(Ratio::from_integer)
1229 }
1230
1231 fn from_f32(n: f32) -> Option<Self> {
1232 $approx(n, 10e-20, 30)
1233 }
1234
1235 fn from_f64(n: f64) -> Option<Self> {
1236 $approx(n, 10e-20, 30)
1237 }
1238 }
1239 };
1240 }
1241
1242 from_primitive_integer!(i8, approximate_float);
1243 from_primitive_integer!(i16, approximate_float);
1244 from_primitive_integer!(i32, approximate_float);
1245 from_primitive_integer!(i64, approximate_float);
1246 from_primitive_integer!(i128, approximate_float);
1247 from_primitive_integer!(isize, approximate_float);
1248
1249 from_primitive_integer!(u8, approximate_float_unsigned);
1250 from_primitive_integer!(u16, approximate_float_unsigned);
1251 from_primitive_integer!(u32, approximate_float_unsigned);
1252 from_primitive_integer!(u64, approximate_float_unsigned);
1253 from_primitive_integer!(u128, approximate_float_unsigned);
1254 from_primitive_integer!(usize, approximate_float_unsigned);
1255
1256 impl<T: Integer + Signed + Bounded + NumCast + Clone> Ratio<T> {
approximate_float<F: FloatCore + NumCast>(f: F) -> Option<Ratio<T>>1257 pub fn approximate_float<F: FloatCore + NumCast>(f: F) -> Option<Ratio<T>> {
1258 // 1/10e-20 < 1/2**32 which seems like a good default, and 30 seems
1259 // to work well. Might want to choose something based on the types in the future, e.g.
1260 // T::max().recip() and T::bits() or something similar.
1261 let epsilon = <F as NumCast>::from(10e-20).expect("Can't convert 10e-20");
1262 approximate_float(f, epsilon, 30)
1263 }
1264 }
1265
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,1266 fn approximate_float<T, F>(val: F, max_error: F, max_iterations: usize) -> Option<Ratio<T>>
1267 where
1268 T: Integer + Signed + Bounded + NumCast + Clone,
1269 F: FloatCore + NumCast,
1270 {
1271 let negative = val.is_sign_negative();
1272 let abs_val = val.abs();
1273
1274 let r = approximate_float_unsigned(abs_val, max_error, max_iterations)?;
1275
1276 // Make negative again if needed
1277 Some(if negative { r.neg() } else { r })
1278 }
1279
1280 // No Unsigned constraint because this also works on positive integers and is called
1281 // 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,1282 fn approximate_float_unsigned<T, F>(val: F, max_error: F, max_iterations: usize) -> Option<Ratio<T>>
1283 where
1284 T: Integer + Bounded + NumCast + Clone,
1285 F: FloatCore + NumCast,
1286 {
1287 // Continued fractions algorithm
1288 // http://mathforum.org/dr.math/faq/faq.fractions.html#decfrac
1289
1290 if val < F::zero() || val.is_nan() {
1291 return None;
1292 }
1293
1294 let mut q = val;
1295 let mut n0 = T::zero();
1296 let mut d0 = T::one();
1297 let mut n1 = T::one();
1298 let mut d1 = T::zero();
1299
1300 let t_max = T::max_value();
1301 let t_max_f = <F as NumCast>::from(t_max.clone())?;
1302
1303 // 1/epsilon > T::MAX
1304 let epsilon = t_max_f.recip();
1305
1306 // Overflow
1307 if q > t_max_f {
1308 return None;
1309 }
1310
1311 for _ in 0..max_iterations {
1312 let a = match <T as NumCast>::from(q) {
1313 None => break,
1314 Some(a) => a,
1315 };
1316
1317 let a_f = match <F as NumCast>::from(a.clone()) {
1318 None => break,
1319 Some(a_f) => a_f,
1320 };
1321 let f = q - a_f;
1322
1323 // Prevent overflow
1324 if !a.is_zero()
1325 && (n1 > t_max.clone() / a.clone()
1326 || d1 > t_max.clone() / a.clone()
1327 || a.clone() * n1.clone() > t_max.clone() - n0.clone()
1328 || a.clone() * d1.clone() > t_max.clone() - d0.clone())
1329 {
1330 break;
1331 }
1332
1333 let n = a.clone() * n1.clone() + n0.clone();
1334 let d = a.clone() * d1.clone() + d0.clone();
1335
1336 n0 = n1;
1337 d0 = d1;
1338 n1 = n.clone();
1339 d1 = d.clone();
1340
1341 // Simplify fraction. Doing so here instead of at the end
1342 // allows us to get closer to the target value without overflows
1343 let g = Integer::gcd(&n1, &d1);
1344 if !g.is_zero() {
1345 n1 = n1 / g.clone();
1346 d1 = d1 / g.clone();
1347 }
1348
1349 // Close enough?
1350 let (n_f, d_f) = match (<F as NumCast>::from(n), <F as NumCast>::from(d)) {
1351 (Some(n_f), Some(d_f)) => (n_f, d_f),
1352 _ => break,
1353 };
1354 if (n_f / d_f - val).abs() < max_error {
1355 break;
1356 }
1357
1358 // Prevent division by ~0
1359 if f < epsilon {
1360 break;
1361 }
1362 q = f.recip();
1363 }
1364
1365 // Overflow
1366 if d1.is_zero() {
1367 return None;
1368 }
1369
1370 Some(Ratio::new(n1, d1))
1371 }
1372
1373 #[cfg(not(feature = "num-bigint"))]
1374 macro_rules! to_primitive_small {
1375 ($($type_name:ty)*) => ($(
1376 impl ToPrimitive for Ratio<$type_name> {
1377 fn to_i64(&self) -> Option<i64> {
1378 self.to_integer().to_i64()
1379 }
1380
1381 fn to_i128(&self) -> Option<i128> {
1382 self.to_integer().to_i128()
1383 }
1384
1385 fn to_u64(&self) -> Option<u64> {
1386 self.to_integer().to_u64()
1387 }
1388
1389 fn to_u128(&self) -> Option<u128> {
1390 self.to_integer().to_u128()
1391 }
1392
1393 fn to_f64(&self) -> Option<f64> {
1394 let float = self.numer.to_f64().unwrap() / self.denom.to_f64().unwrap();
1395 if float.is_nan() {
1396 None
1397 } else {
1398 Some(float)
1399 }
1400 }
1401 }
1402 )*)
1403 }
1404
1405 #[cfg(not(feature = "num-bigint"))]
1406 to_primitive_small!(u8 i8 u16 i16 u32 i32);
1407
1408 #[cfg(all(target_pointer_width = "32", not(feature = "num-bigint")))]
1409 to_primitive_small!(usize isize);
1410
1411 #[cfg(not(feature = "num-bigint"))]
1412 macro_rules! to_primitive_64 {
1413 ($($type_name:ty)*) => ($(
1414 impl ToPrimitive for Ratio<$type_name> {
1415 fn to_i64(&self) -> Option<i64> {
1416 self.to_integer().to_i64()
1417 }
1418
1419 fn to_i128(&self) -> Option<i128> {
1420 self.to_integer().to_i128()
1421 }
1422
1423 fn to_u64(&self) -> Option<u64> {
1424 self.to_integer().to_u64()
1425 }
1426
1427 fn to_u128(&self) -> Option<u128> {
1428 self.to_integer().to_u128()
1429 }
1430
1431 fn to_f64(&self) -> Option<f64> {
1432 let float = ratio_to_f64(
1433 self.numer as i128,
1434 self.denom as i128
1435 );
1436 if float.is_nan() {
1437 None
1438 } else {
1439 Some(float)
1440 }
1441 }
1442 }
1443 )*)
1444 }
1445
1446 #[cfg(not(feature = "num-bigint"))]
1447 to_primitive_64!(u64 i64);
1448
1449 #[cfg(all(target_pointer_width = "64", not(feature = "num-bigint")))]
1450 to_primitive_64!(usize isize);
1451
1452 #[cfg(feature = "num-bigint")]
1453 impl<T: Clone + Integer + ToPrimitive + ToBigInt> ToPrimitive for Ratio<T> {
to_i64(&self) -> Option<i64>1454 fn to_i64(&self) -> Option<i64> {
1455 self.to_integer().to_i64()
1456 }
1457
to_i128(&self) -> Option<i128>1458 fn to_i128(&self) -> Option<i128> {
1459 self.to_integer().to_i128()
1460 }
1461
to_u64(&self) -> Option<u64>1462 fn to_u64(&self) -> Option<u64> {
1463 self.to_integer().to_u64()
1464 }
1465
to_u128(&self) -> Option<u128>1466 fn to_u128(&self) -> Option<u128> {
1467 self.to_integer().to_u128()
1468 }
1469
to_f64(&self) -> Option<f64>1470 fn to_f64(&self) -> Option<f64> {
1471 let float = match (self.numer.to_i64(), self.denom.to_i64()) {
1472 (Some(numer), Some(denom)) => ratio_to_f64(
1473 <i128 as From<_>>::from(numer),
1474 <i128 as From<_>>::from(denom),
1475 ),
1476 _ => {
1477 let numer: BigInt = self.numer.to_bigint()?;
1478 let denom: BigInt = self.denom.to_bigint()?;
1479 ratio_to_f64(numer, denom)
1480 }
1481 };
1482 if float.is_nan() {
1483 None
1484 } else {
1485 Some(float)
1486 }
1487 }
1488 }
1489
1490 trait Bits {
bits(&self) -> u641491 fn bits(&self) -> u64;
1492 }
1493
1494 #[cfg(feature = "num-bigint")]
1495 impl Bits for BigInt {
bits(&self) -> u641496 fn bits(&self) -> u64 {
1497 self.bits()
1498 }
1499 }
1500
1501 impl Bits for i128 {
bits(&self) -> u641502 fn bits(&self) -> u64 {
1503 (128 - self.wrapping_abs().leading_zeros()).into()
1504 }
1505 }
1506
1507 /// Converts a ratio of `T` to an f64.
1508 ///
1509 /// In addition to stated trait bounds, `T` must be able to hold numbers 56 bits larger than
1510 /// the largest of `numer` and `denom`. This is automatically true if `T` is `BigInt`.
ratio_to_f64<T: Bits + Clone + Integer + Signed + ShlAssign<usize> + ToPrimitive>( numer: T, denom: T, ) -> f641511 fn ratio_to_f64<T: Bits + Clone + Integer + Signed + ShlAssign<usize> + ToPrimitive>(
1512 numer: T,
1513 denom: T,
1514 ) -> f64 {
1515 assert_eq!(
1516 core::f64::RADIX,
1517 2,
1518 "only floating point implementations with radix 2 are supported"
1519 );
1520
1521 // Inclusive upper and lower bounds to the range of exactly-representable ints in an f64.
1522 const MAX_EXACT_INT: i64 = 1i64 << core::f64::MANTISSA_DIGITS;
1523 const MIN_EXACT_INT: i64 = -MAX_EXACT_INT;
1524
1525 let flo_sign = numer.signum().to_f64().unwrap() / denom.signum().to_f64().unwrap();
1526 if !flo_sign.is_normal() {
1527 return flo_sign;
1528 }
1529
1530 // Fast track: both sides can losslessly be converted to f64s. In this case, letting the
1531 // FPU do the job is faster and easier. In any other case, converting to f64s may lead
1532 // to an inexact result: https://stackoverflow.com/questions/56641441/.
1533 if let (Some(n), Some(d)) = (numer.to_i64(), denom.to_i64()) {
1534 if MIN_EXACT_INT <= n && n <= MAX_EXACT_INT && MIN_EXACT_INT <= d && d <= MAX_EXACT_INT {
1535 return n.to_f64().unwrap() / d.to_f64().unwrap();
1536 }
1537 }
1538
1539 // Otherwise, the goal is to obtain a quotient with at least 55 bits. 53 of these bits will
1540 // be used as the mantissa of the resulting float, and the remaining two are for rounding.
1541 // There's an error of up to 1 on the number of resulting bits, so we may get either 55 or
1542 // 56 bits.
1543 let mut numer = numer.abs();
1544 let mut denom = denom.abs();
1545 let (is_diff_positive, absolute_diff) = match numer.bits().checked_sub(denom.bits()) {
1546 Some(diff) => (true, diff),
1547 None => (false, denom.bits() - numer.bits()),
1548 };
1549
1550 // Filter out overflows and underflows. After this step, the signed difference fits in an
1551 // isize.
1552 if is_diff_positive && absolute_diff > core::f64::MAX_EXP as u64 {
1553 return core::f64::INFINITY * flo_sign;
1554 }
1555 if !is_diff_positive
1556 && absolute_diff > -core::f64::MIN_EXP as u64 + core::f64::MANTISSA_DIGITS as u64 + 1
1557 {
1558 return 0.0 * flo_sign;
1559 }
1560 let diff = if is_diff_positive {
1561 absolute_diff.to_isize().unwrap()
1562 } else {
1563 -absolute_diff.to_isize().unwrap()
1564 };
1565
1566 // Shift is chosen so that the quotient will have 55 or 56 bits. The exception is if the
1567 // quotient is going to be subnormal, in which case it may have fewer bits.
1568 let shift: isize =
1569 diff.max(core::f64::MIN_EXP as isize) - core::f64::MANTISSA_DIGITS as isize - 2;
1570 if shift >= 0 {
1571 denom <<= shift as usize
1572 } else {
1573 numer <<= -shift as usize
1574 };
1575
1576 let (quotient, remainder) = numer.div_rem(&denom);
1577
1578 // This is guaranteed to fit since we've set up quotient to be at most 56 bits.
1579 let mut quotient = quotient.to_u64().unwrap();
1580 let n_rounding_bits = {
1581 let quotient_bits = 64 - quotient.leading_zeros() as isize;
1582 let subnormal_bits = core::f64::MIN_EXP as isize - shift;
1583 quotient_bits.max(subnormal_bits) - core::f64::MANTISSA_DIGITS as isize
1584 } as usize;
1585 debug_assert!(n_rounding_bits == 2 || n_rounding_bits == 3);
1586 let rounding_bit_mask = (1u64 << n_rounding_bits) - 1;
1587
1588 // Round to 53 bits with round-to-even. For rounding, we need to take into account both
1589 // our rounding bits and the division's remainder.
1590 let ls_bit = quotient & (1u64 << n_rounding_bits) != 0;
1591 let ms_rounding_bit = quotient & (1u64 << (n_rounding_bits - 1)) != 0;
1592 let ls_rounding_bits = quotient & (rounding_bit_mask >> 1) != 0;
1593 if ms_rounding_bit && (ls_bit || ls_rounding_bits || !remainder.is_zero()) {
1594 quotient += 1u64 << n_rounding_bits;
1595 }
1596 quotient &= !rounding_bit_mask;
1597
1598 // The quotient is guaranteed to be exactly representable as it's now 53 bits + 2 or 3
1599 // trailing zeros, so there is no risk of a rounding error here.
1600 let q_float = quotient as f64;
1601 q_float * 2f64.powi(shift as i32) * flo_sign
1602 }
1603
1604 #[cfg(test)]
1605 #[cfg(feature = "std")]
hash<T: Hash>(x: &T) -> u641606 fn hash<T: Hash>(x: &T) -> u64 {
1607 use std::collections::hash_map::RandomState;
1608 use std::hash::BuildHasher;
1609 let mut hasher = <RandomState as BuildHasher>::Hasher::new();
1610 x.hash(&mut hasher);
1611 hasher.finish()
1612 }
1613
1614 #[cfg(test)]
1615 mod test {
1616 #[cfg(all(feature = "num-bigint"))]
1617 use super::BigInt;
1618 #[cfg(feature = "num-bigint")]
1619 use super::BigRational;
1620 use super::{Ratio, Rational, Rational64};
1621
1622 use core::f64;
1623 use core::i32;
1624 use core::isize;
1625 use core::str::FromStr;
1626 use num_integer::Integer;
1627 use num_traits::ToPrimitive;
1628 use num_traits::{FromPrimitive, One, Pow, Signed, Zero};
1629
1630 pub const _0: Rational = Ratio { numer: 0, denom: 1 };
1631 pub const _1: Rational = Ratio { numer: 1, denom: 1 };
1632 pub const _2: Rational = Ratio { numer: 2, denom: 1 };
1633 pub const _NEG2: Rational = Ratio {
1634 numer: -2,
1635 denom: 1,
1636 };
1637 pub const _8: Rational = Ratio { numer: 8, denom: 1 };
1638 pub const _15: Rational = Ratio {
1639 numer: 15,
1640 denom: 1,
1641 };
1642 pub const _16: Rational = Ratio {
1643 numer: 16,
1644 denom: 1,
1645 };
1646
1647 pub const _1_2: Rational = Ratio { numer: 1, denom: 2 };
1648 pub const _1_8: Rational = Ratio { numer: 1, denom: 8 };
1649 pub const _1_15: Rational = Ratio {
1650 numer: 1,
1651 denom: 15,
1652 };
1653 pub const _1_16: Rational = Ratio {
1654 numer: 1,
1655 denom: 16,
1656 };
1657 pub const _3_2: Rational = Ratio { numer: 3, denom: 2 };
1658 pub const _5_2: Rational = Ratio { numer: 5, denom: 2 };
1659 pub const _NEG1_2: Rational = Ratio {
1660 numer: -1,
1661 denom: 2,
1662 };
1663 pub const _1_NEG2: Rational = Ratio {
1664 numer: 1,
1665 denom: -2,
1666 };
1667 pub const _NEG1_NEG2: Rational = Ratio {
1668 numer: -1,
1669 denom: -2,
1670 };
1671 pub const _1_3: Rational = Ratio { numer: 1, denom: 3 };
1672 pub const _NEG1_3: Rational = Ratio {
1673 numer: -1,
1674 denom: 3,
1675 };
1676 pub const _2_3: Rational = Ratio { numer: 2, denom: 3 };
1677 pub const _NEG2_3: Rational = Ratio {
1678 numer: -2,
1679 denom: 3,
1680 };
1681 pub const _MIN: Rational = Ratio {
1682 numer: isize::MIN,
1683 denom: 1,
1684 };
1685 pub const _MIN_P1: Rational = Ratio {
1686 numer: isize::MIN + 1,
1687 denom: 1,
1688 };
1689 pub const _MAX: Rational = Ratio {
1690 numer: isize::MAX,
1691 denom: 1,
1692 };
1693 pub const _MAX_M1: Rational = Ratio {
1694 numer: isize::MAX - 1,
1695 denom: 1,
1696 };
1697 pub const _BILLION: Rational = Ratio {
1698 numer: 1_000_000_000,
1699 denom: 1,
1700 };
1701
1702 #[cfg(feature = "num-bigint")]
to_big(n: Rational) -> BigRational1703 pub fn to_big(n: Rational) -> BigRational {
1704 Ratio::new(
1705 FromPrimitive::from_isize(n.numer).unwrap(),
1706 FromPrimitive::from_isize(n.denom).unwrap(),
1707 )
1708 }
1709 #[cfg(not(feature = "num-bigint"))]
to_big(n: Rational) -> Rational1710 pub fn to_big(n: Rational) -> Rational {
1711 Ratio::new(
1712 FromPrimitive::from_isize(n.numer).unwrap(),
1713 FromPrimitive::from_isize(n.denom).unwrap(),
1714 )
1715 }
1716
1717 #[test]
test_test_constants()1718 fn test_test_constants() {
1719 // check our constants are what Ratio::new etc. would make.
1720 assert_eq!(_0, Zero::zero());
1721 assert_eq!(_1, One::one());
1722 assert_eq!(_2, Ratio::from_integer(2));
1723 assert_eq!(_1_2, Ratio::new(1, 2));
1724 assert_eq!(_3_2, Ratio::new(3, 2));
1725 assert_eq!(_NEG1_2, Ratio::new(-1, 2));
1726 assert_eq!(_2, From::from(2));
1727 }
1728
1729 #[test]
test_new_reduce()1730 fn test_new_reduce() {
1731 assert_eq!(Ratio::new(2, 2), One::one());
1732 assert_eq!(Ratio::new(0, i32::MIN), Zero::zero());
1733 assert_eq!(Ratio::new(i32::MIN, i32::MIN), One::one());
1734 }
1735 #[test]
1736 #[should_panic]
test_new_zero()1737 fn test_new_zero() {
1738 let _a = Ratio::new(1, 0);
1739 }
1740
1741 #[test]
test_approximate_float()1742 fn test_approximate_float() {
1743 assert_eq!(Ratio::from_f32(0.5f32), Some(Ratio::new(1i64, 2)));
1744 assert_eq!(Ratio::from_f64(0.5f64), Some(Ratio::new(1i32, 2)));
1745 assert_eq!(Ratio::from_f32(5f32), Some(Ratio::new(5i64, 1)));
1746 assert_eq!(Ratio::from_f64(5f64), Some(Ratio::new(5i32, 1)));
1747 assert_eq!(Ratio::from_f32(29.97f32), Some(Ratio::new(2997i64, 100)));
1748 assert_eq!(Ratio::from_f32(-29.97f32), Some(Ratio::new(-2997i64, 100)));
1749
1750 assert_eq!(Ratio::<i8>::from_f32(63.5f32), Some(Ratio::new(127i8, 2)));
1751 assert_eq!(Ratio::<i8>::from_f32(126.5f32), Some(Ratio::new(126i8, 1)));
1752 assert_eq!(Ratio::<i8>::from_f32(127.0f32), Some(Ratio::new(127i8, 1)));
1753 assert_eq!(Ratio::<i8>::from_f32(127.5f32), None);
1754 assert_eq!(Ratio::<i8>::from_f32(-63.5f32), Some(Ratio::new(-127i8, 2)));
1755 assert_eq!(
1756 Ratio::<i8>::from_f32(-126.5f32),
1757 Some(Ratio::new(-126i8, 1))
1758 );
1759 assert_eq!(
1760 Ratio::<i8>::from_f32(-127.0f32),
1761 Some(Ratio::new(-127i8, 1))
1762 );
1763 assert_eq!(Ratio::<i8>::from_f32(-127.5f32), None);
1764
1765 assert_eq!(Ratio::<u8>::from_f32(-127f32), None);
1766 assert_eq!(Ratio::<u8>::from_f32(127f32), Some(Ratio::new(127u8, 1)));
1767 assert_eq!(Ratio::<u8>::from_f32(127.5f32), Some(Ratio::new(255u8, 2)));
1768 assert_eq!(Ratio::<u8>::from_f32(256f32), None);
1769
1770 assert_eq!(Ratio::<i64>::from_f64(-10e200), None);
1771 assert_eq!(Ratio::<i64>::from_f64(10e200), None);
1772 assert_eq!(Ratio::<i64>::from_f64(f64::INFINITY), None);
1773 assert_eq!(Ratio::<i64>::from_f64(f64::NEG_INFINITY), None);
1774 assert_eq!(Ratio::<i64>::from_f64(f64::NAN), None);
1775 assert_eq!(
1776 Ratio::<i64>::from_f64(f64::EPSILON),
1777 Some(Ratio::new(1, 4503599627370496))
1778 );
1779 assert_eq!(Ratio::<i64>::from_f64(0.0), Some(Ratio::new(0, 1)));
1780 assert_eq!(Ratio::<i64>::from_f64(-0.0), Some(Ratio::new(0, 1)));
1781 }
1782
1783 #[test]
1784 #[allow(clippy::eq_op)]
test_cmp()1785 fn test_cmp() {
1786 assert!(_0 == _0 && _1 == _1);
1787 assert!(_0 != _1 && _1 != _0);
1788 assert!(_0 < _1 && !(_1 < _0));
1789 assert!(_1 > _0 && !(_0 > _1));
1790
1791 assert!(_0 <= _0 && _1 <= _1);
1792 assert!(_0 <= _1 && !(_1 <= _0));
1793
1794 assert!(_0 >= _0 && _1 >= _1);
1795 assert!(_1 >= _0 && !(_0 >= _1));
1796
1797 let _0_2: Rational = Ratio::new_raw(0, 2);
1798 assert_eq!(_0, _0_2);
1799 }
1800
1801 #[test]
test_cmp_overflow()1802 fn test_cmp_overflow() {
1803 use core::cmp::Ordering;
1804
1805 // issue #7 example:
1806 let big = Ratio::new(128u8, 1);
1807 let small = big.recip();
1808 assert!(big > small);
1809
1810 // try a few that are closer together
1811 // (some matching numer, some matching denom, some neither)
1812 let ratios = [
1813 Ratio::new(125_i8, 127_i8),
1814 Ratio::new(63_i8, 64_i8),
1815 Ratio::new(124_i8, 125_i8),
1816 Ratio::new(125_i8, 126_i8),
1817 Ratio::new(126_i8, 127_i8),
1818 Ratio::new(127_i8, 126_i8),
1819 ];
1820
1821 fn check_cmp(a: Ratio<i8>, b: Ratio<i8>, ord: Ordering) {
1822 #[cfg(feature = "std")]
1823 println!("comparing {} and {}", a, b);
1824 assert_eq!(a.cmp(&b), ord);
1825 assert_eq!(b.cmp(&a), ord.reverse());
1826 }
1827
1828 for (i, &a) in ratios.iter().enumerate() {
1829 check_cmp(a, a, Ordering::Equal);
1830 check_cmp(-a, a, Ordering::Less);
1831 for &b in &ratios[i + 1..] {
1832 check_cmp(a, b, Ordering::Less);
1833 check_cmp(-a, -b, Ordering::Greater);
1834 check_cmp(a.recip(), b.recip(), Ordering::Greater);
1835 check_cmp(-a.recip(), -b.recip(), Ordering::Less);
1836 }
1837 }
1838 }
1839
1840 #[test]
test_to_integer()1841 fn test_to_integer() {
1842 assert_eq!(_0.to_integer(), 0);
1843 assert_eq!(_1.to_integer(), 1);
1844 assert_eq!(_2.to_integer(), 2);
1845 assert_eq!(_1_2.to_integer(), 0);
1846 assert_eq!(_3_2.to_integer(), 1);
1847 assert_eq!(_NEG1_2.to_integer(), 0);
1848 }
1849
1850 #[test]
test_numer()1851 fn test_numer() {
1852 assert_eq!(_0.numer(), &0);
1853 assert_eq!(_1.numer(), &1);
1854 assert_eq!(_2.numer(), &2);
1855 assert_eq!(_1_2.numer(), &1);
1856 assert_eq!(_3_2.numer(), &3);
1857 assert_eq!(_NEG1_2.numer(), &(-1));
1858 }
1859 #[test]
test_denom()1860 fn test_denom() {
1861 assert_eq!(_0.denom(), &1);
1862 assert_eq!(_1.denom(), &1);
1863 assert_eq!(_2.denom(), &1);
1864 assert_eq!(_1_2.denom(), &2);
1865 assert_eq!(_3_2.denom(), &2);
1866 assert_eq!(_NEG1_2.denom(), &2);
1867 }
1868
1869 #[test]
test_is_integer()1870 fn test_is_integer() {
1871 assert!(_0.is_integer());
1872 assert!(_1.is_integer());
1873 assert!(_2.is_integer());
1874 assert!(!_1_2.is_integer());
1875 assert!(!_3_2.is_integer());
1876 assert!(!_NEG1_2.is_integer());
1877 }
1878
1879 #[cfg(not(feature = "std"))]
1880 use core::fmt::{self, Write};
1881 #[cfg(not(feature = "std"))]
1882 #[derive(Debug)]
1883 struct NoStdTester {
1884 cursor: usize,
1885 buf: [u8; NoStdTester::BUF_SIZE],
1886 }
1887
1888 #[cfg(not(feature = "std"))]
1889 impl NoStdTester {
new() -> NoStdTester1890 fn new() -> NoStdTester {
1891 NoStdTester {
1892 buf: [0; Self::BUF_SIZE],
1893 cursor: 0,
1894 }
1895 }
1896
clear(&mut self)1897 fn clear(&mut self) {
1898 self.buf = [0; Self::BUF_SIZE];
1899 self.cursor = 0;
1900 }
1901
1902 const WRITE_ERR: &'static str = "Formatted output too long";
1903 const BUF_SIZE: usize = 32;
1904 }
1905
1906 #[cfg(not(feature = "std"))]
1907 impl Write for NoStdTester {
write_str(&mut self, s: &str) -> fmt::Result1908 fn write_str(&mut self, s: &str) -> fmt::Result {
1909 for byte in s.bytes() {
1910 self.buf[self.cursor] = byte;
1911 self.cursor += 1;
1912 if self.cursor >= self.buf.len() {
1913 return Err(fmt::Error {});
1914 }
1915 }
1916 Ok(())
1917 }
1918 }
1919
1920 #[cfg(not(feature = "std"))]
1921 impl PartialEq<str> for NoStdTester {
eq(&self, other: &str) -> bool1922 fn eq(&self, other: &str) -> bool {
1923 let other = other.as_bytes();
1924 for index in 0..self.cursor {
1925 if self.buf.get(index) != other.get(index) {
1926 return false;
1927 }
1928 }
1929 true
1930 }
1931 }
1932
1933 macro_rules! assert_fmt_eq {
1934 ($fmt_args:expr, $string:expr) => {
1935 #[cfg(not(feature = "std"))]
1936 {
1937 let mut tester = NoStdTester::new();
1938 write!(tester, "{}", $fmt_args).expect(NoStdTester::WRITE_ERR);
1939 assert_eq!(tester, *$string);
1940 tester.clear();
1941 }
1942 #[cfg(feature = "std")]
1943 {
1944 assert_eq!(std::fmt::format($fmt_args), $string);
1945 }
1946 };
1947 }
1948
1949 #[test]
test_show()1950 fn test_show() {
1951 // Test:
1952 // :b :o :x, :X, :?
1953 // alternate or not (#)
1954 // positive and negative
1955 // padding
1956 // does not test precision (i.e. truncation)
1957 assert_fmt_eq!(format_args!("{}", _2), "2");
1958 assert_fmt_eq!(format_args!("{:+}", _2), "+2");
1959 assert_fmt_eq!(format_args!("{:-}", _2), "2");
1960 assert_fmt_eq!(format_args!("{}", _1_2), "1/2");
1961 assert_fmt_eq!(format_args!("{}", -_1_2), "-1/2"); // test negatives
1962 assert_fmt_eq!(format_args!("{}", _0), "0");
1963 assert_fmt_eq!(format_args!("{}", -_2), "-2");
1964 assert_fmt_eq!(format_args!("{:+}", -_2), "-2");
1965 assert_fmt_eq!(format_args!("{:b}", _2), "10");
1966 assert_fmt_eq!(format_args!("{:#b}", _2), "0b10");
1967 assert_fmt_eq!(format_args!("{:b}", _1_2), "1/10");
1968 assert_fmt_eq!(format_args!("{:+b}", _1_2), "+1/10");
1969 assert_fmt_eq!(format_args!("{:-b}", _1_2), "1/10");
1970 assert_fmt_eq!(format_args!("{:b}", _0), "0");
1971 assert_fmt_eq!(format_args!("{:#b}", _1_2), "0b1/0b10");
1972 // no std does not support padding
1973 #[cfg(feature = "std")]
1974 assert_eq!(&format!("{:010b}", _1_2), "0000001/10");
1975 #[cfg(feature = "std")]
1976 assert_eq!(&format!("{:#010b}", _1_2), "0b001/0b10");
1977 let half_i8: Ratio<i8> = Ratio::new(1_i8, 2_i8);
1978 assert_fmt_eq!(format_args!("{:b}", -half_i8), "11111111/10");
1979 assert_fmt_eq!(format_args!("{:#b}", -half_i8), "0b11111111/0b10");
1980 #[cfg(feature = "std")]
1981 assert_eq!(&format!("{:05}", Ratio::new(-1_i8, 1_i8)), "-0001");
1982
1983 assert_fmt_eq!(format_args!("{:o}", _8), "10");
1984 assert_fmt_eq!(format_args!("{:o}", _1_8), "1/10");
1985 assert_fmt_eq!(format_args!("{:o}", _0), "0");
1986 assert_fmt_eq!(format_args!("{:#o}", _1_8), "0o1/0o10");
1987 #[cfg(feature = "std")]
1988 assert_eq!(&format!("{:010o}", _1_8), "0000001/10");
1989 #[cfg(feature = "std")]
1990 assert_eq!(&format!("{:#010o}", _1_8), "0o001/0o10");
1991 assert_fmt_eq!(format_args!("{:o}", -half_i8), "377/2");
1992 assert_fmt_eq!(format_args!("{:#o}", -half_i8), "0o377/0o2");
1993
1994 assert_fmt_eq!(format_args!("{:x}", _16), "10");
1995 assert_fmt_eq!(format_args!("{:x}", _15), "f");
1996 assert_fmt_eq!(format_args!("{:x}", _1_16), "1/10");
1997 assert_fmt_eq!(format_args!("{:x}", _1_15), "1/f");
1998 assert_fmt_eq!(format_args!("{:x}", _0), "0");
1999 assert_fmt_eq!(format_args!("{:#x}", _1_16), "0x1/0x10");
2000 #[cfg(feature = "std")]
2001 assert_eq!(&format!("{:010x}", _1_16), "0000001/10");
2002 #[cfg(feature = "std")]
2003 assert_eq!(&format!("{:#010x}", _1_16), "0x001/0x10");
2004 assert_fmt_eq!(format_args!("{:x}", -half_i8), "ff/2");
2005 assert_fmt_eq!(format_args!("{:#x}", -half_i8), "0xff/0x2");
2006
2007 assert_fmt_eq!(format_args!("{:X}", _16), "10");
2008 assert_fmt_eq!(format_args!("{:X}", _15), "F");
2009 assert_fmt_eq!(format_args!("{:X}", _1_16), "1/10");
2010 assert_fmt_eq!(format_args!("{:X}", _1_15), "1/F");
2011 assert_fmt_eq!(format_args!("{:X}", _0), "0");
2012 assert_fmt_eq!(format_args!("{:#X}", _1_16), "0x1/0x10");
2013 #[cfg(feature = "std")]
2014 assert_eq!(format!("{:010X}", _1_16), "0000001/10");
2015 #[cfg(feature = "std")]
2016 assert_eq!(format!("{:#010X}", _1_16), "0x001/0x10");
2017 assert_fmt_eq!(format_args!("{:X}", -half_i8), "FF/2");
2018 assert_fmt_eq!(format_args!("{:#X}", -half_i8), "0xFF/0x2");
2019
2020 #[cfg(has_int_exp_fmt)]
2021 {
2022 assert_fmt_eq!(format_args!("{:e}", -_2), "-2e0");
2023 assert_fmt_eq!(format_args!("{:#e}", -_2), "-2e0");
2024 assert_fmt_eq!(format_args!("{:+e}", -_2), "-2e0");
2025 assert_fmt_eq!(format_args!("{:e}", _BILLION), "1e9");
2026 assert_fmt_eq!(format_args!("{:+e}", _BILLION), "+1e9");
2027 assert_fmt_eq!(format_args!("{:e}", _BILLION.recip()), "1e0/1e9");
2028 assert_fmt_eq!(format_args!("{:+e}", _BILLION.recip()), "+1e0/1e9");
2029
2030 assert_fmt_eq!(format_args!("{:E}", -_2), "-2E0");
2031 assert_fmt_eq!(format_args!("{:#E}", -_2), "-2E0");
2032 assert_fmt_eq!(format_args!("{:+E}", -_2), "-2E0");
2033 assert_fmt_eq!(format_args!("{:E}", _BILLION), "1E9");
2034 assert_fmt_eq!(format_args!("{:+E}", _BILLION), "+1E9");
2035 assert_fmt_eq!(format_args!("{:E}", _BILLION.recip()), "1E0/1E9");
2036 assert_fmt_eq!(format_args!("{:+E}", _BILLION.recip()), "+1E0/1E9");
2037 }
2038 }
2039
2040 mod arith {
2041 use super::super::{Ratio, Rational};
2042 use super::{to_big, _0, _1, _1_2, _2, _3_2, _5_2, _MAX, _MAX_M1, _MIN, _MIN_P1, _NEG1_2};
2043 use core::fmt::Debug;
2044 use num_integer::Integer;
2045 use num_traits::{Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, NumAssign};
2046
2047 #[test]
test_add()2048 fn test_add() {
2049 fn test(a: Rational, b: Rational, c: Rational) {
2050 assert_eq!(a + b, c);
2051 assert_eq!(
2052 {
2053 let mut x = a;
2054 x += b;
2055 x
2056 },
2057 c
2058 );
2059 assert_eq!(to_big(a) + to_big(b), to_big(c));
2060 assert_eq!(a.checked_add(&b), Some(c));
2061 assert_eq!(to_big(a).checked_add(&to_big(b)), Some(to_big(c)));
2062 }
2063 fn test_assign(a: Rational, b: isize, c: Rational) {
2064 assert_eq!(a + b, c);
2065 assert_eq!(
2066 {
2067 let mut x = a;
2068 x += b;
2069 x
2070 },
2071 c
2072 );
2073 }
2074
2075 test(_1, _1_2, _3_2);
2076 test(_1, _1, _2);
2077 test(_1_2, _3_2, _2);
2078 test(_1_2, _NEG1_2, _0);
2079 test_assign(_1_2, 1, _3_2);
2080 }
2081
2082 #[test]
test_add_overflow()2083 fn test_add_overflow() {
2084 // compares Ratio(1, T::max_value()) + Ratio(1, T::max_value())
2085 // to Ratio(1+1, T::max_value()) for each integer type.
2086 // Previously, this calculation would overflow.
2087 fn test_add_typed_overflow<T>()
2088 where
2089 T: Integer + Bounded + Clone + Debug + NumAssign,
2090 {
2091 let _1_max = Ratio::new(T::one(), T::max_value());
2092 let _2_max = Ratio::new(T::one() + T::one(), T::max_value());
2093 assert_eq!(_1_max.clone() + _1_max.clone(), _2_max);
2094 assert_eq!(
2095 {
2096 let mut tmp = _1_max.clone();
2097 tmp += _1_max;
2098 tmp
2099 },
2100 _2_max
2101 );
2102 }
2103 test_add_typed_overflow::<u8>();
2104 test_add_typed_overflow::<u16>();
2105 test_add_typed_overflow::<u32>();
2106 test_add_typed_overflow::<u64>();
2107 test_add_typed_overflow::<usize>();
2108 test_add_typed_overflow::<u128>();
2109
2110 test_add_typed_overflow::<i8>();
2111 test_add_typed_overflow::<i16>();
2112 test_add_typed_overflow::<i32>();
2113 test_add_typed_overflow::<i64>();
2114 test_add_typed_overflow::<isize>();
2115 test_add_typed_overflow::<i128>();
2116 }
2117
2118 #[test]
test_sub()2119 fn test_sub() {
2120 fn test(a: Rational, b: Rational, c: Rational) {
2121 assert_eq!(a - b, c);
2122 assert_eq!(
2123 {
2124 let mut x = a;
2125 x -= b;
2126 x
2127 },
2128 c
2129 );
2130 assert_eq!(to_big(a) - to_big(b), to_big(c));
2131 assert_eq!(a.checked_sub(&b), Some(c));
2132 assert_eq!(to_big(a).checked_sub(&to_big(b)), Some(to_big(c)));
2133 }
2134 fn test_assign(a: Rational, b: isize, c: Rational) {
2135 assert_eq!(a - b, c);
2136 assert_eq!(
2137 {
2138 let mut x = a;
2139 x -= b;
2140 x
2141 },
2142 c
2143 );
2144 }
2145
2146 test(_1, _1_2, _1_2);
2147 test(_3_2, _1_2, _1);
2148 test(_1, _NEG1_2, _3_2);
2149 test_assign(_1_2, 1, _NEG1_2);
2150 }
2151
2152 #[test]
test_sub_overflow()2153 fn test_sub_overflow() {
2154 // compares Ratio(1, T::max_value()) - Ratio(1, T::max_value()) to T::zero()
2155 // for each integer type. Previously, this calculation would overflow.
2156 fn test_sub_typed_overflow<T>()
2157 where
2158 T: Integer + Bounded + Clone + Debug + NumAssign,
2159 {
2160 let _1_max: Ratio<T> = Ratio::new(T::one(), T::max_value());
2161 assert!(T::is_zero(&(_1_max.clone() - _1_max.clone()).numer));
2162 {
2163 let mut tmp: Ratio<T> = _1_max.clone();
2164 tmp -= _1_max;
2165 assert!(T::is_zero(&tmp.numer));
2166 }
2167 }
2168 test_sub_typed_overflow::<u8>();
2169 test_sub_typed_overflow::<u16>();
2170 test_sub_typed_overflow::<u32>();
2171 test_sub_typed_overflow::<u64>();
2172 test_sub_typed_overflow::<usize>();
2173 test_sub_typed_overflow::<u128>();
2174
2175 test_sub_typed_overflow::<i8>();
2176 test_sub_typed_overflow::<i16>();
2177 test_sub_typed_overflow::<i32>();
2178 test_sub_typed_overflow::<i64>();
2179 test_sub_typed_overflow::<isize>();
2180 test_sub_typed_overflow::<i128>();
2181 }
2182
2183 #[test]
test_mul()2184 fn test_mul() {
2185 fn test(a: Rational, b: Rational, c: Rational) {
2186 assert_eq!(a * b, c);
2187 assert_eq!(
2188 {
2189 let mut x = a;
2190 x *= b;
2191 x
2192 },
2193 c
2194 );
2195 assert_eq!(to_big(a) * to_big(b), to_big(c));
2196 assert_eq!(a.checked_mul(&b), Some(c));
2197 assert_eq!(to_big(a).checked_mul(&to_big(b)), Some(to_big(c)));
2198 }
2199 fn test_assign(a: Rational, b: isize, c: Rational) {
2200 assert_eq!(a * b, c);
2201 assert_eq!(
2202 {
2203 let mut x = a;
2204 x *= b;
2205 x
2206 },
2207 c
2208 );
2209 }
2210
2211 test(_1, _1_2, _1_2);
2212 test(_1_2, _3_2, Ratio::new(3, 4));
2213 test(_1_2, _NEG1_2, Ratio::new(-1, 4));
2214 test_assign(_1_2, 2, _1);
2215 }
2216
2217 #[test]
test_mul_overflow()2218 fn test_mul_overflow() {
2219 fn test_mul_typed_overflow<T>()
2220 where
2221 T: Integer + Bounded + Clone + Debug + NumAssign + CheckedMul,
2222 {
2223 let two = T::one() + T::one();
2224 let _3 = T::one() + T::one() + T::one();
2225
2226 // 1/big * 2/3 = 1/(max/4*3), where big is max/2
2227 // make big = max/2, but also divisible by 2
2228 let big = T::max_value() / two.clone() / two.clone() * two.clone();
2229 let _1_big: Ratio<T> = Ratio::new(T::one(), big.clone());
2230 let _2_3: Ratio<T> = Ratio::new(two.clone(), _3.clone());
2231 assert_eq!(None, big.clone().checked_mul(&_3.clone()));
2232 let expected = Ratio::new(T::one(), big / two.clone() * _3.clone());
2233 assert_eq!(expected.clone(), _1_big.clone() * _2_3.clone());
2234 assert_eq!(
2235 Some(expected.clone()),
2236 _1_big.clone().checked_mul(&_2_3.clone())
2237 );
2238 assert_eq!(expected, {
2239 let mut tmp = _1_big;
2240 tmp *= _2_3;
2241 tmp
2242 });
2243
2244 // big/3 * 3 = big/1
2245 // make big = max/2, but make it indivisible by 3
2246 let big = T::max_value() / two / _3.clone() * _3.clone() + T::one();
2247 assert_eq!(None, big.clone().checked_mul(&_3.clone()));
2248 let big_3 = Ratio::new(big.clone(), _3.clone());
2249 let expected = Ratio::new(big, T::one());
2250 assert_eq!(expected, big_3.clone() * _3.clone());
2251 assert_eq!(expected, {
2252 let mut tmp = big_3;
2253 tmp *= _3;
2254 tmp
2255 });
2256 }
2257 test_mul_typed_overflow::<u16>();
2258 test_mul_typed_overflow::<u8>();
2259 test_mul_typed_overflow::<u32>();
2260 test_mul_typed_overflow::<u64>();
2261 test_mul_typed_overflow::<usize>();
2262 test_mul_typed_overflow::<u128>();
2263
2264 test_mul_typed_overflow::<i8>();
2265 test_mul_typed_overflow::<i16>();
2266 test_mul_typed_overflow::<i32>();
2267 test_mul_typed_overflow::<i64>();
2268 test_mul_typed_overflow::<isize>();
2269 test_mul_typed_overflow::<i128>();
2270 }
2271
2272 #[test]
test_div()2273 fn test_div() {
2274 fn test(a: Rational, b: Rational, c: Rational) {
2275 assert_eq!(a / b, c);
2276 assert_eq!(
2277 {
2278 let mut x = a;
2279 x /= b;
2280 x
2281 },
2282 c
2283 );
2284 assert_eq!(to_big(a) / to_big(b), to_big(c));
2285 assert_eq!(a.checked_div(&b), Some(c));
2286 assert_eq!(to_big(a).checked_div(&to_big(b)), Some(to_big(c)));
2287 }
2288 fn test_assign(a: Rational, b: isize, c: Rational) {
2289 assert_eq!(a / b, c);
2290 assert_eq!(
2291 {
2292 let mut x = a;
2293 x /= b;
2294 x
2295 },
2296 c
2297 );
2298 }
2299
2300 test(_1, _1_2, _2);
2301 test(_3_2, _1_2, _1 + _2);
2302 test(_1, _NEG1_2, _NEG1_2 + _NEG1_2 + _NEG1_2 + _NEG1_2);
2303 test_assign(_1, 2, _1_2);
2304 }
2305
2306 #[test]
test_div_overflow()2307 fn test_div_overflow() {
2308 fn test_div_typed_overflow<T>()
2309 where
2310 T: Integer + Bounded + Clone + Debug + NumAssign + CheckedMul,
2311 {
2312 let two = T::one() + T::one();
2313 let _3 = T::one() + T::one() + T::one();
2314
2315 // 1/big / 3/2 = 1/(max/4*3), where big is max/2
2316 // big ~ max/2, and big is divisible by 2
2317 let big = T::max_value() / two.clone() / two.clone() * two.clone();
2318 assert_eq!(None, big.clone().checked_mul(&_3.clone()));
2319 let _1_big: Ratio<T> = Ratio::new(T::one(), big.clone());
2320 let _3_two: Ratio<T> = Ratio::new(_3.clone(), two.clone());
2321 let expected = Ratio::new(T::one(), big / two.clone() * _3.clone());
2322 assert_eq!(expected.clone(), _1_big.clone() / _3_two.clone());
2323 assert_eq!(
2324 Some(expected.clone()),
2325 _1_big.clone().checked_div(&_3_two.clone())
2326 );
2327 assert_eq!(expected, {
2328 let mut tmp = _1_big;
2329 tmp /= _3_two;
2330 tmp
2331 });
2332
2333 // 3/big / 3 = 1/big where big is max/2
2334 // big ~ max/2, and big is not divisible by 3
2335 let big = T::max_value() / two / _3.clone() * _3.clone() + T::one();
2336 assert_eq!(None, big.clone().checked_mul(&_3.clone()));
2337 let _3_big = Ratio::new(_3.clone(), big.clone());
2338 let expected = Ratio::new(T::one(), big);
2339 assert_eq!(expected, _3_big.clone() / _3.clone());
2340 assert_eq!(expected, {
2341 let mut tmp = _3_big;
2342 tmp /= _3;
2343 tmp
2344 });
2345 }
2346 test_div_typed_overflow::<u8>();
2347 test_div_typed_overflow::<u16>();
2348 test_div_typed_overflow::<u32>();
2349 test_div_typed_overflow::<u64>();
2350 test_div_typed_overflow::<usize>();
2351 test_div_typed_overflow::<u128>();
2352
2353 test_div_typed_overflow::<i8>();
2354 test_div_typed_overflow::<i16>();
2355 test_div_typed_overflow::<i32>();
2356 test_div_typed_overflow::<i64>();
2357 test_div_typed_overflow::<isize>();
2358 test_div_typed_overflow::<i128>();
2359 }
2360
2361 #[test]
test_rem()2362 fn test_rem() {
2363 fn test(a: Rational, b: Rational, c: Rational) {
2364 assert_eq!(a % b, c);
2365 assert_eq!(
2366 {
2367 let mut x = a;
2368 x %= b;
2369 x
2370 },
2371 c
2372 );
2373 assert_eq!(to_big(a) % to_big(b), to_big(c))
2374 }
2375 fn test_assign(a: Rational, b: isize, c: Rational) {
2376 assert_eq!(a % b, c);
2377 assert_eq!(
2378 {
2379 let mut x = a;
2380 x %= b;
2381 x
2382 },
2383 c
2384 );
2385 }
2386
2387 test(_3_2, _1, _1_2);
2388 test(_3_2, _1_2, _0);
2389 test(_5_2, _3_2, _1);
2390 test(_2, _NEG1_2, _0);
2391 test(_1_2, _2, _1_2);
2392 test_assign(_3_2, 1, _1_2);
2393 }
2394
2395 #[test]
test_rem_overflow()2396 fn test_rem_overflow() {
2397 // tests that Ratio(1,2) % Ratio(1, T::max_value()) equals 0
2398 // for each integer type. Previously, this calculation would overflow.
2399 fn test_rem_typed_overflow<T>()
2400 where
2401 T: Integer + Bounded + Clone + Debug + NumAssign,
2402 {
2403 let two = T::one() + T::one();
2404 // value near to maximum, but divisible by two
2405 let max_div2 = T::max_value() / two.clone() * two.clone();
2406 let _1_max: Ratio<T> = Ratio::new(T::one(), max_div2);
2407 let _1_two: Ratio<T> = Ratio::new(T::one(), two);
2408 assert!(T::is_zero(&(_1_two.clone() % _1_max.clone()).numer));
2409 {
2410 let mut tmp: Ratio<T> = _1_two;
2411 tmp %= _1_max;
2412 assert!(T::is_zero(&tmp.numer));
2413 }
2414 }
2415 test_rem_typed_overflow::<u8>();
2416 test_rem_typed_overflow::<u16>();
2417 test_rem_typed_overflow::<u32>();
2418 test_rem_typed_overflow::<u64>();
2419 test_rem_typed_overflow::<usize>();
2420 test_rem_typed_overflow::<u128>();
2421
2422 test_rem_typed_overflow::<i8>();
2423 test_rem_typed_overflow::<i16>();
2424 test_rem_typed_overflow::<i32>();
2425 test_rem_typed_overflow::<i64>();
2426 test_rem_typed_overflow::<isize>();
2427 test_rem_typed_overflow::<i128>();
2428 }
2429
2430 #[test]
test_neg()2431 fn test_neg() {
2432 fn test(a: Rational, b: Rational) {
2433 assert_eq!(-a, b);
2434 assert_eq!(-to_big(a), to_big(b))
2435 }
2436
2437 test(_0, _0);
2438 test(_1_2, _NEG1_2);
2439 test(-_1, _1);
2440 }
2441 #[test]
2442 #[allow(clippy::eq_op)]
test_zero()2443 fn test_zero() {
2444 assert_eq!(_0 + _0, _0);
2445 assert_eq!(_0 * _0, _0);
2446 assert_eq!(_0 * _1, _0);
2447 assert_eq!(_0 / _NEG1_2, _0);
2448 assert_eq!(_0 - _0, _0);
2449 }
2450 #[test]
2451 #[should_panic]
test_div_0()2452 fn test_div_0() {
2453 let _a = _1 / _0;
2454 }
2455
2456 #[test]
test_checked_failures()2457 fn test_checked_failures() {
2458 let big = Ratio::new(128u8, 1);
2459 let small = Ratio::new(1, 128u8);
2460 assert_eq!(big.checked_add(&big), None);
2461 assert_eq!(small.checked_sub(&big), None);
2462 assert_eq!(big.checked_mul(&big), None);
2463 assert_eq!(small.checked_div(&big), None);
2464 assert_eq!(_1.checked_div(&_0), None);
2465 }
2466
2467 #[test]
test_checked_zeros()2468 fn test_checked_zeros() {
2469 assert_eq!(_0.checked_add(&_0), Some(_0));
2470 assert_eq!(_0.checked_sub(&_0), Some(_0));
2471 assert_eq!(_0.checked_mul(&_0), Some(_0));
2472 assert_eq!(_0.checked_div(&_0), None);
2473 }
2474
2475 #[test]
test_checked_min()2476 fn test_checked_min() {
2477 assert_eq!(_MIN.checked_add(&_MIN), None);
2478 assert_eq!(_MIN.checked_sub(&_MIN), Some(_0));
2479 assert_eq!(_MIN.checked_mul(&_MIN), None);
2480 assert_eq!(_MIN.checked_div(&_MIN), Some(_1));
2481 assert_eq!(_0.checked_add(&_MIN), Some(_MIN));
2482 assert_eq!(_0.checked_sub(&_MIN), None);
2483 assert_eq!(_0.checked_mul(&_MIN), Some(_0));
2484 assert_eq!(_0.checked_div(&_MIN), Some(_0));
2485 assert_eq!(_1.checked_add(&_MIN), Some(_MIN_P1));
2486 assert_eq!(_1.checked_sub(&_MIN), None);
2487 assert_eq!(_1.checked_mul(&_MIN), Some(_MIN));
2488 assert_eq!(_1.checked_div(&_MIN), None);
2489 assert_eq!(_MIN.checked_add(&_0), Some(_MIN));
2490 assert_eq!(_MIN.checked_sub(&_0), Some(_MIN));
2491 assert_eq!(_MIN.checked_mul(&_0), Some(_0));
2492 assert_eq!(_MIN.checked_div(&_0), None);
2493 assert_eq!(_MIN.checked_add(&_1), Some(_MIN_P1));
2494 assert_eq!(_MIN.checked_sub(&_1), None);
2495 assert_eq!(_MIN.checked_mul(&_1), Some(_MIN));
2496 assert_eq!(_MIN.checked_div(&_1), Some(_MIN));
2497 }
2498
2499 #[test]
test_checked_max()2500 fn test_checked_max() {
2501 assert_eq!(_MAX.checked_add(&_MAX), None);
2502 assert_eq!(_MAX.checked_sub(&_MAX), Some(_0));
2503 assert_eq!(_MAX.checked_mul(&_MAX), None);
2504 assert_eq!(_MAX.checked_div(&_MAX), Some(_1));
2505 assert_eq!(_0.checked_add(&_MAX), Some(_MAX));
2506 assert_eq!(_0.checked_sub(&_MAX), Some(_MIN_P1));
2507 assert_eq!(_0.checked_mul(&_MAX), Some(_0));
2508 assert_eq!(_0.checked_div(&_MAX), Some(_0));
2509 assert_eq!(_1.checked_add(&_MAX), None);
2510 assert_eq!(_1.checked_sub(&_MAX), Some(-_MAX_M1));
2511 assert_eq!(_1.checked_mul(&_MAX), Some(_MAX));
2512 assert_eq!(_1.checked_div(&_MAX), Some(_MAX.recip()));
2513 assert_eq!(_MAX.checked_add(&_0), Some(_MAX));
2514 assert_eq!(_MAX.checked_sub(&_0), Some(_MAX));
2515 assert_eq!(_MAX.checked_mul(&_0), Some(_0));
2516 assert_eq!(_MAX.checked_div(&_0), None);
2517 assert_eq!(_MAX.checked_add(&_1), None);
2518 assert_eq!(_MAX.checked_sub(&_1), Some(_MAX_M1));
2519 assert_eq!(_MAX.checked_mul(&_1), Some(_MAX));
2520 assert_eq!(_MAX.checked_div(&_1), Some(_MAX));
2521 }
2522
2523 #[test]
test_checked_min_max()2524 fn test_checked_min_max() {
2525 assert_eq!(_MIN.checked_add(&_MAX), Some(-_1));
2526 assert_eq!(_MIN.checked_sub(&_MAX), None);
2527 assert_eq!(_MIN.checked_mul(&_MAX), None);
2528 assert_eq!(
2529 _MIN.checked_div(&_MAX),
2530 Some(Ratio::new(_MIN.numer, _MAX.numer))
2531 );
2532 assert_eq!(_MAX.checked_add(&_MIN), Some(-_1));
2533 assert_eq!(_MAX.checked_sub(&_MIN), None);
2534 assert_eq!(_MAX.checked_mul(&_MIN), None);
2535 assert_eq!(_MAX.checked_div(&_MIN), None);
2536 }
2537 }
2538
2539 #[test]
test_round()2540 fn test_round() {
2541 assert_eq!(_1_3.ceil(), _1);
2542 assert_eq!(_1_3.floor(), _0);
2543 assert_eq!(_1_3.round(), _0);
2544 assert_eq!(_1_3.trunc(), _0);
2545
2546 assert_eq!(_NEG1_3.ceil(), _0);
2547 assert_eq!(_NEG1_3.floor(), -_1);
2548 assert_eq!(_NEG1_3.round(), _0);
2549 assert_eq!(_NEG1_3.trunc(), _0);
2550
2551 assert_eq!(_2_3.ceil(), _1);
2552 assert_eq!(_2_3.floor(), _0);
2553 assert_eq!(_2_3.round(), _1);
2554 assert_eq!(_2_3.trunc(), _0);
2555
2556 assert_eq!(_NEG2_3.ceil(), _0);
2557 assert_eq!(_NEG2_3.floor(), -_1);
2558 assert_eq!(_NEG2_3.round(), -_1);
2559 assert_eq!(_NEG2_3.trunc(), _0);
2560
2561 assert_eq!(_1_2.ceil(), _1);
2562 assert_eq!(_1_2.floor(), _0);
2563 assert_eq!(_1_2.round(), _1);
2564 assert_eq!(_1_2.trunc(), _0);
2565
2566 assert_eq!(_NEG1_2.ceil(), _0);
2567 assert_eq!(_NEG1_2.floor(), -_1);
2568 assert_eq!(_NEG1_2.round(), -_1);
2569 assert_eq!(_NEG1_2.trunc(), _0);
2570
2571 assert_eq!(_1.ceil(), _1);
2572 assert_eq!(_1.floor(), _1);
2573 assert_eq!(_1.round(), _1);
2574 assert_eq!(_1.trunc(), _1);
2575
2576 // Overflow checks
2577
2578 let _neg1 = Ratio::from_integer(-1);
2579 let _large_rat1 = Ratio::new(i32::MAX, i32::MAX - 1);
2580 let _large_rat2 = Ratio::new(i32::MAX - 1, i32::MAX);
2581 let _large_rat3 = Ratio::new(i32::MIN + 2, i32::MIN + 1);
2582 let _large_rat4 = Ratio::new(i32::MIN + 1, i32::MIN + 2);
2583 let _large_rat5 = Ratio::new(i32::MIN + 2, i32::MAX);
2584 let _large_rat6 = Ratio::new(i32::MAX, i32::MIN + 2);
2585 let _large_rat7 = Ratio::new(1, i32::MIN + 1);
2586 let _large_rat8 = Ratio::new(1, i32::MAX);
2587
2588 assert_eq!(_large_rat1.round(), One::one());
2589 assert_eq!(_large_rat2.round(), One::one());
2590 assert_eq!(_large_rat3.round(), One::one());
2591 assert_eq!(_large_rat4.round(), One::one());
2592 assert_eq!(_large_rat5.round(), _neg1);
2593 assert_eq!(_large_rat6.round(), _neg1);
2594 assert_eq!(_large_rat7.round(), Zero::zero());
2595 assert_eq!(_large_rat8.round(), Zero::zero());
2596 }
2597
2598 #[test]
test_fract()2599 fn test_fract() {
2600 assert_eq!(_1.fract(), _0);
2601 assert_eq!(_NEG1_2.fract(), _NEG1_2);
2602 assert_eq!(_1_2.fract(), _1_2);
2603 assert_eq!(_3_2.fract(), _1_2);
2604 }
2605
2606 #[test]
test_recip()2607 fn test_recip() {
2608 assert_eq!(_1 * _1.recip(), _1);
2609 assert_eq!(_2 * _2.recip(), _1);
2610 assert_eq!(_1_2 * _1_2.recip(), _1);
2611 assert_eq!(_3_2 * _3_2.recip(), _1);
2612 assert_eq!(_NEG1_2 * _NEG1_2.recip(), _1);
2613
2614 assert_eq!(_3_2.recip(), _2_3);
2615 assert_eq!(_NEG1_2.recip(), _NEG2);
2616 assert_eq!(_NEG1_2.recip().denom(), &1);
2617 }
2618
2619 #[test]
2620 #[should_panic(expected = "division by zero")]
test_recip_fail()2621 fn test_recip_fail() {
2622 let _a = Ratio::new(0, 1).recip();
2623 }
2624
2625 #[test]
test_pow()2626 fn test_pow() {
2627 fn test(r: Rational, e: i32, expected: Rational) {
2628 assert_eq!(r.pow(e), expected);
2629 assert_eq!(Pow::pow(r, e), expected);
2630 assert_eq!(Pow::pow(r, &e), expected);
2631 assert_eq!(Pow::pow(&r, e), expected);
2632 assert_eq!(Pow::pow(&r, &e), expected);
2633 #[cfg(feature = "num-bigint")]
2634 test_big(r, e, expected);
2635 }
2636
2637 #[cfg(feature = "num-bigint")]
2638 fn test_big(r: Rational, e: i32, expected: Rational) {
2639 let r = BigRational::new_raw(r.numer.into(), r.denom.into());
2640 let expected = BigRational::new_raw(expected.numer.into(), expected.denom.into());
2641 assert_eq!((&r).pow(e), expected);
2642 assert_eq!(Pow::pow(r.clone(), e), expected);
2643 assert_eq!(Pow::pow(r.clone(), &e), expected);
2644 assert_eq!(Pow::pow(&r, e), expected);
2645 assert_eq!(Pow::pow(&r, &e), expected);
2646 }
2647
2648 test(_1_2, 2, Ratio::new(1, 4));
2649 test(_1_2, -2, Ratio::new(4, 1));
2650 test(_1, 1, _1);
2651 test(_1, i32::MAX, _1);
2652 test(_1, i32::MIN, _1);
2653 test(_NEG1_2, 2, _1_2.pow(2i32));
2654 test(_NEG1_2, 3, -_1_2.pow(3i32));
2655 test(_3_2, 0, _1);
2656 test(_3_2, -1, _3_2.recip());
2657 test(_3_2, 3, Ratio::new(27, 8));
2658 }
2659
2660 #[test]
2661 #[cfg(feature = "std")]
test_to_from_str()2662 fn test_to_from_str() {
2663 use std::string::{String, ToString};
2664 fn test(r: Rational, s: String) {
2665 assert_eq!(FromStr::from_str(&s), Ok(r));
2666 assert_eq!(r.to_string(), s);
2667 }
2668 test(_1, "1".to_string());
2669 test(_0, "0".to_string());
2670 test(_1_2, "1/2".to_string());
2671 test(_3_2, "3/2".to_string());
2672 test(_2, "2".to_string());
2673 test(_NEG1_2, "-1/2".to_string());
2674 }
2675 #[test]
test_from_str_fail()2676 fn test_from_str_fail() {
2677 fn test(s: &str) {
2678 let rational: Result<Rational, _> = FromStr::from_str(s);
2679 assert!(rational.is_err());
2680 }
2681
2682 let xs = ["0 /1", "abc", "", "1/", "--1/2", "3/2/1", "1/0"];
2683 for &s in xs.iter() {
2684 test(s);
2685 }
2686 }
2687
2688 #[cfg(feature = "num-bigint")]
2689 #[test]
test_from_float()2690 fn test_from_float() {
2691 use num_traits::float::FloatCore;
2692 fn test<T: FloatCore>(given: T, (numer, denom): (&str, &str)) {
2693 let ratio: BigRational = Ratio::from_float(given).unwrap();
2694 assert_eq!(
2695 ratio,
2696 Ratio::new(
2697 FromStr::from_str(numer).unwrap(),
2698 FromStr::from_str(denom).unwrap()
2699 )
2700 );
2701 }
2702
2703 // f32
2704 test(core::f32::consts::PI, ("13176795", "4194304"));
2705 test(2f32.powf(100.), ("1267650600228229401496703205376", "1"));
2706 test(
2707 -(2f32.powf(100.)),
2708 ("-1267650600228229401496703205376", "1"),
2709 );
2710 test(
2711 1.0 / 2f32.powf(100.),
2712 ("1", "1267650600228229401496703205376"),
2713 );
2714 test(684729.48391f32, ("1369459", "2"));
2715 test(-8573.5918555f32, ("-4389679", "512"));
2716
2717 // f64
2718 test(
2719 core::f64::consts::PI,
2720 ("884279719003555", "281474976710656"),
2721 );
2722 test(2f64.powf(100.), ("1267650600228229401496703205376", "1"));
2723 test(
2724 -(2f64.powf(100.)),
2725 ("-1267650600228229401496703205376", "1"),
2726 );
2727 test(684729.48391f64, ("367611342500051", "536870912"));
2728 test(-8573.5918555f64, ("-4713381968463931", "549755813888"));
2729 test(
2730 1.0 / 2f64.powf(100.),
2731 ("1", "1267650600228229401496703205376"),
2732 );
2733 }
2734
2735 #[cfg(feature = "num-bigint")]
2736 #[test]
test_from_float_fail()2737 fn test_from_float_fail() {
2738 use core::{f32, f64};
2739
2740 assert_eq!(Ratio::from_float(f32::NAN), None);
2741 assert_eq!(Ratio::from_float(f32::INFINITY), None);
2742 assert_eq!(Ratio::from_float(f32::NEG_INFINITY), None);
2743 assert_eq!(Ratio::from_float(f64::NAN), None);
2744 assert_eq!(Ratio::from_float(f64::INFINITY), None);
2745 assert_eq!(Ratio::from_float(f64::NEG_INFINITY), None);
2746 }
2747
2748 #[test]
test_signed()2749 fn test_signed() {
2750 assert_eq!(_NEG1_2.abs(), _1_2);
2751 assert_eq!(_3_2.abs_sub(&_1_2), _1);
2752 assert_eq!(_1_2.abs_sub(&_3_2), Zero::zero());
2753 assert_eq!(_1_2.signum(), One::one());
2754 assert_eq!(_NEG1_2.signum(), -<Ratio<isize>>::one());
2755 assert_eq!(_0.signum(), Zero::zero());
2756 assert!(_NEG1_2.is_negative());
2757 assert!(_1_NEG2.is_negative());
2758 assert!(!_NEG1_2.is_positive());
2759 assert!(!_1_NEG2.is_positive());
2760 assert!(_1_2.is_positive());
2761 assert!(_NEG1_NEG2.is_positive());
2762 assert!(!_1_2.is_negative());
2763 assert!(!_NEG1_NEG2.is_negative());
2764 assert!(!_0.is_positive());
2765 assert!(!_0.is_negative());
2766 }
2767
2768 #[test]
2769 #[cfg(feature = "std")]
test_hash()2770 fn test_hash() {
2771 assert!(crate::hash(&_0) != crate::hash(&_1));
2772 assert!(crate::hash(&_0) != crate::hash(&_3_2));
2773
2774 // a == b -> hash(a) == hash(b)
2775 let a = Rational::new_raw(4, 2);
2776 let b = Rational::new_raw(6, 3);
2777 assert_eq!(a, b);
2778 assert_eq!(crate::hash(&a), crate::hash(&b));
2779
2780 let a = Rational::new_raw(123456789, 1000);
2781 let b = Rational::new_raw(123456789 * 5, 5000);
2782 assert_eq!(a, b);
2783 assert_eq!(crate::hash(&a), crate::hash(&b));
2784 }
2785
2786 #[test]
test_into_pair()2787 fn test_into_pair() {
2788 assert_eq!((0, 1), _0.into());
2789 assert_eq!((-2, 1), _NEG2.into());
2790 assert_eq!((1, -2), _1_NEG2.into());
2791 }
2792
2793 #[test]
test_from_pair()2794 fn test_from_pair() {
2795 assert_eq!(_0, Ratio::from((0, 1)));
2796 assert_eq!(_1, Ratio::from((1, 1)));
2797 assert_eq!(_NEG2, Ratio::from((-2, 1)));
2798 assert_eq!(_1_NEG2, Ratio::from((1, -2)));
2799 }
2800
2801 #[test]
ratio_iter_sum()2802 fn ratio_iter_sum() {
2803 // generic function to assure the iter method can be called
2804 // for any Iterator with Item = Ratio<impl Integer> or Ratio<&impl Integer>
2805 fn iter_sums<T: Integer + Clone>(slice: &[Ratio<T>]) -> [Ratio<T>; 3] {
2806 let mut manual_sum = Ratio::new(T::zero(), T::one());
2807 for ratio in slice {
2808 manual_sum = manual_sum + ratio;
2809 }
2810 [manual_sum, slice.iter().sum(), slice.iter().cloned().sum()]
2811 }
2812 // collect into array so test works on no_std
2813 let mut nums = [Ratio::new(0, 1); 1000];
2814 for (i, r) in (0..1000).map(|n| Ratio::new(n, 500)).enumerate() {
2815 nums[i] = r;
2816 }
2817 let sums = iter_sums(&nums[..]);
2818 assert_eq!(sums[0], sums[1]);
2819 assert_eq!(sums[0], sums[2]);
2820 }
2821
2822 #[test]
ratio_iter_product()2823 fn ratio_iter_product() {
2824 // generic function to assure the iter method can be called
2825 // for any Iterator with Item = Ratio<impl Integer> or Ratio<&impl Integer>
2826 fn iter_products<T: Integer + Clone>(slice: &[Ratio<T>]) -> [Ratio<T>; 3] {
2827 let mut manual_prod = Ratio::new(T::one(), T::one());
2828 for ratio in slice {
2829 manual_prod = manual_prod * ratio;
2830 }
2831 [
2832 manual_prod,
2833 slice.iter().product(),
2834 slice.iter().cloned().product(),
2835 ]
2836 }
2837
2838 // collect into array so test works on no_std
2839 let mut nums = [Ratio::new(0, 1); 1000];
2840 for (i, r) in (0..1000).map(|n| Ratio::new(n, 500)).enumerate() {
2841 nums[i] = r;
2842 }
2843 let products = iter_products(&nums[..]);
2844 assert_eq!(products[0], products[1]);
2845 assert_eq!(products[0], products[2]);
2846 }
2847
2848 #[test]
test_num_zero()2849 fn test_num_zero() {
2850 let zero = Rational64::zero();
2851 assert!(zero.is_zero());
2852
2853 let mut r = Rational64::new(123, 456);
2854 assert!(!r.is_zero());
2855 assert_eq!(r + zero, r);
2856
2857 r.set_zero();
2858 assert!(r.is_zero());
2859 }
2860
2861 #[test]
test_num_one()2862 fn test_num_one() {
2863 let one = Rational64::one();
2864 assert!(one.is_one());
2865
2866 let mut r = Rational64::new(123, 456);
2867 assert!(!r.is_one());
2868 assert_eq!(r * one, r);
2869
2870 r.set_one();
2871 assert!(r.is_one());
2872 }
2873
2874 #[test]
test_const()2875 fn test_const() {
2876 const N: Ratio<i32> = Ratio::new_raw(123, 456);
2877 const N_NUMER: &i32 = N.numer();
2878 const N_DENOM: &i32 = N.denom();
2879
2880 assert_eq!(N_NUMER, &123);
2881 assert_eq!(N_DENOM, &456);
2882
2883 let r = N.reduced();
2884 assert_eq!(r.numer(), &(123 / 3));
2885 assert_eq!(r.denom(), &(456 / 3));
2886 }
2887
2888 #[test]
test_ratio_to_i64()2889 fn test_ratio_to_i64() {
2890 assert_eq!(5, Rational64::new(70, 14).to_u64().unwrap());
2891 assert_eq!(-3, Rational64::new(-31, 8).to_i64().unwrap());
2892 assert_eq!(None, Rational64::new(-31, 8).to_u64());
2893 }
2894
2895 #[test]
2896 #[cfg(feature = "num-bigint")]
test_ratio_to_i128()2897 fn test_ratio_to_i128() {
2898 assert_eq!(
2899 1i128 << 70,
2900 Ratio::<i128>::new(1i128 << 77, 1i128 << 7)
2901 .to_i128()
2902 .unwrap()
2903 );
2904 }
2905
2906 #[test]
2907 #[cfg(feature = "num-bigint")]
test_big_ratio_to_f64()2908 fn test_big_ratio_to_f64() {
2909 assert_eq!(
2910 BigRational::new(
2911 "1234567890987654321234567890987654321234567890"
2912 .parse()
2913 .unwrap(),
2914 "3".parse().unwrap()
2915 )
2916 .to_f64(),
2917 Some(411522630329218100000000000000000000000000000f64)
2918 );
2919 assert_eq!(
2920 BigRational::new(BigInt::one(), BigInt::one() << 1050).to_f64(),
2921 Some(0f64)
2922 );
2923 assert_eq!(
2924 BigRational::from(BigInt::one() << 1050).to_f64(),
2925 Some(core::f64::INFINITY)
2926 );
2927 assert_eq!(
2928 BigRational::from((-BigInt::one()) << 1050).to_f64(),
2929 Some(core::f64::NEG_INFINITY)
2930 );
2931 assert_eq!(
2932 BigRational::new(
2933 "1234567890987654321234567890".parse().unwrap(),
2934 "987654321234567890987654321".parse().unwrap()
2935 )
2936 .to_f64(),
2937 Some(1.2499999893125f64)
2938 );
2939 assert_eq!(
2940 BigRational::new_raw(BigInt::one(), BigInt::zero()).to_f64(),
2941 Some(core::f64::INFINITY)
2942 );
2943 assert_eq!(
2944 BigRational::new_raw(-BigInt::one(), BigInt::zero()).to_f64(),
2945 Some(core::f64::NEG_INFINITY)
2946 );
2947 assert_eq!(
2948 BigRational::new_raw(BigInt::zero(), BigInt::zero()).to_f64(),
2949 None
2950 );
2951 }
2952
2953 #[test]
test_ratio_to_f64()2954 fn test_ratio_to_f64() {
2955 assert_eq!(Ratio::<u8>::new(1, 2).to_f64(), Some(0.5f64));
2956 assert_eq!(Rational64::new(1, 2).to_f64(), Some(0.5f64));
2957 assert_eq!(Rational64::new(1, -2).to_f64(), Some(-0.5f64));
2958 assert_eq!(Rational64::new(0, 2).to_f64(), Some(0.0f64));
2959 assert_eq!(Rational64::new(0, -2).to_f64(), Some(-0.0f64));
2960 assert_eq!(Rational64::new((1 << 57) + 1, 1 << 54).to_f64(), Some(8f64));
2961 assert_eq!(
2962 Rational64::new((1 << 52) + 1, 1 << 52).to_f64(),
2963 Some(1.0000000000000002f64),
2964 );
2965 assert_eq!(
2966 Rational64::new((1 << 60) + (1 << 8), 1 << 60).to_f64(),
2967 Some(1.0000000000000002f64),
2968 );
2969 assert_eq!(
2970 Ratio::<i32>::new_raw(1, 0).to_f64(),
2971 Some(core::f64::INFINITY)
2972 );
2973 assert_eq!(
2974 Ratio::<i32>::new_raw(-1, 0).to_f64(),
2975 Some(core::f64::NEG_INFINITY)
2976 );
2977 assert_eq!(Ratio::<i32>::new_raw(0, 0).to_f64(), None);
2978 }
2979 }
2980