working fixed point ???
This commit is contained in:
20
src/main.rs
20
src/main.rs
@@ -1,25 +1,13 @@
|
||||
#![feature(bigint_helper_methods)]
|
||||
|
||||
use client::ClientApp;
|
||||
use util::FixedDec;
|
||||
|
||||
mod client;
|
||||
mod util;
|
||||
|
||||
fn main() {
|
||||
let a = FixedDec::from(0.75);
|
||||
println!("a = {}", a);
|
||||
let b = FixedDec::from(1.75);
|
||||
println!("b = {}", b);
|
||||
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");
|
||||
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