hash_float_test.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. // Copyright 2005-2009 Daniel James.
  2. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  3. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  4. #include "./config.hpp"
  5. #ifdef BOOST_HASH_TEST_STD_INCLUDES
  6. # include <functional>
  7. #else
  8. # include <boost/container_hash/hash.hpp>
  9. #endif
  10. #include <boost/core/lightweight_test.hpp>
  11. #include <cmath>
  12. #include <boost/container_hash/detail/limits.hpp>
  13. #include <boost/container_hash/detail/float_functions.hpp>
  14. #include <boost/config/workaround.hpp>
  15. #include <iostream>
  16. #if defined(BOOST_MSVC)
  17. #pragma warning(push)
  18. #pragma warning(disable:4127) // conditional expression is constant
  19. #pragma warning(disable:4723) // conditional expression is constant
  20. #if BOOST_MSVC < 1400
  21. #pragma warning(disable:4267) // conversion from 'size_t' to 'unsigned int',
  22. // possible loss of data
  23. #endif
  24. #endif
  25. #if defined(__GNUC__) && !defined(BOOST_INTEL_CXX_VERSION)
  26. #pragma GCC diagnostic ignored "-Wfloat-equal"
  27. #endif
  28. char const* float_type(float*) { return "float"; }
  29. char const* float_type(double*) { return "double"; }
  30. char const* float_type(long double*) { return "long double"; }
  31. template <class T>
  32. void float_tests(char const* name, T* = 0)
  33. {
  34. std::cerr
  35. << "\n"
  36. << "Testing " BOOST_STRINGIZE(BOOST_HASH_TEST_NAMESPACE) "::hash<"
  37. << name
  38. << ">\n"
  39. << "\n"
  40. << "boost::hash_detail::limits<T>::digits = "
  41. << boost::hash_detail::limits<T>::digits<< "\n"
  42. << "boost::hash_detail::limits<int>::digits = "
  43. << boost::hash_detail::limits<int>::digits<< "\n"
  44. << "boost::hash_detail::limits<std::size_t>::digits = "
  45. << boost::hash_detail::limits<std::size_t>::digits
  46. << "\n"
  47. << "\n"
  48. << "boost::hash_detail::call_ldexp<T>::float_type = "
  49. << float_type(static_cast<BOOST_DEDUCED_TYPENAME
  50. boost::hash_detail::call_ldexp<T>::float_type*>(0))
  51. << "\n"
  52. << "boost::hash_detail::call_frexp<T>::float_type = "
  53. << float_type(static_cast<BOOST_DEDUCED_TYPENAME
  54. boost::hash_detail::call_frexp<T>::float_type*>(0))
  55. << "\n"
  56. << "boost::hash_detail::select_hash_type<T>::type = "
  57. << float_type(static_cast<BOOST_DEDUCED_TYPENAME
  58. boost::hash_detail::select_hash_type<T>::type*>(0))
  59. << "\n"
  60. << "\n"
  61. ;
  62. BOOST_HASH_TEST_NAMESPACE::hash<T> x1;
  63. T zero = 0;
  64. T minus_zero = (T) -1 * zero;
  65. BOOST_TEST(zero == minus_zero);
  66. BOOST_TEST(x1(zero) == x1(minus_zero));
  67. #if defined(BOOST_HASH_TEST_EXTENSIONS)
  68. BOOST_TEST(x1(zero) == BOOST_HASH_TEST_NAMESPACE::hash_value(zero));
  69. BOOST_TEST(x1(minus_zero) == BOOST_HASH_TEST_NAMESPACE::hash_value(minus_zero));
  70. #endif
  71. BOOST_TEST(x1(zero) != x1(0.5));
  72. BOOST_TEST(x1(minus_zero) != x1(0.5));
  73. BOOST_TEST(x1(0.5) != x1(-0.5));
  74. BOOST_TEST(x1(1) != x1(-1));
  75. using namespace std;
  76. // Doing anything with infinity causes borland to crash.
  77. #if defined(__BORLANDC__)
  78. std::cerr
  79. << "Not running infinity checks on Borland, as it causes it to crash."
  80. "\n";
  81. #else
  82. if(boost::hash_detail::limits<T>::has_infinity) {
  83. T infinity = -log(zero);
  84. T infinity2 = (T) 1. / zero;
  85. T infinity3 = (T) -1. / minus_zero;
  86. T infinity4 = boost::hash_detail::limits<T>::infinity();
  87. T minus_infinity = log(zero);
  88. T minus_infinity2 = (T) -1. / zero;
  89. T minus_infinity3 = (T) 1. / minus_zero;
  90. #if defined(BOOST_HASH_TEST_EXTENSIONS)
  91. BOOST_TEST(x1(infinity) == BOOST_HASH_TEST_NAMESPACE::hash_value(infinity));
  92. BOOST_TEST(x1(minus_infinity)
  93. == BOOST_HASH_TEST_NAMESPACE::hash_value(minus_infinity));
  94. #endif
  95. if(infinity == infinity2)
  96. BOOST_TEST(x1(infinity) == x1(infinity2));
  97. if(infinity == infinity3)
  98. BOOST_TEST(x1(infinity) == x1(infinity3));
  99. if(infinity == infinity4)
  100. BOOST_TEST(x1(infinity) == x1(infinity4));
  101. if(minus_infinity == minus_infinity2)
  102. BOOST_TEST(x1(minus_infinity) == x1(minus_infinity2));
  103. if(minus_infinity == minus_infinity3)
  104. BOOST_TEST(x1(minus_infinity) == x1(minus_infinity3));
  105. BOOST_TEST(infinity != minus_infinity);
  106. if(x1(infinity) == x1(minus_infinity)) {
  107. std::cerr<<"x1(infinity) == x1(-infinity) == "<<x1(infinity)<<"\n";
  108. }
  109. // This should really be 'has_denorm == denorm_present' but some
  110. // compilers don't have 'denorm_present'. See also a later use.
  111. if(boost::hash_detail::limits<T>::has_denorm) {
  112. if(x1(boost::hash_detail::limits<T>::denorm_min()) == x1(infinity))
  113. {
  114. std::cerr
  115. << "x1(denorm_min) == x1(infinity) == "
  116. << x1(infinity)
  117. << "\n";
  118. }
  119. if(x1(boost::hash_detail::limits<T>::denorm_min()) ==
  120. x1(minus_infinity))
  121. {
  122. std::cerr
  123. << "x1(denorm_min) == x1(-infinity) == "
  124. << x1(minus_infinity)
  125. << "\n";
  126. }
  127. }
  128. if(boost::hash_detail::limits<T>::has_quiet_NaN) {
  129. if(x1(boost::hash_detail::limits<T>::quiet_NaN()) == x1(infinity))
  130. {
  131. std::cerr
  132. << "x1(quiet_NaN) == x1(infinity) == "
  133. << x1(infinity)
  134. << "\n";
  135. }
  136. if(x1(boost::hash_detail::limits<T>::quiet_NaN()) ==
  137. x1(minus_infinity))
  138. {
  139. std::cerr
  140. << "x1(quiet_NaN) == x1(-infinity) == "
  141. << x1(minus_infinity)
  142. << "\n";
  143. }
  144. }
  145. }
  146. #endif
  147. T max = (boost::hash_detail::limits<T>::max)();
  148. T half_max = max / 2;
  149. T quarter_max = max / 4;
  150. T three_quarter_max = max - quarter_max;
  151. // Check the limits::max is in range.
  152. BOOST_TEST(max != half_max);
  153. BOOST_TEST(max != quarter_max);
  154. BOOST_TEST(max != three_quarter_max);
  155. BOOST_TEST(half_max != quarter_max);
  156. BOOST_TEST(half_max != three_quarter_max);
  157. BOOST_TEST(quarter_max != three_quarter_max);
  158. BOOST_TEST(max != -max);
  159. BOOST_TEST(half_max != -half_max);
  160. BOOST_TEST(quarter_max != -quarter_max);
  161. BOOST_TEST(three_quarter_max != -three_quarter_max);
  162. #if defined(BOOST_HASH_TEST_EXTENSIONS)
  163. BOOST_TEST(x1(max) == BOOST_HASH_TEST_NAMESPACE::hash_value(max));
  164. BOOST_TEST(x1(half_max) == BOOST_HASH_TEST_NAMESPACE::hash_value(half_max));
  165. BOOST_TEST(x1(quarter_max) == BOOST_HASH_TEST_NAMESPACE::hash_value(quarter_max));
  166. BOOST_TEST(x1(three_quarter_max) ==
  167. BOOST_HASH_TEST_NAMESPACE::hash_value(three_quarter_max));
  168. #endif
  169. // The '!=' tests could legitimately fail, but with my hash it indicates a
  170. // bug.
  171. BOOST_TEST(x1(max) == x1(max));
  172. BOOST_TEST(x1(max) != x1(quarter_max));
  173. BOOST_TEST(x1(max) != x1(half_max));
  174. BOOST_TEST(x1(max) != x1(three_quarter_max));
  175. BOOST_TEST(x1(quarter_max) == x1(quarter_max));
  176. BOOST_TEST(x1(quarter_max) != x1(half_max));
  177. BOOST_TEST(x1(quarter_max) != x1(three_quarter_max));
  178. BOOST_TEST(x1(half_max) == x1(half_max));
  179. BOOST_TEST(x1(half_max) != x1(three_quarter_max));
  180. BOOST_TEST(x1(three_quarter_max) == x1(three_quarter_max));
  181. BOOST_TEST(x1(max) != x1(-max));
  182. BOOST_TEST(x1(half_max) != x1(-half_max));
  183. BOOST_TEST(x1(quarter_max) != x1(-quarter_max));
  184. BOOST_TEST(x1(three_quarter_max) != x1(-three_quarter_max));
  185. // Intel with gcc stdlib sometimes segfaults on calls to asin and acos.
  186. #if !((defined(__INTEL_COMPILER) || defined(__ICL) || \
  187. defined(__ICC) || defined(__ECC)) && \
  188. (defined(__GLIBCPP__) || defined(__GLIBCXX__)))
  189. T v1 = asin((T) 1);
  190. T v2 = acos((T) 0);
  191. if(v1 == v2)
  192. BOOST_TEST(x1(v1) == x1(v2));
  193. #if defined(BOOST_HASH_TEST_EXTENSIONS)
  194. BOOST_TEST(x1(v1) == BOOST_HASH_TEST_NAMESPACE::hash_value(v1));
  195. BOOST_TEST(x1(v2) == BOOST_HASH_TEST_NAMESPACE::hash_value(v2));
  196. #endif
  197. #endif
  198. #if defined(BOOST_HASH_TEST_EXTENSIONS)
  199. BOOST_TEST(x1(boost::hash_detail::limits<T>::epsilon()) ==
  200. BOOST_HASH_TEST_NAMESPACE::hash_value(
  201. boost::hash_detail::limits<T>::epsilon()));
  202. #endif
  203. BOOST_TEST(boost::hash_detail::limits<T>::epsilon() != (T) 0);
  204. if(x1(boost::hash_detail::limits<T>::epsilon()) == x1((T) 0))
  205. std::cerr<<"x1(epsilon) == x1(0) == "<<x1((T) 0)<<"\n";
  206. BOOST_TEST(-boost::hash_detail::limits<T>::epsilon() != (T) 0);
  207. if(x1(-boost::hash_detail::limits<T>::epsilon()) == x1((T) 0))
  208. std::cerr<<"x1(-epsilon) == x1(0) == "<<x1((T) 0)<<"\n";
  209. BOOST_TEST((T) 1 + boost::hash_detail::limits<T>::epsilon() != (T) 1);
  210. if(x1((T) 1 + boost::hash_detail::limits<T>::epsilon()) == x1((T) 1))
  211. std::cerr<<"x1(1 + epsilon) == x1(1) == "<<x1((T) 1)<<"\n";
  212. BOOST_TEST((T) 1 - boost::hash_detail::limits<T>::epsilon() != (T) 1);
  213. if(x1((T) 1 - boost::hash_detail::limits<T>::epsilon()) == x1((T) 1))
  214. std::cerr<<"x1(1 - epsilon) == x1(1) == "<<x1((T) 1)<<"\n";
  215. BOOST_TEST((T) -1 + boost::hash_detail::limits<T>::epsilon() != (T) -1);
  216. if(x1((T) -1 + boost::hash_detail::limits<T>::epsilon()) == x1((T) -1))
  217. std::cerr<<"x1(-1 + epsilon) == x1(-1) == "<<x1((T) -1)<<"\n";
  218. BOOST_TEST((T) -1 - boost::hash_detail::limits<T>::epsilon() != (T) -1);
  219. if(x1((T) -1 - boost::hash_detail::limits<T>::epsilon()) == x1((T) -1))
  220. std::cerr<<"x1(-1 - epsilon) == x1(-1) == "<<x1((T) -1)<<"\n";
  221. // As before.
  222. if(boost::hash_detail::limits<T>::has_denorm) {
  223. if(x1(boost::hash_detail::limits<T>::denorm_min()) == x1(zero)) {
  224. std::cerr<<"x1(denorm_min) == x1(zero) == "<<x1(zero)<<"\n";
  225. }
  226. #if !BOOST_WORKAROUND(__DECCXX_VER,<70190006) && defined(BOOST_HASH_TEST_EXTENSIONS)
  227. // The Tru64/CXX standard library prior to 7.1 contains a bug in the
  228. // specialization of boost::hash_detail::limits::denorm_min() for long
  229. // doubles which causes this test to fail.
  230. if(x1(boost::hash_detail::limits<T>::denorm_min()) !=
  231. BOOST_HASH_TEST_NAMESPACE::hash_value(
  232. boost::hash_detail::limits<T>::denorm_min()))
  233. {
  234. std::cerr
  235. << "x1(boost::hash_detail::limits<T>::denorm_min()) = "
  236. << x1(boost::hash_detail::limits<T>::denorm_min())
  237. << "\nhash_value(boost::hash_detail::limits<T>::denorm_min())"
  238. " = "
  239. << BOOST_HASH_TEST_NAMESPACE::hash_value(
  240. boost::hash_detail::limits<T>::denorm_min())
  241. << "\nx1(0) = "
  242. << x1(0)
  243. << "\n";
  244. }
  245. #endif
  246. }
  247. // NaN also causes borland to crash.
  248. #if !defined(__BORLANDC__) && defined(BOOST_HASH_TEST_EXTENSIONS)
  249. if(boost::hash_detail::limits<T>::has_quiet_NaN) {
  250. if(x1(boost::hash_detail::limits<T>::quiet_NaN()) == x1(1.0)) {
  251. std::cerr<<"x1(quiet_NaN) == x1(1.0) == "<<x1(1.0)<<"\n";
  252. }
  253. BOOST_TEST(x1(boost::hash_detail::limits<T>::quiet_NaN()) ==
  254. BOOST_HASH_TEST_NAMESPACE::hash_value(
  255. boost::hash_detail::limits<T>::quiet_NaN()));
  256. }
  257. #endif
  258. }
  259. #if defined(BOOST_MSVC)
  260. #pragma warning(pop)
  261. #endif