use super::*;
use crate::RoundFrom;
impl<
const N: u32,
const ES: u32,
const SIZE: usize,
> Quire<N, ES, SIZE> {
fn leading_run(&self) -> u32 {
let quire: &[u64] = self.as_u64_array();
let idx_last = quire.len() - 1;
match quire[idx_last] as i64 >= 0 {
true => {
for i in 0 .. quire.len() {
if quire[idx_last - i] != 0 {
return i as u32 * 64 + quire[idx_last - i].leading_zeros()
}
}
quire.len() as u32 * 64
},
false => {
for i in 0 .. quire.len() {
if quire[idx_last - i] != u64::MAX {
return i as u32 * 64 + quire[idx_last - i].leading_ones()
}
}
quire.len() as u32 * 64
},
}
}
}
impl<
const N: u32,
const ES: u32,
Int: crate::Int,
const SIZE: usize,
> RoundFrom<&'_ Quire<N, ES, SIZE>> for Posit<N, ES, Int> {
fn round_from(value: &'_ Quire<N, ES, SIZE>) -> Self {
const { assert!(Int::BITS <= 64, "Only posits up to 64 bits are currently supported") };
if value.is_nar() { return Posit::NAR }
let leading = value.leading_run() - 1;
if leading + 1 == Quire::<N, ES, SIZE>::BITS {
return unsafe { core::mem::transmute_copy(value) }
}
let leading_ints = (leading / Int::BITS) as usize;
let leading_bits = (leading % Int::BITS) as u32;
let quire: &[Int] = value.as_int_array();
let idx_last = quire.len() - 1;
let value_width = Quire::<N, ES, SIZE>::BITS - leading;
if const { Int::BITS <= 8 }
&& value_width > 2 * Quire::<N, ES, SIZE>::WIDTH + 1 {
return if quire[idx_last].is_positive() {Posit::MAX} else {Posit::MIN}
}
let exp = Int::of_u32(value_width) - Int::of_u32(Quire::<N, ES, SIZE>::WIDTH) - Int::ONE - Int::ONE;
let frac = {
let frac_hi = quire[idx_last - leading_ints] << leading_bits;
let frac_lo = if leading_bits != 0 && leading_ints < idx_last {
quire[idx_last - leading_ints - 1].lshr(Int::BITS - leading_bits)
} else {
Int::ZERO
};
frac_hi | frac_lo
};
let sticky = {
let sticky_hi = if leading_ints < idx_last {
quire[idx_last - leading_ints - 1] << leading_bits
} else {
Int::ZERO
};
let mut sticky_lo = Int::ZERO;
if leading_ints < idx_last - 1 {
for &i in &quire[.. idx_last - leading_ints - 2] {
sticky_lo |= i
}
}
sticky_hi | sticky_lo
};
unsafe { Decoded{frac, exp}.encode_regular_round(sticky) }
}
}
impl<
const N: u32,
const ES: u32,
Int: crate::Int,
const SIZE: usize,
> RoundFrom<Quire<N, ES, SIZE>> for Posit<N, ES, Int> {
#[inline]
fn round_from(value: Quire<N, ES, SIZE>) -> Self {
Self::round_from(&value)
}
}
impl<
const N: u32,
const ES: u32,
Int: crate::Int,
const SIZE: usize,
> From<Posit<N, ES, Int>> for Quire<N, ES, SIZE> {
fn from(value: Posit<N, ES, Int>) -> Self {
if value == Posit::ZERO {
Self::ZERO
} else if value == Posit::NAR {
Self::NAR
} else {
let mut quire = Self::ZERO;
let decoded = unsafe { value.decode_regular() };
unsafe { quire.add_posit_kernel(decoded) };
quire
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use malachite::rational::Rational;
use proptest::prelude::*;
#[test]
fn leading_run_3() {
let bytes = [
0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
0x00,0x11,0x22,0x33,0x44,0x55,0x66,0b00010000,
];
assert_eq!(3, crate::q16::from_le_bytes(bytes).leading_run());
let bytes = [
0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
0x00,0x11,0x22,0x33,0x44,0x55,0x66,0b11100000,
];
assert_eq!(3, crate::q16::from_le_bytes(bytes).leading_run());
}
#[test]
fn leading_run_1() {
let bytes = [
0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
0x00,0x11,0x22,0x33,0x44,0x55,0x66,0b01001101,
];
assert_eq!(1, crate::q16::from_le_bytes(bytes).leading_run());
let bytes = [
0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
0x00,0x11,0x22,0x33,0x44,0x55,0x66,0b10000000,
];
assert_eq!(1, crate::q16::from_le_bytes(bytes).leading_run());
assert_eq!(1, crate::q32::NAR.leading_run());
}
#[test]
fn leading_run_27() {
let bytes = [
0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
0x00,0x11,0x22,0x33,0b00010111,0b00000000,0b00000000,0b00000000,
];
assert_eq!(27, crate::q16::from_le_bytes(bytes).leading_run());
let bytes = [
0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
0x00,0x11,0x22,0x33,0b11100111,0b11111111,0b11111111,0b11111111,
];
assert_eq!(27, crate::q16::from_le_bytes(bytes).leading_run());
}
mod from_posit {
use super::*;
macro_rules! test_exhaustive {
($name:ident, $posit:ty, $quire:ty) => {
#[test]
fn $name() {
for a in <$posit>::cases_exhaustive_all() {
assert_eq!(Rational::try_from(a), Rational::try_from(<$quire>::from(a)))
}
}
};
}
macro_rules! test_proptest {
($name:ident, $posit:ty, $quire:ty) => {
proptest!{
#![proptest_config(ProptestConfig::with_cases(crate::PROPTEST_CASES))]
#[test]
fn $name(a in <$posit>::cases_proptest_all()) {
assert_eq!(Rational::try_from(a), Rational::try_from(<$quire>::from(a)))
}
}
};
}
test_exhaustive!{posit_10_0_exhaustive, Posit::<10, 0, i16>, Quire::<10, 0, 128>}
test_exhaustive!{posit_10_1_exhaustive, Posit::<10, 1, i16>, Quire::<10, 1, 128>}
test_exhaustive!{posit_10_2_exhaustive, Posit::<10, 2, i16>, Quire::<10, 2, 128>}
test_exhaustive!{posit_10_3_exhaustive, Posit::<10, 3, i16>, Quire::<10, 3, 128>}
test_exhaustive!{posit_8_0_exhaustive, Posit::<8, 0, i8>, Quire::<8, 0, 128>}
test_exhaustive!{p8_exhaustive, crate::p8, crate::q8}
test_exhaustive!{p16_exhaustive, crate::p16, crate::q16}
test_proptest!{p32_proptest, crate::p32, crate::q32}
test_proptest!{p64_proptest, crate::p64, crate::q64}
test_exhaustive!{posit_3_0_exhaustive, Posit::<3, 0, i8>, Quire::<3, 0, 128>}
test_exhaustive!{posit_4_0_exhaustive, Posit::<4, 0, i8>, Quire::<4, 0, 128>}
test_exhaustive!{posit_4_1_exhaustive, Posit::<4, 1, i8>, Quire::<4, 1, 128>}
}
mod from_quire {
use super::*;
macro_rules! test_proptest {
($name:ident, $posit:ty, $quire:ty) => {
proptest!{
#![proptest_config(ProptestConfig::with_cases(crate::PROPTEST_CASES))]
#[test]
fn $name(q in <$quire>::cases_proptest_all()) {
let posit = <$posit>::round_from(&q);
let exact = Rational::try_from(q);
assert!(super::rational::try_is_correct_rounded(exact, posit))
}
}
};
}
test_proptest!{posit_10_0_proptest, Posit::<10, 0, i16>, Quire::<10, 0, 128>}
test_proptest!{posit_10_1_proptest, Posit::<10, 1, i16>, Quire::<10, 1, 128>}
test_proptest!{posit_10_2_proptest, Posit::<10, 2, i16>, Quire::<10, 2, 128>}
test_proptest!{posit_10_3_proptest, Posit::<10, 3, i16>, Quire::<10, 3, 128>}
test_proptest!{posit_8_0_proptest, Posit::<8, 0, i8>, Quire::<8, 0, 128>}
test_proptest!{p8_proptest, crate::p8, crate::q8}
test_proptest!{p16_proptest, crate::p16, crate::q16}
test_proptest!{p32_proptest, crate::p32, crate::q32}
test_proptest!{p64_proptest, crate::p64, crate::q64}
test_proptest!{posit_3_0_proptest, Posit::<3, 0, i8>, Quire::<3, 0, 128>}
test_proptest!{posit_4_0_proptest, Posit::<4, 0, i8>, Quire::<4, 0, 128>}
test_proptest!{posit_4_1_proptest, Posit::<4, 1, i8>, Quire::<4, 1, 128>}
}
mod roundtrip {
use super::*;
macro_rules! test_exhaustive {
($name:ident, $posit:ty, $quire:ty) => {
#[test]
fn $name() {
for p in <$posit>::cases_exhaustive_all() {
assert_eq!(p, <$posit>::round_from(&<$quire>::from(p)))
}
}
};
}
macro_rules! test_proptest {
($name:ident, $posit:ty, $quire:ty) => {
proptest!{
#![proptest_config(ProptestConfig::with_cases(crate::PROPTEST_CASES))]
#[test]
fn $name(p in <$posit>::cases_proptest_all()) {
assert_eq!(p, <$posit>::round_from(&<$quire>::from(p)))
}
}
};
}
test_exhaustive!{posit_10_0_exhaustive, Posit::<10, 0, i16>, Quire::<10, 0, 128>}
test_exhaustive!{posit_10_1_exhaustive, Posit::<10, 1, i16>, Quire::<10, 1, 128>}
test_exhaustive!{posit_10_2_exhaustive, Posit::<10, 2, i16>, Quire::<10, 2, 128>}
test_exhaustive!{posit_10_3_exhaustive, Posit::<10, 3, i16>, Quire::<10, 3, 128>}
test_exhaustive!{posit_8_0_exhaustive, Posit::<8, 0, i8>, Quire::<8, 0, 128>}
test_exhaustive!{p8_exhaustive, crate::p8, crate::q8}
test_exhaustive!{p16_exhaustive, crate::p16, crate::q16}
test_proptest!{p32_proptest, crate::p32, crate::q32}
test_proptest!{p64_proptest, crate::p64, crate::q64}
test_exhaustive!{posit_3_0_exhaustive, Posit::<3, 0, i8>, Quire::<3, 0, 128>}
test_exhaustive!{posit_4_0_exhaustive, Posit::<4, 0, i8>, Quire::<4, 0, 128>}
test_exhaustive!{posit_4_1_exhaustive, Posit::<4, 1, i8>, Quire::<4, 1, 128>}
}
}