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}