]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/math/test/test_next.cpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / libs / math / test / test_next.cpp
CommitLineData
7c673cae
FG
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
6#include <pch.hpp>
7
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/floating_point_comparison.hpp>
13#include <boost/math/special_functions/next.hpp>
14#include <boost/math/special_functions/ulp.hpp>
b32b8144 15#include <boost/multiprecision/cpp_bin_float.hpp>
7c673cae
FG
16#include <iostream>
17#include <iomanip>
18
19#ifdef BOOST_MSVC
20#pragma warning(disable:4127)
21#endif
22
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)
25#include <float.h>
26#include "xmmintrin.h"
27#define TEST_SSE2
28#endif
29#endif
30
31
32template <class T>
33void test_value(const T& val, const char* name)
34{
35 using namespace boost::math;
36 T upper = tools::max_value<T>();
37 T lower = -upper;
38
39 std::cout << "Testing type " << name << " with initial value " << val << std::endl;
40
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);
56
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))
60 {
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);
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
96template <class T>
97void test_values(const T& val, const char* name)
98{
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;
104
105 std::cout << "Testing type " << name << std::endl;
106
107 T den = (std::numeric_limits<T>::min)() / 4;
108 if(den != 0)
109 {
110 std::cout << "Denormals are active\n";
111 }
112 else
113 {
114 std::cout << "Denormals are flushed to zero.\n";
115 }
116
117 test_value(a, name);
118 test_value(-a, name);
119 test_value(b, 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))
126 {
127 test_value(z, name);
128 test_value(-z, name);
129 }
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)
136 {
137#endif
138 if(std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_denorm == std::denorm_present) && ((std::numeric_limits<T>::min)() / 2 != 0))
139 {
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);
144 }
145#if defined(TEST_SSE2)
146 }
147#endif
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,
158 };
159
160 for(unsigned i = 0; i < sizeof(primes)/sizeof(primes[0]); ++i)
161 {
162 T v1 = val;
163 T v2 = val;
164 for(int j = 0; j < primes[i]; ++j)
165 {
166 v1 = boost::math::float_next(v1);
167 v2 = boost::math::float_prior(v2);
168 }
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);
173 }
174 if(std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_infinity))
175 {
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)
181 {
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);
184 }
185 else
186 {
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());
189 }
190 }
b32b8144
FG
191 //
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:
195 //
196 if (std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::digits < 30) && (std::numeric_limits<T>::radix == 2))
197 {
198 T left, right, dist, fresult;
199 boost::uintmax_t result;
200
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:
207 result = 0;
208 for (; left != right; ++result, left = boost::math::float_next(left));
209 fresult = static_cast<T>(result);
210 BOOST_CHECK_EQUAL(fresult, dist);
211
212 left = static_cast<T>(-0.1);
213 right = left * static_cast<T>(4.2);
214 dist = boost::math::float_distance(right, left);
215 result = 0;
216 for (; left != right; ++result, left = boost::math::float_prior(left));
217 fresult = static_cast<T>(result);
218 BOOST_CHECK_EQUAL(fresult, dist);
219
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);
223 result = 0;
224 for (; left != right; ++result, left = boost::math::float_next(left));
225 fresult = static_cast<T>(result);
226 BOOST_CHECK_EQUAL(fresult, dist);
227 }
7c673cae
FG
228}
229
230BOOST_AUTO_TEST_CASE( test_main )
231{
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");
237#endif
b32b8144
FG
238
239 //
240 // Test some multiprecision types:
241 //
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");
246
7c673cae
FG
247#if defined(TEST_SSE2)
248
249#ifdef _MSC_VER
250# pragma message("Compiling SSE2 test code")
251#endif
252#ifdef __GNUC__
253# pragma message "Compiling SSE2 test code"
254#endif
255
256 int mmx_flags = _mm_getcsr(); // We'll restore these later.
257
258#ifdef _WIN32
259 // These tests fail pretty badly on Linux x64, especially with Intel-12.1
260 _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
261 std::cout << "Testing again with Flush-To-Zero set" << std::endl;
262 std::cout << "SSE2 control word is: " << std::hex << _mm_getcsr() << std::endl;
263 test_values(1.0f, "float");
264 test_values(1.0, "double");
265 _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_OFF);
266#endif
267 BOOST_ASSERT((_mm_getcsr() & 0x40) == 0);
268 _mm_setcsr(_mm_getcsr() | 0x40);
269 std::cout << "Testing again with Denormals-Are-Zero set" << std::endl;
270 std::cout << "SSE2 control word is: " << std::hex << _mm_getcsr() << std::endl;
271 test_values(1.0f, "float");
272 test_values(1.0, "double");
273
274 // Restore the MMX flags:
275 _mm_setcsr(mmx_flags);
276#endif
277
278}
279
280