Diffstat (limited to 'src/fast.rs')
-rw-r--r--src/fast.rs88
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;