ARTICLE AD BOX
I benchmarked both solutions for finding the smallest and largest values within a range.
I would have expected std::ranges::minmax_element to be faster than using std::ranges::min_element then std::ranges::max_element as a single traversal should be made instead of two (as discussed there: Why need std::minmax_element?).
But to my surprise, if I didn't made a mistake, std::ranges::minmax_element seems slower (at least on https://quick-bench.com/).
What could explain this behavior? Is this a "bug" that should be fixed in the future?
Here is my bench: https://quick-bench.com/q/ohUNvsA5Egwl0oxgUFzChlD-2C8
And my snippets:
void use_minmax(std::vector<double> const& vec) { auto const [min, max] = std::ranges::minmax(vec); benchmark::DoNotOptimize(min); benchmark::DoNotOptimize(max); } void use_min_and_max(std::vector<double> const& vec) { auto const min = std::ranges::min(vec); auto const max = std::ranges::max(vec); benchmark::DoNotOptimize(min); benchmark::DoNotOptimize(max); }According to the documentation, std::ranges::minmax complexity is in the order of 1.5 times the size of the range (at worst) while using std::ranges::min and std::ranges::min is always in the order of 2 the size of the range. It implies that the actual number of operations for std::ranges::minmax is at worse: cx1.5xN where c would be surprisingly large.
NB: the naive implementation for single pass is actually faster (though not twice faster): https://quick-bench.com/q/lOJq7Eu913Qx1evPz4ICCiC_OaA
[EDIT] here is a more exhaustive comparison, including the naive implementation: https://quick-bench.com/q/5_ibei8zFUM1y9RtM3k5EgnNtwU
With respect to all insightful comments about clang implementation, here is also the gcc benchmark: https://quick-bench.com/q/aAJ_AgZbAMmW5q5z3XEcchEQ69Q
It does not make a better work, though it is more consistent with respect with the two traversal versions.
In vertu of the Zero-overhead principle, this bench is bothering me.
