vexide_core/float/mod.rs
1//! Floating point arithmetic.
2//!
3//! This module provides implementations of math functions of floating point
4//! primitive types (`f32`, `f64`) through the [`Float`] trait.
5
6#[cfg(all(target_vendor = "vex", not(feature = "force_rust_libm")))]
7mod newlib;
8
9#[cfg(any(not(target_vendor = "vex"), feature = "force_rust_libm"))]
10mod rust;
11
12/// Used to make [`powi_impl`] generic across f32 and f64.
13pub(crate) trait One {
14 const ONE: Self;
15}
16
17impl One for f64 {
18 const ONE: Self = 1.0;
19}
20
21impl One for f32 {
22 const ONE: Self = 1.0;
23}
24
25/// Implementation of an integer power function using exponentiation by squaring.
26///
27/// Adapted from <https://github.com/rust-num/num-traits/blob/7ec3d41d39b28190ec1d42db38021107b3951f3a/src/pow.rs#L23>
28#[inline]
29pub(crate) fn powi_impl<T: One + Copy + core::ops::Mul<T, Output = T>>(
30 mut base: T,
31 mut exp: usize,
32) -> T {
33 if exp == 0 {
34 return T::ONE;
35 }
36
37 while exp & 1 == 0 {
38 base = base * base;
39 exp >>= 1;
40 }
41 if exp == 1 {
42 return base;
43 }
44
45 let mut acc = base;
46 while exp > 1 {
47 exp >>= 1;
48 base = base * base;
49 if exp & 1 == 1 {
50 acc = acc * base;
51 }
52 }
53 acc
54}
55
56/// Floating-point math functions
57///
58/// This extension trait defines the missing implementations of floating point
59/// math in `core` present in rust's `std` crate.
60pub trait Float: Sized {
61 /// Returns the largest integer less than or equal to `self`.
62 ///
63 /// This function always returns the precise result.
64 #[must_use = "method returns a new number and does not mutate the original value"]
65 fn floor(self) -> Self;
66
67 /// Returns the smallest integer greater than or equal to `self`.
68 ///
69 /// This function always returns the precise result.
70 #[must_use = "method returns a new number and does not mutate the original value"]
71 fn ceil(self) -> Self;
72
73 /// Returns the nearest integer to `self`. If a value is half-way between two
74 /// integers, round away from `0.0`.
75 ///
76 /// This function always returns the precise result.
77 #[must_use = "method returns a new number and does not mutate the original value"]
78 fn round(self) -> Self;
79
80 /// Returns the nearest integer to a number. Rounds half-way cases to the number
81 /// with an even least significant digit.
82 ///
83 /// This function always returns the precise result.
84 #[must_use = "method returns a new number and does not mutate the original value"]
85 fn round_ties_even(self) -> Self;
86
87 /// Returns the integer part of `self`.
88 /// This means that non-integer numbers are always truncated towards zero.
89 ///
90 /// This function always returns the precise result.
91 #[must_use = "method returns a new number and does not mutate the original value"]
92 fn trunc(self) -> Self;
93
94 /// Returns the fractional part of `self`.
95 ///
96 /// This function always returns the precise result.
97 #[must_use = "method returns a new number and does not mutate the original value"]
98 fn fract(self) -> Self;
99
100 /// Computes the absolute value of `self`.
101 ///
102 /// This function always returns the precise result.
103 #[must_use = "method returns a new number and does not mutate the original value"]
104 fn abs(self) -> Self;
105
106 /// Returns a number that represents the sign of `self`.
107 ///
108 /// - `1.0` if the number is positive, `+0.0` or `INFINITY`
109 /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
110 /// - NaN if the number is NaN
111 #[must_use = "method returns a new number and does not mutate the original value"]
112 fn signum(self) -> Self;
113
114 /// Returns a number composed of the magnitude of `self` and the sign of
115 /// `sign`.
116 ///
117 /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise
118 /// equal to `-self`. If `self` is a NaN, then a NaN with the sign bit of
119 /// `sign` is returned. Note, however, that conserving the sign bit on NaN
120 /// across arithmetical operations is not generally guaranteed.
121 /// See [explanation of NaN as a special value](primitive@f32) for more info.
122 #[must_use = "method returns a new number and does not mutate the original value"]
123 fn copysign(self, sign: Self) -> Self;
124
125 /// Fused multiply-add. Computes `(self * a) + b` with only one rounding
126 /// error, yielding a more accurate result than an unfused multiply-add.
127 ///
128 /// Using `mul_add` *may* be more performant than an unfused multiply-add if
129 /// the target architecture has a dedicated `fma` CPU instruction. However,
130 /// this is not always true, and will be heavily dependant on designing
131 /// algorithms with specific target hardware in mind.
132 #[must_use = "method returns a new number and does not mutate the original value"]
133 fn mul_add(self, a: Self, b: Self) -> Self;
134
135 /// Calculates Euclidean division, the matching method for `rem_euclid`.
136 ///
137 /// This computes the integer `n` such that
138 /// `self = n * rhs + self.rem_euclid(rhs)`.
139 /// In other words, the result is `self / rhs` rounded to the integer `n`
140 /// such that `self >= n * rhs`.
141 #[must_use = "method returns a new number and does not mutate the original value"]
142 fn div_euclid(self, rhs: Self) -> Self;
143
144 /// Calculates the least nonnegative remainder of `self (mod rhs)`.
145 ///
146 /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in
147 /// most cases. However, due to a floating point round-off error it can
148 /// result in `r == rhs.abs()`, violating the mathematical definition, if
149 /// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`.
150 /// This result is not an element of the function's codomain, but it is the
151 /// closest floating point number in the real numbers and thus fulfills the
152 /// property `self == self.div_euclid(rhs) * rhs + self.rem_euclid(rhs)`
153 /// approximately.
154 ///
155 /// # Precision
156 ///
157 /// The result of this operation is guaranteed to be the rounded
158 /// infinite-precision result.
159 #[must_use = "method returns a new number and does not mutate the original value"]
160 fn rem_euclid(self, rhs: Self) -> Self;
161
162 /// Raises a number to an integer power.
163 ///
164 /// Using this function is generally faster than using `powf`.
165 /// It might have a different sequence of rounding operations than `powf`,
166 /// so the results are not guaranteed to agree.
167 ///
168 /// # Platform-specific precision
169 ///
170 /// The precision of this function varies by platform and Rust version.
171 #[must_use = "method returns a new number and does not mutate the original value"]
172 fn powi(self, n: i32) -> Self;
173
174 /// Raises a number to a floating point power.
175 ///
176 /// # Platform-specific precision
177 ///
178 /// The precision of this function varies by platform and Rust version.
179 #[must_use = "method returns a new number and does not mutate the original value"]
180 fn powf(self, n: Self) -> Self;
181
182 /// Returns the square root of a number.
183 ///
184 /// Returns NaN if `self` is a negative number other than `-0.0`.
185 ///
186 /// # Precision
187 ///
188 /// The result of this operation is guaranteed to be the rounded
189 /// infinite-precision result. It is specified by IEEE 754 as `squareRoot`
190 /// and guaranteed not to change.
191 #[must_use = "method returns a new number and does not mutate the original value"]
192 fn sqrt(self) -> Self;
193
194 /// Returns `e^(self)`, (the exponential function).
195 ///
196 /// # Platform-specific precision
197 ///
198 /// The precision of this function varies by platform and Rust version.
199 #[must_use = "method returns a new number and does not mutate the original value"]
200 fn exp(self) -> Self;
201
202 /// Returns `2^(self)`.
203 ///
204 /// # Platform-specific precision
205 ///
206 /// The precision of this function varies by platform and Rust version.
207 #[must_use = "method returns a new number and does not mutate the original value"]
208 fn exp2(self) -> Self;
209
210 /// Returns the natural logarithm of the number.
211 ///
212 /// # Platform-specific precision
213 ///
214 /// The precision of this function varies by platform and Rust version.
215 #[must_use = "method returns a new number and does not mutate the original value"]
216 fn ln(self) -> Self;
217
218 /// Returns the logarithm of the number with respect to an arbitrary base.
219 ///
220 /// The result might not be correctly rounded owing to implementation details;
221 /// `self.log2()` can produce more accurate results for base 2, and
222 /// `self.log10()` can produce more accurate results for base 10.
223 ///
224 /// # Platform-specific precision
225 ///
226 /// The precision of this function varies by platform and Rust version.
227 #[must_use = "method returns a new number and does not mutate the original value"]
228 fn log(self, base: Self) -> Self;
229
230 /// Returns the base 2 logarithm of the number.
231 ///
232 /// # Platform-specific precision
233 ///
234 /// The precision of this function varies by platform and Rust version.
235 #[must_use = "method returns a new number and does not mutate the original value"]
236 fn log2(self) -> Self;
237
238 /// Returns the base 10 logarithm of the number.
239 ///
240 /// # Platform-specific precision
241 ///
242 /// The precision of this function varies by platform and Rust version.
243 #[must_use = "method returns a new number and does not mutate the original value"]
244 fn log10(self) -> Self;
245
246 /// The positive difference of two numbers.
247 ///
248 /// * If `self <= other`: `0.0`
249 /// * Else: `self - other`
250 ///
251 /// # Platform-specific precision
252 ///
253 /// The precision of this function varies by platform and Rust version.
254 /// This function currently corresponds to the `fdim` function from libm.
255 #[deprecated(
256 since = "0.2.0",
257 note = "you probably meant `(self - other).abs()`: \
258 this operation is `(self - other).max(0.0)` \
259 except that `abs_sub` also propagates NaNs (also \
260 known as `fdim` in C). If you truly need the positive \
261 difference, consider using that expression or the C function \
262 `fdim`, depending on how you wish to handle NaN."
263 )]
264 #[must_use = "method returns a new number and does not mutate the original value"]
265 fn abs_sub(self, other: Self) -> Self;
266
267 /// Returns the cube root of a number.
268 ///
269 /// # Platform-specific precision
270 ///
271 /// The precision of this function varies by platform and Rust version.
272 #[must_use = "method returns a new number and does not mutate the original value"]
273 fn cbrt(self) -> Self;
274
275 /// Compute the distance between the origin and a point (`x`, `y`) on the
276 /// Euclidean plane. Equivalently, compute the length of the hypotenuse of a
277 /// right-angle triangle with other sides having length `x.abs()` and
278 /// `y.abs()`.
279 ///
280 /// # Platform-specific precision
281 ///
282 /// The precision of this function varies by platform and Rust version.
283 #[must_use = "method returns a new number and does not mutate the original value"]
284 fn hypot(self, other: Self) -> Self;
285
286 /// Computes the sine of a number (in radians).
287 ///
288 /// # Platform-specific precision
289 ///
290 /// The precision of this function varies by platform and Rust version.
291 #[must_use = "method returns a new number and does not mutate the original value"]
292 fn sin(self) -> Self;
293
294 /// Computes the cosine of a number (in radians).
295 ///
296 /// # Platform-specific precision
297 ///
298 /// The precision of this function varies by platform and Rust version.
299 #[must_use = "method returns a new number and does not mutate the original value"]
300 fn cos(self) -> Self;
301
302 /// Computes the tangent of a number (in radians).
303 ///
304 /// # Platform-specific precision
305 ///
306 /// The precision of this function varies by platform and Rust version.
307 #[must_use = "method returns a new number and does not mutate the original value"]
308 fn tan(self) -> Self;
309
310 /// Computes the arcsine of a number. Return value is in radians in
311 /// the range [-pi/2, pi/2] or NaN if the number is outside the range
312 /// [-1, 1].
313 ///
314 /// # Platform-specific precision
315 ///
316 /// The precision of this function varies by platform and Rust version.
317 #[must_use = "method returns a new number and does not mutate the original value"]
318 fn asin(self) -> Self;
319
320 /// Computes the arccosine of a number. Return value is in radians in
321 /// the range [0, pi] or NaN if the number is outside the range
322 /// [-1, 1].
323 ///
324 /// # Platform-specific precision
325 ///
326 /// The precision of this function varies by platform and Rust version.
327 #[must_use = "method returns a new number and does not mutate the original value"]
328 fn acos(self) -> Self;
329
330 /// Computes the arctangent of a number. Return value is in radians in the
331 /// range [-pi/2, pi/2];
332 ///
333 /// # Platform-specific precision
334 ///
335 /// The precision of this function varies by platform and Rust version.
336 #[must_use = "method returns a new number and does not mutate the original value"]
337 fn atan(self) -> Self;
338
339 /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians.
340 ///
341 /// * `x = 0`, `y = 0`: `0`
342 /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]`
343 /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]`
344 /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)`
345 ///
346 /// # Platform-specific precision
347 ///
348 /// The precision of this function varies by platform and Rust version.
349 #[must_use = "method returns a new number and does not mutate the original value"]
350 fn atan2(self, other: Self) -> Self;
351
352 /// Simultaneously computes the sine and cosine of the number, `x`. Returns
353 /// `(sin(x), cos(x))`.
354 ///
355 /// # Platform-specific precision
356 ///
357 /// The precision of this function varies by platform and Rust version.
358 #[must_use = "method returns a new number and does not mutate the original value"]
359 fn sin_cos(self) -> (Self, Self);
360
361 /// Returns `e^(self) - 1` in a way that is accurate even if the
362 /// number is close to zero.
363 ///
364 /// # Platform-specific precision
365 ///
366 /// The precision of this function varies by platform and Rust version.
367 #[must_use = "method returns a new number and does not mutate the original value"]
368 fn exp_m1(self) -> Self;
369
370 /// Returns `ln(1+n)` (natural logarithm) more accurately than if
371 /// the operations were performed separately.
372 ///
373 /// # Platform-specific precision
374 ///
375 /// The precision of this function varies by platform and Rust version.
376 #[must_use = "method returns a new number and does not mutate the original value"]
377 fn ln_1p(self) -> Self;
378
379 /// Hyperbolic sine function.
380 ///
381 /// # Platform-specific precision
382 ///
383 /// The precision of this function varies by platform and Rust version.
384 #[must_use = "method returns a new number and does not mutate the original value"]
385 fn sinh(self) -> Self;
386
387 /// Hyperbolic cosine function.
388 ///
389 /// # Platform-specific precision
390 ///
391 /// The precision of this function varies by platform and Rust version.
392 #[must_use = "method returns a new number and does not mutate the original value"]
393 fn cosh(self) -> Self;
394
395 /// Hyperbolic tangent function.
396 ///
397 /// # Platform-specific precision
398 ///
399 /// The precision of this function varies by platform and Rust version.
400 #[must_use = "method returns a new number and does not mutate the original value"]
401 fn tanh(self) -> Self;
402
403 /// Inverse hyperbolic sine function.
404 ///
405 /// # Platform-specific precision
406 ///
407 /// The precision of this function varies by platform and Rust version.
408 #[must_use = "method returns a new number and does not mutate the original value"]
409 fn asinh(self) -> Self;
410
411 /// Inverse hyperbolic cosine function.
412 ///
413 /// # Platform-specific precision
414 ///
415 /// The precision of this function varies by platform and Rust version.
416 #[must_use = "method returns a new number and does not mutate the original value"]
417 fn acosh(self) -> Self;
418
419 /// Inverse hyperbolic tangent function.
420 ///
421 /// # Platform-specific precision
422 ///
423 /// The precision of this function varies by platform and Rust version.
424 #[must_use = "method returns a new number and does not mutate the original value"]
425 fn atanh(self) -> Self;
426}