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_bin_float.hpp>
20 #pragma warning(disable:4127)
23 #if !defined(_CRAYC) && !defined(__CUDACC__) && (!defined(__GNUC__) || (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ > 3)))
24 #if (defined(_M_IX86_FP) && (_M_IX86_FP >= 2)) || defined(__SSE2__) || defined(TEST_SSE2)
26 #include "xmmintrin.h"
33 void test_value(const T& val, const char* name)
35 using namespace boost::math;
36 T upper = tools::max_value<T>();
39 std::cout << "Testing type " << name << " with initial value " << val << std::endl;
41 BOOST_CHECK_EQUAL(float_distance(float_next(val), val), -1);
42 BOOST_CHECK(float_next(val) > val);
43 BOOST_CHECK_EQUAL(float_distance(float_prior(val), val), 1);
44 BOOST_CHECK(float_prior(val) < val);
45 BOOST_CHECK_EQUAL(float_distance((boost::math::nextafter)(val, upper), val), -1);
46 BOOST_CHECK((boost::math::nextafter)(val, upper) > val);
47 BOOST_CHECK_EQUAL(float_distance((boost::math::nextafter)(val, lower), val), 1);
48 BOOST_CHECK((boost::math::nextafter)(val, lower) < val);
49 BOOST_CHECK_EQUAL(float_distance(float_next(float_next(val)), val), -2);
50 BOOST_CHECK_EQUAL(float_distance(float_prior(float_prior(val)), val), 2);
51 BOOST_CHECK_EQUAL(float_distance(float_prior(float_prior(val)), float_next(float_next(val))), 4);
52 BOOST_CHECK_EQUAL(float_distance(float_prior(float_next(val)), val), 0);
53 BOOST_CHECK_EQUAL(float_distance(float_next(float_prior(val)), val), 0);
54 BOOST_CHECK_EQUAL(float_prior(float_next(val)), val);
55 BOOST_CHECK_EQUAL(float_next(float_prior(val)), val);
57 BOOST_CHECK_EQUAL(float_distance(float_advance(val, 4), val), -4);
58 BOOST_CHECK_EQUAL(float_distance(float_advance(val, -4), val), 4);
59 if(std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_denorm == std::denorm_present))
61 BOOST_CHECK_EQUAL(float_distance(float_advance(float_next(float_next(val)), 4), float_next(float_next(val))), -4);
62 BOOST_CHECK_EQUAL(float_distance(float_advance(float_next(float_next(val)), -4), float_next(float_next(val))), 4);
67 T fn = float_next(val);
70 BOOST_CHECK_LE(ulp(val), boost::math::tools::min_value<T>());
74 BOOST_CHECK_EQUAL(fn, n);
79 BOOST_CHECK_GE(boost::math::tools::min_value<T>(), ulp(val));
84 T fp = float_prior(val);
87 BOOST_CHECK_LE(ulp(val), boost::math::tools::min_value<T>());
91 BOOST_CHECK_EQUAL(fp, n);
97 void test_values(const T& val, const char* name)
99 static const T a = static_cast<T>(1.3456724e22);
100 static const T b = static_cast<T>(1.3456724e-22);
101 static const T z = 0;
102 static const T one = 1;
103 static const T two = 2;
105 std::cout << "Testing type " << name << std::endl;
107 T den = (std::numeric_limits<T>::min)() / 4;
110 std::cout << "Denormals are active\n";
114 std::cout << "Denormals are flushed to zero.\n";
118 test_value(-a, name);
120 test_value(-b, name);
121 test_value(boost::math::tools::epsilon<T>(), name);
122 test_value(-boost::math::tools::epsilon<T>(), name);
123 test_value(boost::math::tools::min_value<T>(), name);
124 test_value(-boost::math::tools::min_value<T>(), name);
125 if (std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_denorm == std::denorm_present) && ((std::numeric_limits<T>::min)() / 2 != 0))
128 test_value(-z, name);
130 test_value(one, name);
131 test_value(-one, name);
132 test_value(two, name);
133 test_value(-two, name);
134 #if defined(TEST_SSE2)
135 if((_mm_getcsr() & (_MM_FLUSH_ZERO_ON | 0x40)) == 0)
138 if(std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_denorm == std::denorm_present) && ((std::numeric_limits<T>::min)() / 2 != 0))
140 test_value(std::numeric_limits<T>::denorm_min(), name);
141 test_value(-std::numeric_limits<T>::denorm_min(), name);
142 test_value(2 * std::numeric_limits<T>::denorm_min(), name);
143 test_value(-2 * std::numeric_limits<T>::denorm_min(), name);
145 #if defined(TEST_SSE2)
148 static const int primes[] = {
149 11, 13, 17, 19, 23, 29,
150 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
151 73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
152 127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
153 179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
154 233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
155 283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
156 353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
157 419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
160 for(unsigned i = 0; i < sizeof(primes)/sizeof(primes[0]); ++i)
164 for(int j = 0; j < primes[i]; ++j)
166 v1 = boost::math::float_next(v1);
167 v2 = boost::math::float_prior(v2);
169 BOOST_CHECK_EQUAL(boost::math::float_distance(v1, val), -primes[i]);
170 BOOST_CHECK_EQUAL(boost::math::float_distance(v2, val), primes[i]);
171 BOOST_CHECK_EQUAL(boost::math::float_advance(val, primes[i]), v1);
172 BOOST_CHECK_EQUAL(boost::math::float_advance(val, -primes[i]), v2);
174 if(std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_infinity))
176 BOOST_CHECK_EQUAL(boost::math::float_prior(std::numeric_limits<T>::infinity()), (std::numeric_limits<T>::max)());
177 BOOST_CHECK_EQUAL(boost::math::float_next(-std::numeric_limits<T>::infinity()), -(std::numeric_limits<T>::max)());
178 BOOST_MATH_CHECK_THROW(boost::math::float_prior(-std::numeric_limits<T>::infinity()), std::domain_error);
179 BOOST_MATH_CHECK_THROW(boost::math::float_next(std::numeric_limits<T>::infinity()), std::domain_error);
180 if(boost::math::policies:: BOOST_MATH_OVERFLOW_ERROR_POLICY == boost::math::policies::throw_on_error)
182 BOOST_MATH_CHECK_THROW(boost::math::float_prior(-(std::numeric_limits<T>::max)()), std::overflow_error);
183 BOOST_MATH_CHECK_THROW(boost::math::float_next((std::numeric_limits<T>::max)()), std::overflow_error);
187 BOOST_CHECK_EQUAL(boost::math::float_prior(-(std::numeric_limits<T>::max)()), -std::numeric_limits<T>::infinity());
188 BOOST_CHECK_EQUAL(boost::math::float_next((std::numeric_limits<T>::max)()), std::numeric_limits<T>::infinity());
192 // We need to test float_distance over mulyiple orders of magnitude,
193 // the only way to get an accurate true result is to count the representations
194 // between the two end points, but we can only really do this for type float:
196 if (std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::digits < 30) && (std::numeric_limits<T>::radix == 2))
198 T left, right, dist, fresult;
199 boost::uintmax_t result;
201 left = static_cast<T>(0.1);
202 right = left * static_cast<T>(4.2);
203 dist = boost::math::float_distance(left, right);
204 // We have to use a wider integer type for the accurate count, since there
205 // aren't enough bits in T to get a true result if the values differ
206 // by more than a factor of 2:
208 for (; left != right; ++result, left = boost::math::float_next(left));
209 fresult = static_cast<T>(result);
210 BOOST_CHECK_EQUAL(fresult, dist);
212 left = static_cast<T>(-0.1);
213 right = left * static_cast<T>(4.2);
214 dist = boost::math::float_distance(right, left);
216 for (; left != right; ++result, left = boost::math::float_prior(left));
217 fresult = static_cast<T>(result);
218 BOOST_CHECK_EQUAL(fresult, dist);
220 left = static_cast<T>(-1.1) * (std::numeric_limits<T>::min)();
221 right = static_cast<T>(-4.1) * left;
222 dist = boost::math::float_distance(left, right);
224 for (; left != right; ++result, left = boost::math::float_next(left));
225 fresult = static_cast<T>(result);
226 BOOST_CHECK_EQUAL(fresult, dist);
230 BOOST_AUTO_TEST_CASE( test_main )
232 test_values(1.0f, "float");
233 test_values(1.0, "double");
234 #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
235 test_values(1.0L, "long double");
236 test_values(boost::math::concepts::real_concept(0), "real_concept");
240 // Test some multiprecision types:
242 test_values(boost::multiprecision::cpp_bin_float_quad(0), "cpp_bin_float_quad");
243 // This is way to slow to test routinely:
244 //test_values(boost::multiprecision::cpp_bin_float_single(0), "cpp_bin_float_single");
245 test_values(boost::multiprecision::cpp_bin_float_50(0), "cpp_bin_float_50");
247 #if defined(TEST_SSE2)
249 int mmx_flags = _mm_getcsr(); // We'll restore these later.
252 // These tests fail pretty badly on Linux x64, especially with Intel-12.1
253 _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
254 std::cout << "Testing again with Flush-To-Zero set" << std::endl;
255 std::cout << "SSE2 control word is: " << std::hex << _mm_getcsr() << std::endl;
256 test_values(1.0f, "float");
257 test_values(1.0, "double");
258 _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_OFF);
260 BOOST_ASSERT((_mm_getcsr() & 0x40) == 0);
261 _mm_setcsr(_mm_getcsr() | 0x40);
262 std::cout << "Testing again with Denormals-Are-Zero set" << std::endl;
263 std::cout << "SSE2 control word is: " << std::hex << _mm_getcsr() << std::endl;
264 test_values(1.0f, "float");
265 test_values(1.0, "double");
267 // Restore the MMX flags:
268 _mm_setcsr(mmx_flags);