diff --git a/.gitignore b/.gitignore index 3ca43ae..a6e9b5f 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,9 @@ Cargo.lock # MSVC Windows builds of rustc generate these, which store debugging information *.pdb + + +# Added by cargo + +/target +/Cargo.lock diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..639900d --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..31e6534 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/staticdot.iml b/.idea/staticdot.iml new file mode 100644 index 0000000..9b4cf84 --- /dev/null +++ b/.idea/staticdot.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..a09086c --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "staticdot" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..8d9349f --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,87 @@ +use std::ops; +use std::ops::{Add, BitAnd, Div, Mul, Shl, Shr, Sub}; + +const INTEGER_BITS: i32 = 8; +const FRACTION_BITS: i32 = 24; +/// in oder to create the fraction bits mask we first fill all bits with 1 by initializing it with -1 +/// then we reinterpret the -1 as unsigned and shift it to the left. We need to do this in order to +/// avoid arithmetic shifts +const FRACTION_MASK: i32 = (-1i32 as u32 >> INTEGER_BITS) as i32; + +#[derive(Copy, Clone)] +pub struct Fixed32(i32); + +impl From for Fixed32 { + fn from(value: i32) -> Self { + Fixed32(value.shl(FRACTION_BITS)) + } +} + +impl From for Fixed32 { + fn from(value: f32) -> Self { + let integral = (value as i32).shl(FRACTION_BITS); + let fraction = (value.fract() * 1.shl(FRACTION_BITS) as f32) as i32; + Fixed32(integral | fraction) + } +} + +impl Into for Fixed32 { + fn into(self) -> i32 { + self.0.shr(FRACTION_BITS) + } +} + +impl Into for Fixed32 { + fn into(self) -> f32 { + let integral = self.0.shr(FRACTION_BITS) as f32; + let fraction = self.0.bitand(FRACTION_MASK) as f32 / 1.shl(FRACTION_BITS) as f32; + integral + fraction + } +} + +impl Add for Fixed32 { + type Output = Fixed32; + + fn add(self, rhs: Fixed32) -> Self::Output { + Fixed32(self.0 + rhs.0) + } +} + +impl Sub for Fixed32 { + type Output = Fixed32; + + fn sub(self, rhs: Fixed32) -> Self::Output { + Fixed32(self.0 - rhs.0) + } +} + +impl Mul for Fixed32 { + type Output = Fixed32; + + fn mul(self, rhs: Fixed32) -> Self::Output { + Fixed32(self.0.shr(FRACTION_BITS / 2) * rhs.0.shr(FRACTION_BITS / 2)) + } +} + +impl Div for Fixed32 { + type Output = Fixed32; + + fn div(self, rhs: Fixed32) -> Self::Output { + Fixed32((self.0 / rhs.0.shr(FRACTION_BITS / 2)).shl(FRACTION_BITS / 2)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test() { + let a = Fixed32::from(9); + let b = Fixed32::from(3); + + let c = a * a / b; + + println!("{}", Into::::into(c)); + } +}