From cae97c67d8cf3ef9a3582eed309c544ebe3d51eb Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 11 Jun 2006 15:29:09 +0000 Subject: [PATCH] Tweak the float hashing algorithm to perform fewer calls to ldexp for some types and possibly generate a better hash value. [SVN r34273] --- .../boost/functional/detail/hash_float.hpp | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/include/boost/functional/detail/hash_float.hpp b/include/boost/functional/detail/hash_float.hpp index 5699b7e..c04267b 100644 --- a/include/boost/functional/detail/hash_float.hpp +++ b/include/boost/functional/detail/hash_float.hpp @@ -18,7 +18,6 @@ #include #include #include -#include // Don't use fpclassify or _fpclass for stlport. #if !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION) @@ -49,22 +48,34 @@ namespace boost inline std::size_t float_hash_impl(T v) { int exp = 0; - errno = 0; - v = boost::hash_detail::call_frexp(v, &exp); - if(errno) return 0; - std::size_t seed = 0; + // 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. + if(v >= 0) { + v = boost::hash_detail::call_frexp(v, &exp) - 0.5; + } + else { + v = -boost::hash_detail::call_frexp(v, &exp) - 0.5; + exp = ~exp; + } + BOOST_ASSERT(0 <= v && v < 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 * - boost::static_log2::radix>::value + - std::numeric_limits::digits - 1) - / 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); } @@ -116,7 +127,7 @@ namespace boost return 0; } #else - return float_hash_impl(v); + return v == 0 ? 0 : float_hash_impl(v); #endif } }