rust ffast-math (defunct, use lower)
Diffstat (limited to 'src/lib.rs')
| -rw-r--r-- | src/lib.rs | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..f7a3c46 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,144 @@ +//! library providing a fast float wrapper. +//! ``` +//! # use umath::FFloat; +//! # unsafe { +//! let mut f = FFloat::new(5.0); +//! f *= 7.0; +//! assert_eq!(*f, 35.0); +//! # } +//! ``` +#![feature(core_intrinsics)] +#![warn(clippy::pedantic, clippy::dbg_macro, clippy::use_self, missing_docs)] +use std::ops::{ + Add as add, AddAssign as add_assign, Deref, DerefMut, Div as div, DivAssign as div_assign, + Mul as mul, MulAssign as mul_assign, Rem as rem, RemAssign as rem_assign, Sub as sub, + SubAssign as sub_assign, +}; + +mod r#trait; +use r#trait::FastFloat; + +/// Float wrapper that uses `ffast-math`. +/// ``` +/// # use umath::FFloat; +/// # unsafe { +/// let result = FFloat::new(27.0) * 42109.0; +/// assert_eq!(*result, 1136943.0); +/// # } +/// ``` +pub struct FFloat<T>(T); + +impl<T: FastFloat> FFloat<T> { + /// Create a new [`FFloat`] from your {[`f32`], [`f64`]}. + /// There is no checked new, because it needs to be `unsafe` so that i can make sure you will never do any funny. + /// + /// # Safety + /// + /// you must solemnly swear that your number is not [`NAN`](std::f32::NAN) | [`INF`](std::f32::INFINITY), and you will not make it [`NAN`](std::f32::NAN) | [`INF`](std::f32::INFINITY). + /// ``` + /// # use umath::FFloat; + /// // SAFETY: i have verified that 7.0 is infact, not NAN or INF. + /// let f = unsafe { FFloat::new(7.0) }; + /// ``` + pub unsafe fn new(from: T) -> Self { + debug_assert!(!from.bad()); + Self(from) + } +} + +impl<T> Deref for FFloat<T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<T> DerefMut for FFloat<T> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +macro_rules! op { + ($name:ident) => { + impl<T: FastFloat> $name<T> for FFloat<T> { + type Output = FFloat<T>; + + fn $name(self, rhs: T) -> Self::Output { + unsafe { Self::new(T::$name(self.0, rhs)) } + } + } + + impl<T: FastFloat> $name<&T> for FFloat<T> { + type Output = FFloat<T>; + + fn $name(self, rhs: &T) -> Self::Output { + unsafe { Self::new(T::$name(self.0, *rhs)) } + } + } + + impl<T: FastFloat> $name for FFloat<T> { + type Output = FFloat<T>; + fn $name(self, FFloat(rhs): FFloat<T>) -> Self::Output { + unsafe { Self::new(T::$name(self.0, rhs)) } + } + } + + impl<T: FastFloat> $name<&FFloat<T>> for FFloat<T> { + type Output = FFloat<T>; + fn $name(self, FFloat(rhs): &FFloat<T>) -> Self::Output { + unsafe { Self::new(T::$name(self.0, *rhs)) } + } + } + }; +} + +op!(add); +op!(div); +op!(mul); +op!(rem); +op!(sub); + +macro_rules! assign { + ($name:ident, $op:ident) => { + impl<T: FastFloat> $name<T> for FFloat<T> { + fn $name(&mut self, rhs: T) { + *self = unsafe { Self::new(T::$op(self.0, rhs)) }; + } + } + + impl<T: FastFloat> $name<&T> for FFloat<T> { + fn $name(&mut self, rhs: &T) { + *self = unsafe { Self::new(T::$op(self.0, *rhs)) }; + } + } + + impl<T: FastFloat> $name for FFloat<T> { + fn $name(&mut self, FFloat(rhs): FFloat<T>) { + *self = unsafe { Self::new(T::$op(self.0, rhs)) }; + } + } + + impl<T: FastFloat> $name<&FFloat<T>> for FFloat<T> { + fn $name(&mut self, FFloat(rhs): &FFloat<T>) { + *self = unsafe { Self::new(T::$op(self.0, *rhs)) }; + } + } + }; +} +assign!(add_assign, add); +assign!(div_assign, div); +assign!(mul_assign, mul); +assign!(rem_assign, rem); +assign!(sub_assign, sub); + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn it_works() { + let result = unsafe { FFloat::new(2.0) + FFloat::new(2.0) }; + assert_eq!(*result, 4.0); + } +} |