rust ffast-math (defunct, use lower)
-rw-r--r--.gitignore2
-rw-r--r--Cargo.toml9
-rw-r--r--LICENSE21
-rw-r--r--src/lib.rs144
-rw-r--r--src/trait.rs30
5 files changed, 206 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..96ef6c0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+/target
+Cargo.lock
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..cd66a30
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "umath"
+version = "0.0.0"
+description = "ffast-math in rust"
+license = "MIT"
+repository = "https://github.com/bend-n/umath"
+authors = ["bend-n <[email protected]>"]
+edition = "2021"
+exclude = [".gitignore"]
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..1fafc15
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 bendn
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
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);
+ }
+}
diff --git a/src/trait.rs b/src/trait.rs
new file mode 100644
index 0000000..dfe0c21
--- /dev/null
+++ b/src/trait.rs
@@ -0,0 +1,30 @@
+use std::intrinsics::{
+ fadd_fast as add, fdiv_fast as div, fmul_fast as mul, frem_fast as rem, fsub_fast as sub,
+};
+macro_rules! meth {
+ ($($name:ident)|+) => {
+ pub trait FastFloat: Copy {
+ $(#[doc(hidden)] unsafe fn $name(a: Self, b: Self) -> Self;)+
+ #[doc(hidden)]
+ fn bad(self) -> bool;
+ }
+
+ impl FastFloat for f32 {
+ $(unsafe fn $name(a: Self, b: Self) -> Self {
+ $name(a, b)
+ })+
+
+
+ fn bad(self) -> bool { self.is_nan() || self.is_infinite() }
+ }
+
+ impl FastFloat for f64 {
+ $(unsafe fn $name(a: Self, b: Self) -> Self {
+ $name(a, b)
+ })+
+
+ fn bad(self) -> bool { self.is_nan() || self.is_infinite() }
+ }
+ };
+}
+meth!(add | sub | div | mul | rem);