use super::P32E2;
use crate::{u32_with_sign, u64_with_sign};
use core::f64;
use core::mem::transmute;
crate::macros::impl_convert!(P32E2);
impl P32E2 {
pub const fn from_f32(float: f32) -> Self {
use crate::RawFloat;
let ui: u32 = unsafe { transmute(float) };
let sign = (ui & f32::SIGN_MASK) != 0;
let uip = ui & !f32::SIGN_MASK;
if uip == 0 {
Self::ZERO
} else if uip >= 0x_7f80_0000 {
Self::NAR
} else if uip >= 0x_7b80_0000 {
if !sign {
Self::MAX
} else {
Self::MIN
}
} else if uip == 0x_3f80_0000 {
if !sign {
Self::ONE
} else {
Self::ONE.neg()
}
} else if uip <= 0x_0380_0000 {
if !sign {
Self::MIN_POSITIVE
} else {
Self::MIN_POSITIVE.neg()
}
} else {
Self::from_bits(crate::convert::convert_float!(P32E2, f32, ui, u64, i64))
}
}
pub const fn from_f64(float: f64) -> Self {
use crate::RawFloat;
let ui: u64 = unsafe { transmute(float) };
let sign = (ui & f64::SIGN_MASK) != 0;
let uip = ui & !f64::SIGN_MASK;
if uip == 0 {
Self::ZERO
} else if uip >= 0x_7ff0_0000_0000_0000 {
Self::NAR
} else if uip >= 0x_4770_0000_0000_0000 {
if !sign {
Self::MAX
} else {
Self::MIN
}
} else if uip == 0x_3ff0_0000_0000_0000 {
if !sign {
Self::ONE
} else {
Self::ONE.neg()
}
} else if uip <= 0x_3870_0000_0000_0000 {
if !sign {
Self::MIN_POSITIVE
} else {
Self::MIN_POSITIVE.neg()
}
} else {
Self::from_bits(crate::convert::convert_float!(P32E2, f64, ui))
}
}
#[inline]
pub const fn to_f32(self) -> f32 {
self.to_f64() as f32
}
pub const 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 & P32E2::SIGN_MASK;
if sign_a != 0 {
ui_a = ui_a.wrapping_neg();
}
let (k_a, tmp) = P32E2::separate_bits_tmp(ui_a);
let frac_a = ((tmp << 3) as u64) << 20;
let exp_a = (((k_a as u64) << 2) + ((tmp >> 29) as u64)).wrapping_add(1023) << 52;
unsafe { transmute(exp_a + frac_a + ((sign_a as u64) << 32)) }
}
}
#[inline]
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 & 0x8000_0000) != 0;
if sign {
ui_a = ui_a.wrapping_neg();
}
if ui_a > 0x_7faf_ffff {
return if sign {
i32::min_value()
} else {
i32::max_value()
};
};
let i_z = convert_p32bits_to_u32(ui_a);
u32_with_sign(i_z, sign) as i32
}
#[inline]
pub const fn to_u32(self) -> u32 {
if self.is_nar() {
return 0x8000_0000; }
let ui_a = self.to_bits();
if ui_a > 0x8000_0000 {
return 0;
}
convert_p32bits_to_u32(ui_a)
}
#[inline]
pub const fn to_i64(self) -> i64 {
let mut ui_a = self.to_bits();
if ui_a == 0x8000_0000 {
return i64::min_value();
}
let sign = (ui_a & 0x8000_0000) != 0;
if sign {
ui_a = ui_a.wrapping_neg();
}
if ui_a > 0x_7fff_afff {
return if sign {
i64::min_value()
} else {
i64::max_value()
};
};
let i_z = convert_p32bits_to_u64(ui_a);
u64_with_sign(i_z, sign) as i64
}
#[inline]
pub const fn to_u64(self) -> u64 {
let ui_a = self.to_bits();
if ui_a == 0x8000_0000 {
0x8000_0000_0000_0000
} else if ui_a > 0x8000_0000 {
0
} else {
convert_p32bits_to_u64(ui_a)
}
}
#[inline]
pub const fn from_i32(mut i_a: i32) -> Self {
if i_a < -2_147_483_135 {
return Self::from_bits(0x_8050_0000);
}
if i_a > 2_147_483_135 {
return Self::from_bits(0x_7FB0_0000);
}
let sign = i_a.is_negative();
if sign {
i_a = -i_a;
}
Self::from_bits(u32_with_sign(convert_u32_to_p32bits(i_a as u32), sign))
}
#[inline]
pub const fn from_u32(i_a: u32) -> Self {
Self::from_bits(convert_u32_to_p32bits(i_a))
}
#[inline]
pub const fn from_i64(mut i_a: i64) -> Self {
if i_a < -9_222_809_086_901_354_495 {
return Self::from_bits(0x_8000_5000);
}
if i_a > 9_222_809_086_901_354_495 {
return Self::from_bits(0x_7FFF_B000); }
let sign = i_a.is_negative();
if sign {
i_a = -i_a;
}
Self::from_bits(u32_with_sign(convert_u64_to_p32bits(i_a as u64), sign))
}
#[inline]
pub const fn from_u64(a: u64) -> Self {
Self::from_bits(convert_u64_to_p32bits(a))
}
}
const fn convert_p32bits_to_u32(ui_a: u32) -> u32 {
if ui_a <= 0x3800_0000 {
0 } else if ui_a < 0x4400_0000 {
1 } else if ui_a <= 0x4A00_0000 {
2 } else if ui_a > 0x7FAF_FFFF {
0x7FFF_FFFF
} else {
let (scale, bits) = P32E2::calculate_scale(ui_a);
let mut i_z64 = (((bits as u64) | 0x1000_0000) & 0x1FFF_FFFF) << 34; 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_p32bits_to_u64(ui_a: u32) -> u64 {
if ui_a <= 0x3800_0000 {
0 } else if ui_a < 0x4400_0000 {
1 } else if ui_a <= 0x4A00_0000 {
2 } else if ui_a > 0x7FFF_BFFF {
0xFFFF_FFFF_FFFF_FFFF
} else {
let (scale, bits) = P32E2::calculate_scale(ui_a);
let mut i_z: u64 = (((bits as u64) | 0x1000_0000) & 0x1FFF_FFFF) << 34;
if scale < 62 {
let mut mask = 0x4000_0000_0000_0000_u64 >> 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) } else if scale > 64 {
i_z << (scale - 62)
} else {
i_z
}
}
}
const fn convert_u32_to_p32bits(a: u32) -> u32 {
let mut mask = 0x8000_0000_u32;
if a > 0xFFFF_FBFF {
0x7FC0_0000 } else if a < 0x2 {
a << 30
} else {
let mut frac_a = a;
let mut log2 = 31_i8;
while (frac_a & mask) == 0 {
log2 -= 1;
frac_a <<= 1;
}
let k = log2 >> 2;
let exp_a: u32 = ((log2 & 0x3) as u32) << (27 - k);
frac_a ^= mask;
let mut ui_a = (0x7FFF_FFFF ^ (0x3FFF_FFFF >> k)) | exp_a | frac_a >> (k + 4);
mask = 0x8 << k;
if ((mask & frac_a) != 0) && ((((mask - 1) & frac_a) | ((mask << 1) & frac_a)) != 0) {
ui_a += 1;
}
ui_a
}
}
const fn convert_u64_to_p32bits(a: u64) -> u32 {
let mut mask = 0x8000_0000_0000_0000_u64;
if a > 0xFFFB_FFFF_FFFF_FBFF {
0x7FFF_C000 } else if a < 0x2 {
(a << 30) as u32
} else {
let mut frac_a = a;
let mut log2 = 63_i8;
while (frac_a & mask) == 0 {
log2 -= 1;
frac_a <<= 1;
}
let k = log2 >> 2;
let exp_a: u32 = ((log2 & 0x3) as u32) << (27 - k);
frac_a ^= mask;
let mut ui_a: u64 =
(0x7FFF_FFFF ^ (0x3FFF_FFFF >> k)) as u64 | exp_a as u64 | (frac_a >> (k + 36));
mask = 0x8_0000_0000 << k;
if ((mask & frac_a) != 0) && ((((mask - 1) & frac_a) | ((mask << 1) & frac_a)) != 0) {
ui_a += 1;
}
ui_a as u32
}
}
#[test]
fn convert_f64_p32_rand() {
use rand::Rng;
let mut rng = rand::thread_rng();
for _ in 0..100_000 {
let f: f64 = rng.gen();
let _p = P32E2::from(f);
}
}
#[test]
fn convert_f32_p32_rand() {
use rand::Rng;
let mut rng = rand::thread_rng();
for _ in 0..100_000 {
let f: f32 = rng.gen();
let _p = P32E2::from(f);
}
}
#[test]
fn convert_p32_f64() {
use rand::Rng;
let mut rng = rand::thread_rng();
for _ in 0..100_000 {
let p: P32E2 = rng.gen();
let f = f64::from(p);
assert_eq!(p, P32E2::from(f));
}
}
#[test]
fn convert_p32_i32() {
use rand::Rng;
let mut rng = rand::thread_rng();
for _ in 0..100_000 {
let p: P32E2 = rng.gen();
let f = f64::from(p).round();
if p % P32E2::new(0x_3800_0000) == P32E2::ZERO {
continue;
}
if f as i32 == i32::min_value() {
continue;
}
assert_eq!(i32::from(p), f as i32);
}
}
#[test]
fn convert_p32_i64() {
use rand::Rng;
let mut rng = rand::thread_rng();
for _ in 0..100_000 {
let p: P32E2 = rng.gen();
let f = f64::from(p).round();
if p % P32E2::new(0x_3800_0000) == P32E2::ZERO {
continue;
}
if f as i64 == i64::min_value() {
continue;
}
assert_eq!(i64::from(p), f as i64);
}
}