vexide_core/float/
rust.rs

1//! Implementation of floating-point math using the pure rust port of MUSL's
2//! libm. <https://github.com/rust-lang/libm/>
3//!
4//! This serves as the only floating-point implementation when compiling for
5//! non-VEX targets, and can be forced to be used on ARM using the `force-rust-libm`
6//! feature.
7//!
8//! This implementation exists for two reasons:
9//! - You are dead-set on getting a pure-rust program build and don't want to
10//!   be linked to any C libraries whatsoever.
11//! - You are compiling for a non-VEX target, where an ARM-specific libm won't
12//!   work.
13//!
14//! At the time of writing this, this rust implementation results in both
15//! significantly larger binary sizes as well as several times slower math
16//! operations than the newlib implementations, so this isn't recommended on
17//! ARM.
18
19use super::{powi_impl, Float};
20
21impl Float for f32 {
22    #[inline]
23    fn floor(self) -> Self {
24        libm::floorf(self)
25    }
26
27    #[inline]
28    fn ceil(self) -> Self {
29        libm::ceilf(self)
30    }
31
32    #[inline]
33    fn round(self) -> Self {
34        libm::roundf(self)
35    }
36
37    #[inline]
38    fn round_ties_even(self) -> Self {
39        libm::rintf(self)
40    }
41
42    #[inline]
43    fn trunc(self) -> Self {
44        libm::truncf(self)
45    }
46
47    #[inline]
48    fn fract(self) -> Self {
49        self - self.trunc()
50    }
51
52    #[inline]
53    fn abs(self) -> Self {
54        libm::fabsf(self)
55    }
56
57    #[inline]
58    fn signum(self) -> Self {
59        if self.is_nan() {
60            Self::NAN
61        } else {
62            1.0_f32.copysign(self)
63        }
64    }
65
66    #[inline]
67    fn copysign(self, sign: Self) -> Self {
68        libm::copysignf(self, sign)
69    }
70
71    #[inline]
72    fn mul_add(self, a: Self, b: Self) -> Self {
73        libm::fmaf(self, a, b)
74    }
75
76    #[inline]
77    fn div_euclid(self, rhs: Self) -> Self {
78        let q = (self / rhs).trunc();
79        if self % rhs < 0.0 {
80            return if rhs > 0.0 { q - 1.0 } else { q + 1.0 };
81        }
82        q
83    }
84
85    #[inline]
86    fn rem_euclid(self, rhs: Self) -> Self {
87        let r = self % rhs;
88        if r < 0.0 {
89            r + rhs.abs()
90        } else {
91            r
92        }
93    }
94
95    #[inline]
96    fn powi(mut self, mut exp: i32) -> Self {
97        if exp < 0 {
98            exp = exp.wrapping_neg();
99            self = self.recip();
100        }
101        // It should always be possible to convert a positive `i32` to a `usize`.
102        // Note, `i32::MIN` will wrap and still be negative, so we need to convert
103        // to `u32` without sign-extension before growing to `usize`.
104        powi_impl(self, exp as usize)
105    }
106
107    #[inline]
108    fn powf(self, n: Self) -> Self {
109        libm::powf(self, n)
110    }
111
112    #[inline]
113    fn sqrt(self) -> Self {
114        libm::sqrtf(self)
115    }
116
117    #[inline]
118    fn exp(self) -> Self {
119        libm::expf(self)
120    }
121
122    #[inline]
123    fn exp2(self) -> Self {
124        libm::exp2f(self)
125    }
126
127    #[inline]
128    fn ln(self) -> Self {
129        libm::logf(self)
130    }
131
132    #[inline]
133    fn log(self, base: Self) -> Self {
134        self.ln() / base.ln()
135    }
136
137    #[inline]
138    fn log2(self) -> Self {
139        libm::log2f(self)
140    }
141
142    #[inline]
143    fn log10(self) -> Self {
144        libm::log10f(self)
145    }
146
147    #[inline]
148    fn abs_sub(self, other: Self) -> Self {
149        libm::fdimf(self, other)
150    }
151
152    #[inline]
153    fn cbrt(self) -> Self {
154        libm::cbrtf(self)
155    }
156
157    #[inline]
158    fn hypot(self, other: Self) -> Self {
159        libm::hypotf(self, other)
160    }
161
162    #[inline]
163    fn sin(self) -> Self {
164        libm::sinf(self)
165    }
166
167    #[inline]
168    fn cos(self) -> Self {
169        libm::cosf(self)
170    }
171
172    #[inline]
173    fn tan(self) -> Self {
174        libm::tanf(self)
175    }
176
177    #[inline]
178    fn asin(self) -> Self {
179        libm::asinf(self)
180    }
181
182    #[inline]
183    fn acos(self) -> Self {
184        libm::acosf(self)
185    }
186
187    #[inline]
188    fn atan(self) -> Self {
189        libm::atanf(self)
190    }
191
192    #[inline]
193    fn atan2(self, other: Self) -> Self {
194        libm::atan2f(self, other)
195    }
196
197    #[inline]
198    fn sin_cos(self) -> (Self, Self) {
199        (self.sin(), self.cos())
200    }
201
202    #[inline]
203    fn exp_m1(self) -> Self {
204        libm::expm1f(self)
205    }
206
207    #[inline]
208    fn ln_1p(self) -> Self {
209        libm::log1pf(self)
210    }
211
212    #[inline]
213    fn sinh(self) -> Self {
214        libm::sinhf(self)
215    }
216
217    #[inline]
218    fn cosh(self) -> Self {
219        libm::coshf(self)
220    }
221
222    #[inline]
223    fn tanh(self) -> Self {
224        libm::tanhf(self)
225    }
226
227    #[inline]
228    fn asinh(self) -> Self {
229        libm::asinhf(self)
230    }
231
232    #[inline]
233    fn acosh(self) -> Self {
234        libm::acoshf(self)
235    }
236
237    #[inline]
238    fn atanh(self) -> Self {
239        libm::atanhf(self)
240    }
241}
242
243impl Float for f64 {
244    #[inline]
245    fn floor(self) -> Self {
246        libm::floor(self)
247    }
248
249    #[inline]
250    fn ceil(self) -> Self {
251        libm::ceil(self)
252    }
253
254    #[inline]
255    fn round(self) -> Self {
256        libm::round(self)
257    }
258
259    #[inline]
260    fn round_ties_even(self) -> Self {
261        libm::rint(self)
262    }
263
264    #[inline]
265    fn trunc(self) -> Self {
266        libm::trunc(self)
267    }
268
269    #[inline]
270    fn fract(self) -> Self {
271        self - self.trunc()
272    }
273
274    #[inline]
275    fn abs(self) -> Self {
276        libm::fabs(self)
277    }
278
279    #[inline]
280    fn signum(self) -> Self {
281        if self.is_nan() {
282            Self::NAN
283        } else {
284            1.0_f64.copysign(self)
285        }
286    }
287
288    #[inline]
289    fn copysign(self, sign: Self) -> Self {
290        libm::copysign(self, sign)
291    }
292
293    #[inline]
294    fn mul_add(self, a: Self, b: Self) -> Self {
295        libm::fma(self, a, b)
296    }
297
298    #[inline]
299    fn div_euclid(self, rhs: Self) -> Self {
300        let q = (self / rhs).trunc();
301        if self % rhs < 0.0 {
302            return if rhs > 0.0 { q - 1.0 } else { q + 1.0 };
303        }
304        q
305    }
306
307    #[inline]
308    fn rem_euclid(self, rhs: Self) -> Self {
309        let r = self % rhs;
310        if r < 0.0 {
311            r + rhs.abs()
312        } else {
313            r
314        }
315    }
316
317    #[inline]
318    fn powi(mut self, mut exp: i32) -> Self {
319        if exp < 0 {
320            exp = exp.wrapping_neg();
321            self = self.recip();
322        }
323        // It should always be possible to convert a positive `i32` to a `usize`.
324        // Note, `i32::MIN` will wrap and still be negative, so we need to convert
325        // to `u32` without sign-extension before growing to `usize`.
326        powi_impl(self, exp as usize)
327    }
328
329    #[inline]
330    fn powf(self, n: Self) -> Self {
331        libm::pow(self, n)
332    }
333
334    #[inline]
335    fn sqrt(self) -> Self {
336        libm::sqrt(self)
337    }
338
339    #[inline]
340    fn exp(self) -> Self {
341        libm::exp(self)
342    }
343
344    #[inline]
345    fn exp2(self) -> Self {
346        libm::exp2(self)
347    }
348
349    #[inline]
350    fn ln(self) -> Self {
351        libm::log(self)
352    }
353
354    #[inline]
355    fn log(self, base: Self) -> Self {
356        self.ln() / base.ln()
357    }
358
359    #[inline]
360    fn log2(self) -> Self {
361        libm::log2(self)
362    }
363
364    #[inline]
365    fn log10(self) -> Self {
366        libm::log10(self)
367    }
368
369    #[inline]
370    fn abs_sub(self, other: Self) -> Self {
371        libm::fdim(self, other)
372    }
373
374    #[inline]
375    fn cbrt(self) -> Self {
376        libm::cbrt(self)
377    }
378
379    #[inline]
380    fn hypot(self, other: Self) -> Self {
381        libm::hypot(self, other)
382    }
383
384    #[inline]
385    fn sin(self) -> Self {
386        libm::sin(self)
387    }
388
389    #[inline]
390    fn cos(self) -> Self {
391        libm::cos(self)
392    }
393
394    #[inline]
395    fn tan(self) -> Self {
396        libm::tan(self)
397    }
398
399    #[inline]
400    fn asin(self) -> Self {
401        libm::asin(self)
402    }
403
404    #[inline]
405    fn acos(self) -> Self {
406        libm::acos(self)
407    }
408
409    #[inline]
410    fn atan(self) -> Self {
411        libm::atan(self)
412    }
413
414    #[inline]
415    fn atan2(self, other: Self) -> Self {
416        libm::atan2(self, other)
417    }
418
419    #[inline]
420    fn sin_cos(self) -> (Self, Self) {
421        (self.sin(), self.cos())
422    }
423
424    #[inline]
425    fn exp_m1(self) -> Self {
426        libm::expm1(self)
427    }
428
429    #[inline]
430    fn ln_1p(self) -> Self {
431        libm::log1p(self)
432    }
433
434    #[inline]
435    fn sinh(self) -> Self {
436        libm::sinh(self)
437    }
438
439    #[inline]
440    fn cosh(self) -> Self {
441        libm::cosh(self)
442    }
443
444    #[inline]
445    fn tanh(self) -> Self {
446        libm::tanh(self)
447    }
448
449    #[inline]
450    fn asinh(self) -> Self {
451        libm::asinh(self)
452    }
453
454    #[inline]
455    fn acosh(self) -> Self {
456        libm::acosh(self)
457    }
458
459    #[inline]
460    fn atanh(self) -> Self {
461        libm::atanh(self)
462    }
463}