use super::*;
impl<
const N: u32,
const ES: u32,
Int: crate::Int,
const RS: u32,
> Posit<N, ES, Int, RS> {
pub fn nearest_int(self) -> Self {
if self.is_special() { return self }
let decoded = unsafe { self.decode_regular() };
let integral_bits = (Int::ONE + Int::ONE).wrapping_add(decoded.exp);
if integral_bits <= Int::ZERO {
return Posit::ZERO
}
if integral_bits >= Int::of_u32(Int::BITS) {
return self;
}
let integral_bits = integral_bits.as_u32();
let fractional_bits = Int::BITS - integral_bits;
let integral = decoded.frac >> fractional_bits;
let fractional = decoded.frac << integral_bits;
let round = !fractional.is_positive();
let sticky = fractional << 1 != Int::ZERO;
let odd = integral.get_lsb();
let round_up: bool = round & (odd | sticky);
let integral_rounded = integral + Int::from(round_up);
if integral_rounded == Int::ZERO {
return Posit::ZERO
}
let true_fractional_bits = unsafe { integral_rounded.leading_run_minus_one() };
let frac = integral_rounded << true_fractional_bits;
let exp = decoded.exp + (Int::of_u32(fractional_bits) - Int::of_u32(true_fractional_bits));
unsafe { Decoded { frac, exp }.encode_regular() }
}
pub fn floor(self) -> Self {
if self.is_special() { return self }
let decoded = unsafe { self.decode_regular() };
let integral_bits = (Int::ONE + Int::ONE).wrapping_add(decoded.exp);
if integral_bits <= Int::ZERO {
return if self >= Posit::ZERO {Posit::ZERO} else {Posit::MINUS_ONE}
}
if integral_bits >= Int::of_u32(Int::BITS) {
return self;
}
let integral_bits = integral_bits.as_u32();
let frac = decoded.frac.mask_msb(integral_bits);
let exp = decoded.exp;
if frac == Int::ZERO {
return Posit::ZERO
}
unsafe { Decoded { frac, exp }.encode_regular() }
}
pub fn ceil(self) -> Self {
if self.is_special() { return self }
let decoded = unsafe { self.decode_regular() };
let integral_bits = (Int::ONE + Int::ONE).wrapping_add(decoded.exp);
if integral_bits <= Int::ZERO {
return if self >= Posit::ZERO {Posit::ONE} else {Posit::ZERO}
}
if integral_bits >= Int::of_u32(Int::BITS) {
return self;
}
let integral_bits = integral_bits.as_u32();
let fractional_bits = Int::BITS - integral_bits;
let integral = decoded.frac >> fractional_bits;
let fractional = decoded.frac << integral_bits;
let round_up: bool = fractional != Int::ZERO;
let integral_rounded = integral + Int::from(round_up);
if integral_rounded == Int::ZERO {
return Posit::ZERO
}
let true_fractional_bits = unsafe { integral_rounded.leading_run_minus_one() };
let frac = integral_rounded << true_fractional_bits;
let exp = decoded.exp + (Int::of_u32(fractional_bits) - Int::of_u32(true_fractional_bits));
unsafe { Decoded { frac, exp }.encode_regular() }
}
}
#[cfg(test)]
mod tests {
use super::*;
use malachite::rational::Rational;
use proptest::prelude::*;
use malachite::base::rounding_modes::RoundingMode;
fn is_correct_rounded<const N: u32, const ES: u32, Int: crate::Int, const RS: u32>(
posit: Posit<N, ES, Int, RS>,
rounded_posit: Posit<N, ES, Int, RS>,
rounding_mode: RoundingMode,
) -> bool
where
Rational: From<i32> + TryFrom<Posit<N, ES, Int, RS>, Error = super::rational::IsNaR>,
{
use malachite::base::num::arithmetic::traits::RoundToMultiple;
let posit = Rational::try_from(posit)
.map(|exact| exact.round_to_multiple(Rational::from(1), rounding_mode).0);
let rounded_posit = Rational::try_from(rounded_posit);
posit == rounded_posit
}
mod nearest_int {
use super::*;
macro_rules! test_exhaustive {
($name:ident, $posit:ty) => {
#[test]
fn $name() {
for p in <$posit>::cases_exhaustive_all() {
let rounded = p.nearest_int();
assert!(is_correct_rounded(p, rounded, RoundingMode::Nearest), "{p:?} {rounded:?}")
}
}
};
}
macro_rules! test_proptest {
($name:ident, $posit:ty) => {
proptest!{
#![proptest_config(ProptestConfig::with_cases(crate::PROPTEST_CASES))]
#[test]
fn $name(p in <$posit>::cases_proptest_all()) {
let rounded = p.nearest_int();
assert!(is_correct_rounded(p, rounded, RoundingMode::Nearest), "{p:?} {rounded:?}")
}
}
};
}
test_exhaustive!{posit_10_0_exhaustive, Posit<10, 0, i16>}
test_exhaustive!{posit_10_1_exhaustive, Posit<10, 1, i16>}
test_exhaustive!{posit_10_2_exhaustive, Posit<10, 2, i16>}
test_exhaustive!{posit_10_3_exhaustive, Posit<10, 3, i16>}
test_exhaustive!{posit_8_0_exhaustive, Posit<8, 0, i8 >}
test_exhaustive!{p8_exhaustive, crate::p8}
test_exhaustive!{p16_exhaustive, crate::p16}
test_proptest!{p32_proptest, crate::p32}
test_proptest!{p64_proptest, crate::p64}
test_exhaustive!{posit_3_0_exhaustive, Posit::<3, 0, i8>}
test_exhaustive!{posit_4_0_exhaustive, Posit::<4, 0, i8>}
test_exhaustive!{posit_4_1_exhaustive, Posit::<4, 1, i8>}
test_exhaustive!{bposit_8_3_6_exhaustive, Posit::<8, 3, i8, 6>}
test_exhaustive!{bposit_16_5_6_exhaustive, Posit::<16, 5, i16, 6>}
test_proptest!{bposit_32_5_6_proptest, Posit::<32, 5, i32, 6>}
test_proptest!{bposit_64_5_6_proptest, Posit::<64, 5, i64, 6>}
test_exhaustive!{bposit_10_2_6_exhaustive, Posit::<10, 2, i16, 7>}
test_exhaustive!{bposit_10_2_7_exhaustive, Posit::<10, 2, i16, 7>}
test_exhaustive!{bposit_10_2_8_exhaustive, Posit::<10, 2, i16, 8>}
test_exhaustive!{bposit_10_2_9_exhaustive, Posit::<10, 2, i16, 9>}
}
mod floor {
use super::*;
macro_rules! test_exhaustive {
($name:ident, $posit:ty) => {
#[test]
fn $name() {
for p in <$posit>::cases_exhaustive_all() {
let rounded = p.floor();
assert!(is_correct_rounded(p, rounded, RoundingMode::Floor), "{p:?} {rounded:?}")
}
}
};
}
macro_rules! test_proptest {
($name:ident, $posit:ty) => {
proptest!{
#![proptest_config(ProptestConfig::with_cases(crate::PROPTEST_CASES))]
#[test]
fn $name(p in <$posit>::cases_proptest_all()) {
let rounded = p.floor();
assert!(is_correct_rounded(p, rounded, RoundingMode::Floor), "{p:?} {rounded:?}")
}
}
};
}
test_exhaustive!{posit_10_0_exhaustive, Posit<10, 0, i16>}
test_exhaustive!{posit_10_1_exhaustive, Posit<10, 1, i16>}
test_exhaustive!{posit_10_2_exhaustive, Posit<10, 2, i16>}
test_exhaustive!{posit_10_3_exhaustive, Posit<10, 3, i16>}
test_exhaustive!{posit_8_0_exhaustive, Posit<8, 0, i8 >}
test_exhaustive!{p8_exhaustive, crate::p8}
test_exhaustive!{p16_exhaustive, crate::p16}
test_proptest!{p32_proptest, crate::p32}
test_proptest!{p64_proptest, crate::p64}
test_exhaustive!{posit_3_0_exhaustive, Posit::<3, 0, i8>}
test_exhaustive!{posit_4_0_exhaustive, Posit::<4, 0, i8>}
test_exhaustive!{posit_4_1_exhaustive, Posit::<4, 1, i8>}
test_exhaustive!{bposit_8_3_6_exhaustive, Posit::<8, 3, i8, 6>}
test_exhaustive!{bposit_16_5_6_exhaustive, Posit::<16, 5, i16, 6>}
test_proptest!{bposit_32_5_6_proptest, Posit::<32, 5, i32, 6>}
test_proptest!{bposit_64_5_6_proptest, Posit::<64, 5, i64, 6>}
test_exhaustive!{bposit_10_2_6_exhaustive, Posit::<10, 2, i16, 7>}
test_exhaustive!{bposit_10_2_7_exhaustive, Posit::<10, 2, i16, 7>}
test_exhaustive!{bposit_10_2_8_exhaustive, Posit::<10, 2, i16, 8>}
test_exhaustive!{bposit_10_2_9_exhaustive, Posit::<10, 2, i16, 9>}
}
mod ceil {
use super::*;
macro_rules! test_exhaustive {
($name:ident, $posit:ty) => {
#[test]
fn $name() {
for p in <$posit>::cases_exhaustive_all() {
let rounded = p.ceil();
assert!(is_correct_rounded(p, rounded, RoundingMode::Ceiling), "{p:?} {rounded:?}")
}
}
};
}
macro_rules! test_proptest {
($name:ident, $posit:ty) => {
proptest!{
#![proptest_config(ProptestConfig::with_cases(crate::PROPTEST_CASES))]
#[test]
fn $name(p in <$posit>::cases_proptest_all()) {
let rounded = p.ceil();
assert!(is_correct_rounded(p, rounded, RoundingMode::Ceiling), "{p:?} {rounded:?}")
}
}
};
}
test_exhaustive!{posit_10_0_exhaustive, Posit<10, 0, i16>}
test_exhaustive!{posit_10_1_exhaustive, Posit<10, 1, i16>}
test_exhaustive!{posit_10_2_exhaustive, Posit<10, 2, i16>}
test_exhaustive!{posit_10_3_exhaustive, Posit<10, 3, i16>}
test_exhaustive!{posit_8_0_exhaustive, Posit<8, 0, i8 >}
test_exhaustive!{p8_exhaustive, crate::p8}
test_exhaustive!{p16_exhaustive, crate::p16}
test_proptest!{p32_proptest, crate::p32}
test_proptest!{p64_proptest, crate::p64}
test_exhaustive!{posit_3_0_exhaustive, Posit::<3, 0, i8>}
test_exhaustive!{posit_4_0_exhaustive, Posit::<4, 0, i8>}
test_exhaustive!{posit_4_1_exhaustive, Posit::<4, 1, i8>}
test_exhaustive!{bposit_8_3_6_exhaustive, Posit::<8, 3, i8, 6>}
test_exhaustive!{bposit_16_5_6_exhaustive, Posit::<16, 5, i16, 6>}
test_proptest!{bposit_32_5_6_proptest, Posit::<32, 5, i32, 6>}
test_proptest!{bposit_64_5_6_proptest, Posit::<64, 5, i64, 6>}
test_exhaustive!{bposit_10_2_6_exhaustive, Posit::<10, 2, i16, 6>}
test_exhaustive!{bposit_10_2_7_exhaustive, Posit::<10, 2, i16, 7>}
test_exhaustive!{bposit_10_2_8_exhaustive, Posit::<10, 2, i16, 8>}
test_exhaustive!{bposit_10_2_9_exhaustive, Posit::<10, 2, i16, 9>}
}
}