working fixed point ???
This commit is contained in:
20
src/main.rs
20
src/main.rs
@@ -1,25 +1,13 @@
|
|||||||
#![feature(bigint_helper_methods)]
|
#![feature(bigint_helper_methods)]
|
||||||
|
|
||||||
use client::ClientApp;
|
use client::ClientApp;
|
||||||
use util::FixedDec;
|
|
||||||
|
|
||||||
mod client;
|
mod client;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let a = FixedDec::from(0.75);
|
let event_loop = winit::event_loop::EventLoop::new().expect("Failed to create event loop");
|
||||||
println!("a = {}", a);
|
event_loop
|
||||||
let b = FixedDec::from(1.75);
|
.run_app(&mut ClientApp::new())
|
||||||
println!("b = {}", b);
|
.expect("Failed to run event loop");
|
||||||
println!("a + b = {}", &a + &b);
|
|
||||||
let c = FixedDec::from(1.0 / 16.0);
|
|
||||||
println!("c = {}", c);
|
|
||||||
println!("a + c = {}", &a + &c);
|
|
||||||
println!("-a = {}", -&a);
|
|
||||||
println!("b - a = {}", &b - &a);
|
|
||||||
println!("-c = {}", -&c);
|
|
||||||
// let event_loop = winit::event_loop::EventLoop::new().expect("Failed to create event loop");
|
|
||||||
// event_loop
|
|
||||||
// .run_app(&mut ClientApp::new())
|
|
||||||
// .expect("Failed to run event loop");
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,338 +0,0 @@
|
|||||||
use num_traits::Zero;
|
|
||||||
use std::{
|
|
||||||
fmt::{Binary, Debug, Display},
|
|
||||||
ops::{Add, AddAssign, Mul, Neg, Shr, Sub, SubAssign},
|
|
||||||
};
|
|
||||||
|
|
||||||
const POS: bool = false;
|
|
||||||
const NEG: bool = true;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct FixedDec {
|
|
||||||
sign: bool,
|
|
||||||
dec: i32,
|
|
||||||
parts: Vec<u32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FixedDec {
|
|
||||||
pub fn zeros() -> Self {
|
|
||||||
Self::zero()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dec_len(&self) -> i32 {
|
|
||||||
self.parts.len() as i32 - self.dec
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part(&self, i: i32) -> u32 {
|
|
||||||
let Ok(i): Result<usize, _> = i.try_into() else {
|
|
||||||
return self.pre_padding();
|
|
||||||
};
|
|
||||||
self.parts.get(i).cloned().unwrap_or(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_pos(&self) -> bool {
|
|
||||||
!self.sign
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_neg(&self) -> bool {
|
|
||||||
self.sign
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pre_padding(&self) -> u32 {
|
|
||||||
match self.sign {
|
|
||||||
POS => 0,
|
|
||||||
NEG => !0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Zero for FixedDec {
|
|
||||||
fn zero() -> Self {
|
|
||||||
Self {
|
|
||||||
sign: POS,
|
|
||||||
dec: 0,
|
|
||||||
parts: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_zero(&self) -> bool {
|
|
||||||
self.parts.iter().all(|&b| b == 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Shr<u32> for FixedDec {
|
|
||||||
type Output = Self;
|
|
||||||
|
|
||||||
fn shr(self, rhs: u32) -> Self::Output {
|
|
||||||
let mut parts = Vec::new();
|
|
||||||
let sr = rhs % 32;
|
|
||||||
let sl = 32 - sr;
|
|
||||||
let mask = (1 << sr) - 1;
|
|
||||||
let dec = self.dec - (rhs / 32) as i32;
|
|
||||||
let mut rem = 0;
|
|
||||||
for part in self.parts {
|
|
||||||
parts.push((part >> sr) ^ rem);
|
|
||||||
rem = (part & mask) << sl;
|
|
||||||
}
|
|
||||||
if rem != 0 {
|
|
||||||
parts.push(rem);
|
|
||||||
}
|
|
||||||
Self {
|
|
||||||
dec,
|
|
||||||
parts,
|
|
||||||
sign: self.sign,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Add for FixedDec {
|
|
||||||
type Output = Self;
|
|
||||||
|
|
||||||
fn add(self, rhs: Self) -> Self::Output {
|
|
||||||
&self + &rhs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AddAssign<&FixedDec> for FixedDec {
|
|
||||||
fn add_assign(&mut self, rhs: &FixedDec) {
|
|
||||||
let dec = self.dec.max(rhs.dec);
|
|
||||||
let left_i = -dec;
|
|
||||||
let right_i = self.dec_len().max(rhs.dec_len());
|
|
||||||
let len = (right_i - left_i) as usize;
|
|
||||||
if dec != self.dec {
|
|
||||||
let fill = self.pre_padding();
|
|
||||||
let fill_len = rhs.dec - self.dec;
|
|
||||||
self.parts.splice(0..0, (0..fill_len).map(|_| fill));
|
|
||||||
self.dec += fill_len;
|
|
||||||
}
|
|
||||||
if self.parts.len() != len {
|
|
||||||
self.parts.resize(len, 0);
|
|
||||||
}
|
|
||||||
let mut carry = false;
|
|
||||||
let rhs_offset = rhs.dec - self.dec;
|
|
||||||
for i in (0..self.parts.len()).rev() {
|
|
||||||
let a = self.parts[i];
|
|
||||||
let b = rhs.part(i as i32 + rhs_offset);
|
|
||||||
let (res, c) = a.carrying_add(b, carry);
|
|
||||||
self.parts[i] = res;
|
|
||||||
carry = c;
|
|
||||||
}
|
|
||||||
let sign = if self.sign == rhs.sign {
|
|
||||||
if self.sign == POS && carry {
|
|
||||||
self.parts.insert(0, 1);
|
|
||||||
self.dec += 1;
|
|
||||||
} else if self.sign == NEG && !carry {
|
|
||||||
self.parts.insert(0, !1);
|
|
||||||
self.dec += 1;
|
|
||||||
}
|
|
||||||
self.sign
|
|
||||||
} else if carry {
|
|
||||||
POS
|
|
||||||
} else {
|
|
||||||
NEG
|
|
||||||
};
|
|
||||||
self.sign = sign;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SubAssign<&FixedDec> for FixedDec {
|
|
||||||
fn sub_assign(&mut self, rhs: &FixedDec) {
|
|
||||||
*self += &-rhs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Add for &FixedDec {
|
|
||||||
type Output = FixedDec;
|
|
||||||
|
|
||||||
fn add(self, rhs: Self) -> Self::Output {
|
|
||||||
let mut dec = self.dec.max(rhs.dec);
|
|
||||||
let left_i = -dec;
|
|
||||||
let right_i = self.dec_len().max(rhs.dec_len());
|
|
||||||
let mut parts = Vec::with_capacity((right_i - left_i) as usize);
|
|
||||||
let mut carry = false;
|
|
||||||
for i in (left_i..right_i).rev() {
|
|
||||||
let a = self.part(i + self.dec);
|
|
||||||
let b = rhs.part(i + rhs.dec);
|
|
||||||
let (res, c) = a.carrying_add(b, carry);
|
|
||||||
parts.push(res);
|
|
||||||
carry = c;
|
|
||||||
}
|
|
||||||
let sign = if self.sign == rhs.sign {
|
|
||||||
if self.is_pos() && carry {
|
|
||||||
parts.push(1);
|
|
||||||
dec += 1;
|
|
||||||
} else if self.is_neg() && !carry {
|
|
||||||
parts.push(!1);
|
|
||||||
dec += 1;
|
|
||||||
}
|
|
||||||
self.sign
|
|
||||||
} else if carry {
|
|
||||||
POS
|
|
||||||
} else {
|
|
||||||
NEG
|
|
||||||
};
|
|
||||||
parts.reverse();
|
|
||||||
FixedDec { parts, dec, sign }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Sub for &FixedDec {
|
|
||||||
type Output = FixedDec;
|
|
||||||
|
|
||||||
fn sub(self, rhs: Self) -> Self::Output {
|
|
||||||
self + &(-rhs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Neg for &FixedDec {
|
|
||||||
type Output = FixedDec;
|
|
||||||
|
|
||||||
fn neg(self) -> Self::Output {
|
|
||||||
let parts = self.parts.iter().map(|p| !p).collect();
|
|
||||||
let mut res = FixedDec {
|
|
||||||
parts,
|
|
||||||
sign: !self.sign,
|
|
||||||
dec: self.dec,
|
|
||||||
};
|
|
||||||
res += &Self::Output {
|
|
||||||
parts: vec![1],
|
|
||||||
dec: self.dec - (self.parts.len() as i32 - 1),
|
|
||||||
sign: POS,
|
|
||||||
};
|
|
||||||
res
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Mul for &FixedDec {
|
|
||||||
type Output = FixedDec;
|
|
||||||
|
|
||||||
fn mul(self, rhs: Self) -> Self::Output {
|
|
||||||
let mut parts: Vec<u32> = vec![0; self.parts.len() + rhs.parts.len()];
|
|
||||||
for (i, &x) in self.parts.iter().enumerate().rev() {
|
|
||||||
let mut carry: u32 = 0;
|
|
||||||
for (j, &y) in rhs.parts.iter().enumerate().rev() {
|
|
||||||
let (lsb, msb) = mul_lmsb(x, y);
|
|
||||||
let k = i + j + 1;
|
|
||||||
let (res, carry1) = parts[k].overflowing_add(lsb);
|
|
||||||
parts[k] = res;
|
|
||||||
let (res, carry2) = parts[k].overflowing_add(carry);
|
|
||||||
parts[k] = res;
|
|
||||||
// dude I have no clue if this can overflow; I know msb can take 1 without
|
|
||||||
// overflowing, but I'm not sure if 2 can get here when it's max
|
|
||||||
carry = (carry1 as u32) + (carry2 as u32) + msb;
|
|
||||||
}
|
|
||||||
if carry > 0 {
|
|
||||||
parts[i] = carry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Self::Output {
|
|
||||||
dec: self.dec + rhs.dec,
|
|
||||||
parts,
|
|
||||||
sign: self.sign == rhs.sign,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mul_lmsb(x: u32, y: u32) -> (u32, u32) {
|
|
||||||
let lsb = x.wrapping_mul(y);
|
|
||||||
let a = x & 0xffff;
|
|
||||||
let b = x >> 16;
|
|
||||||
let c = y & 0xffff;
|
|
||||||
let d = y >> 16;
|
|
||||||
let ad = a * d + ((a * c) >> 16);
|
|
||||||
let bc = b * c;
|
|
||||||
let car = ad > (0xffffffff - bc);
|
|
||||||
let msb = ((ad + bc) >> 16) + ((car as u32) << 16) + b * d;
|
|
||||||
(lsb, msb)
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
let raw = value.to_bits() & INV_SIGN_MASK;
|
|
||||||
let exp = (raw >> 23) as i32 - 127;
|
|
||||||
let frac = (raw & FRAC_MASK) + FRAC_BIT;
|
|
||||||
let start = -exp - 1;
|
|
||||||
let end = -exp + 23;
|
|
||||||
let start_i = start.div_euclid(32);
|
|
||||||
let end_i = (end - 1).div_euclid(32);
|
|
||||||
let parts = if start_i == end_i {
|
|
||||||
vec![frac << (8 - start.rem_euclid(32))]
|
|
||||||
} else {
|
|
||||||
let s = end.rem_euclid(32);
|
|
||||||
vec![frac >> s, frac << (32 - s)]
|
|
||||||
};
|
|
||||||
Self {
|
|
||||||
sign: POS,
|
|
||||||
dec: -start_i,
|
|
||||||
parts,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&FixedDec> for f32 {
|
|
||||||
fn from(value: &FixedDec) -> Self {
|
|
||||||
let mut sign = 0;
|
|
||||||
let value = if value.is_neg() {
|
|
||||||
sign = 1 << 31;
|
|
||||||
&-value
|
|
||||||
} else {
|
|
||||||
value
|
|
||||||
};
|
|
||||||
let mut skip_count = 0;
|
|
||||||
let mut iter = value
|
|
||||||
.parts
|
|
||||||
.iter()
|
|
||||||
.inspect(|_| skip_count += 1)
|
|
||||||
.skip_while(|&&x| x == 0);
|
|
||||||
|
|
||||||
let Some(v) = iter.next() else {
|
|
||||||
return 0.0;
|
|
||||||
};
|
|
||||||
let start = v.leading_zeros();
|
|
||||||
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)
|
|
||||||
};
|
|
||||||
let exp = (127 - (skip_count * 32 + start)) << 23;
|
|
||||||
let res = frac + exp + sign;
|
|
||||||
println!();
|
|
||||||
println!("res: {:032b}", res);
|
|
||||||
println!("ans: {:032b}", 0.75f32.to_bits());
|
|
||||||
f32::from_bits(res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for FixedDec {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "{}", f32::from(self))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Binary for FixedDec {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
if self.sign == NEG {
|
|
||||||
write!(f, "-")?;
|
|
||||||
}
|
|
||||||
if self.dec < 0 {
|
|
||||||
write!(f, ".")?;
|
|
||||||
for _ in 0..(-self.dec) {
|
|
||||||
write!(f, "00000000000000000000000000000000")?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (i, part) in self.parts.iter().enumerate() {
|
|
||||||
if i as i32 == self.dec {
|
|
||||||
write!(f, ".")?;
|
|
||||||
} else if i != 0 {
|
|
||||||
write!(f, "_")?;
|
|
||||||
}
|
|
||||||
write!(f, "{:032b}", part)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
117
src/util/fixed/conversion.rs
Normal file
117
src/util/fixed/conversion.rs
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
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 {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
let s = Self {
|
||||||
|
sign: POS,
|
||||||
|
dec,
|
||||||
|
parts,
|
||||||
|
};
|
||||||
|
if value.is_sign_negative() {
|
||||||
|
-&s
|
||||||
|
} else {
|
||||||
|
s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<FixedDec> for f32 {
|
||||||
|
fn from(value: FixedDec) -> Self {
|
||||||
|
Self::from(&value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&FixedDec> for f32 {
|
||||||
|
fn from(value: &FixedDec) -> Self {
|
||||||
|
if value.is_zero() {
|
||||||
|
return if value.sign == POS { 0.0 } else { -0.0 };
|
||||||
|
}
|
||||||
|
let mut sign = 0;
|
||||||
|
let value = if value.is_neg() {
|
||||||
|
sign = 1 << 31;
|
||||||
|
&-value
|
||||||
|
} else {
|
||||||
|
value
|
||||||
|
};
|
||||||
|
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 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
87
src/util/fixed/mod.rs
Normal file
87
src/util/fixed/mod.rs
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
mod conversion;
|
||||||
|
mod op;
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test;
|
||||||
|
|
||||||
|
use num_traits::Zero;
|
||||||
|
use std::fmt::{Binary, Display};
|
||||||
|
|
||||||
|
const POS: bool = false;
|
||||||
|
const NEG: bool = true;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct FixedDec {
|
||||||
|
sign: bool,
|
||||||
|
dec: i32,
|
||||||
|
parts: Vec<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FixedDec {
|
||||||
|
pub fn zeros() -> Self {
|
||||||
|
Self::zero()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dec_len(&self) -> i32 {
|
||||||
|
self.parts.len() as i32 - self.dec
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part(&self, i: i32) -> u32 {
|
||||||
|
let Ok(i): Result<usize, _> = i.try_into() else {
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
self.parts.get(i).cloned().unwrap_or(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_pos(&self) -> bool {
|
||||||
|
!self.sign
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_neg(&self) -> bool {
|
||||||
|
self.sign
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn trim(&mut self) {
|
||||||
|
let rem_beg = self
|
||||||
|
.parts
|
||||||
|
.iter()
|
||||||
|
.take_while(|&&x| x == 0)
|
||||||
|
.count();
|
||||||
|
self.parts.drain(0..rem_beg);
|
||||||
|
let rem_end = self.parts.iter().rev().take_while(|&&x| x == 0).count();
|
||||||
|
self.parts.truncate(self.parts.len() - rem_end);
|
||||||
|
if self.parts.is_empty() {
|
||||||
|
self.dec = 0;
|
||||||
|
} else {
|
||||||
|
self.dec -= rem_beg as i32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for FixedDec {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", f32::from(self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Binary for FixedDec {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
if self.sign == NEG {
|
||||||
|
write!(f, "-")?;
|
||||||
|
}
|
||||||
|
if self.dec < 0 {
|
||||||
|
write!(f, ".")?;
|
||||||
|
for _ in 0..(-self.dec) {
|
||||||
|
write!(f, "00000000000000000000000000000000")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i, part) in self.parts.iter().enumerate() {
|
||||||
|
if i as i32 == self.dec {
|
||||||
|
write!(f, ".")?;
|
||||||
|
} else if i != 0 {
|
||||||
|
write!(f, "_")?;
|
||||||
|
}
|
||||||
|
write!(f, "{:032b}", part)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
230
src/util/fixed/op.rs
Normal file
230
src/util/fixed/op.rs
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
use std::ops::{Add, AddAssign, Mul, Neg, Shr, Sub, SubAssign};
|
||||||
|
|
||||||
|
impl Zero for FixedDec {
|
||||||
|
fn zero() -> Self {
|
||||||
|
Self {
|
||||||
|
sign: POS,
|
||||||
|
dec: 0,
|
||||||
|
parts: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_zero(&self) -> bool {
|
||||||
|
self.parts.iter().all(|&b| b == 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Shr<u32> for FixedDec {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn shr(self, rhs: u32) -> Self::Output {
|
||||||
|
let mut parts = Vec::new();
|
||||||
|
let sr = rhs % 32;
|
||||||
|
let sl = 32 - sr;
|
||||||
|
let mask = (1 << sr) - 1;
|
||||||
|
let dec = self.dec - (rhs / 32) as i32;
|
||||||
|
let mut rem = 0;
|
||||||
|
for part in self.parts {
|
||||||
|
parts.push((part >> sr) ^ rem);
|
||||||
|
rem = (part & mask) << sl;
|
||||||
|
}
|
||||||
|
if rem != 0 {
|
||||||
|
parts.push(rem);
|
||||||
|
}
|
||||||
|
Self {
|
||||||
|
dec,
|
||||||
|
parts,
|
||||||
|
sign: self.sign,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for FixedDec {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(mut self, rhs: Self) -> Self::Output {
|
||||||
|
self += &rhs;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign<FixedDec> for FixedDec {
|
||||||
|
fn add_assign(&mut self, rhs: FixedDec) {
|
||||||
|
*self += &rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign<&FixedDec> for FixedDec {
|
||||||
|
fn add_assign(&mut self, rhs: &FixedDec) {
|
||||||
|
let (dec, len) = new_dec(self, rhs);
|
||||||
|
if dec != self.dec {
|
||||||
|
let fill_len = rhs.dec - self.dec;
|
||||||
|
self.parts.splice(0..0, (0..fill_len).map(|_| 0));
|
||||||
|
self.dec += fill_len;
|
||||||
|
}
|
||||||
|
if self.parts.len() != len {
|
||||||
|
self.parts.resize(len, 0);
|
||||||
|
}
|
||||||
|
let src = trust(&self.parts);
|
||||||
|
add(self, &|i| src[i], rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn trust<'b, T>(x: &T) -> &'b T {
|
||||||
|
unsafe { std::mem::transmute(x) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for &FixedDec {
|
||||||
|
type Output = FixedDec;
|
||||||
|
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
let (dec, len) = new_dec(self, rhs);
|
||||||
|
let mut parts = Vec::with_capacity(len);
|
||||||
|
#[allow(clippy::uninit_vec)]
|
||||||
|
unsafe {
|
||||||
|
parts.set_len(len);
|
||||||
|
}
|
||||||
|
let mut res = FixedDec {
|
||||||
|
sign: self.sign,
|
||||||
|
dec,
|
||||||
|
parts,
|
||||||
|
};
|
||||||
|
#[allow(clippy::suspicious_arithmetic_impl)]
|
||||||
|
let offset = self.dec - dec;
|
||||||
|
add(&mut res, &|i| self.part(i as i32 + offset), rhs);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add(dest: &mut FixedDec, at: &impl Fn(usize) -> u32, rhs: &FixedDec) {
|
||||||
|
let mut carry = false;
|
||||||
|
let same_sign = dest.sign == rhs.sign;
|
||||||
|
let rhs_offset = rhs.dec - dest.dec;
|
||||||
|
for i in (0..dest.parts.len()).rev() {
|
||||||
|
let a = at(i);
|
||||||
|
let b = rhs.part(i as i32 + rhs_offset);
|
||||||
|
(dest.parts[i], carry) = carry_add(a, b, same_sign, carry);
|
||||||
|
}
|
||||||
|
if same_sign {
|
||||||
|
if carry {
|
||||||
|
dest.parts.insert(0, 1);
|
||||||
|
dest.dec += 1;
|
||||||
|
}
|
||||||
|
} else if carry {
|
||||||
|
dest.sign = !dest.sign
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_dec(x: &FixedDec, y: &FixedDec) -> (i32, usize) {
|
||||||
|
let dec = x.dec.max(y.dec);
|
||||||
|
let left_i = -dec;
|
||||||
|
let right_i = x.dec_len().max(y.dec_len());
|
||||||
|
let len = (right_i - left_i) as usize;
|
||||||
|
(dec, len)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn carry_add(a: u32, b: u32, same_sign: bool, carry: bool) -> (u32, bool) {
|
||||||
|
if same_sign {
|
||||||
|
a.carrying_add(b, carry)
|
||||||
|
} else {
|
||||||
|
let (res, c) = a.overflowing_sub(b);
|
||||||
|
let (res, c2) = res.overflowing_sub(carry as u32);
|
||||||
|
(res, c || c2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub for &FixedDec {
|
||||||
|
type Output = FixedDec;
|
||||||
|
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
self + &(-rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub for FixedDec {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn sub(mut self, rhs: Self) -> Self::Output {
|
||||||
|
self += &(-rhs);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubAssign<&FixedDec> for FixedDec {
|
||||||
|
fn sub_assign(&mut self, rhs: &FixedDec) {
|
||||||
|
*self += &-rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Neg for &FixedDec {
|
||||||
|
type Output = FixedDec;
|
||||||
|
|
||||||
|
fn neg(self) -> Self::Output {
|
||||||
|
let mut res = self.clone();
|
||||||
|
res.sign = !res.sign;
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Neg for FixedDec {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn neg(mut self) -> Self::Output {
|
||||||
|
self.sign = !self.sign;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul for &FixedDec {
|
||||||
|
type Output = FixedDec;
|
||||||
|
|
||||||
|
fn mul(self, rhs: Self) -> Self::Output {
|
||||||
|
let sign = self.sign != rhs.sign;
|
||||||
|
let mut parts: Vec<u32> = vec![0; self.parts.len() + rhs.parts.len()];
|
||||||
|
let dec = self.dec + rhs.dec;
|
||||||
|
|
||||||
|
for (i, &x) in self.parts.iter().enumerate().rev() {
|
||||||
|
let mut carry: u32 = 0;
|
||||||
|
for (j, &y) in rhs.parts.iter().enumerate().rev() {
|
||||||
|
let (lsb, msb) = x.widening_mul(y);
|
||||||
|
// let (lsb, msb) = mul_lmsb(x, y);
|
||||||
|
let k = i + j + 1;
|
||||||
|
let (res, carry1) = parts[k].overflowing_add(lsb);
|
||||||
|
parts[k] = res;
|
||||||
|
let (res, carry2) = parts[k].overflowing_add(carry);
|
||||||
|
parts[k] = res;
|
||||||
|
// dude I have no clue if this can overflow; I know msb can take 1 without
|
||||||
|
// overflowing, but I'm not sure if 2 can get here when it's max
|
||||||
|
carry = (carry1 as u32) + (carry2 as u32) + msb;
|
||||||
|
}
|
||||||
|
parts[i] = carry
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut res = Self::Output { dec, parts, sign };
|
||||||
|
res.trim();
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul for FixedDec {
|
||||||
|
type Output = FixedDec;
|
||||||
|
|
||||||
|
fn mul(self, rhs: Self) -> Self::Output {
|
||||||
|
&self * &rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mul_lmsb(x: u32, y: u32) -> (u32, u32) {
|
||||||
|
let lsb = x.wrapping_mul(y);
|
||||||
|
let a = x & 0xffff;
|
||||||
|
let b = x >> 16;
|
||||||
|
let c = y & 0xffff;
|
||||||
|
let d = y >> 16;
|
||||||
|
let ad = a * d + ((a * c) >> 16);
|
||||||
|
let bc = b * c;
|
||||||
|
let carry = ad > (0xffffffff - bc);
|
||||||
|
let msb = ((ad + bc) >> 16) + ((carry as u32) << 16) + b * d;
|
||||||
|
(lsb, msb)
|
||||||
|
}
|
||||||
96
src/util/fixed/test.rs
Normal file
96
src/util/fixed/test.rs
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
macro_rules! assert_bits_eq {
|
||||||
|
($left:expr, $right:expr, $dec:expr $(,)?) => {
|
||||||
|
assert!(
|
||||||
|
$left == $right,
|
||||||
|
"\n left: {:032b} = {:?}\n right: {:032b} = {:?}\n from: {:?}",
|
||||||
|
$left.to_bits(),
|
||||||
|
$left,
|
||||||
|
$right.to_bits(),
|
||||||
|
$right,
|
||||||
|
$dec,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
($left:expr, $right:expr, $dec:expr, $arg:tt, $($args:tt)+) => {
|
||||||
|
assert!(
|
||||||
|
$left == $right,
|
||||||
|
concat!("\n expr: ", $arg, "\n left: {:032b} = {:?}\n right: {:032b} = {:?}\n from: {:?}"),
|
||||||
|
$($args)+,
|
||||||
|
$left.to_bits(),
|
||||||
|
$left,
|
||||||
|
$right.to_bits(),
|
||||||
|
$right,
|
||||||
|
$dec,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn conversion() {
|
||||||
|
fn test(x: f32) {
|
||||||
|
let dec = FixedDec::from(x);
|
||||||
|
assert_bits_eq!(x, f32::from(&dec), dec)
|
||||||
|
}
|
||||||
|
test(f32::from_bits(0b00000000_00000000_00000000_00000001));
|
||||||
|
test(f32::from_bits(0b00000000_01000000_00000000_00000001));
|
||||||
|
test(f32::from_bits(0b00010000_01000000_00000000_00000001));
|
||||||
|
test(f32::from_bits(0b10000000_00000000_00000000_00000001));
|
||||||
|
test(f32::from_bits(0b10000100_00010000_00010000_00100001));
|
||||||
|
test(f32::from_bits(0b10000100_00000000_00000000_00000000));
|
||||||
|
test(f32::from_bits(0b00111111_11111111_11111111_11111111));
|
||||||
|
test(f32::from_bits(0b10111111_11111111_11111111_11111111));
|
||||||
|
test(0.75 + 0.125);
|
||||||
|
test(1.75);
|
||||||
|
test(1.0 / 16.0);
|
||||||
|
test(3.75);
|
||||||
|
test(-3.75);
|
||||||
|
test(1000000000.75);
|
||||||
|
test(-1000000000.75);
|
||||||
|
assert!(FixedDec::from(0.0).is_zero());
|
||||||
|
test(-1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_sub() {
|
||||||
|
fn test_add(x: f32, y: f32) {
|
||||||
|
let a = x + y;
|
||||||
|
let dec = FixedDec::from(x) + FixedDec::from(y);
|
||||||
|
assert_bits_eq!(a, f32::from(&dec), dec, "{} + {}", x, y);
|
||||||
|
}
|
||||||
|
test_add(0.25, 0.75);
|
||||||
|
test_add(1.25, 0.125);
|
||||||
|
test_add(1.25, -0.125);
|
||||||
|
test_add(100.25, -0.125);
|
||||||
|
test_add(-1.25, 0.125);
|
||||||
|
test_add(-100.25, -0.125);
|
||||||
|
test_add(100.25, -0.125);
|
||||||
|
// test_add(0.25, -0.00000000125);
|
||||||
|
test_add(0.25, -0.0000125);
|
||||||
|
test_add(100000000000000.0, -100000000000.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mul() {
|
||||||
|
fn test_mul(x: f32, y: f32) {
|
||||||
|
let a = x * y;
|
||||||
|
let dec = FixedDec::from(x) * FixedDec::from(y);
|
||||||
|
assert_bits_eq!(a, f32::from(&dec), dec, "{:?} * {:?}", x, y);
|
||||||
|
}
|
||||||
|
test_mul(0.0, 0.0);
|
||||||
|
test_mul(1.0, 1.0);
|
||||||
|
test_mul(1.0, 0.0);
|
||||||
|
test_mul(2.0, 1.0);
|
||||||
|
test_mul(2.0, 0.5);
|
||||||
|
test_mul(20.0, 0.245);
|
||||||
|
test_mul(0.03819, 0.0183488);
|
||||||
|
test_mul(30492.39, 9130.391);
|
||||||
|
|
||||||
|
test_mul(2.0, -1.0);
|
||||||
|
test_mul(0.0, -1.0);
|
||||||
|
test_mul(-1.0, 0.0);
|
||||||
|
test_mul(1.0, -1.0);
|
||||||
|
test_mul(2.0, -1.20904);
|
||||||
|
test_mul(-249.0, -1.20904);
|
||||||
|
test_mul(-30492.39, 9130.391);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user