Last summer I worked with MATLAB code that was copied-down from equations directly, when floating point math allows for a lot of optimisations that aren't always obvious, like exp_m1. Here are a few lints I thought of that specifically apply to floats:
a * b + c => a.mul_add(b, c)x.powf(y) => x.powi(y) (when y is an integer)x.powi(2) => x * x2.powf(x) => x.exp2()x.logN() / y.logN() => x.logbase(y)x.logbase(E) => x.log()x.logbase(10) => x.log10()x.logbase(2) => x.log2().x * PI / 180 => x.to_radians()x * 180 / PI => x.to_degrees()x.powf(1/3) => x.cbrt() (not equivalent, but almost certainly what was meant)x.powf(1/2) => x.sqrt()x.exp() - 1 => x.exp_m1()(x + 1).log() => x.log_1p()sqrt(x * x + y * y) => x.hypot(y) (I see this one used a lot)Obviously we can't catch every case, and these would be best as hints rather than suggestions, but it'd be nice to at least suggest these options to the user so that they're aware that they exist.
I think that the scope of this should be limited to just suggesting builtin functions for now because the list of mathematical identities is way too large for clippy to incorporate. People who do things like x.log() + y.log() instead of (xy).log() can simplify their equations themselves, but people who don't know that x.hypot(y) exists for example should be made aware.
Just as a sidenote: https://github.com/mcarton/rust-herbie-lint is a project which would also figure out more elaborate transformations but unfortunately hasn't been been update in a year. The actual tool Herbie had a 1.0 release in June so maybe some folks which are familiar with compiler internals could revive rust-herbie-lint. (I failed miserably the last time I tried...)
Herbie looks like a fantastic tool; it'd be great if we could leverage that somehow.
sqrt(x * x + y * y) => x.hypot(y)(I see this one used a lot)
For good reason: it's almost as accurate as x.hypot(y) in non-overflow cases, and much faster. hypot() jumps through a lot of hoops for the last 0.5 ulp of accuracy, and to give a correct answer when the naive sum would overflow. It's also a non-inlined call to clib, vs. a handful of optimizer-friendly instructions.
(Check out glibc's implementation at https://github.com/lattera/glibc/blob/master/math/w_hypot.c and https://github.com/lattera/glibc/blob/master/sysdeps/ieee754/dbl-64/e_hypot.c to see the difference.)
It would still make sense in a explicit "lint-for-numeric-accuracy" mode (and Herbie would be amazing for that), but questionable for a default lint. The other suggestions all seem like much more likely wins.
You do make a good point, @jpetkau, and I think it would make sense to allow configuring the lint to prefer either performance or accuracy.
I'd liike to tackle the remaining suggestions on this issue. As I understand it, they are:
Were all of the things listed in the OP implemented in the merged PR? Not sure if this should be kept open or not
cc @thiagoarrais do you know if some of the suggestions in the OP are still missing?
I've tried to tackle all of them, yeah. After #4897 and #5443 (plus some other stuff that made its way into master independently) this should be done.
Thanks for checking! Just wanted to make sure nothing got missed. :)
Most helpful comment
I'd liike to tackle the remaining suggestions on this issue. As I understand it, they are: