5 ms·
This reminds me of an issue that I ran into with rust [0] when I was trying to optimize some machine learning code. Rust's über-strict type-safe math operations
by ComputerGuru 2y ago
This reminds me of an issue that I ran into with rust [0] when I was trying to optimize some machine learning code. Rust's über-strict type-safe math operations have you use matching types to get the euclidean non-negative remainder of x mod y. When you have a float-point x value but an integral y value, the operation can be performed much more cheaply than when y is also a floating point value.
The problem is that you end up promoting y from an integer to an f64 and get a much slower operation. I ended up writing my own `rem_i64(self: &f64, divisor: i64) -> f64` routine that was some ~35x faster (a huge win when crunching massive arrays), but as there are range limitations (since f64::MAX > i64::MAX) you can't naively replace all call sites based on the type signatures. However, with some support from the compiler it would be completely doable anytime the compiler is able to infer an upper/lower bound on the f64 dividend, when the result of the operation is coerced to an integer afterwards, or when the dividend is a constant value that doesn't exceed that range.
So now I copy that function around from ML project to ML project, because what else can I do?
(A “workaround” was to use a slower-but-still-faster `rem_i128(self: &f64, divisor: i128) -> f64` to raise the functional limits of the operation, but you're never going to match the range of a 64-bit floating point value until you use 512-bit integral math!)
[0]: https://github.com/rust-lang/rust/issues/83973 https://github.com/rust-lang/rust/issues/83973
Godbolt link: https://godbolt.org/z/EqrEqExnc https://godbolt.org/z/EqrEqExnc
- toast0 2y ago> So now I copy that function around from ML project to ML project, because what else can I do? Aren't you supposed to make a crate? Which is copying with more steps, but might make your life easier (or harder).
- ComputerGuru 2y agoI knew someone would pipe in with that suggestion as I was writing that comment! Yes, I suppose that would be the canonical way to go. But it's just one function; four lines! I'm getting isEven() vibes!
- pryelluw 2y agoI package unrelated classes, functions, utilities like yours into one module/crate/library and just keep adding stuff to it. Sort of like my own standard library.
- mikepurvis 2y agoThat works for a time but it’s ultimately not great for new/external contributors to be faced with your code being full of unfamiliar idioms and utility functions coming from a single kitchen sink package.
- pryelluw 2y agoYeah strictly for my own personal use. Having a bunch of unrelated stuff in one place is bananas
- mikepurvis 2y agoYou do still see it though; a bunch of the core infrastructure packages in ROS depend on this grab bag of utilities related to console capture, cli, and colouring: https://osrf-pycommon.readthedocs.io/en/latest/ https://osrf-pycommon.readthedocs.io/en/latest/
- pryelluw 2y agoI do tend to stumble into it with hardware relates libs like ROS. Web adjacent libraries/frameworks, IMO, tends to package things a little nicer (though the js ecosystem just said YOLO).
- marcosdumay 2y agoReally don't. If that crate becomes successful, it will basically greenlight a lot of functionality that was just there because it happened to be made by the same author. And all that extra functionality will only reduce the chances of the really useful function to get into the spotlight. Both are bad for the ecosystem. If the GP has related useful little functions, yes, pack them together. Otherwise, I'd say a crate for a small little function isn't a problem at all.
- deleted 2y ago[deleted]