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)
8 #include <boost/math/concepts/real_concept.hpp>
9 #include <boost/math/tools/test.hpp>
10 #define BOOST_TEST_MAIN
11 #include <boost/test/unit_test.hpp>
12 #include <boost/test/tools/floating_point_comparison.hpp>
13 #include <boost/math/special_functions/next.hpp>
14 #include <boost/math/special_functions/ulp.hpp>
15 #include <boost/multiprecision/cpp_dec_float.hpp>
16 #include <boost/multiprecision/debug_adaptor.hpp>
21 #pragma warning(disable:4127)
25 bool is_normalized_value(const T& val)
28 // Returns false if value has guard digits that are non-zero
30 boost::intmax_t shift = std::numeric_limits<T>::digits - ilogb(val) - 1;
31 T shifted = scalbn(val, shift);
32 return floor(shifted) == shifted;
36 void test_value(const T& val, const char* name)
38 using namespace boost::math;
39 T upper = tools::max_value<T>();
42 std::cout << "Testing type " << name << " with initial value " << val << std::endl;
44 BOOST_CHECK_EQUAL(float_distance(float_next(val), val), -1);
45 BOOST_CHECK(float_next(val) > val);
46 BOOST_CHECK_EQUAL(float_distance(float_prior(val), val), 1);
47 BOOST_CHECK(float_prior(val) < val);
48 BOOST_CHECK_EQUAL(float_distance((boost::math::nextafter)(val, upper), val), -1);
49 BOOST_CHECK((boost::math::nextafter)(val, upper) > val);
50 BOOST_CHECK_EQUAL(float_distance((boost::math::nextafter)(val, lower), val), 1);
51 BOOST_CHECK((boost::math::nextafter)(val, lower) < val);
52 BOOST_CHECK_EQUAL(float_distance(float_next(float_next(val)), val), -2);
53 BOOST_CHECK_EQUAL(float_distance(float_prior(float_prior(val)), val), 2);
54 BOOST_CHECK_EQUAL(float_distance(float_prior(float_prior(val)), float_next(float_next(val))), 4);
55 BOOST_CHECK_EQUAL(float_distance(float_prior(float_next(val)), val), 0);
56 BOOST_CHECK_EQUAL(float_distance(float_next(float_prior(val)), val), 0);
57 if (is_normalized_value(val))
59 BOOST_CHECK_EQUAL(float_prior(float_next(val)), val);
60 BOOST_CHECK_EQUAL(float_next(float_prior(val)), val);
62 BOOST_CHECK_EQUAL(float_distance(float_advance(val, 4), val), -4);
63 BOOST_CHECK_EQUAL(float_distance(float_advance(val, -4), val), 4);
64 if(std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_denorm == std::denorm_present))
66 BOOST_CHECK_EQUAL(float_distance(float_advance(float_next(float_next(val)), 4), float_next(float_next(val))), -4);
67 BOOST_CHECK_EQUAL(float_distance(float_advance(float_next(float_next(val)), -4), float_next(float_next(val))), 4);
69 if (is_normalized_value(val))
74 T fn = float_next(val);
77 BOOST_CHECK_LE(ulp(val), boost::math::tools::min_value<T>());
81 BOOST_CHECK_EQUAL(fn, n);
86 BOOST_CHECK_GE(boost::math::tools::min_value<T>(), ulp(val));
91 T fp = float_prior(val);
94 BOOST_CHECK_LE(ulp(val), boost::math::tools::min_value<T>());
98 BOOST_CHECK_EQUAL(fp, n);
105 void test_values(const T& val, const char* name)
107 static const T a = boost::lexical_cast<T>("1.3456724e22");
108 static const T b = boost::lexical_cast<T>("1.3456724e-22");
109 static const T z = 0;
110 static const T one = 1;
111 static const T radix = std::numeric_limits<T>::radix;
113 std::cout << "Testing type " << name << std::endl;
115 T den = (std::numeric_limits<T>::min)() / 4;
118 std::cout << "Denormals are active\n";
122 std::cout << "Denormals are flushed to zero.\n";
126 test_value(T(-a), name);
128 test_value(T(-b), name);
129 test_value(T(b / 3), name);
130 test_value(T(-b / 3), name);
131 test_value(boost::math::tools::epsilon<T>(), name);
132 test_value(T(-boost::math::tools::epsilon<T>()), name);
133 test_value(boost::math::tools::min_value<T>(), name);
134 test_value(T(-boost::math::tools::min_value<T>()), name);
135 if (std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_denorm == std::denorm_present) && ((std::numeric_limits<T>::min)() / 2 != 0))
138 test_value(T(-z), name);
140 test_value(one, name);
141 test_value(T(-one), name);
142 test_value(radix, name);
143 test_value(T(-radix), name);
145 if(std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_denorm == std::denorm_present) && ((std::numeric_limits<T>::min)() / 2 != 0))
147 test_value(std::numeric_limits<T>::denorm_min(), name);
148 test_value(T(-std::numeric_limits<T>::denorm_min()), name);
149 test_value(T(2 * std::numeric_limits<T>::denorm_min()), name);
150 test_value(T(-2 * std::numeric_limits<T>::denorm_min()), name);
153 static const int primes[] = {
154 11, 13, 17, 19, 23, 29,
155 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
156 73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
157 127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
158 179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
159 233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
160 283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
161 353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
162 419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
165 for(unsigned i = 0; i < sizeof(primes)/sizeof(primes[0]); ++i)
169 for(int j = 0; j < primes[i]; ++j)
171 v1 = boost::math::float_next(v1);
172 v2 = boost::math::float_prior(v2);
174 BOOST_CHECK_EQUAL(boost::math::float_distance(v1, val), -primes[i]);
175 BOOST_CHECK_EQUAL(boost::math::float_distance(v2, val), primes[i]);
176 BOOST_CHECK_EQUAL(boost::math::float_advance(val, primes[i]), v1);
177 BOOST_CHECK_EQUAL(boost::math::float_advance(val, -primes[i]), v2);
179 if(std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_infinity))
181 BOOST_CHECK_EQUAL(boost::math::float_prior(std::numeric_limits<T>::infinity()), (std::numeric_limits<T>::max)());
182 BOOST_CHECK_EQUAL(boost::math::float_next(-std::numeric_limits<T>::infinity()), -(std::numeric_limits<T>::max)());
183 BOOST_MATH_CHECK_THROW(boost::math::float_prior(-std::numeric_limits<T>::infinity()), std::domain_error);
184 BOOST_MATH_CHECK_THROW(boost::math::float_next(std::numeric_limits<T>::infinity()), std::domain_error);
185 if(boost::math::policies:: BOOST_MATH_OVERFLOW_ERROR_POLICY == boost::math::policies::throw_on_error)
187 BOOST_MATH_CHECK_THROW(boost::math::float_prior(-(std::numeric_limits<T>::max)()), std::overflow_error);
188 BOOST_MATH_CHECK_THROW(boost::math::float_next((std::numeric_limits<T>::max)()), std::overflow_error);
192 BOOST_CHECK_EQUAL(boost::math::float_prior(-(std::numeric_limits<T>::max)()), -std::numeric_limits<T>::infinity());
193 BOOST_CHECK_EQUAL(boost::math::float_next((std::numeric_limits<T>::max)()), std::numeric_limits<T>::infinity());
198 BOOST_AUTO_TEST_CASE( test_main )
200 // Very slow, but debuggable:
201 //test_values(boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::cpp_dec_float_50::backend_type> >(0), "cpp_dec_float_50");
203 // Faster, but no good for diagnising the cause of any issues:
204 test_values(boost::multiprecision::cpp_dec_float_50(0), "cpp_dec_float_50");