devela/num/float/wrapper/
libm_std.rs

1// devela::num::float::wrapper::libm_std
2//
3//! Methods depending on libm, std, or their absence
4//
5// TOC
6// - impls for libm
7// - impls for std && not(libm)
8// - impls for not(std) && not(libm)
9// - macro helper: impl_fp!
10
11use crate::Float;
12
13#[cfg(feature = "dep_libm")]
14mod _libm {
15    use super::{super::super::shared_docs::*, impl_fp, Float};
16    use crate::{_dep::libm::Libm, iif};
17
18    // custom implementations are commented out
19    impl_fp![libm:f*:
20        r"The largest integer less than or equal to `x`.
21        $$ \lfloor x \rfloor = \max \{ n \in \mathbb{Z} \,|\, n \leq x \} $$ "
22        floor = floor: ;
23        r"The smallest integer greater than or equal to `x`.
24        $$ \lceil x \rceil = \min \{ n \in \mathbb{Z} \,|\, n \geq x \} $$"
25        ceil = ceil: ;
26        "The nearest integer to itself, rounding ties away from `0.0`."
27        round = round_ties_away: ;
28        "The integral part."
29        trunc = trunc: ;
30        // fract
31        // split == modf
32        // abs
33        // signum
34        // copysign = copysign: sign;
35        "Fused multiply-add. Computes (self * mul) + add with only one rounding error."
36        fma = mul_add: mul, add;
37        // div_euclid
38        // rem_euclid
39        "Raises itself to the `p` floating point power."
40        pow = powf: p;
41        // powi
42        "Square root."
43        sqrt = sqrt: ;
44        "$e^x$ (the exponential function)."
45        exp = exp: ;
46        "$2^x$."
47        exp2 = exp2: ;
48        "$e^x -1$, more accurately for small values of `x`."
49        expm1 = exp_m1: ;
50        // ln = ln: x;
51        "The natural logarithm."
52        log = ln: ;
53        "The natural logarithm plus 1, more accurately."
54        log1p = ln_1p: ;
55        // log
56        "The base 2 logarithm."
57        log2 = log2: ;
58        "The base 10 logarithm."
59        log10 = log10: ;
60        "The cubic root."
61        cbrt = cbrt: ;
62        "The hypothenuse (the euclidean distance)."
63        hypot = hypot: other;
64        "The sine."
65        sin = sin: ;
66        "The cosine."
67        cos = cos: ;
68        "The tangent."
69        tan = tan: ;
70        "The arc sine."
71        asin = asin: ;
72        "The arc cosine."
73        acos = acos: ;
74        "The arc tangent."
75        atan = atan: ;
76        "The arc tangent of two variables."
77        atan2 = atan2: other;
78        // sin_cos
79        "The hyperbolic sine."
80        sinh = sinh: ;
81        "The hyperbolic cosine."
82        cosh = cosh: ;
83        "The hyperbolic tangent."
84        tanh = tanh: ;
85        "The inverse hyperbolic sine."
86        asinh = asinh: ;
87        "The inverse hyperbolic cosine."
88        acosh = acosh: ;
89        "The inverse hyperbolic tangent."
90        atanh = atanh: ;
91        // fmax = max: other;
92        // fmin = min: other;
93
94        /* only in libm */
95
96        "`10^x`."
97        exp10 = exp10: ;
98        "The gamma function. Generalizes the factorial function to complex numbers."
99        tgamma = gamma: ;
100        "The natural logarithm of the absolute value of the gamma function."
101        lgamma = lgamma: ;
102        "The error function."
103        erf = erf: ;
104        "The complementary error function (1 - erf)."
105        erfc = erfc: ;
106        "The bessel function of the first kind, of order 0."
107        j0 = j0: ;
108        "The bessel function of the first kind, of order 1."
109        j1 = j1: ;
110        // jn
111        "The bessel function of the second kind, of order 0."
112        y0 = y0: ;
113        "The bessel function of the second kind, of order 1."
114        y1 = y1:
115        // yn
116    ]; // IMPORTANT: do not end with `;`
117
118    /// $f:   the floating-point type.
119    /// $e:   the integer type for integer exponentiation.
120    /// $cap: the capability feature enables the given implementation. E.g "_float_f32".
121    macro_rules! custom_impls {
122        () => {
123            custom_impls![(f32, i32):"_float_f32", (f64, i32):"_float_f64"];
124        };
125
126        ($( ($f:ty, $e:ty): $cap:literal ),+) => {
127            $( custom_impls![@$f, $e, $cap]; )+
128        };
129        (@$f:ty, $e:ty, $cap:literal) => {
130            #[doc = crate::doc_availability!(feature = $cap)]
131            ///
132            /// # *Implementations using the `libm` feature*.
133            #[cfg(feature = $cap )]
134            // #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = $cap)))]
135            impl Float<$f> {
136                /// The fractional part.
137                /// # Formulation
138                #[doc = FORMULA_FRACT!()]
139                pub fn fract(self) -> Float<$f> { Float(self.0 - Libm::<$f>::trunc(self.0)) }
140
141                /// The integral and fractional parts.
142                /// # Formulation
143                #[doc = FORMULA_SPLIT!()]
144                pub fn split(self) -> (Float<$f>, Float<$f>) {
145                    let (i, f) = Libm::<$f>::modf(self.0);
146                    (Self(i), Self(f))
147                }
148
149                /// Returns the nearest integer to `x`, rounding ties to the nearest even integer.
150                pub fn round_ties_even(self) -> Float<$f> {
151                    let r = self.round_ties_away();
152                    iif![r.0 % 2.0 == 0.0; r;
153                        iif![(self - r).abs() == 0.5; r - self.signum(); r]]
154                }
155
156                /// Raises `x` to the `p` integer power.
157                pub fn powi(self, p: $e) -> Float<$f> { self.powf(p as $f) }
158
159                /// The logarithm of the number with respect to an arbitrary base.
160                pub fn log(self, base: $f) -> Float<$f> {
161                    // Float(Self::ln(base).0 / Self::ln(self).0)
162                    Float(Float(base).ln().0 / self.ln().0)
163                }
164
165                /// The sine and cosine.
166                pub fn sin_cos(self) -> (Float<$f>, Float<$f>) {
167                    let (sin, cos) = Libm::<$f>::sincos(self.0);
168                    (Float(sin), Float(cos))
169                }
170
171                /* only in libm */
172
173                /// The natural logarithm of the absolute value of the gamma function,
174                /// plus its sign.
175                pub fn lgamma_r(self) -> (Float<$f>, $e) {
176                    let (f, sign) = Libm::<$f>::lgamma_r(self.0);
177                    (Float(f), sign)
178                }
179                /// Bessel function of the first kind, of order `n`.
180                pub fn jn(self, n: $e) -> Float<$f> { Float(Libm::<$f>::jn(n, self.0)) }
181                /// Bessel function of the second kind, of order `n`.
182                pub fn yn(self, n: $e) -> Float<$f> { Float(Libm::<$f>::yn(n, self.0)) }
183            }
184        };
185    }
186    custom_impls!();
187}
188
189#[cfg(all(not(feature = "dep_libm"), feature = "std"))]
190mod _std {
191    use super::{super::super::shared_docs::*, impl_fp, Float};
192
193    // custom implementations are commented out:
194    impl_fp![std:f*:
195        r"The largest integer less than or equal to `x`.
196        $$ \lfloor x \rfloor = \max \{ n \in \mathbb{Z} \,|\, n \leq x \} $$ "
197        floor = floor: ;
198        r"The smallest integer greater than or equal to `x`.
199        $$ \lceil x \rceil = \min \{ n \in \mathbb{Z} \,|\, n \geq x \} $$"
200        ceil = ceil: ;
201        "The nearest integer to `x`, rounding ties away from `0.0`."
202        round = round_ties_away: ;
203        "The nearest integer to `x`, rounding ties to the nearest even integer."
204        round_ties_even = round_ties_even: ;
205        r"The integral part.
206        $$ \text{trunc}(x) = \begin{cases}
207        \lfloor x \rfloor, & \text{if } x \geq 0 \\
208        \lceil x \rceil, & \text{if } x < 0
209        \end{cases} $$"
210        trunc = trunc: ;
211        r"The fractional part.
212        $$ \text{fract}(x) = x - \text{trunc}(x) $$"
213        fract = fract: ;
214        // split == modf
215        // abs
216        // signum = signum: ;
217        // copysign = copysign: sign;
218        "Fused multiply-add. Computes (self * mul) + add with only one rounding error."
219        mul_add = mul_add: mul, add;
220        // implemented manually for all:
221        // div_euclid = div_euclid: other;
222        // rem_euclid = rem_euclid: other;
223        "Raises itself to the `p` floating point power."
224        powf = powf: p;
225        // powi
226        "The square root."
227        sqrt = sqrt: ;
228        "$e^x$ (the exponential function)."
229        exp = exp: ;
230        "$2^x$."
231        exp2 = exp2: ;
232        "$e^x -1$, more accurately for small values of `x`."
233        exp_m1 = exp_m1: ;
234        "The natural logarithm."
235        ln = ln: ;
236        "The natural logarithm plus 1, more accurately."
237        ln_1p = ln_1p: ;
238        "The logarithm of the number with respect to an arbitrary base."
239        log = log: base;
240        "The base 2 logarithm."
241        log2 = log2: ;
242        "The base 10 logarithm."
243        log10 = log10: ;
244        "The cubic root."
245        cbrt = cbrt: ;
246        "The hypothenuse (the euclidean distance)."
247        hypot = hypot: other;
248        "The sine."
249        sin = sin: ;
250        "The cosine."
251        cos = cos: ;
252        "The tangent."
253        tan = tan: ;
254        "The arc sine."
255        asin = asin: ;
256        "The arc cosine."
257        acos = acos: ;
258        "The arc tangent."
259        atan = atan: ;
260        "The arc tangent of two variables."
261        atan2 = atan2: other;
262        // sin_cos
263        "The hyperbolic sine."
264        sinh = sinh: ;
265        "The hyperbolic cosine."
266        cosh = cosh: ;
267        "The hyperbolic tangent."
268        tanh = tanh: ;
269        "The inverse hyperbolic sine."
270        asinh = asinh: ;
271        "The inverse hyperbolic cosine."
272        acosh = acosh: ;
273        "The inverse hyperbolic tangent."
274        atanh = atanh:
275        // clamp = clamp: min, max;
276        // max = max: other;
277        // min = min: other
278
279        /* not implemented */
280        // exp10: https://internals.rust-lang.org/t/enh-add-exp10-and-expf-base-x-f64-f32-methods-to-stdlib-to-symmetrize-api
281        // WAIT: (next_up, next_down) [float_next_up_down](https://github.com/rust-lang/rust/issues/91399)
282        // WAIT: (gamma, ln_gamma) [float_gamma](https://github.com/rust-lang/rust/issues/99842)
283    ]; // IMPORTANT: do not end with `;`
284
285    /// $f:   the floating-point type.
286    /// $e:   the integer type for integer exponentiation.
287    /// $cap: the capability feature that enables the given implementation. E.g "_float_f32".
288    macro_rules! custom_impls {
289        () => {
290            custom_impls![(f32, i32):"_float_f32", (f64, i32):"_float_f64"];
291        };
292        ($( ($f:ty, $e:ty): $cap:literal ),+) => {
293            $( custom_impls![@$f, $e, $cap]; )+
294        };
295        (@$f:ty, $e:ty, $cap:literal) => {
296            #[doc = crate::doc_availability!(feature = $cap)]
297            ///
298            /// # *Implementations using the `std` feature*.
299            #[cfg(feature = $cap )]
300            // #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = $cap)))]
301            impl Float<$f> {
302                /// Raises itself to the `p` integer power.
303                pub fn powi(self, p: $e) -> Float<$f> { Float(<$f>::powi(self.0, p)) }
304                /// Both the sine and cosine.
305                pub fn sin_cos(self) -> (Float<$f>, Float<$f>) {
306                    let (sin, cos) = <$f>::sin_cos(self.0);
307                    (Float(sin), Float(cos))
308                }
309                /// The integral and fractional parts of `x`.
310                /// # Formulation
311                #[doc = FORMULA_SPLIT!()]
312                pub fn split(self) -> (Float<$f>, Float<$f>) {
313                    let trunc = self.trunc();
314                    (trunc, Float(self.0 - trunc.0))
315                }
316            }
317        };
318    }
319    custom_impls!();
320}
321
322#[cfg(all(not(feature = "dep_libm"), not(feature = "std")))]
323mod _no_std_no_libm {
324    use super::{super::super::shared_docs::*, Float};
325
326    /// $f:   the floating-point type.
327    /// $uf:  unsigned int type with the same bit-size.
328    /// $ie:  the integer type for integer exponentiation.
329    /// $cap: the capability feature that enables the given implementation. E.g "_float_f32".
330    macro_rules! custom_impls {
331        () => {
332            custom_impls![(f32, u32, i32):"_float_f32", (f64, u64, i32):"_float_f64"];
333        };
334        ($( ($f:ty, $uf:ty, $ie:ty) : $cap:literal ),+) => {
335            $( custom_impls![@$f, $uf, $ie, $cap]; )+
336        };
337        (@$f:ty, $uf:ty, $ie:ty, $cap:literal) => {
338            #[doc = crate::doc_availability!(feature = $cap)]
339            ///
340            /// # *Implementations without `std` or `libm`*.
341            #[cfg(feature = $cap )]
342            // #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = $cap)))]
343            impl Float<$f> {
344                /// The largest integer less than or equal to itself.
345                /// # Formulation
346                #[doc = crate::FORMULA_FLOOR!()]
347                pub const fn floor(self) -> Float<$f> { self.const_floor() }
348
349                /// The smallest integer greater than or equal to itself.
350                /// # Formulation
351                #[doc = FORMULA_CEIL!()]
352                pub const fn ceil(self) -> Float<$f> { self.const_ceil() }
353
354                /// The nearest integer to itself, default rounding
355                ///
356                /// This is the default [`round_ties_away`] implementation.
357                pub const fn round(self) -> Float<$f> { self.const_round() }
358
359                /// The nearest integer to itself, rounding ties away from `0.0`.
360                ///
361                /// This is the default [`round`] implementation.
362                ///
363                /// # Formulation
364                #[doc = FORMULA_ROUND_TIES_AWAY!()]
365                pub const fn round_ties_away(self) -> Float<$f> {self.const_round_ties_away() }
366
367                /// Returns the nearest integer to `x`, rounding ties to the nearest even integer.
368                /// # Formulation
369                #[doc = FORMULA_ROUND_TIES_EVEN!()]
370                pub const fn round_ties_even(self) -> Float<$f> { self.const_round_ties_even() }
371
372                /// The integral part.
373                /// This means that non-integer numbers are always truncated towards zero.
374                ///
375                /// # Formulation
376                #[doc = FORMULA_TRUNC!()]
377                ///
378                /// This implementation uses bitwise manipulation to remove the fractional part
379                /// of the floating-point number. The exponent is extracted, and a mask is
380                /// created to remove the fractional part. The new bits are then used to create
381                /// the truncated floating-point number.
382                pub const fn trunc(self) -> Float<$f> { self.const_trunc() }
383
384                /// The fractional part.
385                /// # Formulation
386                #[doc = FORMULA_FRACT!()]
387                pub const fn fract(self) -> Float<$f> { self.const_fract() }
388
389                /// The integral and fractional parts.
390                /// # Formulation
391                #[doc = FORMULA_SPLIT!()]
392                pub const fn split(self) -> (Float<$f>, Float<$f>) { self.const_split() }
393
394                /// Raises itself to the `p` integer power.
395                pub const fn powi(self, p: $ie) -> Float<$f> { self.const_powi(p) }
396            }
397        };
398    }
399    custom_impls!();
400}
401
402/// macro helper for implementing methods for `Float`, from either `libm` or `std`.
403///
404/// $lib: the library to use.
405/// $f: the floating-point type to support.
406/// $doc: an optional documentation string.
407/// $opfn: the original operation function name.
408/// $op: the new operation function name in Float.
409#[cfg(any(feature = "dep_libm", feature = "std"))]
410macro_rules! impl_fp {
411    (
412        // Matches a wildcard floating-point type (f*).
413        // Expands to specific floating-point types (f32, f64).
414        $lib:ident : f* : $($ops:tt)*
415    ) => {
416        impl_fp![$lib : f32 : $($ops)*];
417        impl_fp![$lib : f64 : $($ops)*];
418    };
419    (
420        // Matches a specific floating-point type and any number of operations.
421        // Generates the impl block for Float<$f> and calls the matching implementation.
422        $lib:ident : $f:ty : $($ops:tt)*
423    ) => { $crate::paste! {
424        #[doc = "# *This implementation block leverages the `" $lib "` feature.*"]
425        impl Float<$f> {
426            impl_fp![@$lib : $f : $($ops)*];
427        }
428    }};
429    (
430        // Matches multiple operations and uses recursion to process each one.
431        @$lib:ident : $f:ty : $($doc:literal)? $opfn:ident = $op:ident : $($arg:ident),*
432        ; $($rest:tt)*
433    ) => {
434        impl_fp![@$lib : $f : $($doc)? $opfn = $op : $($arg),*];
435        impl_fp![@$lib : $f : $($rest)*];
436    };
437    (
438        // Matches a single operation and implements it using the `libm` library.
439        @libm : $f:ty : $($doc:literal)? $opfn:ident = $op:ident : $($arg:ident),* $(;)?
440    ) => {
441        $(#[doc = $doc])?
442        pub fn $op(self, $($arg: $f),*) -> Float<$f> {
443            Float($crate::_dep::libm::Libm::<$f>::$opfn(self.0, $($arg),*))
444        }
445    };
446    (
447        // Matches a single operation and implements it using the `std` library.
448        @std : $f:ty : $($doc:literal)? $opfn:ident = $op:ident : $($arg:ident),* $(;)?
449    ) => {
450        $(#[doc = $doc])?
451        pub fn $op(self, $($arg: $f),*) -> Float<$f> {
452            Float(<$f>::$opfn(self.0, $($arg),*))
453        }
454    };
455}
456#[cfg(any(feature = "dep_libm", feature = "std"))]
457use impl_fp;