From 26473491c42fae18d310fe97bf643932d14d1856 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 26 Sep 2006 20:35:58 +0000 Subject: [PATCH] Attempting to work round the dodgy std::numeric_limits on some BSDs. [SVN r35345] --- hash/test/hash_float_test.cpp | 84 +++++++++---------- .../boost/functional/detail/hash_float.hpp | 61 ++++++++++++-- 2 files changed, 98 insertions(+), 47 deletions(-) diff --git a/hash/test/hash_float_test.cpp b/hash/test/hash_float_test.cpp index 2f964b9..97b687c 100644 --- a/hash/test/hash_float_test.cpp +++ b/hash/test/hash_float_test.cpp @@ -24,12 +24,12 @@ void float_tests(char const* name, T* = 0) std::cerr<<"\n" <<"Testing " BOOST_STRINGIZE(HASH_NAMESPACE) "::hash<"<\n" <<"\n" - <<"std::numeric_limits::digits = " - <::digits<<"\n" - <<"std::numeric_limits::digits = " - <::digits<<"\n" - <<"std::numeric_limits::digits = " - <::digits<<"\n" + <<"boost::hash_detail::float_limits::digits = " + <::digits<<"\n" + <<"boost::hash_detail::float_limits::digits = " + <::digits<<"\n" + <<"boost::hash_detail::float_limits::digits = " + <::digits<<"\n" <<"\n" ; @@ -50,11 +50,11 @@ void float_tests(char const* name, T* = 0) #if defined(__BORLANDC__) std::cerr<<"Not running infinity checks on Borland, as it causes it to crash.\n"; #else - if(std::numeric_limits::has_infinity) { + if(boost::hash_detail::float_limits::has_infinity) { T infinity = -log(zero); T infinity2 = (T) 1. / zero; T infinity3 = (T) -1. / minus_zero; - T infinity4 = std::numeric_limits::infinity(); + T infinity4 = boost::hash_detail::float_limits::infinity(); T minus_infinity = log(zero); T minus_infinity2 = (T) -1. / zero; @@ -84,26 +84,26 @@ void float_tests(char const* name, T* = 0) // This should really be 'has_denorm == denorm_present' but some // compilers don't have 'denorm_present'. See also a later use. - if(std::numeric_limits::has_denorm) { - if(x1(std::numeric_limits::denorm_min()) == x1(infinity)) { + if(boost::hash_detail::float_limits::has_denorm) { + if(x1(boost::hash_detail::float_limits::denorm_min()) == x1(infinity)) { std::cerr<<"x1(denorm_min) == x1(infinity) == "<::denorm_min()) == x1(minus_infinity)) { + if(x1(boost::hash_detail::float_limits::denorm_min()) == x1(minus_infinity)) { std::cerr<<"x1(denorm_min) == x1(-infinity) == "<::has_quiet_NaN) { - if(x1(std::numeric_limits::quiet_NaN()) == x1(infinity)) { + if(boost::hash_detail::float_limits::has_quiet_NaN) { + if(x1(boost::hash_detail::float_limits::quiet_NaN()) == x1(infinity)) { std::cerr<<"x1(quiet_NaN) == x1(infinity) == "<::quiet_NaN()) == x1(minus_infinity)) { + if(x1(boost::hash_detail::float_limits::quiet_NaN()) == x1(minus_infinity)) { std::cerr<<"x1(quiet_NaN) == x1(-infinity) == "<::max)(); + T max = (boost::hash_detail::float_limits::max)(); T half_max = max / 2; T quarter_max = max / 4; T three_quarter_max = max - quarter_max; @@ -132,50 +132,50 @@ void float_tests(char const* name, T* = 0) BOOST_TEST(x1(v1) == HASH_NAMESPACE::hash_value(v1)); BOOST_TEST(x1(v2) == HASH_NAMESPACE::hash_value(v2)); - BOOST_TEST(x1(std::numeric_limits::epsilon()) == - HASH_NAMESPACE::hash_value(std::numeric_limits::epsilon())); + BOOST_TEST(x1(boost::hash_detail::float_limits::epsilon()) == + HASH_NAMESPACE::hash_value(boost::hash_detail::float_limits::epsilon())); - BOOST_TEST(std::numeric_limits::epsilon() != (T) 0); - if(x1(std::numeric_limits::epsilon()) == x1((T) 0)) + BOOST_TEST(boost::hash_detail::float_limits::epsilon() != (T) 0); + if(x1(boost::hash_detail::float_limits::epsilon()) == x1((T) 0)) std::cerr<<"x1(epsilon) == x1(0) == "<::epsilon() != (T) 0); - if(x1(-std::numeric_limits::epsilon()) == x1((T) 0)) + BOOST_TEST(-boost::hash_detail::float_limits::epsilon() != (T) 0); + if(x1(-boost::hash_detail::float_limits::epsilon()) == x1((T) 0)) std::cerr<<"x1(-epsilon) == x1(0) == "<::epsilon() != (T) 1); - if(x1((T) 1 + std::numeric_limits::epsilon()) == x1((T) 1)) + BOOST_TEST((T) 1 + boost::hash_detail::float_limits::epsilon() != (T) 1); + if(x1((T) 1 + boost::hash_detail::float_limits::epsilon()) == x1((T) 1)) std::cerr<<"x1(1 + epsilon) == x1(1) == "<::epsilon() != (T) 1); - if(x1((T) 1 - std::numeric_limits::epsilon()) == x1((T) 1)) + BOOST_TEST((T) 1 - boost::hash_detail::float_limits::epsilon() != (T) 1); + if(x1((T) 1 - boost::hash_detail::float_limits::epsilon()) == x1((T) 1)) std::cerr<<"x1(1 - epsilon) == x1(1) == "<::epsilon() != (T) -1); - if(x1((T) -1 + std::numeric_limits::epsilon()) == x1((T) -1)) + BOOST_TEST((T) -1 + boost::hash_detail::float_limits::epsilon() != (T) -1); + if(x1((T) -1 + boost::hash_detail::float_limits::epsilon()) == x1((T) -1)) std::cerr<<"x1(-1 + epsilon) == x1(-1) == "<::epsilon() != (T) -1); - if(x1((T) -1 - std::numeric_limits::epsilon()) == x1((T) -1)) + BOOST_TEST((T) -1 - boost::hash_detail::float_limits::epsilon() != (T) -1); + if(x1((T) -1 - boost::hash_detail::float_limits::epsilon()) == x1((T) -1)) std::cerr<<"x1(-1 - epsilon) == x1(-1) == "<::has_denorm) { - if(x1(std::numeric_limits::denorm_min()) == x1(zero)) { + if(boost::hash_detail::float_limits::has_denorm) { + if(x1(boost::hash_detail::float_limits::denorm_min()) == x1(zero)) { std::cerr<<"x1(denorm_min) == x1(zero) == "<::denorm_min()) != - HASH_NAMESPACE::hash_value(std::numeric_limits::denorm_min())) + if(x1(boost::hash_detail::float_limits::denorm_min()) != + HASH_NAMESPACE::hash_value(boost::hash_detail::float_limits::denorm_min())) { - std::cerr<<"x1(std::numeric_limits::denorm_min()) = " - << x1(std::numeric_limits::denorm_min()) - << "\nhash_value(std::numeric_limits::denorm_min()) = " + std::cerr<<"x1(boost::hash_detail::float_limits::denorm_min()) = " + << x1(boost::hash_detail::float_limits::denorm_min()) + << "\nhash_value(boost::hash_detail::float_limits::denorm_min()) = " << HASH_NAMESPACE::hash_value( - std::numeric_limits::denorm_min()) + boost::hash_detail::float_limits::denorm_min()) << "\nx1(0) = "<::has_quiet_NaN) { - if(x1(std::numeric_limits::quiet_NaN()) == x1(1.0)) { + if(boost::hash_detail::float_limits::has_quiet_NaN) { + if(x1(boost::hash_detail::float_limits::quiet_NaN()) == x1(1.0)) { std::cerr<<"x1(quiet_NaN) == x1(1.0) == "<::quiet_NaN()) == - HASH_NAMESPACE::hash_value(std::numeric_limits::quiet_NaN())); + BOOST_TEST(x1(boost::hash_detail::float_limits::quiet_NaN()) == + HASH_NAMESPACE::hash_value(boost::hash_detail::float_limits::quiet_NaN())); } #endif } diff --git a/include/boost/functional/detail/hash_float.hpp b/include/boost/functional/detail/hash_float.hpp index ebdf966..f7aa74b 100644 --- a/include/boost/functional/detail/hash_float.hpp +++ b/include/boost/functional/detail/hash_float.hpp @@ -35,10 +35,61 @@ # endif #endif +// On FreeBSD and OpenBSD, numeric_limits is not reliable for long doubles, but +// the macros defined in are. I don't know if this is also be the case for +// other BSDs, but using the macros if they're available seems like the best +// choice. + +#if defined(__FreeBSD__) || defined(__NetBSD__) && \ + defined(__OpenBSD__) || defined(__DragonFly__) +#include +#endif + namespace boost { namespace hash_detail { + template + struct float_limits : std::numeric_limits {}; + +#if defined(__FreeBSD__) || defined(__NetBSD__) && \ + defined(__OpenBSD__) || defined(__DragonFly__) + template <> + struct float_limits + : std::numeric_limits + { +#if defined(LDBL_EPSILON) + static long double epsilon() { + return LDBL_EPSILON; + } +#endif + +#if defined(LDBL_MANT_DIG) + BOOST_STATIC_CONSTANT(int, digits = LDBL_MANT_DIG); +#endif + +#if defined(LDBL_MAX) + static long double (max)() { + return LDBL_MAX; + } +#endif + +#if defined(LDBL_MIN) + static long double (min)() { + return LDBL_MIN; + } +#endif + +#if defined(LDBL_MAX_EXP) + BOOST_STATIC_CONSTANT(int, max_exponent = LDBL_MAX_EXP); +#endif + +#if defined(LDBL_MIN_EXP) + BOOST_STATIC_CONSTANT(int, min_exponent = LDBL_MIN_EXP); +#endif + }; +#endif // __FreeBSD__/__NetBSD__/__OpenBSD__/__DragonFly__ + inline void hash_float_combine(std::size_t& seed, std::size_t value) { seed ^= value + (seed<<6) + (seed>>2); @@ -63,19 +114,19 @@ namespace boost //BOOST_ASSERT(0 <= v && v < 0.5); v = boost::hash_detail::call_ldexp(v, - std::numeric_limits::digits + 1); + float_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 - 1) - / std::numeric_limits::digits; + = (float_limits::digits * + boost::static_log2::radix>::value - 1) + / float_limits::digits; for(std::size_t i = 0; i < length; ++i) { - v = boost::hash_detail::call_ldexp(v, std::numeric_limits::digits); + v = boost::hash_detail::call_ldexp(v, float_limits::digits); std::size_t part = static_cast(v); v -= part; hash_float_combine(seed, part);