I think putting the buckets in eytzinger layout might help with cache locality here? though on the other hand they might all fit into cache anyways..

I'd also want to try interpolation search for this (not necessarily linear interpolation since we're doing floats) - you can take much better guesses than "it's in the middle somewhere" by not having to look at the data through a 1-bit-wide pinhole as comparison algorithms do.

Binary search is log time but otherwise pretty awful. If you don’t specifically need a sorted array, use something like a B-tree instead.

> I'd also want to try interpolation search for this

Years ago, when ORC unwinding tables were being implemented for the Linux kernel, the main performance bottleneck was binary search to turn a virtual address into an unwind record. I suggested adding a little array to reduce the range to be binary searched, and this was a huge speed up.

The same trick could work for floats as in the article: use an order-preserving float to int mapping and find the range of mapped integers that actually exist in the data set. Divide it equally into, say, a few thousand buckets. For each bucket, record the first index in the actual table that corresponds to that bucket. Then, to look up an actual entry, query two adjacent table entries to find the subrange that needs to be binary searched and search that.

The benefit will depend on the distribution of the table. In the best case it will eliminate the log factor entirely and make each lookup take a small constant number of queries.

I imagine a similar trick could be used with B-trees, but it would be more complex.

Better guesses reduce the number of guesses, so there will be less branch misprediction, but there will still be mispredictions for each remaining branch. So I would guess branchless interpolation search would still help.

In practice because the real code in scikit-learn is used in parallel, memory bandwidth starts being a problem in real usage. Plus, in the overall algorithm (this is just a small part) the time spent on binary search is now low enough that there are other, more significant bottlenecks elsewhere. So in practice the branchless optimization had enough impact on the original motivating code base that there didn't seem much point spending more time on it.