diff --git a/include/boost/functional/detail/hash_float.hpp b/include/boost/functional/detail/hash_float.hpp index a58eed7..efeb2af 100644 --- a/include/boost/functional/detail/hash_float.hpp +++ b/include/boost/functional/detail/hash_float.hpp @@ -15,6 +15,7 @@ #endif #include +#include #include #include #include @@ -82,23 +83,42 @@ namespace boost } #else + template inline std::size_t float_hash_impl(T v) { int exp = 0; + v = boost::hash_detail::call_frexp(v, &exp); - std::size_t seed = 0; + // A postive value is easier to hash, so combine the + // sign with the exponent. + if(v < 0) { + v = -v; + exp += std::numeric_limits::max_exponent - + std::numeric_limits::min_exponent; + } + // The result of frexp is always between 0.5 and 1, so its + // top bit will always be 1. Subtract by 0.5 to remove that. + v -= T(0.5); + v = boost::hash_detail::call_ldexp(v, + std::numeric_limits::digits + 1); + std::size_t seed = static_cast(v); + v -= seed; + + // ceiling(digits(T) * log2(radix(T))/ digits(size_t)) - 1; std::size_t const length - = (std::numeric_limits::digits + - std::numeric_limits::digits - 1) - / std::numeric_limits::digits; + = (std::numeric_limits::digits * + boost::static_log2::radix>::value + - 1) + / std::numeric_limits::digits; for(std::size_t i = 0; i != length; ++i) { - v = boost::hash_detail::call_ldexp(v, std::numeric_limits::digits); - int const part = static_cast(v); + v = boost::hash_detail::call_ldexp(v, + std::numeric_limits::digits); + std::size_t part = static_cast(v); v -= part; hash_float_combine(seed, part); }