dashu_ratio/
round.rs

1use crate::{repr::Repr, RBig, Relaxed};
2use dashu_base::{DivRem, Sign, UnsignedAbs};
3use dashu_int::IBig;
4
5impl Repr {
6    #[inline]
7    pub fn split_at_point(self) -> (IBig, Self) {
8        let (trunc, r) = (&self.numerator).div_rem(&self.denominator);
9
10        let fract = if r.is_zero() {
11            Repr::zero()
12        } else {
13            // no need to reduce here
14            Repr {
15                numerator: r,
16                denominator: self.denominator,
17            }
18        };
19        (trunc, fract)
20    }
21
22    #[inline]
23    pub fn ceil(&self) -> IBig {
24        let (mut q, r) = (&self.numerator).div_rem(&self.denominator);
25        if r > IBig::ZERO {
26            q += IBig::ONE;
27        }
28        q
29    }
30
31    #[inline]
32    pub fn floor(&self) -> IBig {
33        let (mut q, r) = (&self.numerator).div_rem(&self.denominator);
34        if r < IBig::ZERO {
35            q -= IBig::ONE;
36        }
37        q
38    }
39
40    #[inline]
41    pub fn trunc(&self) -> IBig {
42        (&self.numerator) / (&self.denominator)
43    }
44
45    #[inline]
46    pub fn fract(&self) -> Self {
47        let r = (&self.numerator) % (&self.denominator);
48        if r.is_zero() {
49            Repr::zero()
50        } else {
51            Repr {
52                numerator: r,
53                denominator: self.denominator.clone(),
54            }
55        }
56    }
57
58    #[inline]
59    pub fn round(&self) -> IBig {
60        let (mut q, r) = (&self.numerator).div_rem(&self.denominator);
61        if (r.unsigned_abs() << 1) >= self.denominator {
62            match self.numerator.sign() {
63                Sign::Positive => q += IBig::ONE,
64                Sign::Negative => q -= IBig::ONE,
65            }
66        }
67        q
68    }
69}
70
71impl RBig {
72    /// Split the rational number into integral and fractional parts (split at the radix point).
73    ///
74    /// It's return is equivalent to `(self.trunc(), self.fract())`
75    ///
76    /// # Examples
77    ///
78    /// ```
79    /// # use dashu_int::IBig;
80    /// # use dashu_ratio::RBig;
81    /// assert_eq!(RBig::ONE.split_at_point(), (IBig::ONE, RBig::ZERO));
82    ///
83    /// let a = RBig::from_parts(22.into(), 7u8.into());
84    /// let (trunc, fract) = a.split_at_point();
85    /// assert_eq!(trunc, IBig::from(3));
86    /// assert_eq!(fract, RBig::from_parts(1.into(), 7u8.into()));
87    /// ```
88    #[inline]
89    pub fn split_at_point(self) -> (IBig, Self) {
90        let (trunc, fract) = self.0.split_at_point();
91        (trunc, Self(fract))
92    }
93
94    /// Compute the least integer that is greater than or equal to this number.
95    ///
96    /// # Examples
97    ///
98    /// ```
99    /// # use dashu_int::IBig;
100    /// # use dashu_ratio::RBig;
101    /// assert_eq!(RBig::ONE.ceil(), IBig::ONE);
102    ///
103    /// let a = RBig::from_parts(22.into(), 7u8.into());
104    /// assert_eq!(a.ceil(), IBig::from(4));
105    /// ```
106    #[inline]
107    pub fn ceil(&self) -> IBig {
108        self.0.ceil()
109    }
110
111    /// Compute the greatest integer that is less than or equal to this number.
112    ///
113    /// # Examples
114    ///
115    /// ```
116    /// # use dashu_int::IBig;
117    /// # use dashu_ratio::RBig;
118    /// assert_eq!(RBig::ONE.floor(), IBig::ONE);
119    ///
120    /// let a = RBig::from_parts(22.into(), 7u8.into());
121    /// assert_eq!(a.floor(), IBig::from(3));
122    /// ```
123    #[inline]
124    pub fn floor(&self) -> IBig {
125        self.0.floor()
126    }
127
128    /// Compute the integer that closest to this number.
129    ///
130    /// It will return the one farther from zero when the number has the 1/2 as its fractional part.
131    ///
132    /// # Examples
133    ///
134    /// ```
135    /// # use dashu_int::IBig;
136    /// # use dashu_ratio::RBig;
137    /// assert_eq!(RBig::ONE.round(), IBig::ONE);
138    ///
139    /// let a = RBig::from_parts(22.into(), 7u8.into());
140    /// assert_eq!(a.round(), IBig::from(3));
141    /// ```
142    #[inline]
143    pub fn round(&self) -> IBig {
144        self.0.round()
145    }
146
147    /// Returns the integral part of the rational number.
148    ///
149    /// It's guaranteed that `self == self.trunc() + self.fract()`.
150    ///
151    /// # Examples
152    ///
153    /// ```
154    /// # use dashu_int::IBig;
155    /// # use dashu_ratio::RBig;
156    /// assert_eq!(RBig::ONE.trunc(), IBig::ONE);
157    ///
158    /// let a = RBig::from_parts(22.into(), 7u8.into());
159    /// assert_eq!(a.trunc(), IBig::from(3));
160    /// ```
161    #[inline]
162    pub fn trunc(&self) -> IBig {
163        self.0.trunc()
164    }
165
166    /// Returns the fractional part of the rational number
167    ///
168    /// It's guaranteed that `self == self.trunc() + self.fract()`.
169    ///
170    /// # Examples
171    ///
172    /// ```
173    /// # use dashu_int::IBig;
174    /// # use dashu_ratio::RBig;
175    /// assert_eq!(RBig::ONE.fract(), RBig::ZERO);
176    ///
177    /// let a = RBig::from_parts(22.into(), 7u8.into());
178    /// assert_eq!(a.fract(), RBig::from_parts(1.into(), 7u8.into()));
179    /// ```
180    #[inline]
181    pub fn fract(&self) -> Self {
182        Self(self.0.fract())
183    }
184}
185
186impl Relaxed {
187    /// Split the rational number into integral and fractional parts (split at the radix point).
188    ///
189    /// See [RBig::split_at_point] for details.
190    #[inline]
191    pub fn split_at_point(self) -> (IBig, Self) {
192        let (trunc, fract) = self.0.split_at_point();
193        (trunc, Self(fract))
194    }
195
196    /// Compute the smallest integer that is greater than this number.
197    ///
198    /// See [RBig::ceil] for details.
199    #[inline]
200    pub fn ceil(&self) -> IBig {
201        self.0.ceil()
202    }
203
204    /// Compute the largest integer that is less than or equal to this number.
205    ///
206    /// See [RBig::floor] for details.
207    #[inline]
208    pub fn floor(&self) -> IBig {
209        self.0.floor()
210    }
211
212    /// Compute the integer that closest to this number.
213    ///
214    /// See [RBig::round] for details.
215    #[inline]
216    pub fn round(&self) -> IBig {
217        self.0.round()
218    }
219
220    /// Returns the integral part of the rational number.
221    ///
222    /// See [RBig::trunc] for details.
223    #[inline]
224    pub fn trunc(&self) -> IBig {
225        self.0.trunc()
226    }
227
228    /// Returns the fractional part of the rational number
229    ///
230    /// See [RBig::fract] for details.
231    #[inline]
232    pub fn fract(&self) -> Self {
233        Self(self.0.fract())
234    }
235}