diff --git a/include/boost/histogram/axis/regular.hpp b/include/boost/histogram/axis/regular.hpp index a5c7c124..99950536 100644 --- a/include/boost/histogram/axis/regular.hpp +++ b/include/boost/histogram/axis/regular.hpp @@ -314,16 +314,18 @@ class regular : public iterator_mixin(z * size()); } } else { - if (z < 1) { - if (z >= 0) - return static_cast(z * size()); - else - return -1; - } + // Branch-free so that random data does not mispredict. The clamped value + // keeps the conversion to int in range for any input. fmin(NaN, 1) is 1, + // so NaN maps to size(); the order of fmin and fmax matters. + const bool below = z < 0; + const auto zc = std::fmax(std::fmin(z, decltype(z){1}), decltype(z){0}); + index_type i = static_cast(zc * size()); + i = below ? -1 : i; // upper edge of last bin is inclusive if overflow bin is not present - if (!options_type::test(option::overflow) && z == 1) return size() - 1; + if (!options_type::test(option::overflow)) i = z == 1 ? size() - 1 : i; + return i; // size() if x is NaN } - return size(); // also returned if x is NaN + return size(); } /// Returns index and shift (if axis has grown) for the passed argument. diff --git a/include/boost/histogram/detail/fill_n.hpp b/include/boost/histogram/detail/fill_n.hpp index a282a403..0d849ab2 100644 --- a/include/boost/histogram/detail/fill_n.hpp +++ b/include/boost/histogram/detail/fill_n.hpp @@ -219,7 +219,8 @@ void fill_n_storage(S& s, const Index idx, weight_type&& w, Ts&&... ps) noexc template void fill_n_nd(const std::size_t offset, S& storage, A& axes, const std::size_t vsize, const T* values, Ts&&... ts) { - constexpr std::size_t buffer_size = 1ul << 14; + // 32 kB of indices; a larger buffer spills out of L1 and slows the passes below + constexpr std::size_t buffer_size = 1ul << 12; Index indices[buffer_size]; /*