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 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