use super::PxE1;
use crate::{u32_with_sign, u64_with_sign};
use core::f64;
impl<const N: u32> From<PxE1<{ N }>> for f32 {
#[inline]
fn from(a: PxE1<{ N }>) -> Self {
a.to_f32()
}
}
impl<const N: u32> From<PxE1<{ N }>> for f64 {
#[inline]
fn from(p_a: PxE1<{ N }>) -> Self {
p_a.to_f64()
}
}
impl<const N: u32> From<f32> for PxE1<{ N }> {
#[inline]
fn from(float: f32) -> Self {
Self::from_f32(float)
}
}
impl<const N: u32> From<f64> for PxE1<{ N }> {
#[inline]
fn from(float: f64) -> Self {
Self::from_f64(float)
}
}
impl<const N: u32> From<PxE1<{ N }>> for i32 {
#[inline]
fn from(p_a: PxE1<{ N }>) -> Self {
p_a.to_i32()
}
}
impl<const N: u32> From<PxE1<{ N }>> for u32 {
#[inline]
fn from(p_a: PxE1<{ N }>) -> Self {
p_a.to_u32()
}
}
impl<const N: u32> From<PxE1<{ N }>> for i64 {
#[inline]
fn from(p_a: PxE1<{ N }>) -> Self {
p_a.to_i64()
}
}
impl<const N: u32> From<PxE1<{ N }>> for u64 {
#[inline]
fn from(p_a: PxE1<{ N }>) -> Self {
p_a.to_u64()
}
}
impl<const N: u32> From<u64> for PxE1<{ N }> {
#[inline]
fn from(a: u64) -> Self {
Self::from_u64(a)
}
}
impl<const N: u32> From<i64> for PxE1<{ N }> {
#[inline]
fn from(a: i64) -> Self {
Self::from_i64(a)
}
}
impl<const N: u32> From<u32> for PxE1<{ N }> {
#[inline]
fn from(a: u32) -> Self {
Self::from_u32(a)
}
}
impl<const N: u32> From<i32> for PxE1<{ N }> {
#[inline]
fn from(a: i32) -> Self {
Self::from_i32(a)
}
}
impl<const N: u32> PxE1<{ N }> {
#[inline]
pub fn to_f32(self) -> f32 {
self.to_f64() as f32
}
pub fn to_f64(self) -> f64 {
let mut ui_a = self.to_bits();
if self.is_zero() {
0.
} else if self.is_nar() {
f64::NAN
} else {
let sign_a = ui_a & 0x_8000_0000;
if sign_a != 0 {
ui_a = ui_a.wrapping_neg();
}
let (k_a, tmp) = PxE1::<{ N }>::separate_bits_tmp(ui_a);
let frac_a = ((tmp << 2) as u64) << 20;
let exp_a = (((k_a as u64) << 1) + ((tmp >> 30) as u64)).wrapping_add(1023) << 52;
f64::from_bits(exp_a + frac_a + ((sign_a as u64) << 32))
}
}
#[inline]
pub fn from_f32(float: f32) -> Self {
Self::from_f64(float as f64)
}
#[allow(clippy::cognitive_complexity)]
pub fn from_f64(mut float: f64) -> Self {
let mut reg: u32;
let mut frac = 0_u32;
let mut exp = 0_i32;
let mut bit_n_plus_one = false;
let mut bits_more = false;
if float == 0. {
return Self::ZERO;
} else if !float.is_finite() {
return Self::NAR;
}
let sign = float < 0.;
let u_z: u32 = if float == 1. {
0x4000_0000
} else if float == -1. {
0xC000_0000
} else if !(-1. ..=1.).contains(&float) {
if sign {
float = -float;
}
let reg_s = true;
reg = 1; if (N == 2) && (float <= 8.673_617_379_884_035_e-19) {
1
} else {
while float >= 4. {
float *= 0.25; reg += 1;
}
if float >= 2. {
float *= 0.5;
exp += 1;
}
let frac_length = (N - 3) as isize - (reg as isize);
if frac_length < 0 {
if reg == N - 2 {
bit_n_plus_one = exp != 0;
exp = 0;
}
if float > 1. {
bits_more = true;
}
} else {
frac = crate::convert_fraction_p32(
float,
frac_length as u16,
&mut bit_n_plus_one,
&mut bits_more,
);
}
if (reg == 30) && (frac > 0) {
bits_more = true;
frac = 0;
}
u32_with_sign(
if reg > (N - 2) {
if reg_s {
0x_7FFF_FFFF & Self::mask()
} else {
0x1 << (32 - N)
}
} else {
let regime = if reg_s { ((1 << reg) - 1) << 1 } else { 1_u32 };
let mut u_z = (regime << (30 - reg))
+ ((exp as u32) << (29 - reg))
+ ((frac << (32 - N)) as u32);
if (u_z == 0) && (frac > 0) {
u_z = 0x1 << (32 - N);
}
if bit_n_plus_one {
u_z += (((u_z >> (32 - N)) & 0x1) | (bits_more as u32)) << (32 - N);
}
u_z
},
sign,
)
}
} else if (float < 1.) || (float > -1.) {
if sign {
float = -float;
}
let reg_s = false;
reg = 0;
while float < 1. {
float *= 4.;
reg += 1;
}
if float >= 2. {
float *= 0.5;
exp += 1;
}
let frac_length = (N - 3) as isize - (reg as isize);
if frac_length < 0 {
if reg == N - 2 {
bit_n_plus_one = exp != 0;
exp = 0;
}
if float > 1. {
bits_more = true;
}
} else {
frac = crate::convert_fraction_p32(
float,
frac_length as u16,
&mut bit_n_plus_one,
&mut bits_more,
);
}
if (reg == 30) && (frac > 0) {
bits_more = true;
frac = 0;
}
u32_with_sign(
if reg > (N - 2) {
if reg_s {
0x_7FFF_FFFF & Self::mask()
} else {
0x1 << (32 - N)
}
} else {
let regime = if reg_s { ((1 << reg) - 1) << 1 } else { 1_u32 };
let mut u_z = (regime << (30 - reg))
+ ((exp as u32) << (29 - reg))
+ ((frac << (32 - N)) as u32);
if (u_z == 0) && (frac > 0) {
u_z = 0x1 << (32 - N);
}
if bit_n_plus_one {
u_z += (((u_z >> (32 - N)) & 0x1) | (bits_more as u32)) << (32 - N);
}
u_z
},
sign,
)
} else {
0x8000_0000
};
Self::from_bits(u_z)
}
pub const fn to_i32(self) -> i32 {
if self.is_nar() {
return i32::min_value();
}
let mut ui_a = self.to_bits();
let sign = ui_a > 0x_8000_0000;
if sign {
ui_a = ui_a.wrapping_neg(); }
let i_z = convert_px1bits_to_u32(ui_a);
u32_with_sign(i_z, sign) as i32
}
pub const fn to_u32(self) -> u32 {
let ui_a = self.to_bits();
if ui_a >= 0x_8000_0000 {
0
} else {
convert_px1bits_to_u32(ui_a)
}
}
pub const fn to_i64(self) -> i64 {
if self.is_nar() {
return i64::min_value();
}
let mut ui_a = self.to_bits();
let sign = ui_a > 0x_8000_0000;
if sign {
ui_a = ui_a.wrapping_neg(); }
let i_z = convert_px1bits_to_u64(ui_a);
u64_with_sign(i_z, sign) as i64
}
pub const fn to_u64(self) -> u64 {
let ui_a = self.to_bits();
if ui_a >= 0x_8000_0000 {
0
} else {
convert_px1bits_to_u64(ui_a)
}
}
pub const fn from_u64(a: u64) -> Self {
let ui_a = if a == 0x_8000_0000_0000_0000 {
0x_8000_0000
} else if N == 2 {
if a > 0 {
0x_4000_0000
} else {
0
}
} else if a > 0x_8000_0000_0000_0000 {
0x_7FFF_FFFF & ((0x_8000_0000_u64 >> (N - 1)) as u32) } else {
convert_u64_to_px1bits::<{ N }>(a)
};
Self::from_bits(ui_a)
}
pub const fn from_i64(_a: i64) -> Self {
todo!()
}
pub const fn from_i32(a: i32) -> Self {
let mut log2 = 31_i8;
let mut ui_a = 0u32;
let mask = 0x80000000_u32;
let sign = a >> 31 != 0;
let a = if sign { -a as u32 } else { a as u32 };
if a == 0x80000000 {
ui_a = 0x80000000;
} else if N == 2 {
if a > 0 {
ui_a = 0x40000000;
}
} else if a > 2147418111 {
ui_a = 0x7FFF9FFF; } else if a < 0x2 {
ui_a = (a << 30) as u32;
} else {
let mut frac_a = a;
while (frac_a & mask) == 0 {
log2 -= 1;
frac_a <<= 1;
}
let k = (log2 >> 1) as u32;
let exp_a = ((log2 & 0x1) as u32) << (28 - k);
frac_a ^= mask;
if k >= (N - 2) {
ui_a = 0x7FFFFFFF & Self::mask();
} else if k == (N - 3) {
ui_a = 0x7FFFFFFF ^ (0x3FFFFFFF >> k);
if (exp_a & 0x2) != 0 && ((exp_a & 0x1) | frac_a) != 0 {
ui_a |= 0x80000000_u32 >> (N - 1);
}
} else if k == (N - 4) {
ui_a = (0x7FFFFFFF ^ (0x3FFFFFFF >> k)) | ((exp_a & 0x2) << (27 - k));
if exp_a & 0x1 != 0 && (((0x80000000_u32 >> (N - 1)) & ui_a) | frac_a) != 0 {
ui_a += 0x80000000_u32 >> (N - 1);
}
} else if k == (N - 5) {
ui_a = (0x7FFFFFFF ^ (0x3FFFFFFF >> k)) | (exp_a << (27 - k));
let mask = 0x8 << (k - N);
if (mask & frac_a) != 0 {
if (((mask - 1) & frac_a) | (exp_a & 0x1)) != 0 {
ui_a += 0x80000000_u32 >> (N - 1);
}
}
} else {
ui_a =
((0x7FFFFFFFu32 ^ (0x3FFFFFFF >> k)) | (exp_a << (27 - k)) | frac_a >> (k + 4))
& Self::mask();
let mask = 0x8 << (k - N); if (mask & frac_a) != 0 && (((mask - 1) & frac_a) | ((mask << 1) & frac_a)) != 0 {
ui_a += 0x80000000_u32 >> (N - 1);
}
}
}
Self::from_bits(if sign { ui_a.wrapping_neg() } else { ui_a })
}
pub const fn from_u32(_a: u32) -> Self {
todo!()
}
}
#[inline]
const fn calculate_scale(mut bits: u32) -> (u32, u32) {
let mut scale = 0_u32;
bits -= 0x_4000_0000; while (0x_2000_0000 & bits) != 0 {
scale += 2; bits = (bits - 0x_2000_0000) << 1; }
bits <<= 1; if (0x_2000_0000 & bits) != 0 {
scale += 1;
}
(scale, bits)
}
const fn convert_px1bits_to_u32(ui_a: u32) -> u32 {
if ui_a <= 0x_3000_0000 {
0
} else if ui_a < 0x_4800_0000 {
1
} else if ui_a <= 0x_5400_0000 {
2
} else if ui_a > 0x_7FFF_BFFF {
4_294_967_295
} else {
let (scale, bits) = calculate_scale(ui_a);
let mut i_z64 = ((bits | 0x_2000_0000) as u64) << 33;
let mut mask = 0x4000_0000_0000_0000_u64 >> scale;
let bit_last = i_z64 & mask; mask >>= 1;
let mut tmp = i_z64 & mask;
let bit_n_plus_one = tmp != 0; i_z64 ^= tmp; tmp = i_z64 & (mask - 1); i_z64 ^= tmp;
if bit_n_plus_one {
if (bit_last | tmp) != 0 {
i_z64 += mask << 1;
}
}
(i_z64 >> (62 - scale)) as u32 }
}
const fn convert_px1bits_to_u64(ui_a: u32) -> u64 {
if ui_a <= 0x_3000_0000 {
0
} else if ui_a < 0x_4800_0000 {
1
} else if ui_a <= 0x_5400_0000 {
2
} else {
let (scale, bits) = calculate_scale(ui_a);
let mut i_z = ((bits | 0x_2000_0000) as u64) << 33; let mut mask = 0x_4000_0000_0000_0000 >> scale;
let bit_last = i_z & mask; mask >>= 1;
let mut tmp = i_z & mask;
let bit_n_plus_one = tmp != 0; i_z ^= tmp; tmp = i_z & (mask - 1); i_z ^= tmp;
if bit_n_plus_one {
if (bit_last | tmp) != 0 {
i_z += mask << 1;
}
}
i_z >> (62 - scale) }
}
const fn convert_u64_to_px1bits<const N: u32>(a: u64) -> u32 {
let mut log2 = 63_i8; let mut mask = 0x_8000_0000_0000_0000_u64;
if a < 0x2 {
(a as u32) << 30
} else {
let mut frac64_a = a;
while (frac64_a & mask) == 0 {
log2 -= 1;
frac64_a <<= 1;
}
let k = (log2 >> 1) as u32;
let exp_a = (log2 & 0x1) as u32;
frac64_a ^= mask;
frac64_a <<= 1;
let mut ui_a: u32;
if k >= (N - 2) {
ui_a = 0x_7FFF_FFFF & PxE1::<{ N }>::mask();
} else if k == (N - 3) {
ui_a = 0x_7FFF_FFFF ^ (0x_3FFF_FFFF >> k);
if ((exp_a & 0x1) != 0) && (frac64_a != 0) {
ui_a |= 0x_8000_0000_u32 >> (N - 1);
}
} else if k == (N - 4) {
ui_a = (0x_7FFF_FFFF ^ (0x_3FFF_FFFF >> k)) | (exp_a << (28 - k));
mask = 0x_0008_0000_0000_u64 << (k + 32 - N);
if (mask & frac64_a) != 0 {
if (((mask - 1) & frac64_a) | ((exp_a & 0x1) as u64)) != 0 {
ui_a += 0x_8000_0000_u32 >> (N - 1);
}
}
} else {
ui_a = (0x_7FFF_FFFF ^ (0x_3FFF_FFFF >> k))
| (exp_a << (28 - k))
| (((frac64_a >> (k + 36)) as u32) & PxE1::<{ N }>::mask());
mask = 0x_0008_0000_0000_u64 << (k + 32 - N); if ((mask & frac64_a) != 0)
&& ((((mask - 1) & frac64_a) | ((mask << 1) & frac64_a)) != 0)
{
ui_a += 0x_8000_0000_u32 >> (N - 1);
}
}
ui_a
}
}