1use super::*;
2
3use crate::underlying::const_as;
4
5#[inline]
12unsafe fn round_from_kernel<
13 FromInt: crate::Int,
14 const N: u32,
15 const ES: u32,
16 Int: crate::Int,
17 const RS: u32,
18>(int: FromInt) -> (Decoded<N, ES, RS, Int>, Int) {
19 let shift_right = if const { Int::BITS >= FromInt::BITS } {0} else {FromInt::BITS - Int::BITS};
23
24 let shift_left = if const { Int::BITS <= FromInt::BITS } {0} else {Int::BITS - FromInt::BITS};
27
28 let underflow = unsafe { int.leading_run_minus_one() };
45 let frac = const_as::<FromInt, Int>(int << underflow >> shift_right) << shift_left;
46 let exp = {
47 let exp = Decoded::<N, ES, N, FromInt>::FRAC_WIDTH.wrapping_sub(underflow);
48 const_as::<i32, Int>(exp as i32)
49 };
50 let sticky = {
51 let true_shift = shift_right.saturating_sub(underflow);
52 Int::from(int.mask_lsb(true_shift) != FromInt::ZERO)
53 };
54
55 (Decoded{frac, exp}, sticky)
56}
57
58#[inline]
60fn round_into_kernel<
61 ToInt: crate::Int,
62 const N: u32,
63 const ES: u32,
64 Int: crate::Int,
65 const RS: u32,
66>(decoded: Decoded<N, ES, RS, Int>) -> ToInt {
67 let diff_right = if const { ToInt::BITS >= Int::BITS } {0} else {Int::BITS - ToInt::BITS};
71
72 let diff_left = if const { ToInt::BITS <= Int::BITS } {0} else {ToInt::BITS - Int::BITS};
75
76 let shift = Int::of_u32(Decoded::<N, ES, RS, Int>::FRAC_WIDTH).wrapping_sub(decoded.exp);
115
116 if shift < Int::ZERO {
118 let shift_left = (-shift).as_u32();
119 if shift_left > diff_left {
120 return ToInt::MIN;
122 }
123 const_as::<Int, ToInt>(decoded.frac) << shift_left
124 }
125 else if shift == Int::ZERO {
127 if diff_right != 0 {
128 return ToInt::MIN;
130 }
131 const_as::<Int, ToInt>(decoded.frac)
132 }
133 else {
136 let shift_right = shift.as_u32();
137 if shift_right > Int::BITS {
138 return ToInt::ZERO;
140 }
141 if shift_right < diff_right {
142 return ToInt::MIN;
144 }
145 let sticky = decoded.frac.mask_lsb(shift_right - 1);
147 let int = decoded.frac >> (shift_right - 1);
148 let round = int.get_lsb();
149 let int = int >> 1;
150 let odd = int.get_lsb();
151 let round_up: bool = round & (odd | (sticky != Int::ZERO));
158 const_as::<Int, ToInt>(int).wrapping_add(ToInt::from(round_up))
159 }
160}
161
162macro_rules! make_impl {
163 ($t:ty) => {
164 impl<
165 const N: u32,
166 const ES: u32,
167 Int: crate::Int,
168 const RS: u32,
169 > RoundFrom<$t> for Posit<N, ES, Int, RS> {
170 #[doc = concat!("Convert an `", stringify!($t), "` into a `Posit`, [rounding according to the standard]:")]
171 #[doc = concat!(" - If the value is [`", stringify!($t), "::MIN`] (i.e. the value where the most significant bit is 1 and the rest are 0), it converts to [NaR](Posit::NAR).")]
173 fn round_from(value: $t) -> Self {
177 if value == 0 { return Posit::ZERO }
180 if value == <$t>::MIN { return Posit::NAR }
181
182 if const { <$t>::BITS as i128 > 1 << Decoded::<N, ES, RS, Int>::FRAC_WIDTH } {
185 let limit = 1 << (1 << Decoded::<N, ES, RS, Int>::FRAC_WIDTH);
186 if value >= limit { return Posit::MAX }
187 if value <= -limit { return Posit::MIN }
188 }
189
190 let (result, sticky) = unsafe { round_from_kernel(value) };
192 unsafe { result.encode_regular_round(sticky) }
194 }
195 }
196
197 impl<
198 const N: u32,
199 const ES: u32,
200 Int: crate::Int,
201 const RS: u32,
202 > RoundFrom<Posit<N, ES, Int, RS>> for $t {
203 #[doc = concat!("Convert a `Posit` into an `", stringify!($t), "`, [rounding according to the standard]:")]
204 #[doc = concat!(" - If the value is [NaR](Posit::NAR), or if overflows the target type, then it converts to [`", stringify!($t), "::MIN`] (i.e. the value where the most significant bit is 1 and the rest are 0).")]
206 fn round_from(value: Posit<N, ES, Int, RS>) -> Self {
211 if value == Posit::ZERO { return 0 }
212 if value == Posit::NAR { return <$t>::MIN }
213
214 let decoded = unsafe { value.decode_regular() };
216 round_into_kernel(decoded)
217 }
218 }
219 }
220}
221
222make_impl!{i8}
223make_impl!{i16}
224make_impl!{i32}
225make_impl!{i64}
226make_impl!{i128}
227
228#[cfg(test)]
229mod tests {
230 use super::*;
231 use malachite::rational::Rational;
232 use proptest::prelude::*;
233
234 mod int_to_posit {
235 use super::*;
236
237 fn is_correct_rounded<FromInt: crate::Int, const N: u32, const ES: u32, Int: crate::Int, const RS: u32>(
239 int: FromInt,
240 ) -> bool
241 where
242 FromInt: Into<Rational> + RoundInto<Posit<N, ES, Int, RS>>,
243 Rational: TryFrom<Posit<N, ES, Int, RS>, Error = super::rational::IsNaR>,
244 {
245 let posit: Posit<N, ES, Int, RS> = int.round_into();
246 if int == FromInt::MIN {
247 posit == Posit::NAR
248 } else {
249 let exact: Rational = int.into();
250 super::rational::is_correct_rounded(exact, posit)
251 }
252 }
253
254 macro_rules! make_exhaustive {
255 ($t:ident) => {
256 mod $t {
257 use super::*;
258
259 #[test]
260 fn posit_10_0_exhaustive() {
261 for int in $t::MIN ..= $t::MAX {
262 assert!(is_correct_rounded::<$t, 10, 0, i16, 10>(int), "{:?}", int)
263 }
264 }
265
266 #[test]
267 fn posit_10_1_exhaustive() {
268 for int in $t::MIN ..= $t::MAX {
269 assert!(is_correct_rounded::<$t, 10, 1, i16, 10>(int), "{:?}", int)
270 }
271 }
272
273 #[test]
274 fn posit_10_2_exhaustive() {
275 for int in $t::MIN ..= $t::MAX {
276 assert!(is_correct_rounded::<$t, 10, 2, i16, 10>(int), "{:?}", int)
277 }
278 }
279
280 #[test]
281 fn posit_10_3_exhaustive() {
282 for int in $t::MIN ..= $t::MAX {
283 assert!(is_correct_rounded::<$t, 10, 3, i16, 10>(int), "{:?}", int)
284 }
285 }
286
287 #[test]
288 fn posit_8_0_exhaustive() {
289 for int in $t::MIN ..= $t::MAX {
290 assert!(is_correct_rounded::<$t, 8, 0, i8, 8>(int), "{:?}", int)
291 }
292 }
293
294 #[test]
295 fn p8_exhaustive() {
296 for int in $t::MIN ..= $t::MAX {
297 assert!(is_correct_rounded::<$t, 8, 2, i8, 8>(int), "{:?}", int)
298 }
299 }
300
301 #[test]
302 fn p16_exhaustive() {
303 for int in $t::MIN ..= $t::MAX {
304 assert!(is_correct_rounded::<$t, 16, 2, i16, 16>(int), "{:?}", int)
305 }
306 }
307
308 #[test]
309 fn p32_exhaustive() {
310 for int in $t::MIN ..= $t::MAX {
311 assert!(is_correct_rounded::<$t, 32, 2, i32, 32>(int), "{:?}", int)
312 }
313 }
314
315 #[test]
316 fn p64_exhaustive() {
317 for int in $t::MIN ..= $t::MAX {
318 assert!(is_correct_rounded::<$t, 64, 2, i64, 64>(int), "{:?}", int)
319 }
320 }
321
322 #[test]
323 fn posit_3_0_exhaustive() {
324 for int in $t::MIN ..= $t::MAX {
325 assert!(is_correct_rounded::<$t, 3, 0, i8, 3>(int), "{:?}", int)
326 }
327 }
328
329 #[test]
330 fn posit_4_0_exhaustive() {
331 for int in $t::MIN ..= $t::MAX {
332 assert!(is_correct_rounded::<$t, 4, 0, i8, 4>(int), "{:?}", int)
333 }
334 }
335
336 #[test]
337 fn posit_4_1_exhaustive() {
338 for int in $t::MIN ..= $t::MAX {
339 assert!(is_correct_rounded::<$t, 4, 1, i8, 4>(int), "{:?}", int)
340 }
341 }
342
343 #[test]
344 fn bposit_8_3_6_proptest() {
345 for int in $t::MIN ..= $t::MAX {
346 assert!(is_correct_rounded::<$t, 8, 3, i8, 6>(int), "{:?}", int)
347 }
348 }
349
350 #[test]
351 fn bposit_16_5_6_proptest() {
352 for int in $t::MIN ..= $t::MAX {
353 assert!(is_correct_rounded::<$t, 16, 5, i16, 6>(int), "{:?}", int)
354 }
355 }
356
357 #[test]
358 fn bposit_32_5_6_proptest() {
359 for int in $t::MIN ..= $t::MAX {
360 assert!(is_correct_rounded::<$t, 32, 5, i32, 6>(int), "{:?}", int)
361 }
362 }
363
364 #[test]
365 fn bposit_64_5_6_proptest() {
366 for int in $t::MIN ..= $t::MAX {
367 assert!(is_correct_rounded::<$t, 64, 5, i64, 6>(int), "{:?}", int)
368 }
369 }
370
371 #[test]
372 fn bposit_10_2_6_proptest() {
373 for int in $t::MIN ..= $t::MAX {
374 assert!(is_correct_rounded::<$t, 10, 2, i16, 6>(int), "{:?}", int)
375 }
376 }
377
378 #[test]
379 fn bposit_10_2_7_proptest() {
380 for int in $t::MIN ..= $t::MAX {
381 assert!(is_correct_rounded::<$t, 10, 2, i16, 7>(int), "{:?}", int)
382 }
383 }
384
385 #[test]
386 fn bposit_10_2_8_proptest() {
387 for int in $t::MIN ..= $t::MAX {
388 assert!(is_correct_rounded::<$t, 10, 2, i16, 8>(int), "{:?}", int)
389 }
390 }
391
392 #[test]
393 fn bposit_10_2_9_proptest() {
394 for int in $t::MIN ..= $t::MAX {
395 assert!(is_correct_rounded::<$t, 10, 2, i16, 9>(int), "{:?}", int)
396 }
397 }
398 }
399 }
400 }
401
402 macro_rules! make_proptest {
403 ($t:ident) => {
404 mod $t {
405 use super::*;
406
407 proptest!{
408 #![proptest_config(ProptestConfig::with_cases(crate::PROPTEST_CASES))]
409
410 #[test]
411 fn posit_10_0_proptest(int in any::<$t>()) {
412 assert!(is_correct_rounded::<$t, 10, 0, i16, 10>(int), "{:?}", int)
413 }
414
415 #[test]
416 fn posit_10_1_proptest(int in any::<$t>()) {
417 assert!(is_correct_rounded::<$t, 10, 1, i16, 10>(int), "{:?}", int)
418 }
419
420 #[test]
421 fn posit_10_2_proptest(int in any::<$t>()) {
422 assert!(is_correct_rounded::<$t, 10, 2, i16, 10>(int), "{:?}", int)
423 }
424
425 #[test]
426 fn posit_10_3_proptest(int in any::<$t>()) {
427 assert!(is_correct_rounded::<$t, 10, 3, i16, 10>(int), "{:?}", int)
428 }
429
430 #[test]
431 fn posit_8_0_proptest(int in any::<$t>()) {
432 assert!(is_correct_rounded::<$t, 8, 0, i8, 8>(int), "{:?}", int)
433 }
434
435 #[test]
436 fn p8_proptest(int in any::<$t>()) {
437 assert!(is_correct_rounded::<$t, 8, 2, i8, 8>(int), "{:?}", int)
438 }
439
440 #[test]
441 fn p16_proptest(int in any::<$t>()) {
442 assert!(is_correct_rounded::<$t, 16, 2, i16, 16>(int), "{:?}", int)
443 }
444
445 #[test]
446 fn p32_proptest(int in any::<$t>()) {
447 assert!(is_correct_rounded::<$t, 32, 2, i32, 32>(int), "{:?}", int)
448 }
449
450 #[test]
451 fn p64_proptest(int in any::<$t>()) {
452 assert!(is_correct_rounded::<$t, 64, 2, i64, 64>(int), "{:?}", int)
453 }
454
455 #[test]
456 fn posit_3_0_proptest(int in any::<$t>()) {
457 assert!(is_correct_rounded::<$t, 3, 0, i8, 3>(int), "{:?}", int)
458 }
459
460 #[test]
461 fn posit_4_0_proptest(int in any::<$t>()) {
462 assert!(is_correct_rounded::<$t, 4, 0, i8, 4>(int), "{:?}", int)
463 }
464
465 #[test]
466 fn posit_4_1_proptest(int in any::<$t>()) {
467 assert!(is_correct_rounded::<$t, 4, 1, i8, 4>(int), "{:?}", int)
468 }
469
470 #[test]
471 fn bposit_8_3_6_proptest(int in any::<$t>()) {
472 assert!(is_correct_rounded::<$t, 8, 3, i8, 6>(int), "{:?}", int)
473 }
474
475 #[test]
476 fn bposit_16_5_6_proptest(int in any::<$t>()) {
477 assert!(is_correct_rounded::<$t, 16, 5, i16, 6>(int), "{:?}", int)
478 }
479
480 #[test]
481 fn bposit_32_5_6_proptest(int in any::<$t>()) {
482 assert!(is_correct_rounded::<$t, 32, 5, i32, 6>(int), "{:?}", int)
483 }
484
485 #[test]
486 fn bposit_64_5_6_proptest(int in any::<$t>()) {
487 assert!(is_correct_rounded::<$t, 64, 5, i64, 6>(int), "{:?}", int)
488 }
489
490 #[test]
491 fn bposit_10_2_6_proptest(int in any::<$t>()) {
492 assert!(is_correct_rounded::<$t, 10, 2, i16, 6>(int), "{:?}", int)
493 }
494
495 #[test]
496 fn bposit_10_2_7_proptest(int in any::<$t>()) {
497 assert!(is_correct_rounded::<$t, 10, 2, i16, 7>(int), "{:?}", int)
498 }
499
500 #[test]
501 fn bposit_10_2_8_proptest(int in any::<$t>()) {
502 assert!(is_correct_rounded::<$t, 10, 2, i16, 8>(int), "{:?}", int)
503 }
504
505 #[test]
506 fn bposit_10_2_9_proptest(int in any::<$t>()) {
507 assert!(is_correct_rounded::<$t, 10, 2, i16, 9>(int), "{:?}", int)
508 }
509 }
510 }
511 }
512 }
513
514 make_exhaustive!{i8}
515 make_exhaustive!{i16}
516 make_proptest!{i32}
517 make_proptest!{i64}
518 make_proptest!{i128}
519 }
520
521 mod posit_to_int {
522 use super::*;
523
524 fn is_correct_rounded<ToInt: crate::Int, const N: u32, const ES: u32, Int: crate::Int, const RS: u32>(
526 posit: Posit<N, ES, Int, RS>,
527 int: ToInt,
528 ) -> bool
529 where
530 ToInt: RoundFrom<Posit<N, ES, Int, RS>>,
531 Rational: From<i32> + From<ToInt> + TryFrom<Posit<N, ES, Int, RS>, Error = super::rational::IsNaR>,
532 {
534 match Rational::try_from(posit) {
535 Ok(exact) => {
536 use malachite::base::num::arithmetic::traits::RoundToMultiple;
537 use malachite::base::rounding_modes::RoundingMode;
538 let rounded = exact.round_to_multiple(Rational::from(1), RoundingMode::Nearest).0;
539 if rounded > Rational::from(ToInt::MAX) {
540 int == ToInt::MIN
541 } else if rounded < Rational::from(ToInt::MIN) {
542 int == ToInt::MIN
543 } else {
544 Rational::from(int) == rounded
545 }
546 },
547 Err(super::rational::IsNaR) => {
548 int == ToInt::MIN
549 }
550 }
551 }
552
553 macro_rules! make_exhaustive {
554 ($name:ident, $t:ty) => {
555 mod $name {
556 use super::*;
557
558 #[test]
559 fn i8_exhaustive() {
560 for p in <$t>::cases_exhaustive_all() {
561 let int: i8 = p.round_into();
562 assert!(is_correct_rounded(p, int), "{p:?} {int}");
563 }
564 }
565
566 #[test]
567 fn i16_exhaustive() {
568 for p in <$t>::cases_exhaustive_all() {
569 let int: i16 = p.round_into();
570 assert!(is_correct_rounded(p, int), "{p:?} {int}");
571 }
572 }
573
574 #[test]
575 fn i32_exhaustive() {
576 for p in <$t>::cases_exhaustive_all() {
577 let int: i32 = p.round_into();
578 assert!(is_correct_rounded(p, int), "{p:?} {int}");
579 }
580 }
581
582 #[test]
583 fn i64_exhaustive() {
584 for p in <$t>::cases_exhaustive_all() {
585 let int: i64 = p.round_into();
586 assert!(is_correct_rounded(p, int), "{p:?} {int}");
587 }
588 }
589
590 #[test]
591 fn i128_exhaustive() {
592 for p in <$t>::cases_exhaustive_all() {
593 let int: i128 = p.round_into();
594 assert!(is_correct_rounded(p, int), "{p:?} {int}");
595 }
596 }
597 }
598 }
599 }
600
601 macro_rules! make_proptest {
602 ($name:ident, $t:ty) => {
603 mod $name {
604 use super::*;
605
606 proptest!{
607 #![proptest_config(ProptestConfig::with_cases(crate::PROPTEST_CASES))]
608
609 #[test]
610 fn i8_proptest(p in <$t>::cases_proptest_all()) {
611 let int: i8 = p.round_into();
612 assert!(is_correct_rounded(p, int), "{p:?} {int}");
613 }
614
615 #[test]
616 fn i16_proptest(p in <$t>::cases_proptest_all()) {
617 let int: i16 = p.round_into();
618 assert!(is_correct_rounded(p, int), "{p:?} {int}");
619 }
620
621 #[test]
622 fn i32_proptest(p in <$t>::cases_proptest_all()) {
623 let int: i32 = p.round_into();
624 assert!(is_correct_rounded(p, int), "{p:?} {int}");
625 }
626
627 #[test]
628 fn i64_proptest(p in <$t>::cases_proptest_all()) {
629 let int: i64 = p.round_into();
630 assert!(is_correct_rounded(p, int), "{p:?} {int}");
631 }
632
633 #[test]
634 fn i128_proptest(p in <$t>::cases_proptest_all()) {
635 let int: i128 = p.round_into();
636 assert!(is_correct_rounded(p, int), "{p:?} {int}");
637 }
638 }
639 }
640 }
641 }
642
643 make_exhaustive!{posit_10_0, Posit<10, 0, i16>}
644 make_exhaustive!{posit_10_1, Posit<10, 1, i16>}
645 make_exhaustive!{posit_10_2, Posit<10, 2, i16>}
646 make_exhaustive!{posit_10_3, Posit<10, 3, i16>}
647 make_exhaustive!{posit_8_0, Posit<8, 0, i8 >}
648 make_exhaustive!{p8, crate::p8}
649 make_exhaustive!{p16, crate::p16}
650 make_proptest!{p32, crate::p32}
651 make_proptest!{p64, crate::p64}
652 make_exhaustive!{posit_3_0, Posit::<3, 0, i8>}
653 make_exhaustive!{posit_4_0, Posit::<4, 0, i8>}
654 make_exhaustive!{posit_4_1, Posit::<4, 1, i8>}
655 make_exhaustive!{bposit_8_3_6, Posit::<8, 3, i8, 6>}
656 make_exhaustive!{bposit_16_5_6, Posit::<16, 5, i16, 6>}
657 make_proptest!{bposit_32_5_6, Posit::<32, 5, i32, 6>}
658 make_proptest!{bposit_64_5_6, Posit::<64, 5, i64, 6>}
659 make_exhaustive!{bposit_10_2_6, Posit::<10, 2, i16, 6>}
660 make_exhaustive!{bposit_10_2_7, Posit::<10, 2, i16, 7>}
661 make_exhaustive!{bposit_10_2_8, Posit::<10, 2, i16, 8>}
662 make_exhaustive!{bposit_10_2_9, Posit::<10, 2, i16, 9>}
663 }
664}