فهرست منبع

Auto merge of #213 - ExpHP:ratio-pr3, r=cuviper

rational: recip bugfix and documentation tweaks

Cherry picked from #210 (minus the `new_raw` stuff), with small additions [in a third commit](https://github.com/rust-num/num/commit/32dee9a0c8259ee3846a644b3925bf981e261ada).
Homu 8 سال پیش
والد
کامیت
d9f08cb148
1فایلهای تغییر یافته به همراه46 افزوده شده و 20 حذف شده
  1. 46 20
      rational/src/lib.rs

+ 46 - 20
rational/src/lib.rs

@@ -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]