bevy_math/
ops.rs

1//! This mod re-exports the correct versions of floating-point operations with
2//! unspecified precision in the standard library depending on whether the `libm`
3//! crate feature is enabled.
4//!
5//! All the functions here are named according to their versions in the standard
6//! library.
7//!
8//! It also provides `no_std` compatible alternatives to certain floating-point
9//! operations which are not provided in the [`core`] library.
10
11// Note: There are some Rust methods with unspecified precision without a `libm`
12// equivalent:
13// - `f32::powi` (integer powers)
14// - `f32::log` (logarithm with specified base)
15// - `f32::abs_sub` (actually unsure if `libm` has this, but don't use it regardless)
16//
17// Additionally, the following nightly API functions are not presently integrated
18// into this, but they would be candidates once standardized:
19// - `f32::gamma`
20// - `f32::ln_gamma`
21
22#[cfg(all(not(feature = "libm"), feature = "std"))]
23#[expect(
24    clippy::disallowed_methods,
25    reason = "Many of the disallowed methods are disallowed to force code to use the feature-conditional re-exports from this module, but this module itself is exempt from that rule."
26)]
27mod std_ops {
28
29    /// Raises a number to a floating point power.
30    ///
31    /// Precision is specified when the `libm` feature is enabled.
32    #[inline(always)]
33    pub fn powf(x: f32, y: f32) -> f32 {
34        f32::powf(x, y)
35    }
36
37    /// Returns `e^(self)`, (the exponential function).
38    ///
39    /// Precision is specified when the `libm` feature is enabled.
40    #[inline(always)]
41    pub fn exp(x: f32) -> f32 {
42        f32::exp(x)
43    }
44
45    /// Returns `2^(self)`.
46    ///
47    /// Precision is specified when the `libm` feature is enabled.
48    #[inline(always)]
49    pub fn exp2(x: f32) -> f32 {
50        f32::exp2(x)
51    }
52
53    /// Returns the natural logarithm of the number.
54    ///
55    /// Precision is specified when the `libm` feature is enabled.
56    #[inline(always)]
57    pub fn ln(x: f32) -> f32 {
58        f32::ln(x)
59    }
60
61    /// Returns the base 2 logarithm of the number.
62    ///
63    /// Precision is specified when the `libm` feature is enabled.
64    #[inline(always)]
65    pub fn log2(x: f32) -> f32 {
66        f32::log2(x)
67    }
68
69    /// Returns the base 10 logarithm of the number.
70    ///
71    /// Precision is specified when the `libm` feature is enabled.
72    #[inline(always)]
73    pub fn log10(x: f32) -> f32 {
74        f32::log10(x)
75    }
76
77    /// Returns the cube root of a number.
78    ///
79    /// Precision is specified when the `libm` feature is enabled.
80    #[inline(always)]
81    pub fn cbrt(x: f32) -> f32 {
82        f32::cbrt(x)
83    }
84
85    /// Compute the distance between the origin and a point `(x, y)` on the Euclidean plane.
86    /// Equivalently, compute the length of the hypotenuse of a right-angle triangle with other sides having length `x.abs()` and `y.abs()`.
87    ///
88    /// Precision is specified when the `libm` feature is enabled.
89    #[inline(always)]
90    pub fn hypot(x: f32, y: f32) -> f32 {
91        f32::hypot(x, y)
92    }
93
94    /// Computes the sine of a number (in radians).
95    ///
96    /// Precision is specified when the `libm` feature is enabled.
97    #[inline(always)]
98    pub fn sin(x: f32) -> f32 {
99        f32::sin(x)
100    }
101
102    /// Computes the cosine of a number (in radians).
103    ///
104    /// Precision is specified when the `libm` feature is enabled.
105    #[inline(always)]
106    pub fn cos(x: f32) -> f32 {
107        f32::cos(x)
108    }
109
110    /// Computes the tangent of a number (in radians).
111    ///
112    /// Precision is specified when the `libm` feature is enabled.
113    #[inline(always)]
114    pub fn tan(x: f32) -> f32 {
115        f32::tan(x)
116    }
117
118    /// Computes the arcsine of a number. Return value is in radians in
119    /// the range [-pi/2, pi/2] or NaN if the number is outside the range
120    /// [-1, 1].
121    ///
122    /// Precision is specified when the `libm` feature is enabled.
123    #[inline(always)]
124    pub fn asin(x: f32) -> f32 {
125        f32::asin(x)
126    }
127
128    /// Computes the arccosine of a number. Return value is in radians in
129    /// the range [0, pi] or NaN if the number is outside the range
130    /// [-1, 1].
131    ///
132    /// Precision is specified when the `libm` feature is enabled.
133    #[inline(always)]
134    pub fn acos(x: f32) -> f32 {
135        f32::acos(x)
136    }
137
138    /// Computes the arctangent of a number. Return value is in radians in the
139    /// range [-pi/2, pi/2];
140    ///
141    /// Precision is specified when the `libm` feature is enabled.
142    #[inline(always)]
143    pub fn atan(x: f32) -> f32 {
144        f32::atan(x)
145    }
146
147    /// Computes the four-quadrant arctangent of `y` and `x` in radians.
148    ///
149    /// * `x = 0`, `y = 0`: `0`
150    /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]`
151    /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]`
152    /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)`
153    ///
154    /// Precision is specified when the `libm` feature is enabled.
155    #[inline(always)]
156    pub fn atan2(y: f32, x: f32) -> f32 {
157        f32::atan2(y, x)
158    }
159
160    /// Simultaneously computes the sine and cosine of the number, `x`. Returns
161    /// `(sin(x), cos(x))`.
162    ///
163    /// Precision is specified when the `libm` feature is enabled.
164    #[inline(always)]
165    pub fn sin_cos(x: f32) -> (f32, f32) {
166        f32::sin_cos(x)
167    }
168
169    /// Returns `e^(self) - 1` in a way that is accurate even if the
170    /// number is close to zero.
171    ///
172    /// Precision is specified when the `libm` feature is enabled.
173    #[inline(always)]
174    pub fn exp_m1(x: f32) -> f32 {
175        f32::exp_m1(x)
176    }
177
178    /// Returns `ln(1+n)` (natural logarithm) more accurately than if
179    /// the operations were performed separately.
180    ///
181    /// Precision is specified when the `libm` feature is enabled.
182    #[inline(always)]
183    pub fn ln_1p(x: f32) -> f32 {
184        f32::ln_1p(x)
185    }
186
187    /// Hyperbolic sine function.
188    ///
189    /// Precision is specified when the `libm` feature is enabled.
190    #[inline(always)]
191    pub fn sinh(x: f32) -> f32 {
192        f32::sinh(x)
193    }
194
195    /// Hyperbolic cosine function.
196    ///
197    /// Precision is specified when the `libm` feature is enabled.
198    #[inline(always)]
199    pub fn cosh(x: f32) -> f32 {
200        f32::cosh(x)
201    }
202
203    /// Hyperbolic tangent function.
204    ///
205    /// Precision is specified when the `libm` feature is enabled.
206    #[inline(always)]
207    pub fn tanh(x: f32) -> f32 {
208        f32::tanh(x)
209    }
210
211    /// Inverse hyperbolic sine function.
212    ///
213    /// Precision is specified when the `libm` feature is enabled.
214    #[inline(always)]
215    pub fn asinh(x: f32) -> f32 {
216        f32::asinh(x)
217    }
218
219    /// Inverse hyperbolic cosine function.
220    ///
221    /// Precision is specified when the `libm` feature is enabled.
222    #[inline(always)]
223    pub fn acosh(x: f32) -> f32 {
224        f32::acosh(x)
225    }
226
227    /// Inverse hyperbolic tangent function.
228    ///
229    /// Precision is specified when the `libm` feature is enabled.
230    #[inline(always)]
231    pub fn atanh(x: f32) -> f32 {
232        f32::atanh(x)
233    }
234}
235
236#[cfg(any(feature = "libm", all(feature = "nostd-libm", not(feature = "std"))))]
237mod libm_ops {
238
239    /// Raises a number to a floating point power.
240    ///
241    /// Precision is specified when the `libm` feature is enabled.
242    #[inline(always)]
243    pub fn powf(x: f32, y: f32) -> f32 {
244        libm::powf(x, y)
245    }
246
247    /// Returns `e^(self)`, (the exponential function).
248    ///
249    /// Precision is specified when the `libm` feature is enabled.
250    #[inline(always)]
251    pub fn exp(x: f32) -> f32 {
252        libm::expf(x)
253    }
254
255    /// Returns `2^(self)`.
256    ///
257    /// Precision is specified when the `libm` feature is enabled.
258    #[inline(always)]
259    pub fn exp2(x: f32) -> f32 {
260        libm::exp2f(x)
261    }
262
263    /// Returns the natural logarithm of the number.
264    ///
265    /// Precision is specified when the `libm` feature is enabled.
266    #[inline(always)]
267    pub fn ln(x: f32) -> f32 {
268        // This isn't documented in `libm` but this is actually the base e logarithm.
269        libm::logf(x)
270    }
271
272    /// Returns the base 2 logarithm of the number.
273    ///
274    /// Precision is specified when the `libm` feature is enabled.
275    #[inline(always)]
276    pub fn log2(x: f32) -> f32 {
277        libm::log2f(x)
278    }
279
280    /// Returns the base 10 logarithm of the number.
281    ///
282    /// Precision is specified when the `libm` feature is enabled.
283    #[inline(always)]
284    pub fn log10(x: f32) -> f32 {
285        libm::log10f(x)
286    }
287
288    /// Returns the cube root of a number.
289    ///
290    /// Precision is specified when the `libm` feature is enabled.
291    #[inline(always)]
292    pub fn cbrt(x: f32) -> f32 {
293        libm::cbrtf(x)
294    }
295
296    /// Compute the distance between the origin and a point `(x, y)` on the Euclidean plane.
297    ///
298    /// Equivalently, compute the length of the hypotenuse of a right-angle triangle with other sides having length `x.abs()` and `y.abs()`.
299    ///
300    /// Precision is specified when the `libm` feature is enabled.
301    #[inline(always)]
302    pub fn hypot(x: f32, y: f32) -> f32 {
303        libm::hypotf(x, y)
304    }
305
306    /// Computes the sine of a number (in radians).
307    ///
308    /// Precision is specified when the `libm` feature is enabled.
309    #[inline(always)]
310    pub fn sin(x: f32) -> f32 {
311        libm::sinf(x)
312    }
313
314    /// Computes the cosine of a number (in radians).
315    ///
316    /// Precision is specified when the `libm` feature is enabled.
317    #[inline(always)]
318    pub fn cos(x: f32) -> f32 {
319        libm::cosf(x)
320    }
321
322    /// Computes the tangent of a number (in radians).
323    ///
324    /// Precision is specified when the `libm` feature is enabled.
325    #[inline(always)]
326    pub fn tan(x: f32) -> f32 {
327        libm::tanf(x)
328    }
329
330    /// Computes the arcsine of a number. Return value is in radians in
331    /// the range [-pi/2, pi/2] or NaN if the number is outside the range
332    /// [-1, 1].
333    ///
334    /// Precision is specified when the `libm` feature is enabled.
335    #[inline(always)]
336    pub fn asin(x: f32) -> f32 {
337        libm::asinf(x)
338    }
339
340    /// Computes the arccosine of a number. Return value is in radians in
341    /// Hyperbolic tangent function.
342    ///
343    /// Precision is specified when the `libm` feature is enabled.
344    /// the range [0, pi] or NaN if the number is outside the range
345    /// [-1, 1].
346    ///
347    /// Precision is specified when the `libm` feature is enabled.
348    #[inline(always)]
349    pub fn acos(x: f32) -> f32 {
350        libm::acosf(x)
351    }
352
353    /// Computes the arctangent of a number. Return value is in radians in the
354    /// range [-pi/2, pi/2];
355    ///
356    /// Precision is specified when the `libm` feature is enabled.
357    #[inline(always)]
358    pub fn atan(x: f32) -> f32 {
359        libm::atanf(x)
360    }
361
362    /// Computes the four-quadrant arctangent of `y` and `x` in radians.
363    ///
364    /// * `x = 0`, `y = 0`: `0`
365    /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]`
366    /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]`
367    /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)`
368    ///
369    /// Precision is specified when the `libm` feature is enabled.
370    #[inline(always)]
371    pub fn atan2(y: f32, x: f32) -> f32 {
372        libm::atan2f(y, x)
373    }
374
375    /// Simultaneously computes the sine and cosine of the number, `x`. Returns
376    /// `(sin(x), cos(x))`.
377    ///
378    /// Precision is specified when the `libm` feature is enabled.
379    #[inline(always)]
380    pub fn sin_cos(x: f32) -> (f32, f32) {
381        libm::sincosf(x)
382    }
383
384    /// Returns `e^(self) - 1` in a way that is accurate even if the
385    /// number is close to zero.
386    ///
387    /// Precision is specified when the `libm` feature is enabled.
388    #[inline(always)]
389    pub fn exp_m1(x: f32) -> f32 {
390        libm::expm1f(x)
391    }
392
393    /// Returns `ln(1+n)` (natural logarithm) more accurately than if
394    /// the operations were performed separately.
395    ///
396    /// Precision is specified when the `libm` feature is enabled.
397    #[inline(always)]
398    pub fn ln_1p(x: f32) -> f32 {
399        libm::log1pf(x)
400    }
401
402    /// Hyperbolic sine function.
403    ///
404    /// Precision is specified when the `libm` feature is enabled.
405    #[inline(always)]
406    pub fn sinh(x: f32) -> f32 {
407        libm::sinhf(x)
408    }
409
410    /// Hyperbolic cosine function.
411    ///
412    /// Precision is specified when the `libm` feature is enabled.
413    #[inline(always)]
414    pub fn cosh(x: f32) -> f32 {
415        libm::coshf(x)
416    }
417
418    /// Hyperbolic tangent function.
419    ///
420    /// Precision is specified when the `libm` feature is enabled.
421    #[inline(always)]
422    pub fn tanh(x: f32) -> f32 {
423        libm::tanhf(x)
424    }
425
426    /// Inverse hyperbolic sine function.
427    ///
428    /// Precision is specified when the `libm` feature is enabled.
429    #[inline(always)]
430    pub fn asinh(x: f32) -> f32 {
431        libm::asinhf(x)
432    }
433
434    /// Inverse hyperbolic cosine function.
435    ///
436    /// Precision is specified when the `libm` feature is enabled.
437    #[inline(always)]
438    pub fn acosh(x: f32) -> f32 {
439        libm::acoshf(x)
440    }
441
442    /// Inverse hyperbolic tangent function.
443    ///
444    /// Precision is specified when the `libm` feature is enabled.
445    #[inline(always)]
446    pub fn atanh(x: f32) -> f32 {
447        libm::atanhf(x)
448    }
449}
450
451#[cfg(all(any(feature = "libm", feature = "nostd-libm"), not(feature = "std")))]
452mod libm_ops_for_no_std {
453    //! Provides standardized names for [`f32`] operations which may not be
454    //! supported on `no_std` platforms.
455    //! On `no_std` platforms, this forwards to the implementations provided
456    //! by [`libm`].
457
458    /// Calculates the least nonnegative remainder of `self (mod rhs)`.
459    ///
460    /// Precision is specified when the `libm` feature is enabled.
461    #[inline(always)]
462    pub fn rem_euclid(x: f32, y: f32) -> f32 {
463        let result = libm::remainderf(x, y);
464
465        // libm::remainderf has a range of -y/2 to +y/2
466        if result < 0. {
467            result + y
468        } else {
469            result
470        }
471    }
472
473    /// Computes the absolute value of x.
474    ///
475    /// Precision is specified when the `libm` feature is enabled.
476    #[inline(always)]
477    pub fn abs(x: f32) -> f32 {
478        libm::fabsf(x)
479    }
480
481    /// Returns the square root of a number.
482    ///
483    /// Precision is specified when the `libm` feature is enabled.
484    #[inline(always)]
485    pub fn sqrt(x: f32) -> f32 {
486        libm::sqrtf(x)
487    }
488
489    /// Returns a number composed of the magnitude of `x` and the sign of `y`.
490    ///
491    /// Precision is specified when the `libm` feature is enabled.
492    #[inline(always)]
493    pub fn copysign(x: f32, y: f32) -> f32 {
494        libm::copysignf(x, y)
495    }
496
497    /// Returns the nearest integer to `x`. If a value is half-way between two integers, round away from `0.0`.
498    ///
499    /// Precision is specified when the `libm` feature is enabled.
500    #[inline(always)]
501    pub fn round(x: f32) -> f32 {
502        libm::roundf(x)
503    }
504
505    /// Returns the largest integer less than or equal to `x`.
506    ///
507    /// Precision is specified when the `libm` feature is enabled.
508    #[inline(always)]
509    pub fn floor(x: f32) -> f32 {
510        libm::floorf(x)
511    }
512
513    /// Returns the smallest integer greater than or equal to `x`.
514    ///
515    /// Precision is specified when the `libm` feature is enabled.
516    #[inline(always)]
517    pub fn ceil(x: f32) -> f32 {
518        libm::ceilf(x)
519    }
520
521    /// Returns the fractional part of `x`.
522    ///
523    /// This function always returns the precise result.
524    #[inline(always)]
525    pub fn fract(x: f32) -> f32 {
526        libm::modff(x).0
527    }
528}
529
530#[cfg(feature = "std")]
531#[expect(
532    clippy::disallowed_methods,
533    reason = "Many of the disallowed methods are disallowed to force code to use the feature-conditional re-exports from this module, but this module itself is exempt from that rule."
534)]
535mod std_ops_for_no_std {
536    //! Provides standardized names for [`f32`] operations which may not be
537    //! supported on `no_std` platforms.
538    //! On `std` platforms, this forwards directly to the implementations provided
539    //! by [`std`].
540
541    /// Calculates the least nonnegative remainder of `x (mod y)`.
542    ///
543    /// The result of this operation is guaranteed to be the rounded infinite-precision result.
544    #[inline(always)]
545    pub fn rem_euclid(x: f32, y: f32) -> f32 {
546        f32::rem_euclid(x, y)
547    }
548
549    /// Computes the absolute value of x.
550    ///
551    /// This function always returns the precise result.
552    #[inline(always)]
553    pub fn abs(x: f32) -> f32 {
554        f32::abs(x)
555    }
556
557    /// Returns the square root of a number.
558    ///
559    /// The result of this operation is guaranteed to be the rounded infinite-precision result.
560    /// It is specified by IEEE 754 as `squareRoot` and guaranteed not to change.
561    #[inline(always)]
562    pub fn sqrt(x: f32) -> f32 {
563        f32::sqrt(x)
564    }
565
566    /// Returns a number composed of the magnitude of `x` and the sign of `y`.
567    ///
568    /// Equal to `x` if the sign of `x` and `y` are the same, otherwise equal to `-x`. If `x` is a
569    /// `NaN`, then a `NaN` with the sign bit of `y` is returned. Note, however, that conserving the
570    /// sign bit on `NaN` across arithmetical operations is not generally guaranteed.
571    #[inline(always)]
572    pub fn copysign(x: f32, y: f32) -> f32 {
573        f32::copysign(x, y)
574    }
575
576    /// Returns the nearest integer to `x`. If a value is half-way between two integers, round away from `0.0`.
577    ///
578    /// This function always returns the precise result.
579    #[inline(always)]
580    pub fn round(x: f32) -> f32 {
581        f32::round(x)
582    }
583
584    /// Returns the largest integer less than or equal to `x`.
585    ///
586    /// This function always returns the precise result.
587    #[inline(always)]
588    pub fn floor(x: f32) -> f32 {
589        f32::floor(x)
590    }
591
592    /// Returns the smallest integer greater than or equal to `x`.
593    ///
594    /// This function always returns the precise result.
595    #[inline(always)]
596    pub fn ceil(x: f32) -> f32 {
597        f32::ceil(x)
598    }
599
600    /// Returns the fractional part of `x`.
601    ///
602    /// This function always returns the precise result.
603    #[inline(always)]
604    pub fn fract(x: f32) -> f32 {
605        f32::fract(x)
606    }
607}
608
609#[cfg(any(feature = "libm", all(feature = "nostd-libm", not(feature = "std"))))]
610pub use libm_ops::*;
611
612#[cfg(all(not(feature = "libm"), feature = "std"))]
613pub use std_ops::*;
614
615#[cfg(feature = "std")]
616pub use std_ops_for_no_std::*;
617
618#[cfg(all(any(feature = "libm", feature = "nostd-libm"), not(feature = "std")))]
619pub use libm_ops_for_no_std::*;
620
621#[cfg(all(
622    not(feature = "libm"),
623    not(feature = "std"),
624    not(feature = "nostd-libm")
625))]
626compile_error!("Either the `libm`, `std`, or `nostd-libm` feature must be enabled.");
627
628/// This extension trait covers shortfall in determinacy from the lack of a `libm` counterpart
629/// to `f32::powi`. Use this for the common small exponents.
630pub trait FloatPow {
631    /// Squares the f32
632    fn squared(self) -> Self;
633    /// Cubes the f32
634    fn cubed(self) -> Self;
635}
636
637impl FloatPow for f32 {
638    #[inline]
639    fn squared(self) -> Self {
640        self * self
641    }
642    #[inline]
643    fn cubed(self) -> Self {
644        self * self * self
645    }
646}