Last time, we’ve looked at how focus on data properties instead of specific values can simplify logic and improve performance. We’ve also used microbenchmarks comparing time it takes to compute distance and distance squared. This worked well for Go, but Rust is so fast that it takes 0ns for squared distance computation and 1ns for Euclidean distance computation, which makes it tricky to do a proper comparison. So to make things more interesting, we’ll benchmark original problem solutions instead, but first a little bit of setup boilerplate
Rust’s assembly is much more concise than Go’s but still has 2 extra instructions responsible for converting integer to floating point and computing square root:
To make the implementation easier to understand, instead of fancy generics, let’s have a version using distance
and a version using squared distance
And just for fun, let’s also add versions based on Rust’s min_by
iterator function
And finally benchmarks:
Aaaaand the winer is as expected bench_distance_squared
by ~40% as was the case with Go:
Unfortunately iterator-based versions are ~50% and ~100% slower than their hand-rolled versions. Another interesting observation is that Ord trait is not implemented for f64, so we had to use min_by
instead of a simpler min_by_key
version, but for i64
we can actually switch to min_by
:
which in addition to be more concise is also slightly faster:
You can explore the code and assembly it generates in the playground.