128 lines
3.2 KiB
Rust
128 lines
3.2 KiB
Rust
use num_traits::Zero;
|
|
|
|
use super::{FixedDec, POS};
|
|
|
|
const INV_SIGN_MASK: u32 = (1 << 31) - 1;
|
|
const FRAC_BIT: u32 = 1 << 23;
|
|
const FRAC_MASK: u32 = FRAC_BIT - 1;
|
|
|
|
impl From<f32> for FixedDec {
|
|
fn from(value: f32) -> Self {
|
|
if value.is_zero() {
|
|
return Self::zero();
|
|
}
|
|
let raw = value.to_bits() & INV_SIGN_MASK;
|
|
let mut exp = (raw >> 23) as i32 - 127;
|
|
let mut frac = raw & FRAC_MASK;
|
|
let mut start = -exp;
|
|
if exp == -127 {
|
|
exp = -126;
|
|
start = -exp;
|
|
} else {
|
|
frac += FRAC_BIT;
|
|
start -= 1;
|
|
}
|
|
let end = -exp + 23;
|
|
let start_i = start.div_euclid(32);
|
|
let end_i = (end - 1).div_euclid(32);
|
|
let mut parts = Vec::new();
|
|
let mut dec = -start_i;
|
|
if start_i == end_i {
|
|
let val = frac << (8 - start.rem_euclid(32));
|
|
if val != 0 {
|
|
parts.push(val);
|
|
}
|
|
} else {
|
|
let s = end.rem_euclid(32);
|
|
let val_high = frac >> s;
|
|
let val_low = frac << (32 - s);
|
|
if val_high != 0 {
|
|
parts.push(val_high);
|
|
} else {
|
|
dec -= 1;
|
|
}
|
|
if val_low != 0 {
|
|
parts.push(val_low);
|
|
}
|
|
}
|
|
if parts.is_empty() {
|
|
dec = 0;
|
|
}
|
|
Self {
|
|
sign: value.is_sign_negative(),
|
|
dec,
|
|
parts,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<FixedDec> for f32 {
|
|
fn from(value: FixedDec) -> Self {
|
|
Self::from(&value)
|
|
}
|
|
}
|
|
|
|
impl From<&FixedDec> for f32 {
|
|
fn from(value: &FixedDec) -> Self {
|
|
let sign = if value.is_neg() { 1 << 31 } else { 0 };
|
|
|
|
let mut skip_count = 0;
|
|
let mut iter = value.parts.iter().peekable();
|
|
|
|
while let Some(0) = iter.peek() {
|
|
skip_count += 1;
|
|
iter.next();
|
|
}
|
|
|
|
let Some(v) = iter.next() else {
|
|
return if value.is_pos() { 0.0 } else { -0.0 };
|
|
};
|
|
let mut start = v.leading_zeros() + 1;
|
|
let exp_i = (value.dec - skip_count) * 32 - start as i32;
|
|
let mut frac_sh = 0;
|
|
let exp = if exp_i >= -127 {
|
|
if exp_i == -127 {
|
|
start -= 1;
|
|
}
|
|
(exp_i + 127) as u32
|
|
} else {
|
|
let sh = -(exp_i + 32 * 4 - 1);
|
|
if sh < 23 {
|
|
start -= 1;
|
|
frac_sh = sh;
|
|
0
|
|
} else {
|
|
return 0.0;
|
|
}
|
|
};
|
|
let frac = if start > 9 {
|
|
let sh = start - 9;
|
|
(v << sh) + iter.next().copied().map(|v| v >> (32 - sh)).unwrap_or(0)
|
|
} else {
|
|
v >> (9 - start)
|
|
} & !(1 << 23);
|
|
let res = (frac >> frac_sh) + (exp << 23) + sign;
|
|
f32::from_bits(res)
|
|
}
|
|
}
|
|
|
|
impl From<u32> for FixedDec {
|
|
fn from(value: u32) -> Self {
|
|
Self {
|
|
dec: 1,
|
|
sign: POS,
|
|
parts: vec![value],
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<i32> for FixedDec {
|
|
fn from(value: i32) -> Self {
|
|
Self {
|
|
dec: 1,
|
|
sign: value.is_negative(),
|
|
parts: vec![value.try_into().unwrap_or((-value) as u32)],
|
|
}
|
|
}
|
|
}
|