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