use super::*;
use crate::underlying::const_as;
impl<
const N1: u32,
const ES1: u32,
Int1: crate::Int,
const RS1: u32,
> Posit<N1, ES1, Int1, RS1> {
fn round_from_fast<
const N2: u32,
const ES2: u32,
Int2: crate::Int,
const RS2: u32,
>(self) -> Posit<N2, ES2, Int2, RS2> {
if const { ES1 != ES2 || RS1 != RS2 } { unimplemented!() }
if const { N1 <= N2 } {
let bits = const_as::<Int1, Int2>(self.to_bits()) << (N2 - N1);
unsafe { Posit::from_bits_unchecked(bits) }
} else {
let sticky: Int2 = Int2::from(self.to_bits().mask_lsb(N1 - N2 - 1) != Int1::ZERO);
let round: Int2 = const_as(self.to_bits() >> (N1 - N2 - 1));
let bits = const_as::<Int1, Int2>(self.to_bits() >> (N1 - N2));
let round_up = round & (bits | sticky) & Int2::ONE;
let is_special = Posit::<N2, ES2, Int2, RS2>::from_bits(bits).is_special();
let round_up = round_up | ((round | sticky) & Int2::from(is_special));
let bits_rounded = Posit::<N2, ES2, Int2, RS2>::sign_extend(bits.wrapping_add(round_up));
let overflow = !(bits_rounded ^ bits).is_positive();
Posit::from_bits(bits_rounded.wrapping_sub(Int2::from(overflow)))
}
}
fn round_from_slow<
const N2: u32,
const ES2: u32,
Int2: crate::Int,
const RS2: u32,
>(self) -> Posit<N2, ES2, Int2, RS2> {
if self == Self::ZERO {
Posit::ZERO
} else if self == Self::NAR {
Posit::NAR
} else {
let decoded = unsafe { self.decode_regular() };
let shift_right = if const { Int1::BITS <= Int2::BITS } {0} else {Int1::BITS - Int2::BITS};
let shift_left = if const { Int1::BITS >= Int2::BITS } {0} else {Int2::BITS - Int1::BITS};
let frac = const_as::<Int1, Int2>(decoded.frac >> shift_right) << shift_left;
let exp = const_as::<Int1, Int2>(decoded.exp);
let sticky = Int2::from(decoded.frac.mask_lsb(shift_right) != Int1::ZERO);
if Int1::BITS > Int2::BITS
&& Self::MAX_EXP >= const_as(Decoded::<N2, ES2, N2, Int2>::FRAC_DENOM)
&& decoded.exp.abs() >= const_as(Decoded::<N2, ES2, N2, Int2>::FRAC_DENOM) {
let exp = Decoded::<N2, ES2, N2, Int2>::FRAC_DENOM - Int2::ONE;
let exp = if decoded.exp.is_positive() {exp} else {-exp};
return unsafe { Decoded{frac, exp}.encode_regular() }
}
unsafe { Decoded{frac, exp}.encode_regular_round(sticky) }
}
}
}
impl<
const N: u32,
const ES: u32,
Int: crate::Int,
const RS: u32,
> Posit<N, ES, Int, RS> {
pub fn convert<
const N2: u32,
const ES2: u32,
Int2: crate::Int,
const RS2: u32,
>(self) -> Posit<N2, ES2, Int2, RS2> {
if const { ES == ES2 && RS == RS2 } {
self.round_from_fast()
} else {
self.round_from_slow()
}
}
}
#[cfg(test)]
#[allow(non_camel_case_types)]
mod tests {
use super::*;
use malachite::rational::Rational;
use proptest::prelude::*;
macro_rules! test_exhaustive {
($name: ident, $src:ty, $dst:ty) => {
#[test]
fn $name() {
for src in <$src>::cases_exhaustive_all() {
let dst: $dst = src.convert();
assert!(super::rational::try_is_correct_rounded(Rational::try_from(src), dst))
}
}
};
}
macro_rules! test_proptest {
($name: ident, $src:ty, $dst:ty) => {
proptest!{
#![proptest_config(ProptestConfig::with_cases(crate::PROPTEST_CASES))]
#[test]
fn $name(src in <$src>::cases_proptest_all()) {
let dst: $dst = src.convert();
assert!(super::rational::try_is_correct_rounded(Rational::try_from(src), dst))
}
}
};
}
macro_rules! suite_exhaustive {
($name_src:ident, $src:ty) => {
mod $name_src {
use super::*;
test_exhaustive!{posit_10_0_exhaustive, $src, Posit<10, 0, i16>}
test_exhaustive!{posit_10_1_exhaustive, $src, Posit<10, 1, i16>}
test_exhaustive!{posit_10_2_exhaustive, $src, Posit<10, 2, i16>}
test_exhaustive!{posit_10_3_exhaustive, $src, Posit<10, 3, i16>}
test_exhaustive!{posit_8_0_exhaustive, $src, Posit<8, 0, i8>}
test_exhaustive!{posit_20_4_exhaustive, $src, Posit<20, 4, i32>}
test_exhaustive!{p8_exhaustive, $src, crate::p8}
test_exhaustive!{p16_exhaustive, $src, crate::p16}
test_exhaustive!{p32_exhaustive, $src, crate::p32}
test_exhaustive!{p64_exhaustive, $src, crate::p64}
test_exhaustive!{posit_3_0_exhaustive, $src, Posit<3, 0, i8>}
test_exhaustive!{posit_4_0_exhaustive, $src, Posit<4, 0, i8>}
test_exhaustive!{posit_4_1_exhaustive, $src, Posit<4, 1, i8>}
test_exhaustive!{bposit_8_3_6_exhaustive, $src, Posit::<8, 3, i8, 6>}
test_exhaustive!{bposit_16_5_6_exhaustive, $src, Posit::<16, 5, i16, 6>}
test_exhaustive!{bposit_32_5_6_exhaustive, $src, Posit::<32, 5, i32, 6>}
test_exhaustive!{bposit_64_5_6_exhaustive, $src, Posit::<64, 5, i64, 6>}
test_exhaustive!{bposit_10_2_6_exhaustive, $src, Posit::<10, 2, i16, 6>}
test_exhaustive!{bposit_10_2_7_exhaustive, $src, Posit::<10, 2, i16, 7>}
test_exhaustive!{bposit_10_2_8_exhaustive, $src, Posit::<10, 2, i16, 8>}
test_exhaustive!{bposit_10_2_9_exhaustive, $src, Posit::<10, 2, i16, 9>}
}
};
}
macro_rules! suite_proptest {
($name_src:ident, $src:ty) => {
mod $name_src {
use super::*;
test_proptest!{posit_10_0_proptest, $src, Posit<10, 0, i16>}
test_proptest!{posit_10_1_proptest, $src, Posit<10, 1, i16>}
test_proptest!{posit_10_2_proptest, $src, Posit<10, 2, i16>}
test_proptest!{posit_10_3_proptest, $src, Posit<10, 3, i16>}
test_proptest!{posit_8_0_proptest, $src, Posit<8, 0, i8>}
test_proptest!{posit_20_4_proptest, $src, Posit<20, 4, i32>}
test_proptest!{p8_proptest, $src, crate::p8}
test_proptest!{p16_proptest, $src, crate::p16}
test_proptest!{p32_proptest, $src, crate::p32}
test_proptest!{p64_proptest, $src, crate::p64}
test_proptest!{posit_3_0_proptest, $src, Posit<3, 0, i8>}
test_proptest!{posit_4_0_proptest, $src, Posit<4, 0, i8>}
test_proptest!{posit_4_1_proptest, $src, Posit<4, 1, i8>}
test_proptest!{bposit_8_3_6_proptest, $src, Posit::<8, 3, i8, 6>}
test_proptest!{bposit_16_5_6_proptest, $src, Posit::<16, 5, i16, 6>}
test_proptest!{bposit_32_5_6_proptest, $src, Posit::<32, 5, i32, 6>}
test_proptest!{bposit_64_5_6_proptest, $src, Posit::<64, 5, i64, 6>}
test_proptest!{bposit_10_2_6_proptest, $src, Posit::<10, 2, i16, 6>}
test_proptest!{bposit_10_2_7_proptest, $src, Posit::<10, 2, i16, 7>}
test_proptest!{bposit_10_2_8_proptest, $src, Posit::<10, 2, i16, 8>}
test_proptest!{bposit_10_2_9_proptest, $src, Posit::<10, 2, i16, 9>}
}
};
}
suite_exhaustive!{posit_10_0, Posit<10, 0, i16>}
suite_exhaustive!{posit_10_1, Posit<10, 1, i16>}
suite_exhaustive!{posit_10_2, Posit<10, 2, i16>}
suite_exhaustive!{posit_10_3, Posit<10, 3, i16>}
suite_exhaustive!{posit_8_0, Posit<8, 0, i8>}
suite_exhaustive!{posit_20_4, Posit<20, 4, i32>}
suite_exhaustive!{p8, crate::p8}
suite_exhaustive!{p16, crate::p16}
suite_proptest!{p32, crate::p32}
suite_proptest!{p64, crate::p64}
suite_exhaustive!{posit_3_0, Posit<3, 0, i8>}
suite_exhaustive!{posit_4_0, Posit<4, 0, i8>}
suite_exhaustive!{posit_4_1, Posit<4, 1, i8>}
suite_exhaustive!{bposit_8_3_6_exhaustive, Posit::<8, 3, i8, 6>}
suite_exhaustive!{bposit_16_5_6_exhaustive, Posit::<16, 5, i16, 6>}
suite_proptest!{bposit_32_5_6_proptest, Posit::<32, 5, i32, 6>}
suite_proptest!{bposit_64_5_6_proptest, Posit::<64, 5, i64, 6>}
suite_exhaustive!{bposit_10_2_6_exhaustive, Posit::<10, 2, i16, 6>}
suite_exhaustive!{bposit_10_2_7_exhaustive, Posit::<10, 2, i16, 7>}
suite_exhaustive!{bposit_10_2_8_exhaustive, Posit::<10, 2, i16, 8>}
suite_exhaustive!{bposit_10_2_9_exhaustive, Posit::<10, 2, i16, 9>}
}