2019-02-12 14:32:16 -08:00
|
|
|
use serde::Serialize;
|
2019-02-08 21:53:27 -08:00
|
|
|
use std::{fmt::{self, Write},
|
|
|
|
ops};
|
2018-12-13 01:04:09 -08:00
|
|
|
|
2019-02-12 14:32:16 -08:00
|
|
|
#[derive(Serialize)]
|
2018-12-13 01:04:09 -08:00
|
|
|
pub struct Fx32(i32);
|
|
|
|
|
|
|
|
impl Fx32
|
|
|
|
{
|
|
|
|
const FRACBITS: u32 = 16;
|
|
|
|
const FRACMASK: u32 = 0xFFFF;
|
2019-02-04 21:12:10 -08:00
|
|
|
const ONE: i32 = 1 << Fx32::FRACBITS;
|
2018-12-13 01:04:09 -08:00
|
|
|
|
2019-02-08 21:53:27 -08:00
|
|
|
pub fn to_bits(&self) -> u32
|
|
|
|
{
|
|
|
|
self.0 as u32
|
|
|
|
}
|
2019-02-04 21:12:10 -08:00
|
|
|
|
2019-02-08 21:53:27 -08:00
|
|
|
pub fn set_bits(&mut self, bits: u32)
|
|
|
|
{
|
|
|
|
self.0 = bits as i32
|
|
|
|
}
|
2018-12-13 01:04:09 -08:00
|
|
|
|
2019-02-08 21:53:27 -08:00
|
|
|
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)
|
|
|
|
}
|
2018-12-13 01:04:09 -08:00
|
|
|
}
|
|
|
|
|
2019-02-08 21:53:27 -08:00
|
|
|
impl From<i32> for Fx32
|
|
|
|
{
|
|
|
|
fn from(n: i32) -> Fx32
|
|
|
|
{
|
|
|
|
Fx32(n << Fx32::FRACBITS)
|
|
|
|
}
|
|
|
|
}
|
2019-02-04 21:12:10 -08:00
|
|
|
|
|
|
|
impl ops::Add for Fx32
|
2019-02-05 23:01:47 -08:00
|
|
|
{
|
|
|
|
type Output = Fx32;
|
2019-02-08 21:53:27 -08:00
|
|
|
|
|
|
|
fn add(self, o: Fx32) -> Fx32
|
|
|
|
{
|
|
|
|
Fx32(self.0 + o.0)
|
|
|
|
}
|
2019-02-05 23:01:47 -08:00
|
|
|
}
|
|
|
|
|
2018-12-13 01:04:09 -08:00
|
|
|
impl ops::Sub for Fx32
|
2019-02-05 23:01:47 -08:00
|
|
|
{
|
|
|
|
type Output = Fx32;
|
2019-02-08 21:53:27 -08:00
|
|
|
|
|
|
|
fn sub(self, o: Fx32) -> Fx32
|
|
|
|
{
|
|
|
|
Fx32(self.0 - o.0)
|
|
|
|
}
|
2019-02-05 23:01:47 -08:00
|
|
|
}
|
2018-12-13 01:04:09 -08:00
|
|
|
|
|
|
|
impl ops::Mul for Fx32
|
|
|
|
{
|
|
|
|
type Output = Fx32;
|
2019-02-08 21:53:27 -08:00
|
|
|
|
2019-02-04 21:12:10 -08:00
|
|
|
fn mul(self, o: Fx32) -> Fx32
|
2019-02-08 21:53:27 -08:00
|
|
|
{
|
|
|
|
Fx32((self.0 as i64 * o.0 as i64 / Fx32::ONE as i64) as i32)
|
|
|
|
}
|
2018-12-13 01:04:09 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ops::Div for Fx32
|
|
|
|
{
|
|
|
|
type Output = Fx32;
|
2019-02-08 21:53:27 -08:00
|
|
|
|
2019-02-04 21:12:10 -08:00
|
|
|
fn div(self, o: Fx32) -> Fx32
|
2019-02-08 21:53:27 -08:00
|
|
|
{
|
|
|
|
Fx32((self.0 as i64 * Fx32::ONE as i64 / o.0 as i64) as i32)
|
|
|
|
}
|
2018-12-13 01:04:09 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ops::Neg for Fx32
|
2019-02-05 23:01:47 -08:00
|
|
|
{
|
|
|
|
type Output = Fx32;
|
2019-02-08 21:53:27 -08:00
|
|
|
|
|
|
|
fn neg(self) -> Fx32
|
|
|
|
{
|
|
|
|
Fx32(-self.0)
|
|
|
|
}
|
2019-02-05 23:01:47 -08:00
|
|
|
}
|
|
|
|
|
2018-12-13 01:04:09 -08:00
|
|
|
impl ops::Not for Fx32
|
2019-02-05 23:01:47 -08:00
|
|
|
{
|
|
|
|
type Output = Fx32;
|
2019-02-08 21:53:27 -08:00
|
|
|
|
|
|
|
fn not(self) -> Fx32
|
|
|
|
{
|
|
|
|
Fx32(!self.0)
|
|
|
|
}
|
2019-02-05 23:01:47 -08:00
|
|
|
}
|
2018-12-13 01:04:09 -08:00
|
|
|
|
|
|
|
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
|
2019-02-08 21:53:27 -08:00
|
|
|
{
|
|
|
|
fmt::Display::fmt(self, f)
|
|
|
|
}
|
2019-02-04 21:12:10 -08:00
|
|
|
}
|
2018-12-13 01:04:09 -08:00
|
|
|
|
2019-02-04 21:12:10 -08:00
|
|
|
#[test]
|
|
|
|
fn fx32_basic_ops()
|
|
|
|
{
|
|
|
|
let seven_div_2 = 3 << Fx32::FRACBITS | Fx32::FRACMASK / 2 + 1;
|
2019-02-08 21:53:27 -08:00
|
|
|
assert_eq!((Fx32::from(1) + 1.into()).to_bits(), 2 << Fx32::FRACBITS);
|
|
|
|
assert_eq!((Fx32::from(2) - 1.into()).to_bits(), 1 << Fx32::FRACBITS);
|
2019-02-04 21:12:10 -08:00
|
|
|
assert_eq!((Fx32::from(6) * 2.into()).to_bits(), 12 << Fx32::FRACBITS);
|
2019-02-08 21:53:27 -08:00
|
|
|
assert_eq!((Fx32::from(6).mul_i(2)).to_bits(), 12 << Fx32::FRACBITS);
|
2019-02-04 21:12:10 -08:00
|
|
|
assert_eq!((Fx32::from(7) / 2.into()).to_bits(), seven_div_2);
|
2019-02-08 21:53:27 -08:00
|
|
|
assert_eq!((Fx32::from(7).div_i(2)).to_bits(), seven_div_2);
|
2019-02-04 21:12:10 -08:00
|
|
|
}
|
2018-12-13 01:04:09 -08:00
|
|
|
|
2019-02-04 21:12:10 -08:00
|
|
|
#[test]
|
|
|
|
#[should_panic]
|
|
|
|
#[allow(unused_must_use)]
|
|
|
|
fn fx32_overflow()
|
|
|
|
{
|
|
|
|
Fx32::from(32767) + 1.into();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn fx32_printing()
|
|
|
|
{
|
2019-02-08 21:53:27 -08:00
|
|
|
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");
|
2018-12-13 01:04:09 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// EOF
|