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