Commit 06f8008e authored by Andrey Zgarbul's avatar Andrey Zgarbul

x

parent 5c7fa44e
......@@ -809,6 +809,65 @@ impl<const N: u32> From<PxE2<{ N }>> for P8E0 {
}
}
#[cfg(feature = "nightly")]
impl<const N: u32> From<PxE1<{ N }>> for P8E0 {
#[inline]
fn from(p_a: PxE1<{ N }>) -> Self {
let mut ui_a = p_a.to_bits();
if (ui_a == 0x_8000_0000) || (ui_a == 0) {
return P8E0::from_bits((ui_a >> 24) as u8);
}
let sign = PxE1::<{ N }>::sign_ui(ui_a);
if sign {
ui_a = ui_a.wrapping_neg();
}
let (k_a, tmp) = PxE1::<{ N }>::separate_bits_tmp(ui_a);
let mut exp_frac32_a = 0_u32;
let mut reg_a = 0_i8;
let mut u_z: u8 = if (k_a < -3) || (k_a >= 3) {
if k_a < 0 {
0x1
} else {
0x7F
}
} else {
//2nd bit exp
exp_frac32_a = tmp;
let regime = if k_a < 0 {
reg_a = ((-k_a) << 1) - ((exp_frac32_a >> 30) as i8);
if reg_a == 0 {
reg_a = 1;
}
0x40 >> reg_a
} else {
reg_a = if k_a == 0 {
1 + ((exp_frac32_a >> 30) as i8)
} else {
((k_a + 1) << 1) + ((exp_frac32_a >> 30) as i8) - 1
};
0x7F - (0x7F >> reg_a)
};
if reg_a > 5 {
regime
} else {
regime + ((((exp_frac32_a) & 0x_3FFF_FFFF) >> (reg_a + 24)) as u8)
}
};
if (exp_frac32_a & (0x_0080_0000 << reg_a)) != 0 {
let bits_more = (exp_frac32_a & ((0x_0080_0000 << reg_a) - 1)) != 0;
u_z += (u_z & 1) | (bits_more as u8);
}
P8E0::from_bits(u_z.with_sign(sign))
}
}
#[cfg(feature = "alga")]
crate::impl_subset_into!(
u8 as P8E0, P16E1, P32E2;
......
......@@ -45,37 +45,26 @@ pub use polynom::Polynom;
trait WithSign {
fn with_sign(self, sign: bool) -> Self;
}
impl WithSign for u8 {
#[inline]
fn with_sign(self, sign: bool) -> Self {
if sign {
self.wrapping_neg()
} else {
self
}
}
}
impl WithSign for u16 {
#[inline]
fn with_sign(self, sign: bool) -> Self {
if sign {
self.wrapping_neg()
} else {
self
}
}
}
impl WithSign for u32 {
#[inline]
fn with_sign(self, sign: bool) -> Self {
if sign {
self.wrapping_neg()
} else {
self
}
macro_rules! with_sign {
($($uint:ty),*) => {
$(
impl WithSign for $uint {
#[inline]
fn with_sign(self, sign: bool) -> Self {
if sign {
self.wrapping_neg()
} else {
self
}
}
}
)*
}
}
with_sign!(u8, u16, u32, u64);
fn lldiv(numer: i64, denom: i64) -> (i64, i64) {
let mut quot = numer / denom;
let mut rem = numer % denom;
......
......@@ -323,3 +323,118 @@ impl<const N: u32> From<PxE1<{ N }>> for i32 {
i_z.with_sign(sign) as i32
}
}
impl<const N: u32> From<PxE1<{ N }>> for u64 {
#[inline]
fn from(p_a: PxE1<{ N }>) -> Self {
let mut ui_a = p_a.to_bits();
//NaR
if (ui_a >= 0x_8000_0000) && (ui_a <= 0x_3000_0000) {
// 0 <= |pA| <= 1/2 rounds to zero.
0
} else if ui_a < 0x_4800_0000 {
// 1/2 < x < 3/2 rounds to 1.
1
} else if ui_a <= 0x_5400_0000 {
// 3/2 <= x <= 5/2 rounds to 2.
2
} else {
// Decode the posit, left-justifying as we go.
let mut scale = 0_u32;
ui_a -= 0x_4000_0000; // Strip off first regime bit (which is a 1).
while (0x_2000_0000 & ui_a) != 0 {
// Increment scale by 2 for each regime sign bit.
scale += 2; // Regime sign bit is always 1 in this range.
ui_a = (ui_a - 0x_2000_0000) << 1; // Remove the bit; line up the next regime bit.
}
ui_a <<= 1; // Skip over termination bit, which is 0.
if (0x_2000_0000 & ui_a) != 0 {
scale += 1;
} // If exponent is 1, increment the scale.
let mut i_z = ((ui_a | 0x_2000_0000) as u64) << 33; // Left-justify fraction in 64-bit result (one left bit padding)
let mut mask = 0x_4000_0000_0000_0000 >> scale; // Point to the last bit of the integer part.
let bit_last = i_z & mask; // Extract the bit, without shifting it.
mask >>= 1;
let mut tmp = i_z & mask;
let bit_n_plus_one = tmp != 0; // "True" if nonzero.
i_z ^= tmp; // Erase the bit, if it was set.
tmp = i_z & (mask - 1); // tmp has any remaining bits. // This is bits_more
i_z ^= tmp; // Erase those bits, if any were set.
if bit_n_plus_one {
// logic for round to nearest, tie to even
if (bit_last | tmp) != 0 {
i_z += mask << 1;
}
}
i_z >> (62 - scale) // Right-justify the integer.
}
}
}
impl<const N: u32> From<PxE1<{ N }>> for i64 {
#[inline]
fn from(p_a: PxE1<{ N }>) -> Self {
//NaR
if p_a.is_nar() {
return i64::min_value();
}
let mut ui_a = p_a.to_bits();
let sign = ui_a > 0x_8000_0000; // sign is True if pA > NaR.
if sign {
ui_a = ui_a.wrapping_neg(); // A is now |A|.
}
if ui_a <= 0x_3000_0000 {
// 0 <= |pA| <= 1/2 rounds to zero.
return 0;
}
let i_z = if ui_a < 0x_4800_0000 {
// 1/2 < x < 3/2 rounds to 1.
1
} else if ui_a <= 0x_5400_0000 {
// 3/2 <= x <= 5/2 rounds to 2.
2
} else {
// Decode the posit, left-justifying as we go.
let mut scale = 0_u32;
ui_a -= 0x_4000_0000; // Strip off first regime bit (which is a 1).
while (0x_2000_0000 & ui_a) != 0 {
// Increment scale by 2 for each regime sign bit.
scale += 2; // Regime sign bit is always 1 in this range.
ui_a = (ui_a - 0x_2000_0000) << 1; // Remove the bit; line up the next regime bit.
}
ui_a <<= 1; // Skip over termination bit, which is 0.
if (0x_2000_0000 & ui_a) != 0 {
scale += 1;
} // If exponent is 1, increment the scale.
let mut i_z = ((ui_a | 0x_2000_0000) as u64) << 33; // Left-justify fraction in 64-bit result (one left bit padding)
let mut mask = 0x_4000_0000_0000_0000 >> scale; // Point to the last bit of the integer part.
let bit_last = i_z & mask; // Extract the bit, without shifting it.
mask >>= 1;
let mut tmp = i_z & mask;
let bit_n_plus_one = tmp != 0; // "True" if nonzero.
i_z ^= tmp; // Erase the bit, if it was set.
tmp = i_z & (mask - 1); // tmp has any remaining bits. // This is bits_more
i_z ^= tmp; // Erase those bits, if any were set.
if bit_n_plus_one {
// logic for round to nearest, tie to even
if (bit_last | tmp) != 0 {
i_z += mask << 1;
}
}
i_z >> (62 - scale) // Right-justify the integer.
};
i_z.with_sign(sign) as i64
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment