1use super::*;
2
3impl<
4 const N: u32,
5 const ES: u32,
6 Int: crate::Int,
7> Posit<N, ES, Int> {
8 pub fn nearest_int(self) -> Self {
27 if self.is_special() { return self }
28 let decoded = unsafe { self.decode_regular() };
30
31 let integral_bits = (Int::ONE + Int::ONE).wrapping_add(decoded.exp);
53
54 if integral_bits <= Int::ZERO {
59 return Posit::ZERO
60 }
61 if integral_bits >= Int::of_u32(Int::BITS) {
64 return self;
65 }
66
67 let integral_bits = integral_bits.as_u32();
72 let fractional_bits = Int::BITS - integral_bits;
73 let integral = decoded.frac >> fractional_bits;
74 let fractional = decoded.frac << integral_bits;
75
76 let round = !fractional.is_positive();
79 let sticky = fractional << 1 != Int::ZERO;
80 let odd = integral.get_lsb();
81 let round_up: bool = round & (odd | sticky);
82
83 let integral_rounded = integral + Int::from(round_up);
92 if integral_rounded == Int::ZERO {
93 return Posit::ZERO
94 }
95 let true_fractional_bits = unsafe { integral_rounded.leading_run_minus_one() };
97 let frac = integral_rounded << true_fractional_bits;
98 let exp = decoded.exp + (Int::of_u32(fractional_bits) - Int::of_u32(true_fractional_bits));
99
100 unsafe { Decoded { frac, exp }.encode_regular() }
102 }
103
104 pub fn floor(self) -> Self {
117 if self.is_special() { return self }
121 let decoded = unsafe { self.decode_regular() };
123
124 let integral_bits = (Int::ONE + Int::ONE).wrapping_add(decoded.exp);
125
126 if integral_bits <= Int::ZERO {
131 return if self >= Posit::ZERO {Posit::ZERO} else {Posit::MINUS_ONE}
132 }
133 if integral_bits >= Int::of_u32(Int::BITS) {
136 return self;
137 }
138
139 let integral_bits = integral_bits.as_u32();
140 let frac = decoded.frac.mask_msb(integral_bits);
141 let exp = decoded.exp;
142 if frac == Int::ZERO {
143 return Posit::ZERO
144 }
145
146 unsafe { Decoded { frac, exp }.encode_regular() }
148 }
149
150 pub fn ceil(self) -> Self {
163 if self.is_special() { return self }
168 let decoded = unsafe { self.decode_regular() };
170
171 let integral_bits = (Int::ONE + Int::ONE).wrapping_add(decoded.exp);
172 if integral_bits <= Int::ZERO {
177 return if self >= Posit::ZERO {Posit::ONE} else {Posit::ZERO}
178 }
179 if integral_bits >= Int::of_u32(Int::BITS) {
182 return self;
183 }
184
185 let integral_bits = integral_bits.as_u32();
186 let fractional_bits = Int::BITS - integral_bits;
187 let integral = decoded.frac >> fractional_bits;
188 let fractional = decoded.frac << integral_bits;
189
190 let round_up: bool = fractional != Int::ZERO;
191
192 let integral_rounded = integral + Int::from(round_up);
193 if integral_rounded == Int::ZERO {
194 return Posit::ZERO
195 }
196 let true_fractional_bits = unsafe { integral_rounded.leading_run_minus_one() };
198 let frac = integral_rounded << true_fractional_bits;
199 let exp = decoded.exp + (Int::of_u32(fractional_bits) - Int::of_u32(true_fractional_bits));
200
201 unsafe { Decoded { frac, exp }.encode_regular() }
203 }
204}
205
206#[cfg(test)]
207mod tests {
208 use super::*;
209 use malachite::rational::Rational;
210 use proptest::prelude::*;
211
212 use malachite::base::rounding_modes::RoundingMode;
213
214 fn is_correct_rounded<const N: u32, const ES: u32, Int: crate::Int>(
216 posit: Posit<N, ES, Int>,
217 rounded_posit: Posit<N, ES, Int>,
218 rounding_mode: RoundingMode,
219 ) -> bool
220 where
221 Rational: From<i32> + TryFrom<Posit<N, ES, Int>, Error = super::rational::IsNaR>,
222 {
223 use malachite::base::num::arithmetic::traits::RoundToMultiple;
224 let posit = Rational::try_from(posit)
225 .map(|exact| exact.round_to_multiple(Rational::from(1), rounding_mode).0);
226 let rounded_posit = Rational::try_from(rounded_posit);
227 posit == rounded_posit
228 }
229
230 mod nearest_int {
231 use super::*;
232
233 macro_rules! test_exhaustive {
234 ($name:ident, $posit:ty) => {
235 #[test]
236 fn $name() {
237 for p in <$posit>::cases_exhaustive_all() {
238 let rounded = p.nearest_int();
239 assert!(is_correct_rounded(p, rounded, RoundingMode::Nearest), "{p:?} {rounded:?}")
240 }
241 }
242 };
243 }
244
245 macro_rules! test_proptest {
246 ($name:ident, $posit:ty) => {
247 proptest!{
248 #![proptest_config(ProptestConfig::with_cases(crate::PROPTEST_CASES))]
249 #[test]
250 fn $name(p in <$posit>::cases_proptest_all()) {
251 let rounded = p.nearest_int();
252 assert!(is_correct_rounded(p, rounded, RoundingMode::Nearest), "{p:?} {rounded:?}")
253 }
254 }
255 };
256 }
257
258 test_exhaustive!{posit_10_0_exhaustive, Posit<10, 0, i16>}
259 test_exhaustive!{posit_10_1_exhaustive, Posit<10, 1, i16>}
260 test_exhaustive!{posit_10_2_exhaustive, Posit<10, 2, i16>}
261 test_exhaustive!{posit_10_3_exhaustive, Posit<10, 3, i16>}
262
263 test_exhaustive!{posit_8_0_exhaustive, Posit<8, 0, i8 >}
264
265 test_exhaustive!{p8_exhaustive, crate::p8}
266 test_exhaustive!{p16_exhaustive, crate::p16}
267 test_proptest!{p32_proptest, crate::p32}
268 test_proptest!{p64_proptest, crate::p64}
269
270 test_exhaustive!{posit_3_0_exhaustive, Posit::<3, 0, i8>}
271 test_exhaustive!{posit_4_0_exhaustive, Posit::<4, 0, i8>}
272 test_exhaustive!{posit_4_1_exhaustive, Posit::<4, 1, i8>}
273 }
274
275 mod floor {
276 use super::*;
277
278 macro_rules! test_exhaustive {
279 ($name:ident, $posit:ty) => {
280 #[test]
281 fn $name() {
282 for p in <$posit>::cases_exhaustive_all() {
283 let rounded = p.floor();
284 assert!(is_correct_rounded(p, rounded, RoundingMode::Floor), "{p:?} {rounded:?}")
285 }
286 }
287 };
288 }
289
290 macro_rules! test_proptest {
291 ($name:ident, $posit:ty) => {
292 proptest!{
293 #![proptest_config(ProptestConfig::with_cases(crate::PROPTEST_CASES))]
294 #[test]
295 fn $name(p in <$posit>::cases_proptest_all()) {
296 let rounded = p.floor();
297 assert!(is_correct_rounded(p, rounded, RoundingMode::Floor), "{p:?} {rounded:?}")
298 }
299 }
300 };
301 }
302
303 test_exhaustive!{posit_10_0_exhaustive, Posit<10, 0, i16>}
304 test_exhaustive!{posit_10_1_exhaustive, Posit<10, 1, i16>}
305 test_exhaustive!{posit_10_2_exhaustive, Posit<10, 2, i16>}
306 test_exhaustive!{posit_10_3_exhaustive, Posit<10, 3, i16>}
307
308 test_exhaustive!{posit_8_0_exhaustive, Posit<8, 0, i8 >}
309
310 test_exhaustive!{p8_exhaustive, crate::p8}
311 test_exhaustive!{p16_exhaustive, crate::p16}
312 test_proptest!{p32_proptest, crate::p32}
313 test_proptest!{p64_proptest, crate::p64}
314
315 test_exhaustive!{posit_3_0_exhaustive, Posit::<3, 0, i8>}
316 test_exhaustive!{posit_4_0_exhaustive, Posit::<4, 0, i8>}
317 test_exhaustive!{posit_4_1_exhaustive, Posit::<4, 1, i8>}
318 }
319
320 mod ceil {
321 use super::*;
322
323 macro_rules! test_exhaustive {
324 ($name:ident, $posit:ty) => {
325 #[test]
326 fn $name() {
327 for p in <$posit>::cases_exhaustive_all() {
328 let rounded = p.ceil();
329 assert!(is_correct_rounded(p, rounded, RoundingMode::Ceiling), "{p:?} {rounded:?}")
330 }
331 }
332 };
333 }
334
335 macro_rules! test_proptest {
336 ($name:ident, $posit:ty) => {
337 proptest!{
338 #![proptest_config(ProptestConfig::with_cases(crate::PROPTEST_CASES))]
339 #[test]
340 fn $name(p in <$posit>::cases_proptest_all()) {
341 let rounded = p.ceil();
342 assert!(is_correct_rounded(p, rounded, RoundingMode::Ceiling), "{p:?} {rounded:?}")
343 }
344 }
345 };
346 }
347
348 test_exhaustive!{posit_10_0_exhaustive, Posit<10, 0, i16>}
349 test_exhaustive!{posit_10_1_exhaustive, Posit<10, 1, i16>}
350 test_exhaustive!{posit_10_2_exhaustive, Posit<10, 2, i16>}
351 test_exhaustive!{posit_10_3_exhaustive, Posit<10, 3, i16>}
352
353 test_exhaustive!{posit_8_0_exhaustive, Posit<8, 0, i8 >}
354
355 test_exhaustive!{p8_exhaustive, crate::p8}
356 test_exhaustive!{p16_exhaustive, crate::p16}
357 test_proptest!{p32_proptest, crate::p32}
358 test_proptest!{p64_proptest, crate::p64}
359
360 test_exhaustive!{posit_3_0_exhaustive, Posit::<3, 0, i8>}
361 test_exhaustive!{posit_4_0_exhaustive, Posit::<4, 0, i8>}
362 test_exhaustive!{posit_4_1_exhaustive, Posit::<4, 1, i8>}
363 }
364}