Diffstat (limited to 'src/fast.rs')
| -rw-r--r-- | src/fast.rs | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/src/fast.rs b/src/fast.rs new file mode 100644 index 0000000..e375172 --- /dev/null +++ b/src/fast.rs @@ -0,0 +1,88 @@ +//! Provides the fast math trait and macro. See terms and conditions[^1]. +//! +//! [^1]: <https://simonbyrne.github.io/notes/fastmath> +#[allow(unused_imports)] +use std::f32::{INFINITY as INF, NAN}; + +macro_rules! s { + ($($x:tt)+) => { + #[doc = include_str!("fast.safety.md")] + $($x)+; + }; +} + +#[rustfmt::skip] +/// Trait for fast math floats. Try to use [`fast::math`](crate::fast::math). +/// These functions all assume that your float is NOT [`INF`] | [`NAN`]. +/// If so undefined behaviour is incurred. +pub unsafe trait Float: Copy { + s!(unsafe fn add(self, other: Self) -> Self); + s!(unsafe fn sub(self, other: Self) -> Self); + s!(unsafe fn mul(self, other: Self) -> Self); + s!(unsafe fn div(self, other: Self) -> Self); + s!(unsafe fn rem(self, other: Self) -> Self); + + s!(unsafe fn eq(self, other: Self) -> bool); + s!(unsafe fn lt(self, other: Self) -> bool); + s!(unsafe fn le(self, other: Self) -> bool); + s!(unsafe fn ne(self, other: Self) -> bool); + s!(unsafe fn ge(self, other: Self) -> bool); + s!(unsafe fn gt(self, other: Self) -> bool); + + fn deref(&self) -> Self { + *self + } + fn neg(self) -> Self; + + #[doc(hidden)] + unsafe fn finite(self, other: Self) -> Self; +} + +use std::intrinsics::*; +macro_rules! imp { + ($this:ty) => { +#[rustfmt::skip] +unsafe impl Float for $this { + #[inline(always)] + unsafe fn finite(self, other: Self) -> Self { + core::hint::assert_unchecked(self.is_finite()); + core::hint::assert_unchecked(other.is_finite()); + self + } + unsafe fn add(self, other: Self) -> Self { fadd_fast(self.finite(other), other) } + unsafe fn sub(self, other: Self) -> Self { fsub_fast(self.finite(other), other) } + unsafe fn mul(self, other: Self) -> Self { fmul_fast(self.finite(other), other) } + unsafe fn div(self, other: Self) -> Self { fdiv_fast(self.finite(other), other) } + unsafe fn rem(self, other: Self) -> Self { frem_fast(self.finite(other), other) } + + unsafe fn eq(self, other: Self) -> bool { (self.finite(other) + 0.0).to_bits() == (other + 0.0).to_bits() } + unsafe fn lt(self, other: Self) -> bool { self.finite(other) < other } + unsafe fn le(self, other: Self) -> bool { self.finite(other) <= other } + unsafe fn ne(self, other: Self) -> bool { self.finite(other) != other } + unsafe fn ge(self, other: Self) -> bool { self.finite(other) >= other } + unsafe fn gt(self, other: Self) -> bool { self.finite(other) > other } + + fn deref(&self) -> Self { *self } + fn neg(self) -> Self { -self } +} + }; +} +imp!(f32); +imp!(f64); + +/// Changes all the math to fast float math. See [`fadd_fast`]. +/// +/// This allows automatic vectorization of float math for the compiler, among other things. +/// If you intend to create a function in this, first import [`lower::fast::Float`](crate::fast::Float), use [`lower::math`](crate::math). +/// +/// This would lower `a * b + c` to `fadd(fmul(a, b), c)`. +#[macro_export] +#[doc(hidden)] +macro_rules! fast { + ($($x:tt)+) => {{ + use $crate::fast::Float as _; + lower_macros::math! { $($x)+ } + }} +} +#[doc(inline)] +pub use fast as math; |