|
@@ -56,13 +56,24 @@ pub type Rational64 = Ratio<i64>;
|
|
|
pub type BigRational = Ratio<BigInt>;
|
|
|
|
|
|
impl<T: Clone + Integer> Ratio<T> {
|
|
|
- /// Creates a ratio representing the integer `t`.
|
|
|
+ /// Creates a new `Ratio`. Fails if `denom` is zero.
|
|
|
+ #[inline]
|
|
|
+ pub fn new(numer: T, denom: T) -> Ratio<T> {
|
|
|
+ if denom.is_zero() {
|
|
|
+ panic!("denominator == 0");
|
|
|
+ }
|
|
|
+ let mut ret = Ratio::new_raw(numer, denom);
|
|
|
+ ret.reduce();
|
|
|
+ ret
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Creates a `Ratio` representing the integer `t`.
|
|
|
#[inline]
|
|
|
pub fn from_integer(t: T) -> Ratio<T> {
|
|
|
Ratio::new_raw(t, One::one())
|
|
|
}
|
|
|
|
|
|
- /// Creates a ratio without checking for `denom == 0` or reducing.
|
|
|
+ /// Creates a `Ratio` without checking for `denom == 0` or reducing.
|
|
|
#[inline]
|
|
|
pub fn new_raw(numer: T, denom: T) -> Ratio<T> {
|
|
|
Ratio {
|
|
@@ -71,18 +82,7 @@ impl<T: Clone + Integer> Ratio<T> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /// Create a new Ratio. Fails if `denom == 0`.
|
|
|
- #[inline]
|
|
|
- pub fn new(numer: T, denom: T) -> Ratio<T> {
|
|
|
- if denom == Zero::zero() {
|
|
|
- panic!("denominator == 0");
|
|
|
- }
|
|
|
- let mut ret = Ratio::new_raw(numer, denom);
|
|
|
- ret.reduce();
|
|
|
- ret
|
|
|
- }
|
|
|
-
|
|
|
- /// Converts to an integer.
|
|
|
+ /// Converts to an integer, rounding towards zero.
|
|
|
#[inline]
|
|
|
pub fn to_integer(&self) -> T {
|
|
|
self.trunc().numer
|
|
@@ -106,7 +106,7 @@ impl<T: Clone + Integer> Ratio<T> {
|
|
|
self.denom == One::one()
|
|
|
}
|
|
|
|
|
|
- /// Put self into lowest terms, with denom > 0.
|
|
|
+ /// Puts self into lowest terms, with denom > 0.
|
|
|
fn reduce(&mut self) {
|
|
|
let g: T = self.numer.gcd(&self.denom);
|
|
|
|
|
@@ -124,7 +124,10 @@ impl<T: Clone + Integer> Ratio<T> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /// Returns a `reduce`d copy of self.
|
|
|
+ /// Returns a reduced copy of self.
|
|
|
+ ///
|
|
|
+ /// In general, it is not necessary to use this method, as the only
|
|
|
+ /// method of procuring a non-reduced fraction is through `new_raw`.
|
|
|
pub fn reduced(&self) -> Ratio<T> {
|
|
|
let mut ret = self.clone();
|
|
|
ret.reduce();
|
|
@@ -132,9 +135,16 @@ impl<T: Clone + Integer> Ratio<T> {
|
|
|
}
|
|
|
|
|
|
/// Returns the reciprocal.
|
|
|
+ ///
|
|
|
+ /// Fails if the `Ratio` is zero.
|
|
|
#[inline]
|
|
|
pub fn recip(&self) -> Ratio<T> {
|
|
|
- Ratio::new_raw(self.denom.clone(), self.numer.clone())
|
|
|
+ match self.numer.cmp(&T::zero()) {
|
|
|
+ cmp::Ordering::Equal => panic!("numerator == 0"),
|
|
|
+ cmp::Ordering::Greater => Ratio::new_raw(self.denom.clone(), self.numer.clone()),
|
|
|
+ cmp::Ordering::Less => Ratio::new_raw(T::zero() - self.denom.clone(),
|
|
|
+ T::zero() - self.numer.clone())
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/// Rounds towards minus infinity.
|
|
@@ -201,7 +211,9 @@ impl<T: Clone + Integer> Ratio<T> {
|
|
|
Ratio::from_integer(self.numer.clone() / self.denom.clone())
|
|
|
}
|
|
|
|
|
|
- /// Returns the fractional part of a number.
|
|
|
+ /// Returns the fractional part of a number, with division rounded towards zero.
|
|
|
+ ///
|
|
|
+ /// Satisfies `self == self.trunc() + self.fract()`.
|
|
|
#[inline]
|
|
|
pub fn fract(&self) -> Ratio<T> {
|
|
|
Ratio::new_raw(self.numer.clone() % self.denom.clone(), self.denom.clone())
|
|
@@ -209,7 +221,7 @@ impl<T: Clone + Integer> Ratio<T> {
|
|
|
}
|
|
|
|
|
|
impl<T: Clone + Integer + PrimInt> Ratio<T> {
|
|
|
- /// Raises the ratio to the power of an exponent
|
|
|
+ /// Raises the `Ratio` to the power of an exponent.
|
|
|
#[inline]
|
|
|
pub fn pow(&self, expon: i32) -> Ratio<T> {
|
|
|
match expon.cmp(&0) {
|
|
@@ -593,7 +605,7 @@ impl<T> serde::Deserialize for Ratio<T>
|
|
|
where D: serde::Deserializer
|
|
|
{
|
|
|
let (numer, denom) = try!(serde::Deserialize::deserialize(deserializer));
|
|
|
- if denom == Zero::zero() {
|
|
|
+ if denom.is_zero() {
|
|
|
Err(serde::de::Error::invalid_value("denominator is zero"))
|
|
|
} else {
|
|
|
Ok(Ratio::new_raw(numer, denom))
|
|
@@ -664,6 +676,10 @@ mod test {
|
|
|
numer: 2,
|
|
|
denom: 1,
|
|
|
};
|
|
|
+ pub const _NEG2: Rational = Ratio {
|
|
|
+ numer: -2,
|
|
|
+ denom: 1,
|
|
|
+ };
|
|
|
pub const _1_2: Rational = Ratio {
|
|
|
numer: 1,
|
|
|
denom: 2,
|
|
@@ -1002,6 +1018,16 @@ mod test {
|
|
|
assert_eq!(_1_2 * _1_2.recip(), _1);
|
|
|
assert_eq!(_3_2 * _3_2.recip(), _1);
|
|
|
assert_eq!(_NEG1_2 * _NEG1_2.recip(), _1);
|
|
|
+
|
|
|
+ assert_eq!(_3_2.recip(), _2_3);
|
|
|
+ assert_eq!(_NEG1_2.recip(), _NEG2);
|
|
|
+ assert_eq!(_NEG1_2.recip().denom(), &1);
|
|
|
+ }
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ #[should_panic = "== 0"]
|
|
|
+ fn test_recip_fail() {
|
|
|
+ let _a = Ratio::new(0, 1).recip();
|
|
|
}
|
|
|
|
|
|
#[test]
|