Add support for floating point math in `vexide-core`.
What's the motivation for this feature?
vexide programs run in a no_std enviornment. Unfortunately, core is currently missing support for floating point math functions such as f64::sin and f64::cos, etc... which are all extremely important for anyone doing localization or controls work.
Describe the solution you'd like
There are several options we have, each with some level of tradeoffs. So as a quick summary:
- The reason why these methods are not in
coreis becausestd's implementation is based off of LLVM intrinsics, which aren't guaranteed to be there for any given target. These intrinsics are by far going to be the most optimized for our platform, though and are available through the unstable compiler internal featurecore_intriniscs. This doesn't cover every math function (only about 3/4 of them), as Ruststdrelies on the platformcmathimplementations for the rest. - There is an official effort to port MUSL's
libmto Rust under therust-langorganization. It's important to note that this is NOT the typical C libm but rather a port of it to rust. While these work, they aren't fast due to using software floating point math. Our target has vfp3 support and therefore we probably waste performance by using this. - There's also the
libm.astatic library that ships with PROS. Now this is the one that i'm not sure about. I know next to nothing about where this library comes from or how it's implemented (I assume it comes from some part of newlib or glibc though). If it leverages the FPU, then it's going to perform much better than the official rust port, but we don't know if it does so that's going to need benchmarking. There's also the issue that it's written in C, and linking to C static libraries is expensive and means the compiler can't strip out the stuff we don't need.
So, from what I can tell we have maybe two or so options:
- We can keep using the current recommended solution which is to slap
num_traitsinto your project anduse num_traits::real::Real, which reimplements the math functions in terms of rust's libm.- Drawback: Since it uses rust's libm, it's soft float only even though we have access to LLVM intrinsics that are much faster (I think, at least).
- Drawback: It's an external crate and therefore is a level of boilerplate that is added to every project and is outside of vexide's version lifecycle. We could just have this in prelude and be done with it.
- We can reimplement types in terms of
core::intrinsicsand either rust'slibmor PROSlibm.a- Drawback:
core::intrinsicsare unstable and will likely never be stabilized due to being a compiler internal. Womp womp. - I'm generally for this option, but deciding with one's better in terms of size/speed tradeoffs will need benchmarking.
- If we go with Rust's
libmit may or may not be slower. - If we go with PROS'
libm.a, our baseline binary size will likely take a hit (not sure how much).
- Drawback:
Describe the drawbacks, if any
Depending on which option we choose, floating point math may be slower than expected or add binary size.
Describe the alternative solutions, if any
See above
Benchmark Results
To my surprise, it seems like the PROS libm is ~15x slower than the soft-float rust libm.
Additionally we don't have support for LLVM intrinsics like I originally thought, leaving the rust libm as the only way forward with this. For now, it's probably just better to keep using num_traits' Float trait.