test_next_decimal.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. // (C) Copyright John Maddock 2008.
  2. // Use, modification and distribution are subject to the
  3. // Boost Software License, Version 1.0. (See accompanying file
  4. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #include <pch.hpp>
  6. #include <boost/math/concepts/real_concept.hpp>
  7. #include <boost/math/tools/test.hpp>
  8. #define BOOST_TEST_MAIN
  9. #include <boost/test/unit_test.hpp>
  10. #include <boost/test/tools/floating_point_comparison.hpp>
  11. #include <boost/math/special_functions/next.hpp>
  12. #include <boost/math/special_functions/ulp.hpp>
  13. #include <boost/multiprecision/cpp_dec_float.hpp>
  14. #include <boost/multiprecision/debug_adaptor.hpp>
  15. #include <iostream>
  16. #include <iomanip>
  17. #ifdef BOOST_MSVC
  18. #pragma warning(disable:4127)
  19. #endif
  20. template <class T>
  21. bool is_normalized_value(const T& val)
  22. {
  23. //
  24. // Returns false if value has guard digits that are non-zero
  25. //
  26. boost::intmax_t shift = std::numeric_limits<T>::digits - ilogb(val) - 1;
  27. T shifted = scalbn(val, shift);
  28. return floor(shifted) == shifted;
  29. }
  30. template <class T>
  31. void test_value(const T& val, const char* name)
  32. {
  33. using namespace boost::math;
  34. T upper = tools::max_value<T>();
  35. T lower = -upper;
  36. std::cout << "Testing type " << name << " with initial value " << val << std::endl;
  37. BOOST_CHECK_EQUAL(float_distance(float_next(val), val), -1);
  38. BOOST_CHECK(float_next(val) > val);
  39. BOOST_CHECK_EQUAL(float_distance(float_prior(val), val), 1);
  40. BOOST_CHECK(float_prior(val) < val);
  41. BOOST_CHECK_EQUAL(float_distance((boost::math::nextafter)(val, upper), val), -1);
  42. BOOST_CHECK((boost::math::nextafter)(val, upper) > val);
  43. BOOST_CHECK_EQUAL(float_distance((boost::math::nextafter)(val, lower), val), 1);
  44. BOOST_CHECK((boost::math::nextafter)(val, lower) < val);
  45. BOOST_CHECK_EQUAL(float_distance(float_next(float_next(val)), val), -2);
  46. BOOST_CHECK_EQUAL(float_distance(float_prior(float_prior(val)), val), 2);
  47. BOOST_CHECK_EQUAL(float_distance(float_prior(float_prior(val)), float_next(float_next(val))), 4);
  48. BOOST_CHECK_EQUAL(float_distance(float_prior(float_next(val)), val), 0);
  49. BOOST_CHECK_EQUAL(float_distance(float_next(float_prior(val)), val), 0);
  50. if (is_normalized_value(val))
  51. {
  52. BOOST_CHECK_EQUAL(float_prior(float_next(val)), val);
  53. BOOST_CHECK_EQUAL(float_next(float_prior(val)), val);
  54. }
  55. BOOST_CHECK_EQUAL(float_distance(float_advance(val, 4), val), -4);
  56. BOOST_CHECK_EQUAL(float_distance(float_advance(val, -4), val), 4);
  57. if(std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_denorm == std::denorm_present))
  58. {
  59. BOOST_CHECK_EQUAL(float_distance(float_advance(float_next(float_next(val)), 4), float_next(float_next(val))), -4);
  60. BOOST_CHECK_EQUAL(float_distance(float_advance(float_next(float_next(val)), -4), float_next(float_next(val))), 4);
  61. }
  62. if (is_normalized_value(val))
  63. {
  64. if (val > 0)
  65. {
  66. T n = val + ulp(val);
  67. T fn = float_next(val);
  68. if (n > fn)
  69. {
  70. BOOST_CHECK_LE(ulp(val), boost::math::tools::min_value<T>());
  71. }
  72. else
  73. {
  74. BOOST_CHECK_EQUAL(fn, n);
  75. }
  76. }
  77. else if (val == 0)
  78. {
  79. BOOST_CHECK_GE(boost::math::tools::min_value<T>(), ulp(val));
  80. }
  81. else
  82. {
  83. T n = val - ulp(val);
  84. T fp = float_prior(val);
  85. if (n < fp)
  86. {
  87. BOOST_CHECK_LE(ulp(val), boost::math::tools::min_value<T>());
  88. }
  89. else
  90. {
  91. BOOST_CHECK_EQUAL(fp, n);
  92. }
  93. }
  94. }
  95. }
  96. template <class T>
  97. void test_values(const T& val, const char* name)
  98. {
  99. static const T a = boost::lexical_cast<T>("1.3456724e22");
  100. static const T b = boost::lexical_cast<T>("1.3456724e-22");
  101. static const T z = 0;
  102. static const T one = 1;
  103. static const T radix = std::numeric_limits<T>::radix;
  104. std::cout << "Testing type " << name << std::endl;
  105. T den = (std::numeric_limits<T>::min)() / 4;
  106. if(den != 0)
  107. {
  108. std::cout << "Denormals are active\n";
  109. }
  110. else
  111. {
  112. std::cout << "Denormals are flushed to zero.\n";
  113. }
  114. test_value(a, name);
  115. test_value(T(-a), name);
  116. test_value(b, name);
  117. test_value(T(-b), name);
  118. test_value(T(b / 3), name);
  119. test_value(T(-b / 3), name);
  120. test_value(boost::math::tools::epsilon<T>(), name);
  121. test_value(T(-boost::math::tools::epsilon<T>()), name);
  122. test_value(boost::math::tools::min_value<T>(), name);
  123. test_value(T(-boost::math::tools::min_value<T>()), name);
  124. if (std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_denorm == std::denorm_present) && ((std::numeric_limits<T>::min)() / 2 != 0))
  125. {
  126. test_value(z, name);
  127. test_value(T(-z), name);
  128. }
  129. test_value(one, name);
  130. test_value(T(-one), name);
  131. test_value(radix, name);
  132. test_value(T(-radix), name);
  133. if(std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_denorm == std::denorm_present) && ((std::numeric_limits<T>::min)() / 2 != 0))
  134. {
  135. test_value(std::numeric_limits<T>::denorm_min(), name);
  136. test_value(T(-std::numeric_limits<T>::denorm_min()), name);
  137. test_value(T(2 * std::numeric_limits<T>::denorm_min()), name);
  138. test_value(T(-2 * std::numeric_limits<T>::denorm_min()), name);
  139. }
  140. static const int primes[] = {
  141. 11, 13, 17, 19, 23, 29,
  142. 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
  143. 73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
  144. 127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
  145. 179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
  146. 233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
  147. 283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
  148. 353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
  149. 419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
  150. };
  151. for(unsigned i = 0; i < sizeof(primes)/sizeof(primes[0]); ++i)
  152. {
  153. T v1 = val;
  154. T v2 = val;
  155. for(int j = 0; j < primes[i]; ++j)
  156. {
  157. v1 = boost::math::float_next(v1);
  158. v2 = boost::math::float_prior(v2);
  159. }
  160. BOOST_CHECK_EQUAL(boost::math::float_distance(v1, val), -primes[i]);
  161. BOOST_CHECK_EQUAL(boost::math::float_distance(v2, val), primes[i]);
  162. BOOST_CHECK_EQUAL(boost::math::float_advance(val, primes[i]), v1);
  163. BOOST_CHECK_EQUAL(boost::math::float_advance(val, -primes[i]), v2);
  164. }
  165. if(std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_infinity))
  166. {
  167. BOOST_CHECK_EQUAL(boost::math::float_prior(std::numeric_limits<T>::infinity()), (std::numeric_limits<T>::max)());
  168. BOOST_CHECK_EQUAL(boost::math::float_next(-std::numeric_limits<T>::infinity()), -(std::numeric_limits<T>::max)());
  169. BOOST_MATH_CHECK_THROW(boost::math::float_prior(-std::numeric_limits<T>::infinity()), std::domain_error);
  170. BOOST_MATH_CHECK_THROW(boost::math::float_next(std::numeric_limits<T>::infinity()), std::domain_error);
  171. if(boost::math::policies:: BOOST_MATH_OVERFLOW_ERROR_POLICY == boost::math::policies::throw_on_error)
  172. {
  173. BOOST_MATH_CHECK_THROW(boost::math::float_prior(-(std::numeric_limits<T>::max)()), std::overflow_error);
  174. BOOST_MATH_CHECK_THROW(boost::math::float_next((std::numeric_limits<T>::max)()), std::overflow_error);
  175. }
  176. else
  177. {
  178. BOOST_CHECK_EQUAL(boost::math::float_prior(-(std::numeric_limits<T>::max)()), -std::numeric_limits<T>::infinity());
  179. BOOST_CHECK_EQUAL(boost::math::float_next((std::numeric_limits<T>::max)()), std::numeric_limits<T>::infinity());
  180. }
  181. }
  182. }
  183. BOOST_AUTO_TEST_CASE( test_main )
  184. {
  185. // Very slow, but debuggable:
  186. //test_values(boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::cpp_dec_float_50::backend_type> >(0), "cpp_dec_float_50");
  187. // Faster, but no good for diagnising the cause of any issues:
  188. test_values(boost::multiprecision::cpp_dec_float_50(0), "cpp_dec_float_50");
  189. }