Scott Meyers had a very good talk which contained this information: <https://youtu.be/WDIkqP4JbkE?t=3614>
> The spikes in the performance for std::lower_bound at powers of 2 might be due to the nature of how binary search works and the specific implementation of std::lower_bound in the standard library.
> Binary search works by continually halving the search space. When the size of the array is a power of 2, every subdivision during the binary search is a clean halving of the array. This could result in an idealized number of comparisons in theory.
> However, in practice, modern CPU performance is heavily influenced by memory access patterns due to caching effects. When an array size is a power of 2, elements that are frequently compared may end up located at memory addresses that conflict in the CPU cache (a phenomenon known as "cache aliasing" or "cache line collisions"). The CPU cache works by storing data that is spatially and temporally close together, and it uses certain bits of the memory address to determine where in the cache to place that data.
> When the size of the array is a power of 2, it's more likely that two distinct memory locations will map to the same cache line, leading to cache eviction where one piece of data pushes out the other, causing a cache miss the next time that evicted location is accessed. This results in extra memory latency, slowing down the execution of the algorithm.
> The performance spikes you see are likely a combination of these factors. While the algorithm is doing an optimal number of comparisons, the cache line collisions might be causing additional memory latency that slows down the overall performance.
> This would also explain why the branchless binary search algorithm does not show the same performance spikes at powers of 2 - its memory access pattern is different and may not result in the same level of cache line collisions.
It’s been a long time since I looked into this, if I recall correctly binary search with close to power of 2 sized data is slower because of some interaction with the caches which causes the data to constantly have to be reloaded from memory.