Maraiah/src/durandal/fx32.rs

175 lines
3.0 KiB
Rust

use std::{fmt::{self, 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