1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
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;