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}