Skip to main content

macerator/
unary.rs

1use half::f16;
2use paste::paste;
3
4use crate::{Scalar, Simd, Vector};
5
6pub trait VRecip: Scalar {
7    fn vrecip<S: Simd>(input: Vector<S, Self>) -> Vector<S, Self>;
8    fn is_accelerated<S: Simd>() -> bool;
9}
10
11impl<S: Simd, T: VRecip> Vector<S, T> {
12    /// Elementwise reciprocal (`1 / x`).
13    ///
14    /// `f32`/`f64` are accurate within a few ULP using Newton-Raphson refinement.
15    /// Special values (`±0`, `±inf`, `NaN`) map accurately across all backends.
16    ///
17    /// Backends that flush subnormals (e.g. SSE/AVX2 `rcp_ps`) saturate subnormal inputs
18    /// or subnormal results to signed `±inf`/`±0`, preserving sign without returning NaN.
19    /// `f16` uses unrefined hardware estimates (~8-bit precision) for now.
20    #[inline(always)]
21    pub fn recip(self) -> Self {
22        T::vrecip(self)
23    }
24}
25
26pub trait VSqrt: Scalar {
27    fn vsqrt<S: Simd>(input: Vector<S, Self>) -> Vector<S, Self>;
28    fn is_accelerated<S: Simd>() -> bool;
29}
30
31impl<S: Simd, T: VSqrt> Vector<S, T> {
32    /// Elementwise square root. Correctly rounded on every SIMD backend; the
33    /// scalar fallback uses the platform's `sqrt`.
34    #[inline(always)]
35    pub fn sqrt(self) -> Self {
36        T::vsqrt(self)
37    }
38}
39
40pub trait VAbs: Scalar {
41    fn vabs<S: Simd>(input: Vector<S, Self>) -> Vector<S, Self>;
42    fn is_accelerated<S: Simd>() -> bool;
43}
44
45impl<S: Simd, T: VAbs> Vector<S, T> {
46    /// Elementwise absolute value. For signed integers, `MIN` wraps to itself.
47    #[inline(always)]
48    pub fn abs(self) -> Self {
49        T::vabs(self)
50    }
51}
52
53macro_rules! impl_unop {
54    ($trait: ident, $name: ident, $($ty: ty),*) => {
55        $(paste! {
56            impl $trait for $ty {
57                #[inline(always)]
58                fn [<$trait:lower>]<S: Simd>(input: Vector<S, Self>) -> Vector<S, Self> {
59                    S::typed(S::[<$name _ $ty>](*input))
60                }
61                #[inline(always)]
62                fn is_accelerated<S: Simd>() -> bool {
63                    S::[<$name _ $ty _supported>]()
64                }
65            }
66        })*
67    };
68}
69
70impl_unop!(VRecip, recip, f16, f32, f64);
71impl_unop!(VAbs, abs, i8, i16, f16, i32, i64, f32, f64);
72impl_unop!(VSqrt, sqrt, f16, f32, f64);