simba/scalar/
real.rs

1use num::Signed;
2use std::{f32, f64};
3
4use approx::{RelativeEq, UlpsEq};
5
6use crate::scalar::ComplexField;
7
8#[cfg(all(
9    any(target_arch = "nvptx", target_arch = "nvptx64"),
10    not(feature = "std"),
11    not(feature = "libm_force"),
12    feature = "cuda"
13))]
14use cuda_std::GpuFloat;
15#[cfg(all(not(feature = "std"), not(feature = "libm_force"), feature = "libm"))]
16use num::Float;
17//#[cfg(feature = "decimal")]
18//use decimal::d128;
19
20/// Trait shared by all reals.
21#[allow(missing_docs)]
22pub trait RealField:
23    ComplexField<RealField = Self>
24    + RelativeEq<Epsilon = Self>
25    + UlpsEq<Epsilon = Self>
26    + Signed
27    + PartialOrd
28{
29    /// Is the sign of this real number positive?
30    fn is_sign_positive(&self) -> bool;
31    /// Is the sign of this real number negative?
32    fn is_sign_negative(&self) -> bool;
33    /// Copies the sign of `sign` to `self`.
34    ///
35    /// - Returns `self.simd_abs()` if `sign` is positive or positive-zero.
36    /// - Returns `-self.simd_abs()` if `sign` is negative or negative-zero.
37    fn copysign(self, sign: Self) -> Self;
38
39    fn max(self, other: Self) -> Self;
40    fn min(self, other: Self) -> Self;
41    fn clamp(self, min: Self, max: Self) -> Self;
42    fn atan2(self, other: Self) -> Self;
43
44    /// The smallest finite positive value representable using this type.
45    fn min_value() -> Option<Self>;
46    /// The largest finite positive value representable using this type.
47    fn max_value() -> Option<Self>;
48
49    fn pi() -> Self;
50    fn two_pi() -> Self;
51    fn frac_pi_2() -> Self;
52    fn frac_pi_3() -> Self;
53    fn frac_pi_4() -> Self;
54    fn frac_pi_6() -> Self;
55    fn frac_pi_8() -> Self;
56    fn frac_1_pi() -> Self;
57    fn frac_2_pi() -> Self;
58    fn frac_2_sqrt_pi() -> Self;
59
60    fn e() -> Self;
61    fn log2_e() -> Self;
62    fn log10_e() -> Self;
63    fn ln_2() -> Self;
64    fn ln_10() -> Self;
65}
66
67macro_rules! impl_real(
68    ($($T:ty, $M:ident, $cpysgn_mod: ident, $atan_mod: ident);*) => ($(
69        impl RealField for $T {
70            #[inline]
71            fn is_sign_positive(&self) -> bool {
72                $M::is_sign_positive(*self)
73            }
74
75            #[inline]
76            fn is_sign_negative(&self) -> bool {
77                $M::is_sign_negative(*self)
78            }
79
80            #[inline(always)]
81            fn copysign(self, sign: Self) -> Self {
82                $cpysgn_mod::copysign(self, sign)
83            }
84
85            #[inline]
86            fn max(self, other: Self) -> Self {
87                $M::max(self, other)
88            }
89
90            #[inline]
91            fn min(self, other: Self) -> Self {
92                $M::min(self, other)
93            }
94
95            #[inline]
96            fn clamp(self, min: Self, max: Self) -> Self {
97                if self < min {
98                    min
99                } else if self > max {
100                    max
101                } else {
102                    self
103                }
104            }
105
106            #[inline]
107            fn atan2(self, other: Self) -> Self {
108                $atan_mod::atan2(self, other)
109            }
110
111
112            /// The smallest finite positive value representable using this type.
113            #[inline]
114            fn min_value() -> Option<Self> {
115                Some($M::MIN)
116            }
117
118            /// The largest finite positive value representable using this type.
119            #[inline]
120            fn max_value() -> Option<Self> {
121                Some($M::MAX)
122            }
123
124            /// Archimedes' constant.
125            #[inline]
126            fn pi() -> Self {
127                $M::consts::PI
128            }
129
130            /// 2.0 * pi.
131            #[inline]
132            fn two_pi() -> Self {
133                $M::consts::PI + $M::consts::PI
134            }
135
136            /// pi / 2.0.
137            #[inline]
138            fn frac_pi_2() -> Self {
139                $M::consts::FRAC_PI_2
140            }
141
142            /// pi / 3.0.
143            #[inline]
144            fn frac_pi_3() -> Self {
145                $M::consts::FRAC_PI_3
146            }
147
148            /// pi / 4.0.
149            #[inline]
150            fn frac_pi_4() -> Self {
151                $M::consts::FRAC_PI_4
152            }
153
154            /// pi / 6.0.
155            #[inline]
156            fn frac_pi_6() -> Self {
157                $M::consts::FRAC_PI_6
158            }
159
160            /// pi / 8.0.
161            #[inline]
162            fn frac_pi_8() -> Self {
163                $M::consts::FRAC_PI_8
164            }
165
166            /// 1.0 / pi.
167            #[inline]
168            fn frac_1_pi() -> Self {
169                $M::consts::FRAC_1_PI
170            }
171
172            /// 2.0 / pi.
173            #[inline]
174            fn frac_2_pi() -> Self {
175                $M::consts::FRAC_2_PI
176            }
177
178            /// 2.0 / sqrt(pi).
179            #[inline]
180            fn frac_2_sqrt_pi() -> Self {
181                $M::consts::FRAC_2_SQRT_PI
182            }
183
184
185            /// Euler's number.
186            #[inline]
187            fn e() -> Self {
188                $M::consts::E
189            }
190
191            /// log2(e).
192            #[inline]
193            fn log2_e() -> Self {
194                $M::consts::LOG2_E
195            }
196
197            /// log10(e).
198            #[inline]
199            fn log10_e() -> Self {
200                $M::consts::LOG10_E
201            }
202
203            /// ln(2.0).
204            #[inline]
205            fn ln_2() -> Self {
206                $M::consts::LN_2
207            }
208
209            /// ln(10.0).
210            #[inline]
211            fn ln_10() -> Self {
212                $M::consts::LN_10
213            }
214        }
215    )*)
216);
217
218#[cfg(all(
219    not(target_arch = "nvptx"),
220    not(target_arch = "nvptx64"),
221    not(feature = "std"),
222    not(feature = "libm_force"),
223    feature = "libm"
224))]
225impl_real!(f32, f32, Float, Float; f64, f64, Float, Float);
226#[cfg(all(feature = "std", not(feature = "libm_force")))]
227impl_real!(f32, f32, f32, f32; f64, f64, f64, f64);
228#[cfg(all(
229    any(target_arch = "nvptx", target_arch = "nvptx64"),
230    not(feature = "std"),
231    not(feature = "libm_force"),
232    feature = "cuda"
233))]
234impl_real!(
235    f32, f32, GpuFloat, GpuFloat;
236    f64, f64, GpuFloat, GpuFloat
237);
238#[cfg(feature = "libm_force")]
239impl_real!(f32, f32, libm_force_f32, libm_force_f32; f64, f64, libm_force, libm_force);
240
241// We use this dummy module to remove the 'f' suffix at the end of
242// each libm functions to make our generic Real/ComplexField impl
243// macros work.
244#[cfg(feature = "libm_force")]
245mod libm_force_f32 {
246    #[inline(always)]
247    pub fn atan2(y: f32, x: f32) -> f32 {
248        libm_force::atan2f(y, x)
249    }
250
251    #[inline(always)]
252    pub fn copysign(x: f32, y: f32) -> f32 {
253        libm_force::copysignf(x, y)
254    }
255}
256
257//#[cfg(feature = "decimal")]
258//impl_real!(d128, d128, d128);