Coverage Report

Created: 2025-12-05 07:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/num-rational-0.4.2/src/lib.rs
Line
Count
Source
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.60 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::{
42
    Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, ConstOne, ConstZero, FromPrimitive,
43
    Inv, Num, NumCast, One, Pow, Signed, ToPrimitive, Unsigned, Zero,
44
};
45
46
mod pow;
47
48
/// Represents the ratio between two numbers.
49
#[derive(Copy, Clone, Debug)]
50
#[allow(missing_docs)]
51
pub struct Ratio<T> {
52
    /// Numerator.
53
    numer: T,
54
    /// Denominator.
55
    denom: T,
56
}
57
58
/// Alias for a `Ratio` of machine-sized integers.
59
#[deprecated(
60
    since = "0.4.0",
61
    note = "it's better to use a specific size, like `Rational32` or `Rational64`"
62
)]
63
pub type Rational = Ratio<isize>;
64
/// Alias for a `Ratio` of 32-bit-sized integers.
65
pub type Rational32 = Ratio<i32>;
66
/// Alias for a `Ratio` of 64-bit-sized integers.
67
pub type Rational64 = Ratio<i64>;
68
69
#[cfg(feature = "num-bigint")]
70
/// Alias for arbitrary precision rationals.
71
pub type BigRational = Ratio<BigInt>;
72
73
/// These method are `const`.
74
impl<T> Ratio<T> {
75
    /// Creates a `Ratio` without checking for `denom == 0` or reducing.
76
    ///
77
    /// **There are several methods that will panic if used on a `Ratio` with
78
    /// `denom == 0`.**
79
    #[inline]
80
0
    pub const fn new_raw(numer: T, denom: T) -> Ratio<T> {
81
0
        Ratio { numer, denom }
82
0
    }
Unexecuted instantiation: <num_rational::Ratio<num_bigint::bigint::BigInt>>::new_raw
Unexecuted instantiation: <num_rational::Ratio<i8>>::new_raw
Unexecuted instantiation: <num_rational::Ratio<u8>>::new_raw
Unexecuted instantiation: <num_rational::Ratio<isize>>::new_raw
Unexecuted instantiation: <num_rational::Ratio<usize>>::new_raw
Unexecuted instantiation: <num_rational::Ratio<i32>>::new_raw
Unexecuted instantiation: <num_rational::Ratio<u32>>::new_raw
Unexecuted instantiation: <num_rational::Ratio<i128>>::new_raw
Unexecuted instantiation: <num_rational::Ratio<u128>>::new_raw
Unexecuted instantiation: <num_rational::Ratio<i16>>::new_raw
Unexecuted instantiation: <num_rational::Ratio<u16>>::new_raw
Unexecuted instantiation: <num_rational::Ratio<i64>>::new_raw
Unexecuted instantiation: <num_rational::Ratio<u64>>::new_raw
83
84
    /// Deconstructs a `Ratio` into its numerator and denominator.
85
    #[inline]
86
0
    pub fn into_raw(self) -> (T, T) {
87
0
        (self.numer, self.denom)
88
0
    }
89
90
    /// Gets an immutable reference to the numerator.
91
    #[inline]
92
0
    pub const fn numer(&self) -> &T {
93
0
        &self.numer
94
0
    }
Unexecuted instantiation: <num_rational::Ratio<i32>>::numer
Unexecuted instantiation: <num_rational::Ratio<i64>>::numer
Unexecuted instantiation: <num_rational::Ratio<_>>::numer
95
96
    /// Gets an immutable reference to the denominator.
97
    #[inline]
98
0
    pub const fn denom(&self) -> &T {
99
0
        &self.denom
100
0
    }
Unexecuted instantiation: <num_rational::Ratio<i32>>::denom
Unexecuted instantiation: <num_rational::Ratio<i64>>::denom
Unexecuted instantiation: <num_rational::Ratio<_>>::denom
101
}
102
103
impl<T: Clone + Integer> Ratio<T> {
104
    /// Creates a new `Ratio`.
105
    ///
106
    /// **Panics if `denom` is zero.**
107
    #[inline]
108
0
    pub fn new(numer: T, denom: T) -> Ratio<T> {
109
0
        let mut ret = Ratio::new_raw(numer, denom);
110
0
        ret.reduce();
111
0
        ret
112
0
    }
Unexecuted instantiation: <num_rational::Ratio<num_bigint::bigint::BigInt>>::new
Unexecuted instantiation: <num_rational::Ratio<i8>>::new
Unexecuted instantiation: <num_rational::Ratio<u8>>::new
Unexecuted instantiation: <num_rational::Ratio<isize>>::new
Unexecuted instantiation: <num_rational::Ratio<usize>>::new
Unexecuted instantiation: <num_rational::Ratio<i32>>::new
Unexecuted instantiation: <num_rational::Ratio<u32>>::new
Unexecuted instantiation: <num_rational::Ratio<i128>>::new
Unexecuted instantiation: <num_rational::Ratio<u128>>::new
Unexecuted instantiation: <num_rational::Ratio<i16>>::new
Unexecuted instantiation: <num_rational::Ratio<u16>>::new
Unexecuted instantiation: <num_rational::Ratio<i64>>::new
Unexecuted instantiation: <num_rational::Ratio<u64>>::new
113
114
    /// Creates a `Ratio` representing the integer `t`.
115
    #[inline]
116
0
    pub fn from_integer(t: T) -> Ratio<T> {
117
0
        Ratio::new_raw(t, One::one())
118
0
    }
Unexecuted instantiation: <num_rational::Ratio<num_bigint::bigint::BigInt>>::from_integer
Unexecuted instantiation: <num_rational::Ratio<i8>>::from_integer
Unexecuted instantiation: <num_rational::Ratio<u8>>::from_integer
Unexecuted instantiation: <num_rational::Ratio<isize>>::from_integer
Unexecuted instantiation: <num_rational::Ratio<usize>>::from_integer
Unexecuted instantiation: <num_rational::Ratio<i32>>::from_integer
Unexecuted instantiation: <num_rational::Ratio<u32>>::from_integer
Unexecuted instantiation: <num_rational::Ratio<i128>>::from_integer
Unexecuted instantiation: <num_rational::Ratio<u128>>::from_integer
Unexecuted instantiation: <num_rational::Ratio<i16>>::from_integer
Unexecuted instantiation: <num_rational::Ratio<u16>>::from_integer
Unexecuted instantiation: <num_rational::Ratio<i64>>::from_integer
Unexecuted instantiation: <num_rational::Ratio<u64>>::from_integer
119
120
    /// Converts to an integer, rounding towards zero.
121
    #[inline]
122
0
    pub fn to_integer(&self) -> T {
123
0
        self.trunc().numer
124
0
    }
125
126
    /// Returns true if the rational number is an integer (denominator is 1).
127
    #[inline]
128
0
    pub fn is_integer(&self) -> bool {
129
0
        self.denom.is_one()
130
0
    }
131
132
    /// Puts self into lowest terms, with `denom` > 0.
133
    ///
134
    /// **Panics if `denom` is zero.**
135
0
    fn reduce(&mut self) {
136
0
        if self.denom.is_zero() {
137
0
            panic!("denominator == 0");
138
0
        }
139
0
        if self.numer.is_zero() {
140
0
            self.denom.set_one();
141
0
            return;
142
0
        }
143
0
        if self.numer == self.denom {
144
0
            self.set_one();
145
0
            return;
146
0
        }
147
0
        let g: T = self.numer.gcd(&self.denom);
148
149
        // FIXME(#5992): assignment operator overloads
150
        // T: Clone + Integer != T: Clone + NumAssign
151
152
        #[inline]
153
0
        fn replace_with<T: Zero>(x: &mut T, f: impl FnOnce(T) -> T) {
154
0
            let y = core::mem::replace(x, T::zero());
155
0
            *x = f(y);
156
0
        }
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<num_bigint::bigint::BigInt, <num_rational::Ratio<num_bigint::bigint::BigInt>>::reduce::{closure#0}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<num_bigint::bigint::BigInt, <num_rational::Ratio<num_bigint::bigint::BigInt>>::reduce::{closure#2}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<num_bigint::bigint::BigInt, <num_rational::Ratio<num_bigint::bigint::BigInt>>::reduce::{closure#3}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<num_bigint::bigint::BigInt, <num_rational::Ratio<num_bigint::bigint::BigInt>>::reduce::{closure#1}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<i8, <num_rational::Ratio<i8>>::reduce::{closure#0}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<i8, <num_rational::Ratio<i8>>::reduce::{closure#2}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<i8, <num_rational::Ratio<i8>>::reduce::{closure#3}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<i8, <num_rational::Ratio<i8>>::reduce::{closure#1}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<u8, <num_rational::Ratio<u8>>::reduce::{closure#0}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<u8, <num_rational::Ratio<u8>>::reduce::{closure#2}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<u8, <num_rational::Ratio<u8>>::reduce::{closure#3}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<u8, <num_rational::Ratio<u8>>::reduce::{closure#1}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<isize, <num_rational::Ratio<isize>>::reduce::{closure#0}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<isize, <num_rational::Ratio<isize>>::reduce::{closure#2}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<isize, <num_rational::Ratio<isize>>::reduce::{closure#3}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<isize, <num_rational::Ratio<isize>>::reduce::{closure#1}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<usize, <num_rational::Ratio<usize>>::reduce::{closure#0}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<usize, <num_rational::Ratio<usize>>::reduce::{closure#2}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<usize, <num_rational::Ratio<usize>>::reduce::{closure#3}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<usize, <num_rational::Ratio<usize>>::reduce::{closure#1}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<i32, <num_rational::Ratio<i32>>::reduce::{closure#0}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<i32, <num_rational::Ratio<i32>>::reduce::{closure#2}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<i32, <num_rational::Ratio<i32>>::reduce::{closure#3}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<i32, <num_rational::Ratio<i32>>::reduce::{closure#1}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<u32, <num_rational::Ratio<u32>>::reduce::{closure#0}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<u32, <num_rational::Ratio<u32>>::reduce::{closure#2}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<u32, <num_rational::Ratio<u32>>::reduce::{closure#3}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<u32, <num_rational::Ratio<u32>>::reduce::{closure#1}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<i128, <num_rational::Ratio<i128>>::reduce::{closure#0}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<i128, <num_rational::Ratio<i128>>::reduce::{closure#2}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<i128, <num_rational::Ratio<i128>>::reduce::{closure#3}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<i128, <num_rational::Ratio<i128>>::reduce::{closure#1}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<u128, <num_rational::Ratio<u128>>::reduce::{closure#0}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<u128, <num_rational::Ratio<u128>>::reduce::{closure#2}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<u128, <num_rational::Ratio<u128>>::reduce::{closure#3}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<u128, <num_rational::Ratio<u128>>::reduce::{closure#1}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<i16, <num_rational::Ratio<i16>>::reduce::{closure#0}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<i16, <num_rational::Ratio<i16>>::reduce::{closure#2}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<i16, <num_rational::Ratio<i16>>::reduce::{closure#3}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<i16, <num_rational::Ratio<i16>>::reduce::{closure#1}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<u16, <num_rational::Ratio<u16>>::reduce::{closure#0}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<u16, <num_rational::Ratio<u16>>::reduce::{closure#2}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<u16, <num_rational::Ratio<u16>>::reduce::{closure#3}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<u16, <num_rational::Ratio<u16>>::reduce::{closure#1}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<i64, <num_rational::Ratio<i64>>::reduce::{closure#0}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<i64, <num_rational::Ratio<i64>>::reduce::{closure#2}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<i64, <num_rational::Ratio<i64>>::reduce::{closure#3}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<i64, <num_rational::Ratio<i64>>::reduce::{closure#1}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<u64, <num_rational::Ratio<u64>>::reduce::{closure#0}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<u64, <num_rational::Ratio<u64>>::reduce::{closure#2}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<u64, <num_rational::Ratio<u64>>::reduce::{closure#3}>
Unexecuted instantiation: <num_rational::Ratio<_>>::reduce::replace_with::<u64, <num_rational::Ratio<u64>>::reduce::{closure#1}>
157
158
        // self.numer /= g;
159
0
        replace_with(&mut self.numer, |x| x / g.clone());
Unexecuted instantiation: <num_rational::Ratio<num_bigint::bigint::BigInt>>::reduce::{closure#0}
Unexecuted instantiation: <num_rational::Ratio<i8>>::reduce::{closure#0}
Unexecuted instantiation: <num_rational::Ratio<u8>>::reduce::{closure#0}
Unexecuted instantiation: <num_rational::Ratio<isize>>::reduce::{closure#0}
Unexecuted instantiation: <num_rational::Ratio<usize>>::reduce::{closure#0}
Unexecuted instantiation: <num_rational::Ratio<i32>>::reduce::{closure#0}
Unexecuted instantiation: <num_rational::Ratio<u32>>::reduce::{closure#0}
Unexecuted instantiation: <num_rational::Ratio<i128>>::reduce::{closure#0}
Unexecuted instantiation: <num_rational::Ratio<u128>>::reduce::{closure#0}
Unexecuted instantiation: <num_rational::Ratio<i16>>::reduce::{closure#0}
Unexecuted instantiation: <num_rational::Ratio<u16>>::reduce::{closure#0}
Unexecuted instantiation: <num_rational::Ratio<i64>>::reduce::{closure#0}
Unexecuted instantiation: <num_rational::Ratio<u64>>::reduce::{closure#0}
160
161
        // self.denom /= g;
162
0
        replace_with(&mut self.denom, |x| x / g);
Unexecuted instantiation: <num_rational::Ratio<num_bigint::bigint::BigInt>>::reduce::{closure#1}
Unexecuted instantiation: <num_rational::Ratio<i8>>::reduce::{closure#1}
Unexecuted instantiation: <num_rational::Ratio<u8>>::reduce::{closure#1}
Unexecuted instantiation: <num_rational::Ratio<isize>>::reduce::{closure#1}
Unexecuted instantiation: <num_rational::Ratio<usize>>::reduce::{closure#1}
Unexecuted instantiation: <num_rational::Ratio<i32>>::reduce::{closure#1}
Unexecuted instantiation: <num_rational::Ratio<u32>>::reduce::{closure#1}
Unexecuted instantiation: <num_rational::Ratio<i128>>::reduce::{closure#1}
Unexecuted instantiation: <num_rational::Ratio<u128>>::reduce::{closure#1}
Unexecuted instantiation: <num_rational::Ratio<i16>>::reduce::{closure#1}
Unexecuted instantiation: <num_rational::Ratio<u16>>::reduce::{closure#1}
Unexecuted instantiation: <num_rational::Ratio<i64>>::reduce::{closure#1}
Unexecuted instantiation: <num_rational::Ratio<u64>>::reduce::{closure#1}
163
164
        // keep denom positive!
165
0
        if self.denom < T::zero() {
166
0
            replace_with(&mut self.numer, |x| T::zero() - x);
Unexecuted instantiation: <num_rational::Ratio<num_bigint::bigint::BigInt>>::reduce::{closure#2}
Unexecuted instantiation: <num_rational::Ratio<i8>>::reduce::{closure#2}
Unexecuted instantiation: <num_rational::Ratio<u8>>::reduce::{closure#2}
Unexecuted instantiation: <num_rational::Ratio<isize>>::reduce::{closure#2}
Unexecuted instantiation: <num_rational::Ratio<usize>>::reduce::{closure#2}
Unexecuted instantiation: <num_rational::Ratio<i32>>::reduce::{closure#2}
Unexecuted instantiation: <num_rational::Ratio<u32>>::reduce::{closure#2}
Unexecuted instantiation: <num_rational::Ratio<i128>>::reduce::{closure#2}
Unexecuted instantiation: <num_rational::Ratio<u128>>::reduce::{closure#2}
Unexecuted instantiation: <num_rational::Ratio<i16>>::reduce::{closure#2}
Unexecuted instantiation: <num_rational::Ratio<u16>>::reduce::{closure#2}
Unexecuted instantiation: <num_rational::Ratio<i64>>::reduce::{closure#2}
Unexecuted instantiation: <num_rational::Ratio<u64>>::reduce::{closure#2}
167
0
            replace_with(&mut self.denom, |x| T::zero() - x);
Unexecuted instantiation: <num_rational::Ratio<num_bigint::bigint::BigInt>>::reduce::{closure#3}
Unexecuted instantiation: <num_rational::Ratio<i8>>::reduce::{closure#3}
Unexecuted instantiation: <num_rational::Ratio<u8>>::reduce::{closure#3}
Unexecuted instantiation: <num_rational::Ratio<isize>>::reduce::{closure#3}
Unexecuted instantiation: <num_rational::Ratio<usize>>::reduce::{closure#3}
Unexecuted instantiation: <num_rational::Ratio<i32>>::reduce::{closure#3}
Unexecuted instantiation: <num_rational::Ratio<u32>>::reduce::{closure#3}
Unexecuted instantiation: <num_rational::Ratio<i128>>::reduce::{closure#3}
Unexecuted instantiation: <num_rational::Ratio<u128>>::reduce::{closure#3}
Unexecuted instantiation: <num_rational::Ratio<i16>>::reduce::{closure#3}
Unexecuted instantiation: <num_rational::Ratio<u16>>::reduce::{closure#3}
Unexecuted instantiation: <num_rational::Ratio<i64>>::reduce::{closure#3}
Unexecuted instantiation: <num_rational::Ratio<u64>>::reduce::{closure#3}
168
0
        }
169
0
    }
Unexecuted instantiation: <num_rational::Ratio<num_bigint::bigint::BigInt>>::reduce
Unexecuted instantiation: <num_rational::Ratio<i8>>::reduce
Unexecuted instantiation: <num_rational::Ratio<u8>>::reduce
Unexecuted instantiation: <num_rational::Ratio<isize>>::reduce
Unexecuted instantiation: <num_rational::Ratio<usize>>::reduce
Unexecuted instantiation: <num_rational::Ratio<i32>>::reduce
Unexecuted instantiation: <num_rational::Ratio<u32>>::reduce
Unexecuted instantiation: <num_rational::Ratio<i128>>::reduce
Unexecuted instantiation: <num_rational::Ratio<u128>>::reduce
Unexecuted instantiation: <num_rational::Ratio<i16>>::reduce
Unexecuted instantiation: <num_rational::Ratio<u16>>::reduce
Unexecuted instantiation: <num_rational::Ratio<i64>>::reduce
Unexecuted instantiation: <num_rational::Ratio<u64>>::reduce
170
171
    /// Returns a reduced copy of self.
172
    ///
173
    /// In general, it is not necessary to use this method, as the only
174
    /// method of procuring a non-reduced fraction is through `new_raw`.
175
    ///
176
    /// **Panics if `denom` is zero.**
177
0
    pub fn reduced(&self) -> Ratio<T> {
178
0
        let mut ret = self.clone();
179
0
        ret.reduce();
180
0
        ret
181
0
    }
182
183
    /// Returns the reciprocal.
184
    ///
185
    /// **Panics if the `Ratio` is zero.**
186
    #[inline]
187
0
    pub fn recip(&self) -> Ratio<T> {
188
0
        self.clone().into_recip()
189
0
    }
190
191
    #[inline]
192
0
    fn into_recip(self) -> Ratio<T> {
193
0
        match self.numer.cmp(&T::zero()) {
194
0
            cmp::Ordering::Equal => panic!("division by zero"),
195
0
            cmp::Ordering::Greater => Ratio::new_raw(self.denom, self.numer),
196
0
            cmp::Ordering::Less => Ratio::new_raw(T::zero() - self.denom, T::zero() - self.numer),
197
        }
198
0
    }
199
200
    /// Rounds towards minus infinity.
201
    #[inline]
202
0
    pub fn floor(&self) -> Ratio<T> {
203
0
        if *self < Zero::zero() {
204
0
            let one: T = One::one();
205
0
            Ratio::from_integer(
206
0
                (self.numer.clone() - self.denom.clone() + one) / self.denom.clone(),
207
            )
208
        } else {
209
0
            Ratio::from_integer(self.numer.clone() / self.denom.clone())
210
        }
211
0
    }
212
213
    /// Rounds towards plus infinity.
214
    #[inline]
215
0
    pub fn ceil(&self) -> Ratio<T> {
216
0
        if *self < Zero::zero() {
217
0
            Ratio::from_integer(self.numer.clone() / self.denom.clone())
218
        } else {
219
0
            let one: T = One::one();
220
0
            Ratio::from_integer(
221
0
                (self.numer.clone() + self.denom.clone() - one) / self.denom.clone(),
222
            )
223
        }
224
0
    }
225
226
    /// Rounds to the nearest integer. Rounds half-way cases away from zero.
227
    #[inline]
228
0
    pub fn round(&self) -> Ratio<T> {
229
0
        let zero: Ratio<T> = Zero::zero();
230
0
        let one: T = One::one();
231
0
        let two: T = one.clone() + one.clone();
232
233
        // Find unsigned fractional part of rational number
234
0
        let mut fractional = self.fract();
235
0
        if fractional < zero {
236
0
            fractional = zero - fractional
237
0
        };
238
239
        // The algorithm compares the unsigned fractional part with 1/2, that
240
        // is, a/b >= 1/2, or a >= b/2. For odd denominators, we use
241
        // a >= (b/2)+1. This avoids overflow issues.
242
0
        let half_or_larger = if fractional.denom.is_even() {
243
0
            fractional.numer >= fractional.denom / two
244
        } else {
245
0
            fractional.numer >= (fractional.denom / two) + one
246
        };
247
248
0
        if half_or_larger {
249
0
            let one: Ratio<T> = One::one();
250
0
            if *self >= Zero::zero() {
251
0
                self.trunc() + one
252
            } else {
253
0
                self.trunc() - one
254
            }
255
        } else {
256
0
            self.trunc()
257
        }
258
0
    }
259
260
    /// Rounds towards zero.
261
    #[inline]
262
0
    pub fn trunc(&self) -> Ratio<T> {
263
0
        Ratio::from_integer(self.numer.clone() / self.denom.clone())
264
0
    }
265
266
    /// Returns the fractional part of a number, with division rounded towards zero.
267
    ///
268
    /// Satisfies `self == self.trunc() + self.fract()`.
269
    #[inline]
270
0
    pub fn fract(&self) -> Ratio<T> {
271
0
        Ratio::new_raw(self.numer.clone() % self.denom.clone(), self.denom.clone())
272
0
    }
273
274
    /// Raises the `Ratio` to the power of an exponent.
275
    #[inline]
276
0
    pub fn pow(&self, expon: i32) -> Ratio<T>
277
0
    where
278
0
        for<'a> &'a T: Pow<u32, Output = T>,
279
    {
280
0
        Pow::pow(self, expon)
281
0
    }
282
}
283
284
#[cfg(feature = "num-bigint")]
285
impl Ratio<BigInt> {
286
    /// Converts a float into a rational number.
287
0
    pub fn from_float<T: FloatCore>(f: T) -> Option<BigRational> {
288
0
        if !f.is_finite() {
289
0
            return None;
290
0
        }
291
0
        let (mantissa, exponent, sign) = f.integer_decode();
292
0
        let bigint_sign = if sign == 1 { Sign::Plus } else { Sign::Minus };
293
0
        if exponent < 0 {
294
0
            let one: BigInt = One::one();
295
0
            let denom: BigInt = one << ((-exponent) as usize);
296
0
            let numer: BigUint = FromPrimitive::from_u64(mantissa).unwrap();
297
0
            Some(Ratio::new(BigInt::from_biguint(bigint_sign, numer), denom))
298
        } else {
299
0
            let mut numer: BigUint = FromPrimitive::from_u64(mantissa).unwrap();
300
0
            numer <<= exponent as usize;
301
0
            Some(Ratio::from_integer(BigInt::from_biguint(
302
0
                bigint_sign,
303
0
                numer,
304
0
            )))
305
        }
306
0
    }
Unexecuted instantiation: <num_rational::Ratio<num_bigint::bigint::BigInt>>::from_float::<f64>
Unexecuted instantiation: <num_rational::Ratio<num_bigint::bigint::BigInt>>::from_float::<f32>
307
}
308
309
impl<T: Clone + Integer> Default for Ratio<T> {
310
    /// Returns zero
311
0
    fn default() -> Self {
312
0
        Ratio::zero()
313
0
    }
314
}
315
316
// From integer
317
impl<T> From<T> for Ratio<T>
318
where
319
    T: Clone + Integer,
320
{
321
0
    fn from(x: T) -> Ratio<T> {
322
0
        Ratio::from_integer(x)
323
0
    }
324
}
325
326
// From pair (through the `new` constructor)
327
impl<T> From<(T, T)> for Ratio<T>
328
where
329
    T: Clone + Integer,
330
{
331
0
    fn from(pair: (T, T)) -> Ratio<T> {
332
0
        Ratio::new(pair.0, pair.1)
333
0
    }
334
}
335
336
// Comparisons
337
338
// Mathematically, comparing a/b and c/d is the same as comparing a*d and b*c, but it's very easy
339
// for those multiplications to overflow fixed-size integers, so we need to take care.
340
341
impl<T: Clone + Integer> Ord for Ratio<T> {
342
    #[inline]
343
0
    fn cmp(&self, other: &Self) -> cmp::Ordering {
344
        // With equal denominators, the numerators can be directly compared
345
0
        if self.denom == other.denom {
346
0
            let ord = self.numer.cmp(&other.numer);
347
0
            return if self.denom < T::zero() {
348
0
                ord.reverse()
349
            } else {
350
0
                ord
351
            };
352
0
        }
353
354
        // With equal numerators, the denominators can be inversely compared
355
0
        if self.numer == other.numer {
356
0
            if self.numer.is_zero() {
357
0
                return cmp::Ordering::Equal;
358
0
            }
359
0
            let ord = self.denom.cmp(&other.denom);
360
0
            return if self.numer < T::zero() {
361
0
                ord
362
            } else {
363
0
                ord.reverse()
364
            };
365
0
        }
366
367
        // Unfortunately, we don't have CheckedMul to try.  That could sometimes avoid all the
368
        // division below, or even always avoid it for BigInt and BigUint.
369
        // FIXME- future breaking change to add Checked* to Integer?
370
371
        // Compare as floored integers and remainders
372
0
        let (self_int, self_rem) = self.numer.div_mod_floor(&self.denom);
373
0
        let (other_int, other_rem) = other.numer.div_mod_floor(&other.denom);
374
0
        match self_int.cmp(&other_int) {
375
0
            cmp::Ordering::Greater => cmp::Ordering::Greater,
376
0
            cmp::Ordering::Less => cmp::Ordering::Less,
377
            cmp::Ordering::Equal => {
378
0
                match (self_rem.is_zero(), other_rem.is_zero()) {
379
0
                    (true, true) => cmp::Ordering::Equal,
380
0
                    (true, false) => cmp::Ordering::Less,
381
0
                    (false, true) => cmp::Ordering::Greater,
382
                    (false, false) => {
383
                        // Compare the reciprocals of the remaining fractions in reverse
384
0
                        let self_recip = Ratio::new_raw(self.denom.clone(), self_rem);
385
0
                        let other_recip = Ratio::new_raw(other.denom.clone(), other_rem);
386
0
                        self_recip.cmp(&other_recip).reverse()
387
                    }
388
                }
389
            }
390
        }
391
0
    }
392
}
393
394
impl<T: Clone + Integer> PartialOrd for Ratio<T> {
395
    #[inline]
396
0
    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
397
0
        Some(self.cmp(other))
398
0
    }
399
}
400
401
impl<T: Clone + Integer> PartialEq for Ratio<T> {
402
    #[inline]
403
0
    fn eq(&self, other: &Self) -> bool {
404
0
        self.cmp(other) == cmp::Ordering::Equal
405
0
    }
406
}
407
408
impl<T: Clone + Integer> Eq for Ratio<T> {}
409
410
// NB: We can't just `#[derive(Hash)]`, because it needs to agree
411
// with `Eq` even for non-reduced ratios.
412
impl<T: Clone + Integer + Hash> Hash for Ratio<T> {
413
0
    fn hash<H: Hasher>(&self, state: &mut H) {
414
0
        recurse(&self.numer, &self.denom, state);
415
416
0
        fn recurse<T: Integer + Hash, H: Hasher>(numer: &T, denom: &T, state: &mut H) {
417
0
            if !denom.is_zero() {
418
0
                let (int, rem) = numer.div_mod_floor(denom);
419
0
                int.hash(state);
420
0
                recurse(denom, &rem, state);
421
0
            } else {
422
0
                denom.hash(state);
423
0
            }
424
0
        }
425
0
    }
426
}
427
428
mod 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
0
        fn sum<I>(iter: I) -> Self
436
0
        where
437
0
            I: Iterator<Item = Ratio<T>>,
438
        {
439
0
            iter.fold(Self::zero(), |sum, num| sum + num)
440
0
        }
441
    }
442
443
    impl<'a, T: Integer + Clone> Sum<&'a Ratio<T>> for Ratio<T> {
444
0
        fn sum<I>(iter: I) -> Self
445
0
        where
446
0
            I: Iterator<Item = &'a Ratio<T>>,
447
        {
448
0
            iter.fold(Self::zero(), |sum, num| sum + num)
449
0
        }
450
    }
451
452
    impl<T: Integer + Clone> Product for Ratio<T> {
453
0
        fn product<I>(iter: I) -> Self
454
0
        where
455
0
            I: Iterator<Item = Ratio<T>>,
456
        {
457
0
            iter.fold(Self::one(), |prod, num| prod * num)
458
0
        }
459
    }
460
461
    impl<'a, T: Integer + Clone> Product<&'a Ratio<T>> for Ratio<T> {
462
0
        fn product<I>(iter: I) -> Self
463
0
        where
464
0
            I: Iterator<Item = &'a Ratio<T>>,
465
        {
466
0
            iter.fold(Self::one(), |prod, num| prod * num)
467
0
        }
468
    }
469
}
470
471
mod 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
0
        fn add_assign(&mut self, other: Ratio<T>) {
480
0
            if self.denom == other.denom {
481
0
                self.numer += other.numer
482
0
            } else {
483
0
                let lcm = self.denom.lcm(&other.denom);
484
0
                let lhs_numer = self.numer.clone() * (lcm.clone() / self.denom.clone());
485
0
                let rhs_numer = other.numer * (lcm.clone() / other.denom);
486
0
                self.numer = lhs_numer + rhs_numer;
487
0
                self.denom = lcm;
488
0
            }
489
0
            self.reduce();
490
0
        }
491
    }
492
493
    // (a/b) / (c/d) = (a/gcd_ac)*(d/gcd_bd) / ((c/gcd_ac)*(b/gcd_bd))
494
    impl<T: Clone + Integer + NumAssign> DivAssign for Ratio<T> {
495
0
        fn div_assign(&mut self, other: Ratio<T>) {
496
0
            let gcd_ac = self.numer.gcd(&other.numer);
497
0
            let gcd_bd = self.denom.gcd(&other.denom);
498
0
            self.numer /= gcd_ac.clone();
499
0
            self.numer *= other.denom / gcd_bd.clone();
500
0
            self.denom /= gcd_bd;
501
0
            self.denom *= other.numer / gcd_ac;
502
0
            self.reduce(); // TODO: remove this line. see #8.
503
0
        }
504
    }
505
506
    // a/b * c/d = (a/gcd_ad)*(c/gcd_bc) / ((d/gcd_ad)*(b/gcd_bc))
507
    impl<T: Clone + Integer + NumAssign> MulAssign for Ratio<T> {
508
0
        fn mul_assign(&mut self, other: Ratio<T>) {
509
0
            let gcd_ad = self.numer.gcd(&other.denom);
510
0
            let gcd_bc = self.denom.gcd(&other.numer);
511
0
            self.numer /= gcd_ad.clone();
512
0
            self.numer *= other.numer / gcd_bc.clone();
513
0
            self.denom /= gcd_bc;
514
0
            self.denom *= other.denom / gcd_ad;
515
0
            self.reduce(); // TODO: remove this line. see #8.
516
0
        }
517
    }
518
519
    impl<T: Clone + Integer + NumAssign> RemAssign for Ratio<T> {
520
0
        fn rem_assign(&mut self, other: Ratio<T>) {
521
0
            if self.denom == other.denom {
522
0
                self.numer %= other.numer
523
0
            } else {
524
0
                let lcm = self.denom.lcm(&other.denom);
525
0
                let lhs_numer = self.numer.clone() * (lcm.clone() / self.denom.clone());
526
0
                let rhs_numer = other.numer * (lcm.clone() / other.denom);
527
0
                self.numer = lhs_numer % rhs_numer;
528
0
                self.denom = lcm;
529
0
            }
530
0
            self.reduce();
531
0
        }
532
    }
533
534
    impl<T: Clone + Integer + NumAssign> SubAssign for Ratio<T> {
535
0
        fn sub_assign(&mut self, other: Ratio<T>) {
536
0
            if self.denom == other.denom {
537
0
                self.numer -= other.numer
538
0
            } else {
539
0
                let lcm = self.denom.lcm(&other.denom);
540
0
                let lhs_numer = self.numer.clone() * (lcm.clone() / self.denom.clone());
541
0
                let rhs_numer = other.numer * (lcm.clone() / other.denom);
542
0
                self.numer = lhs_numer - rhs_numer;
543
0
                self.denom = lcm;
544
0
            }
545
0
            self.reduce();
546
0
        }
547
    }
548
549
    // a/b + c/1 = (a*1 + b*c) / (b*1) = (a + b*c) / b
550
    impl<T: Clone + Integer + NumAssign> AddAssign<T> for Ratio<T> {
551
0
        fn add_assign(&mut self, other: T) {
552
0
            self.numer += self.denom.clone() * other;
553
0
            self.reduce();
554
0
        }
555
    }
556
557
    impl<T: Clone + Integer + NumAssign> DivAssign<T> for Ratio<T> {
558
0
        fn div_assign(&mut self, other: T) {
559
0
            let gcd = self.numer.gcd(&other);
560
0
            self.numer /= gcd.clone();
561
0
            self.denom *= other / gcd;
562
0
            self.reduce(); // TODO: remove this line. see #8.
563
0
        }
564
    }
565
566
    impl<T: Clone + Integer + NumAssign> MulAssign<T> for Ratio<T> {
567
0
        fn mul_assign(&mut self, other: T) {
568
0
            let gcd = self.denom.gcd(&other);
569
0
            self.denom /= gcd.clone();
570
0
            self.numer *= other / gcd;
571
0
            self.reduce(); // TODO: remove this line. see #8.
572
0
        }
573
    }
574
575
    // a/b % c/1 = (a*1 % b*c) / (b*1) = (a % b*c) / b
576
    impl<T: Clone + Integer + NumAssign> RemAssign<T> for Ratio<T> {
577
0
        fn rem_assign(&mut self, other: T) {
578
0
            self.numer %= self.denom.clone() * other;
579
0
            self.reduce();
580
0
        }
581
    }
582
583
    // a/b - c/1 = (a*1 - b*c) / (b*1) = (a - b*c) / b
584
    impl<T: Clone + Integer + NumAssign> SubAssign<T> for Ratio<T> {
585
0
        fn sub_assign(&mut self, other: T) {
586
0
            self.numer -= self.denom.clone() * other;
587
0
            self.reduce();
588
0
        }
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
0
                fn $method(&mut self, other: &Ratio<T>) {
596
0
                    self.$method(other.clone())
597
0
                }
Unexecuted instantiation: <num_rational::Ratio<_> as core::ops::arith::AddAssign<&num_rational::Ratio<_>>>::add_assign
Unexecuted instantiation: <num_rational::Ratio<_> as core::ops::arith::DivAssign<&num_rational::Ratio<_>>>::div_assign
Unexecuted instantiation: <num_rational::Ratio<_> as core::ops::arith::MulAssign<&num_rational::Ratio<_>>>::mul_assign
Unexecuted instantiation: <num_rational::Ratio<_> as core::ops::arith::RemAssign<&num_rational::Ratio<_>>>::rem_assign
Unexecuted instantiation: <num_rational::Ratio<_> as core::ops::arith::SubAssign<&num_rational::Ratio<_>>>::sub_assign
598
            }
599
            impl<'a, T: Clone + Integer + NumAssign> $imp<&'a T> for Ratio<T> {
600
                #[inline]
601
0
                fn $method(&mut self, other: &T) {
602
0
                    self.$method(other.clone())
603
0
                }
Unexecuted instantiation: <num_rational::Ratio<_> as core::ops::arith::AddAssign<&_>>::add_assign
Unexecuted instantiation: <num_rational::Ratio<_> as core::ops::arith::DivAssign<&_>>::div_assign
Unexecuted instantiation: <num_rational::Ratio<_> as core::ops::arith::MulAssign<&_>>::mul_assign
Unexecuted instantiation: <num_rational::Ratio<_> as core::ops::arith::RemAssign<&_>>::rem_assign
Unexecuted instantiation: <num_rational::Ratio<_> as core::ops::arith::SubAssign<&_>>::sub_assign
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
615
macro_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
0
            fn $method(self, other: &'b Ratio<T>) -> Ratio<T> {
622
0
                self.clone().$method(other.clone())
623
0
            }
Unexecuted instantiation: <&num_rational::Ratio<_> as core::ops::arith::Sub>::sub
Unexecuted instantiation: <&num_rational::Ratio<_> as core::ops::arith::Rem>::rem
Unexecuted instantiation: <&num_rational::Ratio<_> as core::ops::arith::Mul>::mul
Unexecuted instantiation: <&num_rational::Ratio<_> as core::ops::arith::Div>::div
Unexecuted instantiation: <&num_rational::Ratio<_> as core::ops::arith::Add>::add
624
        }
625
        impl<'a, 'b, T: Clone + Integer> $imp<&'b T> for &'a Ratio<T> {
626
            type Output = Ratio<T>;
627
628
            #[inline]
629
0
            fn $method(self, other: &'b T) -> Ratio<T> {
630
0
                self.clone().$method(other.clone())
631
0
            }
Unexecuted instantiation: <&num_rational::Ratio<_> as core::ops::arith::Sub<&_>>::sub
Unexecuted instantiation: <&num_rational::Ratio<_> as core::ops::arith::Rem<&_>>::rem
Unexecuted instantiation: <&num_rational::Ratio<_> as core::ops::arith::Mul<&_>>::mul
Unexecuted instantiation: <&num_rational::Ratio<_> as core::ops::arith::Div<&_>>::div
Unexecuted instantiation: <&num_rational::Ratio<_> as core::ops::arith::Add<&_>>::add
632
        }
633
    };
634
}
635
636
macro_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
0
            fn $method(self, other: Ratio<T>) -> Ratio<T> {
646
0
                self.clone().$method(other)
647
0
            }
Unexecuted instantiation: <&num_rational::Ratio<_> as core::ops::arith::Sub<num_rational::Ratio<_>>>::sub
Unexecuted instantiation: <&num_rational::Ratio<_> as core::ops::arith::Rem<num_rational::Ratio<_>>>::rem
Unexecuted instantiation: <&num_rational::Ratio<_> as core::ops::arith::Mul<num_rational::Ratio<_>>>::mul
Unexecuted instantiation: <&num_rational::Ratio<_> as core::ops::arith::Div<num_rational::Ratio<_>>>::div
Unexecuted instantiation: <&num_rational::Ratio<_> as core::ops::arith::Add<num_rational::Ratio<_>>>::add
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
0
            fn $method(self, other: T) -> Ratio<T> {
657
0
                self.clone().$method(other)
658
0
            }
Unexecuted instantiation: <&num_rational::Ratio<_> as core::ops::arith::Sub<_>>::sub
Unexecuted instantiation: <&num_rational::Ratio<_> as core::ops::arith::Rem<_>>::rem
Unexecuted instantiation: <&num_rational::Ratio<_> as core::ops::arith::Mul<_>>::mul
Unexecuted instantiation: <&num_rational::Ratio<_> as core::ops::arith::Div<_>>::div
Unexecuted instantiation: <&num_rational::Ratio<_> as core::ops::arith::Add<_>>::add
659
        }
660
    };
661
}
662
663
macro_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
0
            fn $method(self, other: &Ratio<T>) -> Ratio<T> {
673
0
                self.$method(other.clone())
674
0
            }
Unexecuted instantiation: <num_rational::Ratio<_> as core::ops::arith::Sub<&num_rational::Ratio<_>>>::sub
Unexecuted instantiation: <num_rational::Ratio<_> as core::ops::arith::Rem<&num_rational::Ratio<_>>>::rem
Unexecuted instantiation: <num_rational::Ratio<_> as core::ops::arith::Mul<&num_rational::Ratio<_>>>::mul
Unexecuted instantiation: <num_rational::Ratio<_> as core::ops::arith::Div<&num_rational::Ratio<_>>>::div
Unexecuted instantiation: <num_rational::Ratio<_> as core::ops::arith::Add<&num_rational::Ratio<_>>>::add
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
0
            fn $method(self, other: &T) -> Ratio<T> {
684
0
                self.$method(other.clone())
685
0
            }
Unexecuted instantiation: <num_rational::Ratio<_> as core::ops::arith::Sub<&_>>::sub
Unexecuted instantiation: <num_rational::Ratio<_> as core::ops::arith::Rem<&_>>::rem
Unexecuted instantiation: <num_rational::Ratio<_> as core::ops::arith::Mul<&_>>::mul
Unexecuted instantiation: <num_rational::Ratio<_> as core::ops::arith::Div<&_>>::div
Unexecuted instantiation: <num_rational::Ratio<_> as core::ops::arith::Add<&_>>::add
686
        }
687
    };
688
}
689
690
macro_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
698
// Arithmetic
699
forward_all_binop!(impl Mul, mul);
700
// a/b * c/d = (a/gcd_ad)*(c/gcd_bc) / ((d/gcd_ad)*(b/gcd_bc))
701
impl<T> Mul<Ratio<T>> for Ratio<T>
702
where
703
    T: Clone + Integer,
704
{
705
    type Output = Ratio<T>;
706
    #[inline]
707
0
    fn mul(self, rhs: Ratio<T>) -> Ratio<T> {
708
0
        let gcd_ad = self.numer.gcd(&rhs.denom);
709
0
        let gcd_bc = self.denom.gcd(&rhs.numer);
710
0
        Ratio::new(
711
0
            self.numer / gcd_ad.clone() * (rhs.numer / gcd_bc.clone()),
712
0
            self.denom / gcd_bc * (rhs.denom / gcd_ad),
713
        )
714
0
    }
715
}
716
// a/b * c/1 = (a*c) / (b*1) = (a*c) / b
717
impl<T> Mul<T> for Ratio<T>
718
where
719
    T: Clone + Integer,
720
{
721
    type Output = Ratio<T>;
722
    #[inline]
723
0
    fn mul(self, rhs: T) -> Ratio<T> {
724
0
        let gcd = self.denom.gcd(&rhs);
725
0
        Ratio::new(self.numer * (rhs / gcd.clone()), self.denom / gcd)
726
0
    }
727
}
728
729
forward_all_binop!(impl Div, div);
730
// (a/b) / (c/d) = (a/gcd_ac)*(d/gcd_bd) / ((c/gcd_ac)*(b/gcd_bd))
731
impl<T> Div<Ratio<T>> for Ratio<T>
732
where
733
    T: Clone + Integer,
734
{
735
    type Output = Ratio<T>;
736
737
    #[inline]
738
0
    fn div(self, rhs: Ratio<T>) -> Ratio<T> {
739
0
        let gcd_ac = self.numer.gcd(&rhs.numer);
740
0
        let gcd_bd = self.denom.gcd(&rhs.denom);
741
0
        Ratio::new(
742
0
            self.numer / gcd_ac.clone() * (rhs.denom / gcd_bd.clone()),
743
0
            self.denom / gcd_bd * (rhs.numer / gcd_ac),
744
        )
745
0
    }
746
}
747
// (a/b) / (c/1) = (a*1) / (b*c) = a / (b*c)
748
impl<T> Div<T> for Ratio<T>
749
where
750
    T: Clone + Integer,
751
{
752
    type Output = Ratio<T>;
753
754
    #[inline]
755
0
    fn div(self, rhs: T) -> Ratio<T> {
756
0
        let gcd = self.numer.gcd(&rhs);
757
0
        Ratio::new(self.numer / gcd.clone(), self.denom * (rhs / gcd))
758
0
    }
759
}
760
761
macro_rules! arith_impl {
762
    (impl $imp:ident, $method:ident) => {
763
        forward_all_binop!(impl $imp, $method);
764
        // Abstracts a/b `op` c/d = (a*lcm/b `op` c*lcm/d)/lcm where lcm = lcm(b,d)
765
        impl<T: Clone + Integer> $imp<Ratio<T>> for Ratio<T> {
766
            type Output = Ratio<T>;
767
            #[inline]
768
0
            fn $method(self, rhs: Ratio<T>) -> Ratio<T> {
769
0
                if self.denom == rhs.denom {
770
0
                    return Ratio::new(self.numer.$method(rhs.numer), rhs.denom);
771
0
                }
772
0
                let lcm = self.denom.lcm(&rhs.denom);
773
0
                let lhs_numer = self.numer * (lcm.clone() / self.denom);
774
0
                let rhs_numer = rhs.numer * (lcm.clone() / rhs.denom);
775
0
                Ratio::new(lhs_numer.$method(rhs_numer), lcm)
776
0
            }
Unexecuted instantiation: <num_rational::Ratio<_> as core::ops::arith::Rem>::rem
Unexecuted instantiation: <num_rational::Ratio<_> as core::ops::arith::Add>::add
Unexecuted instantiation: <num_rational::Ratio<_> as core::ops::arith::Sub>::sub
777
        }
778
        // Abstracts the a/b `op` c/1 = (a*1 `op` b*c) / (b*1) = (a `op` b*c) / b pattern
779
        impl<T: Clone + Integer> $imp<T> for Ratio<T> {
780
            type Output = Ratio<T>;
781
            #[inline]
782
0
            fn $method(self, rhs: T) -> Ratio<T> {
783
0
                Ratio::new(self.numer.$method(self.denom.clone() * rhs), self.denom)
784
0
            }
Unexecuted instantiation: <num_rational::Ratio<_> as core::ops::arith::Sub<_>>::sub
Unexecuted instantiation: <num_rational::Ratio<_> as core::ops::arith::Rem<_>>::rem
Unexecuted instantiation: <num_rational::Ratio<_> as core::ops::arith::Add<_>>::add
785
        }
786
    };
787
}
788
789
arith_impl!(impl Add, add);
790
arith_impl!(impl Sub, sub);
791
arith_impl!(impl Rem, rem);
792
793
// a/b * c/d = (a*c)/(b*d)
794
impl<T> CheckedMul for Ratio<T>
795
where
796
    T: Clone + Integer + CheckedMul,
797
{
798
    #[inline]
799
0
    fn checked_mul(&self, rhs: &Ratio<T>) -> Option<Ratio<T>> {
800
0
        let gcd_ad = self.numer.gcd(&rhs.denom);
801
0
        let gcd_bc = self.denom.gcd(&rhs.numer);
802
0
        Some(Ratio::new(
803
0
            (self.numer.clone() / gcd_ad.clone())
804
0
                .checked_mul(&(rhs.numer.clone() / gcd_bc.clone()))?,
805
0
            (self.denom.clone() / gcd_bc).checked_mul(&(rhs.denom.clone() / gcd_ad))?,
806
        ))
807
0
    }
808
}
809
810
// (a/b) / (c/d) = (a*d)/(b*c)
811
impl<T> CheckedDiv for Ratio<T>
812
where
813
    T: Clone + Integer + CheckedMul,
814
{
815
    #[inline]
816
0
    fn checked_div(&self, rhs: &Ratio<T>) -> Option<Ratio<T>> {
817
0
        if rhs.is_zero() {
818
0
            return None;
819
0
        }
820
0
        let (numer, denom) = if self.denom == rhs.denom {
821
0
            (self.numer.clone(), rhs.numer.clone())
822
0
        } else if self.numer == rhs.numer {
823
0
            (rhs.denom.clone(), self.denom.clone())
824
        } else {
825
0
            let gcd_ac = self.numer.gcd(&rhs.numer);
826
0
            let gcd_bd = self.denom.gcd(&rhs.denom);
827
            (
828
0
                (self.numer.clone() / gcd_ac.clone())
829
0
                    .checked_mul(&(rhs.denom.clone() / gcd_bd.clone()))?,
830
0
                (self.denom.clone() / gcd_bd).checked_mul(&(rhs.numer.clone() / gcd_ac))?,
831
            )
832
        };
833
        // Manual `reduce()`, avoiding sharp edges
834
0
        if denom.is_zero() {
835
0
            None
836
0
        } else if numer.is_zero() {
837
0
            Some(Self::zero())
838
0
        } else if numer == denom {
839
0
            Some(Self::one())
840
        } else {
841
0
            let g = numer.gcd(&denom);
842
0
            let numer = numer / g.clone();
843
0
            let denom = denom / g;
844
0
            let raw = if denom < T::zero() {
845
                // We need to keep denom positive, but 2's-complement MIN may
846
                // overflow negation -- instead we can check multiplying -1.
847
0
                let n1 = T::zero() - T::one();
848
0
                Ratio::new_raw(numer.checked_mul(&n1)?, denom.checked_mul(&n1)?)
849
            } else {
850
0
                Ratio::new_raw(numer, denom)
851
            };
852
0
            Some(raw)
853
        }
854
0
    }
855
}
856
857
// As arith_impl! but for Checked{Add,Sub} traits
858
macro_rules! checked_arith_impl {
859
    (impl $imp:ident, $method:ident) => {
860
        impl<T: Clone + Integer + CheckedMul + $imp> $imp for Ratio<T> {
861
            #[inline]
862
0
            fn $method(&self, rhs: &Ratio<T>) -> Option<Ratio<T>> {
863
0
                let gcd = self.denom.clone().gcd(&rhs.denom);
864
0
                let lcm = (self.denom.clone() / gcd.clone()).checked_mul(&rhs.denom)?;
865
0
                let lhs_numer = (lcm.clone() / self.denom.clone()).checked_mul(&self.numer)?;
866
0
                let rhs_numer = (lcm.clone() / rhs.denom.clone()).checked_mul(&rhs.numer)?;
867
0
                Some(Ratio::new(lhs_numer.$method(&rhs_numer)?, lcm))
868
0
            }
Unexecuted instantiation: <num_rational::Ratio<_> as num_traits::ops::checked::CheckedAdd>::checked_add
Unexecuted instantiation: <num_rational::Ratio<_> as num_traits::ops::checked::CheckedSub>::checked_sub
869
        }
870
    };
871
}
872
873
// a/b + c/d = (lcm/b*a + lcm/d*c)/lcm, where lcm = lcm(b,d)
874
checked_arith_impl!(impl CheckedAdd, checked_add);
875
876
// a/b - c/d = (lcm/b*a - lcm/d*c)/lcm, where lcm = lcm(b,d)
877
checked_arith_impl!(impl CheckedSub, checked_sub);
878
879
impl<T> Neg for Ratio<T>
880
where
881
    T: Clone + Integer + Neg<Output = T>,
882
{
883
    type Output = Ratio<T>;
884
885
    #[inline]
886
0
    fn neg(self) -> Ratio<T> {
887
0
        Ratio::new_raw(-self.numer, self.denom)
888
0
    }
Unexecuted instantiation: <num_rational::Ratio<i8> as core::ops::arith::Neg>::neg
Unexecuted instantiation: <num_rational::Ratio<isize> as core::ops::arith::Neg>::neg
Unexecuted instantiation: <num_rational::Ratio<i32> as core::ops::arith::Neg>::neg
Unexecuted instantiation: <num_rational::Ratio<i128> as core::ops::arith::Neg>::neg
Unexecuted instantiation: <num_rational::Ratio<i16> as core::ops::arith::Neg>::neg
Unexecuted instantiation: <num_rational::Ratio<i64> as core::ops::arith::Neg>::neg
889
}
890
891
impl<'a, T> Neg for &'a Ratio<T>
892
where
893
    T: Clone + Integer + Neg<Output = T>,
894
{
895
    type Output = Ratio<T>;
896
897
    #[inline]
898
0
    fn neg(self) -> Ratio<T> {
899
0
        -self.clone()
900
0
    }
901
}
902
903
impl<T> Inv for Ratio<T>
904
where
905
    T: Clone + Integer,
906
{
907
    type Output = Ratio<T>;
908
909
    #[inline]
910
0
    fn inv(self) -> Ratio<T> {
911
0
        self.recip()
912
0
    }
913
}
914
915
impl<'a, T> Inv for &'a Ratio<T>
916
where
917
    T: Clone + Integer,
918
{
919
    type Output = Ratio<T>;
920
921
    #[inline]
922
0
    fn inv(self) -> Ratio<T> {
923
0
        self.recip()
924
0
    }
925
}
926
927
// Constants
928
impl<T: ConstZero + ConstOne> Ratio<T> {
929
    /// A constant `Ratio` 0/1.
930
    pub const ZERO: Self = Self::new_raw(T::ZERO, T::ONE);
931
}
932
933
impl<T: Clone + Integer + ConstZero + ConstOne> ConstZero for Ratio<T> {
934
    const ZERO: Self = Self::ZERO;
935
}
936
937
impl<T: Clone + Integer> Zero for Ratio<T> {
938
    #[inline]
939
0
    fn zero() -> Ratio<T> {
940
0
        Ratio::new_raw(Zero::zero(), One::one())
941
0
    }
942
943
    #[inline]
944
0
    fn is_zero(&self) -> bool {
945
0
        self.numer.is_zero()
946
0
    }
947
948
    #[inline]
949
0
    fn set_zero(&mut self) {
950
0
        self.numer.set_zero();
951
0
        self.denom.set_one();
952
0
    }
953
}
954
955
impl<T: ConstOne> Ratio<T> {
956
    /// A constant `Ratio` 1/1.
957
    pub const ONE: Self = Self::new_raw(T::ONE, T::ONE);
958
}
959
960
impl<T: Clone + Integer + ConstOne> ConstOne for Ratio<T> {
961
    const ONE: Self = Self::ONE;
962
}
963
964
impl<T: Clone + Integer> One for Ratio<T> {
965
    #[inline]
966
0
    fn one() -> Ratio<T> {
967
0
        Ratio::new_raw(One::one(), One::one())
968
0
    }
969
970
    #[inline]
971
0
    fn is_one(&self) -> bool {
972
0
        self.numer == self.denom
973
0
    }
974
975
    #[inline]
976
0
    fn set_one(&mut self) {
977
0
        self.numer.set_one();
978
0
        self.denom.set_one();
979
0
    }
Unexecuted instantiation: <num_rational::Ratio<num_bigint::bigint::BigInt> as num_traits::identities::One>::set_one
Unexecuted instantiation: <num_rational::Ratio<i8> as num_traits::identities::One>::set_one
Unexecuted instantiation: <num_rational::Ratio<u8> as num_traits::identities::One>::set_one
Unexecuted instantiation: <num_rational::Ratio<isize> as num_traits::identities::One>::set_one
Unexecuted instantiation: <num_rational::Ratio<usize> as num_traits::identities::One>::set_one
Unexecuted instantiation: <num_rational::Ratio<i32> as num_traits::identities::One>::set_one
Unexecuted instantiation: <num_rational::Ratio<u32> as num_traits::identities::One>::set_one
Unexecuted instantiation: <num_rational::Ratio<i128> as num_traits::identities::One>::set_one
Unexecuted instantiation: <num_rational::Ratio<u128> as num_traits::identities::One>::set_one
Unexecuted instantiation: <num_rational::Ratio<i16> as num_traits::identities::One>::set_one
Unexecuted instantiation: <num_rational::Ratio<u16> as num_traits::identities::One>::set_one
Unexecuted instantiation: <num_rational::Ratio<i64> as num_traits::identities::One>::set_one
Unexecuted instantiation: <num_rational::Ratio<u64> as num_traits::identities::One>::set_one
980
}
981
982
impl<T: Clone + Integer> Num for Ratio<T> {
983
    type FromStrRadixErr = ParseRatioError;
984
985
    /// Parses `numer/denom` where the numbers are in base `radix`.
986
0
    fn from_str_radix(s: &str, radix: u32) -> Result<Ratio<T>, ParseRatioError> {
987
0
        if s.splitn(2, '/').count() == 2 {
988
0
            let mut parts = s.splitn(2, '/').map(|ss| {
989
0
                T::from_str_radix(ss, radix).map_err(|_| ParseRatioError {
990
0
                    kind: RatioErrorKind::ParseError,
991
0
                })
992
0
            });
993
0
            let numer: T = parts.next().unwrap()?;
994
0
            let denom: T = parts.next().unwrap()?;
995
0
            if denom.is_zero() {
996
0
                Err(ParseRatioError {
997
0
                    kind: RatioErrorKind::ZeroDenominator,
998
0
                })
999
            } else {
1000
0
                Ok(Ratio::new(numer, denom))
1001
            }
1002
        } else {
1003
0
            Err(ParseRatioError {
1004
0
                kind: RatioErrorKind::ParseError,
1005
0
            })
1006
        }
1007
0
    }
1008
}
1009
1010
impl<T: Clone + Integer + Signed> Signed for Ratio<T> {
1011
    #[inline]
1012
0
    fn abs(&self) -> Ratio<T> {
1013
0
        if self.is_negative() {
1014
0
            -self.clone()
1015
        } else {
1016
0
            self.clone()
1017
        }
1018
0
    }
1019
1020
    #[inline]
1021
0
    fn abs_sub(&self, other: &Ratio<T>) -> Ratio<T> {
1022
0
        if *self <= *other {
1023
0
            Zero::zero()
1024
        } else {
1025
0
            self - other
1026
        }
1027
0
    }
1028
1029
    #[inline]
1030
0
    fn signum(&self) -> Ratio<T> {
1031
0
        if self.is_positive() {
1032
0
            Self::one()
1033
0
        } else if self.is_zero() {
1034
0
            Self::zero()
1035
        } else {
1036
0
            -Self::one()
1037
        }
1038
0
    }
1039
1040
    #[inline]
1041
0
    fn is_positive(&self) -> bool {
1042
0
        (self.numer.is_positive() && self.denom.is_positive())
1043
0
            || (self.numer.is_negative() && self.denom.is_negative())
1044
0
    }
1045
1046
    #[inline]
1047
0
    fn is_negative(&self) -> bool {
1048
0
        (self.numer.is_negative() && self.denom.is_positive())
1049
0
            || (self.numer.is_positive() && self.denom.is_negative())
1050
0
    }
1051
}
1052
1053
// String conversions
1054
macro_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
0
            fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1059
0
                let pre_pad = if self.denom.is_one() {
1060
0
                    format!($fmt_str, self.numer)
1061
                } else {
1062
0
                    if f.alternate() {
1063
0
                        format!(concat!($fmt_str, "/", $fmt_alt), self.numer, self.denom)
1064
                    } else {
1065
0
                        format!(concat!($fmt_str, "/", $fmt_str), self.numer, self.denom)
1066
                    }
1067
                };
1068
0
                if let Some(pre_pad) = pre_pad.strip_prefix("-") {
1069
0
                    f.pad_integral(false, $prefix, pre_pad)
1070
                } else {
1071
0
                    f.pad_integral(true, $prefix, &pre_pad)
1072
                }
1073
0
            }
Unexecuted instantiation: <num_rational::Ratio<_> as core::fmt::Display>::fmt
Unexecuted instantiation: <num_rational::Ratio<_> as core::fmt::Octal>::fmt
Unexecuted instantiation: <num_rational::Ratio<_> as core::fmt::Binary>::fmt
Unexecuted instantiation: <num_rational::Ratio<_> as core::fmt::LowerHex>::fmt
Unexecuted instantiation: <num_rational::Ratio<_> as core::fmt::UpperHex>::fmt
Unexecuted instantiation: <num_rational::Ratio<_> as core::fmt::LowerExp>::fmt
Unexecuted instantiation: <num_rational::Ratio<_> as core::fmt::UpperExp>::fmt
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
1107
impl_formatting!(Display, "", "{}", "{:#}");
1108
impl_formatting!(Octal, "0o", "{:o}", "{:#o}");
1109
impl_formatting!(Binary, "0b", "{:b}", "{:#b}");
1110
impl_formatting!(LowerHex, "0x", "{:x}", "{:#x}");
1111
impl_formatting!(UpperHex, "0x", "{:X}", "{:#X}");
1112
impl_formatting!(LowerExp, "", "{:e}", "{:#e}");
1113
impl_formatting!(UpperExp, "", "{:E}", "{:#E}");
1114
1115
impl<T: FromStr + Clone + Integer> FromStr for Ratio<T> {
1116
    type Err = ParseRatioError;
1117
1118
    /// Parses `numer/denom` or just `numer`.
1119
0
    fn from_str(s: &str) -> Result<Ratio<T>, ParseRatioError> {
1120
0
        let mut split = s.splitn(2, '/');
1121
1122
0
        let n = split.next().ok_or(ParseRatioError {
1123
0
            kind: RatioErrorKind::ParseError,
1124
0
        })?;
1125
0
        let num = FromStr::from_str(n).map_err(|_| ParseRatioError {
1126
0
            kind: RatioErrorKind::ParseError,
1127
0
        })?;
1128
1129
0
        let d = split.next().unwrap_or("1");
1130
0
        let den = FromStr::from_str(d).map_err(|_| ParseRatioError {
1131
0
            kind: RatioErrorKind::ParseError,
1132
0
        })?;
1133
1134
0
        if Zero::is_zero(&den) {
1135
0
            Err(ParseRatioError {
1136
0
                kind: RatioErrorKind::ZeroDenominator,
1137
0
            })
1138
        } else {
1139
0
            Ok(Ratio::new(num, den))
1140
        }
1141
0
    }
1142
}
1143
1144
impl<T> From<Ratio<T>> for (T, T) {
1145
0
    fn from(val: Ratio<T>) -> Self {
1146
0
        (val.numer, val.denom)
1147
0
    }
1148
}
1149
1150
#[cfg(feature = "serde")]
1151
impl<T> serde::Serialize for Ratio<T>
1152
where
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")]
1164
impl<'de, T> serde::Deserialize<'de> for Ratio<T>
1165
where
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
// FIXME: Bubble up specific errors
1187
#[derive(Copy, Clone, Debug, PartialEq)]
1188
pub struct ParseRatioError {
1189
    kind: RatioErrorKind,
1190
}
1191
1192
#[derive(Copy, Clone, Debug, PartialEq)]
1193
enum RatioErrorKind {
1194
    ParseError,
1195
    ZeroDenominator,
1196
}
1197
1198
impl fmt::Display for ParseRatioError {
1199
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1200
0
        self.kind.description().fmt(f)
1201
0
    }
1202
}
1203
1204
#[cfg(feature = "std")]
1205
impl Error for ParseRatioError {
1206
    #[allow(deprecated)]
1207
0
    fn description(&self) -> &str {
1208
0
        self.kind.description()
1209
0
    }
1210
}
1211
1212
impl RatioErrorKind {
1213
0
    fn description(&self) -> &'static str {
1214
0
        match *self {
1215
0
            RatioErrorKind::ParseError => "failed to parse integer",
1216
0
            RatioErrorKind::ZeroDenominator => "zero value denominator",
1217
        }
1218
0
    }
1219
}
1220
1221
#[cfg(feature = "num-bigint")]
1222
impl FromPrimitive for Ratio<BigInt> {
1223
0
    fn from_i64(n: i64) -> Option<Self> {
1224
0
        Some(Ratio::from_integer(n.into()))
1225
0
    }
1226
1227
0
    fn from_i128(n: i128) -> Option<Self> {
1228
0
        Some(Ratio::from_integer(n.into()))
1229
0
    }
1230
1231
0
    fn from_u64(n: u64) -> Option<Self> {
1232
0
        Some(Ratio::from_integer(n.into()))
1233
0
    }
1234
1235
0
    fn from_u128(n: u128) -> Option<Self> {
1236
0
        Some(Ratio::from_integer(n.into()))
1237
0
    }
1238
1239
0
    fn from_f32(n: f32) -> Option<Self> {
1240
0
        Ratio::from_float(n)
1241
0
    }
1242
1243
0
    fn from_f64(n: f64) -> Option<Self> {
1244
0
        Ratio::from_float(n)
1245
0
    }
1246
}
1247
1248
macro_rules! from_primitive_integer {
1249
    ($typ:ty, $approx:ident) => {
1250
        impl FromPrimitive for Ratio<$typ> {
1251
0
            fn from_i64(n: i64) -> Option<Self> {
1252
0
                <$typ as FromPrimitive>::from_i64(n).map(Ratio::from_integer)
1253
0
            }
Unexecuted instantiation: <num_rational::Ratio<i32> as num_traits::cast::FromPrimitive>::from_i64
Unexecuted instantiation: <num_rational::Ratio<i64> as num_traits::cast::FromPrimitive>::from_i64
Unexecuted instantiation: <num_rational::Ratio<i128> as num_traits::cast::FromPrimitive>::from_i64
Unexecuted instantiation: <num_rational::Ratio<isize> as num_traits::cast::FromPrimitive>::from_i64
Unexecuted instantiation: <num_rational::Ratio<u8> as num_traits::cast::FromPrimitive>::from_i64
Unexecuted instantiation: <num_rational::Ratio<u16> as num_traits::cast::FromPrimitive>::from_i64
Unexecuted instantiation: <num_rational::Ratio<u32> as num_traits::cast::FromPrimitive>::from_i64
Unexecuted instantiation: <num_rational::Ratio<u64> as num_traits::cast::FromPrimitive>::from_i64
Unexecuted instantiation: <num_rational::Ratio<u128> as num_traits::cast::FromPrimitive>::from_i64
Unexecuted instantiation: <num_rational::Ratio<usize> as num_traits::cast::FromPrimitive>::from_i64
Unexecuted instantiation: <num_rational::Ratio<i8> as num_traits::cast::FromPrimitive>::from_i64
Unexecuted instantiation: <num_rational::Ratio<i16> as num_traits::cast::FromPrimitive>::from_i64
1254
1255
0
            fn from_i128(n: i128) -> Option<Self> {
1256
0
                <$typ as FromPrimitive>::from_i128(n).map(Ratio::from_integer)
1257
0
            }
Unexecuted instantiation: <num_rational::Ratio<i32> as num_traits::cast::FromPrimitive>::from_i128
Unexecuted instantiation: <num_rational::Ratio<i64> as num_traits::cast::FromPrimitive>::from_i128
Unexecuted instantiation: <num_rational::Ratio<i128> as num_traits::cast::FromPrimitive>::from_i128
Unexecuted instantiation: <num_rational::Ratio<isize> as num_traits::cast::FromPrimitive>::from_i128
Unexecuted instantiation: <num_rational::Ratio<u8> as num_traits::cast::FromPrimitive>::from_i128
Unexecuted instantiation: <num_rational::Ratio<u16> as num_traits::cast::FromPrimitive>::from_i128
Unexecuted instantiation: <num_rational::Ratio<u32> as num_traits::cast::FromPrimitive>::from_i128
Unexecuted instantiation: <num_rational::Ratio<u64> as num_traits::cast::FromPrimitive>::from_i128
Unexecuted instantiation: <num_rational::Ratio<u128> as num_traits::cast::FromPrimitive>::from_i128
Unexecuted instantiation: <num_rational::Ratio<usize> as num_traits::cast::FromPrimitive>::from_i128
Unexecuted instantiation: <num_rational::Ratio<i8> as num_traits::cast::FromPrimitive>::from_i128
Unexecuted instantiation: <num_rational::Ratio<i16> as num_traits::cast::FromPrimitive>::from_i128
1258
1259
0
            fn from_u64(n: u64) -> Option<Self> {
1260
0
                <$typ as FromPrimitive>::from_u64(n).map(Ratio::from_integer)
1261
0
            }
Unexecuted instantiation: <num_rational::Ratio<i32> as num_traits::cast::FromPrimitive>::from_u64
Unexecuted instantiation: <num_rational::Ratio<i64> as num_traits::cast::FromPrimitive>::from_u64
Unexecuted instantiation: <num_rational::Ratio<i128> as num_traits::cast::FromPrimitive>::from_u64
Unexecuted instantiation: <num_rational::Ratio<isize> as num_traits::cast::FromPrimitive>::from_u64
Unexecuted instantiation: <num_rational::Ratio<u8> as num_traits::cast::FromPrimitive>::from_u64
Unexecuted instantiation: <num_rational::Ratio<u16> as num_traits::cast::FromPrimitive>::from_u64
Unexecuted instantiation: <num_rational::Ratio<u32> as num_traits::cast::FromPrimitive>::from_u64
Unexecuted instantiation: <num_rational::Ratio<u64> as num_traits::cast::FromPrimitive>::from_u64
Unexecuted instantiation: <num_rational::Ratio<u128> as num_traits::cast::FromPrimitive>::from_u64
Unexecuted instantiation: <num_rational::Ratio<usize> as num_traits::cast::FromPrimitive>::from_u64
Unexecuted instantiation: <num_rational::Ratio<i8> as num_traits::cast::FromPrimitive>::from_u64
Unexecuted instantiation: <num_rational::Ratio<i16> as num_traits::cast::FromPrimitive>::from_u64
1262
1263
0
            fn from_u128(n: u128) -> Option<Self> {
1264
0
                <$typ as FromPrimitive>::from_u128(n).map(Ratio::from_integer)
1265
0
            }
Unexecuted instantiation: <num_rational::Ratio<i32> as num_traits::cast::FromPrimitive>::from_u128
Unexecuted instantiation: <num_rational::Ratio<i64> as num_traits::cast::FromPrimitive>::from_u128
Unexecuted instantiation: <num_rational::Ratio<i128> as num_traits::cast::FromPrimitive>::from_u128
Unexecuted instantiation: <num_rational::Ratio<isize> as num_traits::cast::FromPrimitive>::from_u128
Unexecuted instantiation: <num_rational::Ratio<u8> as num_traits::cast::FromPrimitive>::from_u128
Unexecuted instantiation: <num_rational::Ratio<u16> as num_traits::cast::FromPrimitive>::from_u128
Unexecuted instantiation: <num_rational::Ratio<u32> as num_traits::cast::FromPrimitive>::from_u128
Unexecuted instantiation: <num_rational::Ratio<u64> as num_traits::cast::FromPrimitive>::from_u128
Unexecuted instantiation: <num_rational::Ratio<u128> as num_traits::cast::FromPrimitive>::from_u128
Unexecuted instantiation: <num_rational::Ratio<usize> as num_traits::cast::FromPrimitive>::from_u128
Unexecuted instantiation: <num_rational::Ratio<i8> as num_traits::cast::FromPrimitive>::from_u128
Unexecuted instantiation: <num_rational::Ratio<i16> as num_traits::cast::FromPrimitive>::from_u128
1266
1267
0
            fn from_f32(n: f32) -> Option<Self> {
1268
0
                $approx(n, 10e-20, 30)
1269
0
            }
Unexecuted instantiation: <num_rational::Ratio<i32> as num_traits::cast::FromPrimitive>::from_f32
Unexecuted instantiation: <num_rational::Ratio<i64> as num_traits::cast::FromPrimitive>::from_f32
Unexecuted instantiation: <num_rational::Ratio<i128> as num_traits::cast::FromPrimitive>::from_f32
Unexecuted instantiation: <num_rational::Ratio<isize> as num_traits::cast::FromPrimitive>::from_f32
Unexecuted instantiation: <num_rational::Ratio<u8> as num_traits::cast::FromPrimitive>::from_f32
Unexecuted instantiation: <num_rational::Ratio<u16> as num_traits::cast::FromPrimitive>::from_f32
Unexecuted instantiation: <num_rational::Ratio<u32> as num_traits::cast::FromPrimitive>::from_f32
Unexecuted instantiation: <num_rational::Ratio<u64> as num_traits::cast::FromPrimitive>::from_f32
Unexecuted instantiation: <num_rational::Ratio<u128> as num_traits::cast::FromPrimitive>::from_f32
Unexecuted instantiation: <num_rational::Ratio<usize> as num_traits::cast::FromPrimitive>::from_f32
Unexecuted instantiation: <num_rational::Ratio<i8> as num_traits::cast::FromPrimitive>::from_f32
Unexecuted instantiation: <num_rational::Ratio<i16> as num_traits::cast::FromPrimitive>::from_f32
1270
1271
0
            fn from_f64(n: f64) -> Option<Self> {
1272
0
                $approx(n, 10e-20, 30)
1273
0
            }
Unexecuted instantiation: <num_rational::Ratio<i32> as num_traits::cast::FromPrimitive>::from_f64
Unexecuted instantiation: <num_rational::Ratio<i64> as num_traits::cast::FromPrimitive>::from_f64
Unexecuted instantiation: <num_rational::Ratio<i128> as num_traits::cast::FromPrimitive>::from_f64
Unexecuted instantiation: <num_rational::Ratio<isize> as num_traits::cast::FromPrimitive>::from_f64
Unexecuted instantiation: <num_rational::Ratio<u8> as num_traits::cast::FromPrimitive>::from_f64
Unexecuted instantiation: <num_rational::Ratio<u16> as num_traits::cast::FromPrimitive>::from_f64
Unexecuted instantiation: <num_rational::Ratio<u32> as num_traits::cast::FromPrimitive>::from_f64
Unexecuted instantiation: <num_rational::Ratio<u64> as num_traits::cast::FromPrimitive>::from_f64
Unexecuted instantiation: <num_rational::Ratio<u128> as num_traits::cast::FromPrimitive>::from_f64
Unexecuted instantiation: <num_rational::Ratio<usize> as num_traits::cast::FromPrimitive>::from_f64
Unexecuted instantiation: <num_rational::Ratio<i8> as num_traits::cast::FromPrimitive>::from_f64
Unexecuted instantiation: <num_rational::Ratio<i16> as num_traits::cast::FromPrimitive>::from_f64
1274
        }
1275
    };
1276
}
1277
1278
from_primitive_integer!(i8, approximate_float);
1279
from_primitive_integer!(i16, approximate_float);
1280
from_primitive_integer!(i32, approximate_float);
1281
from_primitive_integer!(i64, approximate_float);
1282
from_primitive_integer!(i128, approximate_float);
1283
from_primitive_integer!(isize, approximate_float);
1284
1285
from_primitive_integer!(u8, approximate_float_unsigned);
1286
from_primitive_integer!(u16, approximate_float_unsigned);
1287
from_primitive_integer!(u32, approximate_float_unsigned);
1288
from_primitive_integer!(u64, approximate_float_unsigned);
1289
from_primitive_integer!(u128, approximate_float_unsigned);
1290
from_primitive_integer!(usize, approximate_float_unsigned);
1291
1292
impl<T: Integer + Signed + Bounded + NumCast + Clone> Ratio<T> {
1293
0
    pub fn approximate_float<F: FloatCore + NumCast>(f: F) -> Option<Ratio<T>> {
1294
        // 1/10e-20 < 1/2**32 which seems like a good default, and 30 seems
1295
        // to work well. Might want to choose something based on the types in the future, e.g.
1296
        // T::max().recip() and T::bits() or something similar.
1297
0
        let epsilon = <F as NumCast>::from(10e-20).expect("Can't convert 10e-20");
1298
0
        approximate_float(f, epsilon, 30)
1299
0
    }
1300
}
1301
1302
impl<T: Integer + Unsigned + Bounded + NumCast + Clone> Ratio<T> {
1303
0
    pub fn approximate_float_unsigned<F: FloatCore + NumCast>(f: F) -> Option<Ratio<T>> {
1304
        // 1/10e-20 < 1/2**32 which seems like a good default, and 30 seems
1305
        // to work well. Might want to choose something based on the types in the future, e.g.
1306
        // T::max().recip() and T::bits() or something similar.
1307
0
        let epsilon = <F as NumCast>::from(10e-20).expect("Can't convert 10e-20");
1308
0
        approximate_float_unsigned(f, epsilon, 30)
1309
0
    }
1310
}
1311
1312
0
fn approximate_float<T, F>(val: F, max_error: F, max_iterations: usize) -> Option<Ratio<T>>
1313
0
where
1314
0
    T: Integer + Signed + Bounded + NumCast + Clone,
1315
0
    F: FloatCore + NumCast,
1316
{
1317
0
    let negative = val.is_sign_negative();
1318
0
    let abs_val = val.abs();
1319
1320
0
    let r = approximate_float_unsigned(abs_val, max_error, max_iterations)?;
1321
1322
    // Make negative again if needed
1323
0
    Some(if negative { r.neg() } else { r })
1324
0
}
Unexecuted instantiation: num_rational::approximate_float::<i8, f64>
Unexecuted instantiation: num_rational::approximate_float::<i8, f32>
Unexecuted instantiation: num_rational::approximate_float::<isize, f64>
Unexecuted instantiation: num_rational::approximate_float::<isize, f32>
Unexecuted instantiation: num_rational::approximate_float::<i32, f64>
Unexecuted instantiation: num_rational::approximate_float::<i32, f32>
Unexecuted instantiation: num_rational::approximate_float::<i128, f64>
Unexecuted instantiation: num_rational::approximate_float::<i128, f32>
Unexecuted instantiation: num_rational::approximate_float::<i16, f64>
Unexecuted instantiation: num_rational::approximate_float::<i16, f32>
Unexecuted instantiation: num_rational::approximate_float::<i64, f64>
Unexecuted instantiation: num_rational::approximate_float::<i64, f32>
1325
1326
// No Unsigned constraint because this also works on positive integers and is called
1327
// like that, see above
1328
0
fn approximate_float_unsigned<T, F>(val: F, max_error: F, max_iterations: usize) -> Option<Ratio<T>>
1329
0
where
1330
0
    T: Integer + Bounded + NumCast + Clone,
1331
0
    F: FloatCore + NumCast,
1332
{
1333
    // Continued fractions algorithm
1334
    // https://web.archive.org/web/20200629111319/http://mathforum.org:80/dr.math/faq/faq.fractions.html#decfrac
1335
1336
0
    if val < F::zero() || val.is_nan() {
1337
0
        return None;
1338
0
    }
1339
1340
0
    let mut q = val;
1341
0
    let mut n0 = T::zero();
1342
0
    let mut d0 = T::one();
1343
0
    let mut n1 = T::one();
1344
0
    let mut d1 = T::zero();
1345
1346
0
    let t_max = T::max_value();
1347
0
    let t_max_f = <F as NumCast>::from(t_max.clone())?;
1348
1349
    // 1/epsilon > T::MAX
1350
0
    let epsilon = t_max_f.recip();
1351
1352
    // Overflow
1353
0
    if q > t_max_f {
1354
0
        return None;
1355
0
    }
1356
1357
0
    for _ in 0..max_iterations {
1358
0
        let a = match <T as NumCast>::from(q) {
1359
0
            None => break,
1360
0
            Some(a) => a,
1361
        };
1362
1363
0
        let a_f = match <F as NumCast>::from(a.clone()) {
1364
0
            None => break,
1365
0
            Some(a_f) => a_f,
1366
        };
1367
0
        let f = q - a_f;
1368
1369
        // Prevent overflow
1370
0
        if !a.is_zero()
1371
0
            && (n1 > t_max.clone() / a.clone()
1372
0
                || d1 > t_max.clone() / a.clone()
1373
0
                || a.clone() * n1.clone() > t_max.clone() - n0.clone()
1374
0
                || a.clone() * d1.clone() > t_max.clone() - d0.clone())
1375
        {
1376
0
            break;
1377
0
        }
1378
1379
0
        let n = a.clone() * n1.clone() + n0.clone();
1380
0
        let d = a.clone() * d1.clone() + d0.clone();
1381
1382
0
        n0 = n1;
1383
0
        d0 = d1;
1384
0
        n1 = n.clone();
1385
0
        d1 = d.clone();
1386
1387
        // Simplify fraction. Doing so here instead of at the end
1388
        // allows us to get closer to the target value without overflows
1389
0
        let g = Integer::gcd(&n1, &d1);
1390
0
        if !g.is_zero() {
1391
0
            n1 = n1 / g.clone();
1392
0
            d1 = d1 / g.clone();
1393
0
        }
1394
1395
        // Close enough?
1396
0
        let (n_f, d_f) = match (<F as NumCast>::from(n), <F as NumCast>::from(d)) {
1397
0
            (Some(n_f), Some(d_f)) => (n_f, d_f),
1398
0
            _ => break,
1399
        };
1400
0
        if (n_f / d_f - val).abs() < max_error {
1401
0
            break;
1402
0
        }
1403
1404
        // Prevent division by ~0
1405
0
        if f < epsilon {
1406
0
            break;
1407
0
        }
1408
0
        q = f.recip();
1409
    }
1410
1411
    // Overflow
1412
0
    if d1.is_zero() {
1413
0
        return None;
1414
0
    }
1415
1416
0
    Some(Ratio::new(n1, d1))
1417
0
}
Unexecuted instantiation: num_rational::approximate_float_unsigned::<i8, f64>
Unexecuted instantiation: num_rational::approximate_float_unsigned::<i8, f32>
Unexecuted instantiation: num_rational::approximate_float_unsigned::<u8, f64>
Unexecuted instantiation: num_rational::approximate_float_unsigned::<u8, f32>
Unexecuted instantiation: num_rational::approximate_float_unsigned::<isize, f64>
Unexecuted instantiation: num_rational::approximate_float_unsigned::<isize, f32>
Unexecuted instantiation: num_rational::approximate_float_unsigned::<usize, f64>
Unexecuted instantiation: num_rational::approximate_float_unsigned::<usize, f32>
Unexecuted instantiation: num_rational::approximate_float_unsigned::<i32, f64>
Unexecuted instantiation: num_rational::approximate_float_unsigned::<i32, f32>
Unexecuted instantiation: num_rational::approximate_float_unsigned::<u32, f64>
Unexecuted instantiation: num_rational::approximate_float_unsigned::<u32, f32>
Unexecuted instantiation: num_rational::approximate_float_unsigned::<i128, f64>
Unexecuted instantiation: num_rational::approximate_float_unsigned::<i128, f32>
Unexecuted instantiation: num_rational::approximate_float_unsigned::<u128, f64>
Unexecuted instantiation: num_rational::approximate_float_unsigned::<u128, f32>
Unexecuted instantiation: num_rational::approximate_float_unsigned::<i16, f64>
Unexecuted instantiation: num_rational::approximate_float_unsigned::<i16, f32>
Unexecuted instantiation: num_rational::approximate_float_unsigned::<u16, f64>
Unexecuted instantiation: num_rational::approximate_float_unsigned::<u16, f32>
Unexecuted instantiation: num_rational::approximate_float_unsigned::<i64, f64>
Unexecuted instantiation: num_rational::approximate_float_unsigned::<i64, f32>
Unexecuted instantiation: num_rational::approximate_float_unsigned::<u64, f64>
Unexecuted instantiation: num_rational::approximate_float_unsigned::<u64, f32>
1418
1419
#[cfg(not(feature = "num-bigint"))]
1420
macro_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"))]
1452
to_primitive_small!(u8 i8 u16 i16 u32 i32);
1453
1454
#[cfg(all(target_pointer_width = "32", not(feature = "num-bigint")))]
1455
to_primitive_small!(usize isize);
1456
1457
#[cfg(not(feature = "num-bigint"))]
1458
macro_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"))]
1493
to_primitive_64!(u64 i64);
1494
1495
#[cfg(all(target_pointer_width = "64", not(feature = "num-bigint")))]
1496
to_primitive_64!(usize isize);
1497
1498
#[cfg(feature = "num-bigint")]
1499
impl<T: Clone + Integer + ToPrimitive + ToBigInt> ToPrimitive for Ratio<T> {
1500
0
    fn to_i64(&self) -> Option<i64> {
1501
0
        self.to_integer().to_i64()
1502
0
    }
1503
1504
0
    fn to_i128(&self) -> Option<i128> {
1505
0
        self.to_integer().to_i128()
1506
0
    }
1507
1508
0
    fn to_u64(&self) -> Option<u64> {
1509
0
        self.to_integer().to_u64()
1510
0
    }
1511
1512
0
    fn to_u128(&self) -> Option<u128> {
1513
0
        self.to_integer().to_u128()
1514
0
    }
1515
1516
0
    fn to_f64(&self) -> Option<f64> {
1517
0
        let float = match (self.numer.to_i64(), self.denom.to_i64()) {
1518
0
            (Some(numer), Some(denom)) => ratio_to_f64(
1519
0
                <i128 as From<_>>::from(numer),
1520
0
                <i128 as From<_>>::from(denom),
1521
            ),
1522
            _ => {
1523
0
                let numer: BigInt = self.numer.to_bigint()?;
1524
0
                let denom: BigInt = self.denom.to_bigint()?;
1525
0
                ratio_to_f64(numer, denom)
1526
            }
1527
        };
1528
0
        if float.is_nan() {
1529
0
            None
1530
        } else {
1531
0
            Some(float)
1532
        }
1533
0
    }
1534
}
1535
1536
trait Bits {
1537
    fn bits(&self) -> u64;
1538
}
1539
1540
#[cfg(feature = "num-bigint")]
1541
impl Bits for BigInt {
1542
0
    fn bits(&self) -> u64 {
1543
0
        self.bits()
1544
0
    }
1545
}
1546
1547
impl Bits for i128 {
1548
0
    fn bits(&self) -> u64 {
1549
0
        (128 - self.wrapping_abs().leading_zeros()).into()
1550
0
    }
1551
}
1552
1553
/// Converts a ratio of `T` to an f64.
1554
///
1555
/// In addition to stated trait bounds, `T` must be able to hold numbers 56 bits larger than
1556
/// the largest of `numer` and `denom`. This is automatically true if `T` is `BigInt`.
1557
0
fn ratio_to_f64<T: Bits + Clone + Integer + Signed + ShlAssign<usize> + ToPrimitive>(
1558
0
    numer: T,
1559
0
    denom: T,
1560
0
) -> f64 {
1561
    use core::f64::{INFINITY, MANTISSA_DIGITS, MAX_EXP, MIN_EXP, RADIX};
1562
1563
0
    assert_eq!(
1564
        RADIX, 2,
1565
0
        "only floating point implementations with radix 2 are supported"
1566
    );
1567
1568
    // Inclusive upper and lower bounds to the range of exactly-representable ints in an f64.
1569
    const MAX_EXACT_INT: i64 = 1i64 << MANTISSA_DIGITS;
1570
    const MIN_EXACT_INT: i64 = -MAX_EXACT_INT;
1571
1572
0
    let flo_sign = numer.signum().to_f64().unwrap() / denom.signum().to_f64().unwrap();
1573
0
    if !flo_sign.is_normal() {
1574
0
        return flo_sign;
1575
0
    }
1576
1577
    // Fast track: both sides can losslessly be converted to f64s. In this case, letting the
1578
    // FPU do the job is faster and easier. In any other case, converting to f64s may lead
1579
    // to an inexact result: https://stackoverflow.com/questions/56641441/.
1580
0
    if let (Some(n), Some(d)) = (numer.to_i64(), denom.to_i64()) {
1581
0
        let exact = MIN_EXACT_INT..=MAX_EXACT_INT;
1582
0
        if exact.contains(&n) && exact.contains(&d) {
1583
0
            return n.to_f64().unwrap() / d.to_f64().unwrap();
1584
0
        }
1585
0
    }
1586
1587
    // Otherwise, the goal is to obtain a quotient with at least 55 bits. 53 of these bits will
1588
    // be used as the mantissa of the resulting float, and the remaining two are for rounding.
1589
    // There's an error of up to 1 on the number of resulting bits, so we may get either 55 or
1590
    // 56 bits.
1591
0
    let mut numer = numer.abs();
1592
0
    let mut denom = denom.abs();
1593
0
    let (is_diff_positive, absolute_diff) = match numer.bits().checked_sub(denom.bits()) {
1594
0
        Some(diff) => (true, diff),
1595
0
        None => (false, denom.bits() - numer.bits()),
1596
    };
1597
1598
    // Filter out overflows and underflows. After this step, the signed difference fits in an
1599
    // isize.
1600
0
    if is_diff_positive && absolute_diff > MAX_EXP as u64 {
1601
0
        return INFINITY * flo_sign;
1602
0
    }
1603
0
    if !is_diff_positive && absolute_diff > -MIN_EXP as u64 + MANTISSA_DIGITS as u64 + 1 {
1604
0
        return 0.0 * flo_sign;
1605
0
    }
1606
0
    let diff = if is_diff_positive {
1607
0
        absolute_diff.to_isize().unwrap()
1608
    } else {
1609
0
        -absolute_diff.to_isize().unwrap()
1610
    };
1611
1612
    // Shift is chosen so that the quotient will have 55 or 56 bits. The exception is if the
1613
    // quotient is going to be subnormal, in which case it may have fewer bits.
1614
0
    let shift: isize = diff.max(MIN_EXP as isize) - MANTISSA_DIGITS as isize - 2;
1615
0
    if shift >= 0 {
1616
0
        denom <<= shift as usize
1617
    } else {
1618
0
        numer <<= -shift as usize
1619
    };
1620
1621
0
    let (quotient, remainder) = numer.div_rem(&denom);
1622
1623
    // This is guaranteed to fit since we've set up quotient to be at most 56 bits.
1624
0
    let mut quotient = quotient.to_u64().unwrap();
1625
0
    let n_rounding_bits = {
1626
0
        let quotient_bits = 64 - quotient.leading_zeros() as isize;
1627
0
        let subnormal_bits = MIN_EXP as isize - shift;
1628
0
        quotient_bits.max(subnormal_bits) - MANTISSA_DIGITS as isize
1629
0
    } as usize;
1630
0
    debug_assert!(n_rounding_bits == 2 || n_rounding_bits == 3);
1631
0
    let rounding_bit_mask = (1u64 << n_rounding_bits) - 1;
1632
1633
    // Round to 53 bits with round-to-even. For rounding, we need to take into account both
1634
    // our rounding bits and the division's remainder.
1635
0
    let ls_bit = quotient & (1u64 << n_rounding_bits) != 0;
1636
0
    let ms_rounding_bit = quotient & (1u64 << (n_rounding_bits - 1)) != 0;
1637
0
    let ls_rounding_bits = quotient & (rounding_bit_mask >> 1) != 0;
1638
0
    if ms_rounding_bit && (ls_bit || ls_rounding_bits || !remainder.is_zero()) {
1639
0
        quotient += 1u64 << n_rounding_bits;
1640
0
    }
1641
0
    quotient &= !rounding_bit_mask;
1642
1643
    // The quotient is guaranteed to be exactly representable as it's now 53 bits + 2 or 3
1644
    // trailing zeros, so there is no risk of a rounding error here.
1645
0
    let q_float = quotient as f64 * flo_sign;
1646
0
    ldexp(q_float, shift as i32)
1647
0
}
1648
1649
/// Multiply `x` by 2 to the power of `exp`. Returns an accurate result even if `2^exp` is not
1650
/// representable.
1651
0
fn ldexp(x: f64, exp: i32) -> f64 {
1652
    use core::f64::{INFINITY, MANTISSA_DIGITS, MAX_EXP, RADIX};
1653
1654
0
    assert_eq!(
1655
        RADIX, 2,
1656
0
        "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
0
    if x.is_zero() || x.is_infinite() || x.is_nan() {
1664
0
        return x;
1665
0
    }
1666
1667
    // Filter out obvious over / underflows to make sure the resulting exponent fits in an isize.
1668
0
    if exp > 3 * MAX_EXP {
1669
0
        return INFINITY * x.signum();
1670
0
    } else if exp < -3 * MAX_EXP {
1671
0
        return 0.0 * x.signum();
1672
0
    }
1673
1674
    // curr_exp is the x's *biased* exponent, and is in the [-54, MAX_UNSIGNED_EXPONENT] range.
1675
0
    let (bits, curr_exp) = if !x.is_normal() {
1676
        // If x is subnormal, we make it normal by multiplying by 2^53. This causes no loss of
1677
        // precision or rounding.
1678
0
        let normal_x = x * 2f64.powi(MIN_SUBNORMAL_POWER);
1679
0
        let bits = normal_x.to_bits();
1680
        // This cast is safe because the exponent is at most 0x7fe, which fits in an i32.
1681
0
        (
1682
0
            bits,
1683
0
            ((bits & EXPONENT_MASK) >> 52) as i32 - MIN_SUBNORMAL_POWER,
1684
0
        )
1685
    } else {
1686
0
        let bits = x.to_bits();
1687
0
        let curr_exp = (bits & EXPONENT_MASK) >> 52;
1688
        // This cast is safe because the exponent is at most 0x7fe, which fits in an i32.
1689
0
        (bits, curr_exp as i32)
1690
    };
1691
1692
    // The addition can't overflow because exponent is between 0 and 0x7fe, and exp is between
1693
    // -2*MAX_EXP and 2*MAX_EXP.
1694
0
    let new_exp = curr_exp + exp;
1695
1696
0
    if new_exp > MAX_UNSIGNED_EXPONENT {
1697
0
        INFINITY * x.signum()
1698
0
    } else if new_exp > 0 {
1699
        // Normal case: exponent is not too large nor subnormal.
1700
0
        let new_bits = (bits & !EXPONENT_MASK) | ((new_exp as u64) << 52);
1701
0
        f64::from_bits(new_bits)
1702
0
    } else if new_exp >= -(MANTISSA_DIGITS as i32) {
1703
        // Result is subnormal but may not be zero.
1704
        // In this case, we increase the exponent by 54 to make it normal, then multiply the end
1705
        // result by 2^-53. This results in a single multiplication with no prior rounding error,
1706
        // so there is no risk of double rounding.
1707
0
        let new_exp = new_exp + MIN_SUBNORMAL_POWER;
1708
0
        debug_assert!(new_exp >= 0);
1709
0
        let new_bits = (bits & !EXPONENT_MASK) | ((new_exp as u64) << 52);
1710
0
        f64::from_bits(new_bits) * 2f64.powi(-MIN_SUBNORMAL_POWER)
1711
    } else {
1712
        // Result is zero.
1713
0
        return 0.0 * x.signum();
1714
    }
1715
0
}
1716
1717
#[cfg(test)]
1718
#[cfg(feature = "std")]
1719
fn 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)]
1728
mod 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
        // check our constants are what Ratio::new etc. would make.
1832
        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
        // issue #7 example:
1918
        let big = Ratio::new(128u8, 1);
1919
        let small = big.recip();
1920
        assert!(big > small);
1921
1922
        // try a few that are closer together
1923
        // (some matching numer, some matching denom, some neither)
1924
        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
        // Test:
2064
        // :b :o :x, :X, :?
2065
        // alternate or not (#)
2066
        // positive and negative
2067
        // padding
2068
        // does not test precision (i.e. truncation)
2069
        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"); // test negatives
2074
        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
        // no std does not support padding
2085
        #[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
            // compares Ratio(1, T::max_value()) + Ratio(1, T::max_value())
2194
            // to Ratio(1+1, T::max_value()) for each integer type.
2195
            // Previously, this calculation would overflow.
2196
            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
            // compares Ratio(1, T::max_value()) - Ratio(1, T::max_value()) to T::zero()
2264
            // for each integer type. Previously, this calculation would overflow.
2265
            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
                // 1/big * 2/3 = 1/(max/4*3), where big is max/2
2336
                // make big = max/2, but also divisible by 2
2337
                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
                // big/3 * 3 = big/1
2354
                // make big = max/2, but make it indivisible by 3
2355
                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
                // 1/big / 3/2 = 1/(max/4*3), where big is max/2
2425
                // big ~ max/2, and big is divisible by 2
2426
                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
                // 3/big / 3 = 1/big where big is max/2
2443
                // big ~ max/2, and big is not divisible by 3
2444
                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
            // tests that Ratio(1,2) % Ratio(1, T::max_value()) equals 0
2507
            // for each integer type. Previously, this calculation would overflow.
2508
            fn test_rem_typed_overflow<T>()
2509
            where
2510
                T: Integer + Bounded + Clone + Debug + NumAssign,
2511
            {
2512
                let two = T::one() + T::one();
2513
                // value near to maximum, but divisible by two
2514
                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
        // Overflow checks
2686
2687
        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
        // f32
2813
        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
        // f64
2827
        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
        // a == b -> hash(a) == hash(b)
2884
        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
        // generic function to assure the iter method can be called
2913
        // for any Iterator with Item = Ratio<impl Integer> or Ratio<&impl Integer>
2914
        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
        // collect into array so test works on no_std
2922
        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
        // generic function to assure the iter method can be called
2934
        // for any Iterator with Item = Ratio<impl Integer> or Ratio<&impl Integer>
2935
        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
        // collect into array so test works on no_std
2948
        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
            // subnormal
3031
            BigRational::new(BigInt::one(), BigInt::one() << 1050).to_f64(),
3032
            Some(2.0f64.powi(-50).powi(21))
3033
        );
3034
        assert_eq!(
3035
            // definite underflow
3036
            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
        // Cases where ldexp is equivalent to multiplying by 2^exp because there's no over- or
3105
        // underflow.
3106
        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
        // Case where initial value is subnormal
3111
        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
        // Near underflow (2^exp is too small to represent, but not x*2^exp)
3115
        assert_eq!(ldexp(4.0, MIN_EXP - 3), 2f64.powi(MIN_EXP - 1));
3116
3117
        // Near overflow
3118
        assert_eq!(ldexp(0.125, MAX_EXP + 3), 2f64.powi(MAX_EXP));
3119
3120
        // Overflow and underflow cases
3121
        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
        // Special values
3127
        assert_eq!(ldexp(INFINITY, 1), INFINITY);
3128
        assert_eq!(ldexp(NEG_INFINITY, 1), NEG_INFINITY);
3129
        assert!(ldexp(NAN, 1).is_nan());
3130
    }
3131
}