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>(int: FromInt) -> (Decoded<N, ES, Int>, Int) {
18 let shift_right = if const { Int::BITS >= FromInt::BITS } {0} else {FromInt::BITS - Int::BITS};
22
23 let shift_left = if const { Int::BITS <= FromInt::BITS } {0} else {Int::BITS - FromInt::BITS};
26
27 let underflow = unsafe { int.leading_run_minus_one() };
44 let frac = const_as::<FromInt, Int>(int << underflow >> shift_right) << shift_left;
45 let exp = {
46 let exp = Decoded::<N, ES, FromInt>::FRAC_WIDTH.wrapping_sub(underflow);
47 const_as::<i32, Int>(exp as i32)
48 };
49 let sticky = {
50 let true_shift = shift_right.saturating_sub(underflow);
51 Int::from(int.mask_lsb(true_shift) != FromInt::ZERO)
52 };
53
54 (Decoded{frac, exp}, sticky)
55}
56
57#[inline]
59fn round_into_kernel<
60 ToInt: crate::Int,
61 const N: u32,
62 const ES: u32,
63 Int: crate::Int,
64>(decoded: Decoded<N, ES, Int>) -> ToInt {
65 let diff_right = if const { ToInt::BITS >= Int::BITS } {0} else {Int::BITS - ToInt::BITS};
69
70 let diff_left = if const { ToInt::BITS <= Int::BITS } {0} else {ToInt::BITS - Int::BITS};
73
74 let shift = Int::of_u32(Decoded::<N, ES, Int>::FRAC_WIDTH).wrapping_sub(decoded.exp);
113
114 if shift < Int::ZERO {
116 let shift_left = (-shift).as_u32();
117 if shift_left > diff_left {
118 return ToInt::MIN;
120 }
121 const_as::<Int, ToInt>(decoded.frac) << shift_left
122 }
123 else if shift == Int::ZERO {
125 if diff_right != 0 {
126 return ToInt::MIN;
128 }
129 const_as::<Int, ToInt>(decoded.frac)
130 }
131 else {
134 let shift_right = shift.as_u32();
135 if shift_right > Int::BITS {
136 return ToInt::ZERO;
138 }
139 if shift_right < diff_right {
140 return ToInt::MIN;
142 }
143 let sticky = decoded.frac.mask_lsb(shift_right - 1);
145 let int = decoded.frac >> (shift_right - 1);
146 let round = int.get_lsb();
147 let int = int >> 1;
148 let odd = int.get_lsb();
149 let round_up: bool = round & (odd | (sticky != Int::ZERO));
156 const_as::<Int, ToInt>(int).wrapping_add(ToInt::from(round_up))
157 }
158}
159
160macro_rules! make_impl {
161 ($t:ty) => {
162 impl<
163 const N: u32,
164 const ES: u32,
165 Int: crate::Int,
166 > RoundFrom<$t> for Posit<N, ES, Int> {
167 #[doc = concat!("Convert an `", stringify!($t), "` into a `Posit`, [rounding according to the standard]:")]
168 #[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).")]
170 fn round_from(value: $t) -> Self {
174 if value == 0 { return Posit::ZERO }
177 if value == <$t>::MIN { return Posit::NAR }
178
179 if const { <$t>::BITS as i128 > 1 << Decoded::<N, ES, Int>::FRAC_WIDTH } {
182 let limit = 1 << (1 << Decoded::<N, ES, Int>::FRAC_WIDTH);
183 if value >= limit { return Posit::MAX }
184 if value <= -limit { return Posit::MIN }
185 }
186
187 let (result, sticky) = unsafe { round_from_kernel(value) };
189 unsafe { result.encode_regular_round(sticky) }
191 }
192 }
193
194 impl<
195 const N: u32,
196 const ES: u32,
197 Int: crate::Int,
198 > RoundFrom<Posit<N, ES, Int>> for $t {
199 #[doc = concat!("Convert a `Posit` into an `", stringify!($t), "`, [rounding according to the standard]:")]
200 #[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).")]
202 fn round_from(value: Posit<N, ES, Int>) -> Self {
207 if value == Posit::ZERO { return 0 }
208 if value == Posit::NAR { return <$t>::MIN }
209
210 let decoded = unsafe { value.decode_regular() };
212 round_into_kernel(decoded)
213 }
214 }
215 }
216}
217
218make_impl!{i8}
219make_impl!{i16}
220make_impl!{i32}
221make_impl!{i64}
222make_impl!{i128}
223
224#[cfg(test)]
225mod tests {
226 use super::*;
227 use malachite::rational::Rational;
228 use proptest::prelude::*;
229
230 mod int_to_posit {
231 use super::*;
232
233 fn is_correct_rounded<FromInt: crate::Int, const N: u32, const ES: u32, Int: crate::Int>(
235 int: FromInt,
236 ) -> bool
237 where
238 FromInt: Into<Rational> + RoundInto<Posit<N, ES, Int>>,
239 Rational: TryFrom<Posit<N, ES, Int>, Error = super::rational::IsNaR>,
240 {
241 let posit: Posit<N, ES, Int> = int.round_into();
242 if int == FromInt::MIN {
243 posit == Posit::NAR
244 } else {
245 let exact: Rational = int.into();
246 super::rational::is_correct_rounded(exact, posit)
247 }
248 }
249
250 macro_rules! make_exhaustive {
251 ($t:ident) => {
252 mod $t {
253 use super::*;
254
255 #[test]
256 fn posit_10_0_exhaustive() {
257 for int in $t::MIN ..= $t::MAX {
258 assert!(is_correct_rounded::<$t, 10, 0, i16>(int), "{:?}", int);
259 }
260 }
261
262 #[test]
263 fn posit_10_1_exhaustive() {
264 for int in $t::MIN ..= $t::MAX {
265 assert!(is_correct_rounded::<$t, 10, 1, i16>(int), "{:?}", int);
266 }
267 }
268
269 #[test]
270 fn posit_10_2_exhaustive() {
271 for int in $t::MIN ..= $t::MAX {
272 assert!(is_correct_rounded::<$t, 10, 2, i16>(int), "{:?}", int);
273 }
274 }
275
276 #[test]
277 fn posit_10_3_exhaustive() {
278 for int in $t::MIN ..= $t::MAX {
279 assert!(is_correct_rounded::<$t, 10, 3, i16>(int), "{:?}", int);
280 }
281 }
282
283 #[test]
284 fn posit_8_0_exhaustive() {
285 for int in $t::MIN ..= $t::MAX {
286 assert!(is_correct_rounded::<$t, 8, 0, i8>(int), "{:?}", int);
287 }
288 }
289
290 #[test]
291 fn p8_exhaustive() {
292 for int in $t::MIN ..= $t::MAX {
293 assert!(is_correct_rounded::<$t, 8, 2, i8>(int), "{:?}", int);
294 }
295 }
296
297 #[test]
298 fn p16_exhaustive() {
299 for int in $t::MIN ..= $t::MAX {
300 assert!(is_correct_rounded::<$t, 16, 2, i16>(int), "{:?}", int);
301 }
302 }
303
304 #[test]
305 fn p32_exhaustive() {
306 for int in $t::MIN ..= $t::MAX {
307 assert!(is_correct_rounded::<$t, 32, 2, i32>(int), "{:?}", int);
308 }
309 }
310
311 #[test]
312 fn p64_exhaustive() {
313 for int in $t::MIN ..= $t::MAX {
314 assert!(is_correct_rounded::<$t, 64, 2, i64>(int), "{:?}", int);
315 }
316 }
317
318 #[test]
319 fn posit_3_0_exhaustive() {
320 for int in $t::MIN ..= $t::MAX {
321 assert!(is_correct_rounded::<$t, 3, 0, i8>(int), "{:?}", int);
322 }
323 }
324
325 #[test]
326 fn posit_4_0_exhaustive() {
327 for int in $t::MIN ..= $t::MAX {
328 assert!(is_correct_rounded::<$t, 4, 0, i8>(int), "{:?}", int);
329 }
330 }
331
332 #[test]
333 fn posit_4_1_exhaustive() {
334 for int in $t::MIN ..= $t::MAX {
335 assert!(is_correct_rounded::<$t, 4, 1, i8>(int), "{:?}", int);
336 }
337 }
338 }
339 }
340 }
341
342 macro_rules! make_proptest {
343 ($t:ident) => {
344 mod $t {
345 use super::*;
346
347 proptest!{
348 #![proptest_config(ProptestConfig::with_cases(crate::PROPTEST_CASES))]
349
350 #[test]
351 fn posit_10_0_proptest(int in any::<$t>()) {
352 assert!(is_correct_rounded::<$t, 10, 0, i16>(int), "{:?}", int);
353 }
354
355 #[test]
356 fn posit_10_1_proptest(int in any::<$t>()) {
357 assert!(is_correct_rounded::<$t, 10, 1, i16>(int), "{:?}", int);
358 }
359
360 #[test]
361 fn posit_10_2_proptest(int in any::<$t>()) {
362 assert!(is_correct_rounded::<$t, 10, 2, i16>(int), "{:?}", int);
363 }
364
365 #[test]
366 fn posit_10_3_proptest(int in any::<$t>()) {
367 assert!(is_correct_rounded::<$t, 10, 3, i16>(int), "{:?}", int);
368 }
369
370 #[test]
371 fn posit_8_0_proptest(int in any::<$t>()) {
372 assert!(is_correct_rounded::<$t, 8, 0, i8>(int), "{:?}", int);
373 }
374
375 #[test]
376 fn p8_proptest(int in any::<$t>()) {
377 assert!(is_correct_rounded::<$t, 8, 2, i8>(int), "{:?}", int);
378 }
379
380 #[test]
381 fn p16_proptest(int in any::<$t>()) {
382 assert!(is_correct_rounded::<$t, 16, 2, i16>(int), "{:?}", int);
383 }
384
385 #[test]
386 fn p32_proptest(int in any::<$t>()) {
387 assert!(is_correct_rounded::<$t, 32, 2, i32>(int), "{:?}", int);
388 }
389
390 #[test]
391 fn p64_proptest(int in any::<$t>()) {
392 assert!(is_correct_rounded::<$t, 64, 2, i64>(int), "{:?}", int);
393 }
394
395 #[test]
396 fn posit_3_0_proptest(int in any::<$t>()) {
397 assert!(is_correct_rounded::<$t, 3, 0, i8>(int), "{:?}", int);
398 }
399
400 #[test]
401 fn posit_4_0_proptest(int in any::<$t>()) {
402 assert!(is_correct_rounded::<$t, 4, 0, i8>(int), "{:?}", int);
403 }
404
405 #[test]
406 fn posit_4_1_proptest(int in any::<$t>()) {
407 assert!(is_correct_rounded::<$t, 4, 1, i8>(int), "{:?}", int);
408 }
409 }
410 }
411 }
412 }
413
414 make_exhaustive!{i8}
415 make_exhaustive!{i16}
416 make_proptest!{i32}
417 make_proptest!{i64}
418 make_proptest!{i128}
419 }
420
421 mod posit_to_int {
422 use super::*;
423
424 fn is_correct_rounded<ToInt: crate::Int, const N: u32, const ES: u32, Int: crate::Int>(
426 posit: Posit<N, ES, Int>,
427 int: ToInt,
428 ) -> bool
429 where
430 ToInt: RoundFrom<Posit<N, ES, Int>>,
431 Rational: From<i32> + From<ToInt> + TryFrom<Posit<N, ES, Int>, Error = super::rational::IsNaR>,
432 {
434 match Rational::try_from(posit) {
435 Ok(exact) => {
436 use malachite::base::num::arithmetic::traits::RoundToMultiple;
437 use malachite::base::rounding_modes::RoundingMode;
438 let rounded = exact.round_to_multiple(Rational::from(1), RoundingMode::Nearest).0;
439 if rounded > Rational::from(ToInt::MAX) {
440 int == ToInt::MIN
441 } else if rounded < Rational::from(ToInt::MIN) {
442 int == ToInt::MIN
443 } else {
444 Rational::from(int) == rounded
445 }
446 },
447 Err(super::rational::IsNaR) => {
448 int == ToInt::MIN
449 }
450 }
451 }
452
453 macro_rules! make_exhaustive {
454 ($name:ident, $t:ty) => {
455 mod $name {
456 use super::*;
457
458 #[test]
459 fn i8_exhaustive() {
460 for p in <$t>::cases_exhaustive_all() {
461 let int: i8 = p.round_into();
462 assert!(is_correct_rounded(p, int), "{p:?} {int}");
463 }
464 }
465
466 #[test]
467 fn i16_exhaustive() {
468 for p in <$t>::cases_exhaustive_all() {
469 let int: i16 = p.round_into();
470 assert!(is_correct_rounded(p, int), "{p:?} {int}");
471 }
472 }
473
474 #[test]
475 fn i32_exhaustive() {
476 for p in <$t>::cases_exhaustive_all() {
477 let int: i32 = p.round_into();
478 assert!(is_correct_rounded(p, int), "{p:?} {int}");
479 }
480 }
481
482 #[test]
483 fn i64_exhaustive() {
484 for p in <$t>::cases_exhaustive_all() {
485 let int: i64 = p.round_into();
486 assert!(is_correct_rounded(p, int), "{p:?} {int}");
487 }
488 }
489
490 #[test]
491 fn i128_exhaustive() {
492 for p in <$t>::cases_exhaustive_all() {
493 let int: i128 = p.round_into();
494 assert!(is_correct_rounded(p, int), "{p:?} {int}");
495 }
496 }
497 }
498 }
499 }
500
501 macro_rules! make_proptest {
502 ($name:ident, $t:ty) => {
503 mod $name {
504 use super::*;
505
506 proptest!{
507 #![proptest_config(ProptestConfig::with_cases(crate::PROPTEST_CASES))]
508
509 #[test]
510 fn i8_proptest(p in <$t>::cases_proptest_all()) {
511 let int: i8 = p.round_into();
512 assert!(is_correct_rounded(p, int), "{p:?} {int}");
513 }
514
515 #[test]
516 fn i16_proptest(p in <$t>::cases_proptest_all()) {
517 let int: i16 = p.round_into();
518 assert!(is_correct_rounded(p, int), "{p:?} {int}");
519 }
520
521 #[test]
522 fn i32_proptest(p in <$t>::cases_proptest_all()) {
523 let int: i32 = p.round_into();
524 assert!(is_correct_rounded(p, int), "{p:?} {int}");
525 }
526
527 #[test]
528 fn i64_proptest(p in <$t>::cases_proptest_all()) {
529 let int: i64 = p.round_into();
530 assert!(is_correct_rounded(p, int), "{p:?} {int}");
531 }
532
533 #[test]
534 fn i128_proptest(p in <$t>::cases_proptest_all()) {
535 let int: i128 = p.round_into();
536 assert!(is_correct_rounded(p, int), "{p:?} {int}");
537 }
538 }
539 }
540 }
541 }
542
543 make_exhaustive!{posit_10_0, Posit<10, 0, i16>}
544 make_exhaustive!{posit_10_1, Posit<10, 1, i16>}
545 make_exhaustive!{posit_10_2, Posit<10, 2, i16>}
546 make_exhaustive!{posit_10_3, Posit<10, 3, i16>}
547 make_exhaustive!{posit_8_0, Posit<8, 0, i8 >}
548 make_exhaustive!{p8, crate::p8}
549 make_exhaustive!{p16, crate::p16}
550 make_proptest!{p32, crate::p32}
551 make_proptest!{p64, crate::p64}
552 make_exhaustive!{posit_3_0, Posit::<3, 0, i8>}
553 make_exhaustive!{posit_4_0, Posit::<4, 0, i8>}
554 make_exhaustive!{posit_4_1, Posit::<4, 1, i8>}
555 }
556}