Maraiah/src/durandal/fx32.rs

104 lines
2.8 KiB
Rust

use std::{fmt, fmt::Write, ops};
pub struct Fx32(i32);
impl Fx32
{
const FRACBITS: u32 = 16;
const FRACMASK: u32 = 0xFFFF;
const ONE: i32 = 1 << Fx32::FRACBITS;
pub fn to_bits(&self) -> u32 {self.0 as u32}
pub fn set_bits(&mut self, bits: u32) {self.0 = bits as i32}
pub fn from_bits(bits: u32) -> Fx32 {Fx32(bits as i32)}
pub fn integ(&self) -> i16 {(self.0 >> Fx32::FRACBITS) as i16}
pub fn fract(&self) -> u16 {(self.0 as u32 & Fx32::FRACMASK) as u16}
pub fn mul_i(&self, n: i32) -> Fx32 {Fx32(self.0 * n)}
pub fn div_i(&self, n: i32) -> Fx32 {Fx32(self.0 / n)}
}
impl From<i32> for Fx32 {fn from(n: i32) -> Fx32 {Fx32(n << Fx32::FRACBITS)}}
impl ops::Add for Fx32
{type Output = Fx32; fn add(self, o: Fx32) -> Fx32 {Fx32(self.0 + o.0)}}
impl ops::Sub for Fx32
{type Output = Fx32; fn sub(self, o: Fx32) -> Fx32 {Fx32(self.0 - o.0)}}
impl ops::Mul for Fx32
{
type Output = Fx32;
fn mul(self, o: Fx32) -> Fx32
{Fx32((self.0 as i64 * o.0 as i64 / Fx32::ONE as i64) as i32)}
}
impl ops::Div for Fx32
{
type Output = Fx32;
fn div(self, o: Fx32) -> Fx32
{Fx32((self.0 as i64 * Fx32::ONE as i64 / o.0 as i64) as i32)}
}
impl ops::Neg for Fx32
{type Output = Fx32; fn neg(self) -> Fx32 {Fx32(-self.0)}}
impl ops::Not for Fx32
{type Output = Fx32; fn not(self) -> Fx32 {Fx32(!self.0)}}
impl fmt::Display for Fx32
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
{
let prec = f.precision().unwrap_or(1);
let widt = f.width().unwrap_or(0);
write!(f, "{:widt$}.", self.integ(), widt = widt)?;
let mut k = self.to_bits();
for _ in 0..prec {
k &= Fx32::FRACMASK;
k *= 10;
let d = k >> Fx32::FRACBITS;
let d = d % 10;
f.write_char((d as u8 + b'0') as char)?;
}
Ok(())
}
}
impl fmt::Debug for Fx32
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
{fmt::Display::fmt(self, f)}
}
#[test]
fn fx32_basic_ops()
{
let seven_div_2 = 3 << Fx32::FRACBITS | Fx32::FRACMASK / 2 + 1;
assert_eq!((Fx32::from(1) + 1.into()).to_bits(), 2 << Fx32::FRACBITS);
assert_eq!((Fx32::from(2) - 1.into()).to_bits(), 1 << Fx32::FRACBITS);
assert_eq!((Fx32::from(6) * 2.into()).to_bits(), 12 << Fx32::FRACBITS);
assert_eq!((Fx32::from(6).mul_i(2) ).to_bits(), 12 << Fx32::FRACBITS);
assert_eq!((Fx32::from(7) / 2.into()).to_bits(), seven_div_2);
assert_eq!((Fx32::from(7).div_i(2) ).to_bits(), seven_div_2);
}
#[test]
#[should_panic]
#[allow(unused_must_use)]
fn fx32_overflow()
{
Fx32::from(32767) + 1.into();
}
#[test]
fn fx32_printing()
{
assert_eq!(format!("{}", Fx32::from(6)), "6.0");
assert_eq!(format!("{}", Fx32::from(7).div_i(2)), "3.5");
assert_eq!(format!("{:7.7}", Fx32::from_bits(0xDEAD_BEEF)), " -8531.7458343");
}
// EOF