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