]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // (C) Copyright John Maddock 2007. |
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 | #define BOOST_TEST_MAIN | |
10 | #include <boost/test/unit_test.hpp> | |
11 | #include <boost/math/tools/test.hpp> | |
92f5a8d4 | 12 | #include <boost/test/tools/floating_point_comparison.hpp> |
7c673cae FG |
13 | #include <boost/math/special_functions/round.hpp> |
14 | #include <boost/math/special_functions/next.hpp> | |
15 | #include <boost/math/special_functions/trunc.hpp> | |
16 | #include <boost/math/special_functions/modf.hpp> | |
17 | #include <boost/math/special_functions/sign.hpp> | |
18 | #include <boost/random/mersenne_twister.hpp> | |
19 | #include <iostream> | |
20 | #include <iomanip> | |
21 | ||
22 | boost::mt19937 rng; | |
23 | ||
24 | template <class T> | |
25 | T get_random() | |
26 | { | |
27 | // | |
28 | // Fill all the bits in T with random values, | |
29 | // likewise set the exponent to a random value | |
30 | // that will still fit inside a T, and always | |
31 | // have a remainder as well as an integer part. | |
32 | // | |
33 | int bits = boost::math::tools::digits<T>(); | |
34 | int shift = 0; | |
35 | int exponent = rng() % (bits - 4); | |
36 | T result = 0; | |
37 | while(bits > 0) | |
38 | { | |
39 | result += ldexp(static_cast<T>(rng()), shift); | |
40 | shift += std::numeric_limits<int>::digits; | |
41 | bits -= std::numeric_limits<int>::digits; | |
42 | } | |
43 | return rng() & 1u ? -ldexp(frexp(result, &bits), exponent) : ldexp(frexp(result, &bits), exponent); | |
44 | } | |
45 | ||
46 | template <class T, class U> | |
47 | void check_within_half(T a, U u) | |
48 | { | |
49 | BOOST_MATH_STD_USING | |
50 | if(fabs(a-u) > 0.5f) | |
51 | { | |
52 | BOOST_ERROR("Rounded result differed by more than 0.5 from the original"); | |
53 | std::cerr << "Values were: " << std::setprecision(35) << std::setw(40) | |
54 | << std::left << a << u << std::endl; | |
55 | } | |
56 | if((fabs(a - u) == 0.5f) && (fabs(static_cast<T>(u)) < fabs(a))) | |
57 | { | |
58 | BOOST_ERROR("Rounded result was towards zero with boost::round"); | |
59 | std::cerr << "Values were: " << std::setprecision(35) << std::setw(40) | |
60 | << std::left << a << u << std::endl; | |
61 | } | |
62 | } | |
63 | ||
64 | // | |
65 | // We may not have an abs overload for long long so provide a fall back: | |
66 | // | |
67 | template <class T> | |
68 | inline T safe_abs(T const& v ...) | |
69 | { | |
70 | return v < 0 ? -v : v; | |
71 | } | |
72 | ||
73 | template <class T, class U> | |
74 | void check_trunc_result(T a, U u) | |
75 | { | |
76 | BOOST_MATH_STD_USING | |
77 | if(fabs(a-u) >= 1) | |
78 | { | |
79 | BOOST_ERROR("Rounded result differed by more than 1 from the original"); | |
80 | std::cerr << "Values were: " << std::setprecision(35) << std::setw(40) | |
81 | << std::left << a << u << std::endl; | |
82 | } | |
83 | if(abs(a) < safe_abs(u)) | |
84 | { | |
85 | BOOST_ERROR("Truncated result had larger absolute value than the original"); | |
86 | std::cerr << "Values were: " << std::setprecision(35) << std::setw(40) | |
87 | << std::left << a << u << std::endl; | |
88 | } | |
89 | if(fabs(static_cast<T>(u)) > fabs(a)) | |
90 | { | |
91 | BOOST_ERROR("Rounded result was away from zero with boost::trunc"); | |
92 | std::cerr << "Values were: " << std::setprecision(35) << std::setw(40) | |
93 | << std::left << a << u << std::endl; | |
94 | } | |
95 | } | |
96 | ||
97 | template <class T, class U> | |
98 | void check_modf_result(T a, T fract, U ipart) | |
99 | { | |
100 | BOOST_MATH_STD_USING | |
101 | if(fract + ipart != a) | |
102 | { | |
103 | BOOST_ERROR("Fractional and integer results do not add up to the original value"); | |
104 | std::cerr << "Values were: " << std::setprecision(35) << " " | |
105 | << std::left << a << ipart << " " << fract << std::endl; | |
106 | } | |
107 | if((boost::math::sign(a) != boost::math::sign(fract)) && boost::math::sign(fract)) | |
108 | { | |
109 | BOOST_ERROR("Original and fractional parts have differing signs"); | |
110 | std::cerr << "Values were: " << std::setprecision(35) << " " | |
111 | << std::left << a << ipart << " " << fract << std::endl; | |
112 | } | |
113 | if((boost::math::sign(a) != boost::math::sign(ipart)) && boost::math::sign(ipart)) | |
114 | { | |
115 | BOOST_ERROR("Original and integer parts have differing signs"); | |
116 | std::cerr << "Values were: " << std::setprecision(35) << " " | |
117 | << std::left << a << ipart << " " << ipart << std::endl; | |
118 | } | |
119 | if(fabs(a-ipart) >= 1) | |
120 | { | |
121 | BOOST_ERROR("Rounded result differed by more than 1 from the original"); | |
122 | std::cerr << "Values were: " << std::setprecision(35) << std::setw(40) | |
123 | << std::left << a << ipart << std::endl; | |
124 | } | |
125 | } | |
126 | ||
127 | template <class T> | |
128 | void test_round_number(T arg) | |
129 | { | |
130 | BOOST_MATH_STD_USING | |
131 | #ifdef BOOST_HAS_LONG_LONG | |
132 | using boost::math::llround; using boost::math::lltrunc; | |
133 | #endif | |
134 | ||
135 | T r = round(arg); | |
136 | check_within_half(arg, r); | |
137 | r = trunc(arg); | |
138 | check_trunc_result(arg, r); | |
139 | T frac = boost::math::modf(arg, &r); | |
140 | check_modf_result(arg, frac, r); | |
141 | ||
142 | if(abs(r) < (std::numeric_limits<int>::max)()) | |
143 | { | |
144 | int i = iround(arg); | |
145 | check_within_half(arg, i); | |
146 | i = itrunc(arg); | |
92f5a8d4 | 147 | check_trunc_result(arg, T(i)); |
7c673cae FG |
148 | r = boost::math::modf(arg, &i); |
149 | check_modf_result(arg, r, i); | |
150 | } | |
151 | if(std::numeric_limits<T>::digits >= std::numeric_limits<int>::digits) | |
152 | { | |
153 | int si = iround(static_cast<T>((std::numeric_limits<int>::max)())); | |
154 | check_within_half(static_cast<T>((std::numeric_limits<int>::max)()), si); | |
155 | si = iround(static_cast<T>((std::numeric_limits<int>::min)())); | |
156 | check_within_half(static_cast<T>((std::numeric_limits<int>::min)()), si); | |
157 | si = itrunc(static_cast<T>((std::numeric_limits<int>::max)())); | |
92f5a8d4 | 158 | check_trunc_result(static_cast<T>((std::numeric_limits<int>::max)()), T(si)); |
7c673cae | 159 | si = itrunc(static_cast<T>((std::numeric_limits<int>::min)())); |
92f5a8d4 | 160 | check_trunc_result(static_cast<T>((std::numeric_limits<int>::min)()), T(si)); |
7c673cae FG |
161 | } |
162 | if(abs(r) < (std::numeric_limits<long>::max)()) | |
163 | { | |
164 | long l = lround(arg); | |
165 | check_within_half(arg, l); | |
166 | l = ltrunc(arg); | |
92f5a8d4 | 167 | check_trunc_result(arg, T(l)); |
7c673cae FG |
168 | r = boost::math::modf(arg, &l); |
169 | check_modf_result(arg, r, l); | |
170 | } | |
171 | if(std::numeric_limits<T>::digits >= std::numeric_limits<long>::digits) | |
172 | { | |
173 | long k = lround(static_cast<T>((std::numeric_limits<long>::max)())); | |
174 | check_within_half(static_cast<T>((std::numeric_limits<long>::max)()), k); | |
175 | k = lround(static_cast<T>((std::numeric_limits<long>::min)())); | |
176 | check_within_half(static_cast<T>((std::numeric_limits<long>::min)()), k); | |
177 | k = ltrunc(static_cast<T>((std::numeric_limits<long>::max)())); | |
92f5a8d4 | 178 | check_trunc_result(static_cast<T>((std::numeric_limits<long>::max)()), T(k)); |
7c673cae | 179 | k = ltrunc(static_cast<T>((std::numeric_limits<long>::min)())); |
92f5a8d4 | 180 | check_trunc_result(static_cast<T>((std::numeric_limits<long>::min)()), T(k)); |
7c673cae FG |
181 | } |
182 | ||
183 | #ifdef BOOST_HAS_LONG_LONG | |
184 | if(abs(r) < (std::numeric_limits<boost::long_long_type>::max)()) | |
185 | { | |
186 | boost::long_long_type ll = llround(arg); | |
187 | check_within_half(arg, ll); | |
188 | ll = lltrunc(arg); | |
92f5a8d4 | 189 | check_trunc_result(arg, T(ll)); |
7c673cae FG |
190 | r = boost::math::modf(arg, &ll); |
191 | check_modf_result(arg, r, ll); | |
192 | } | |
193 | if(std::numeric_limits<T>::digits >= std::numeric_limits<boost::long_long_type>::digits) | |
194 | { | |
195 | boost::long_long_type j = llround(static_cast<T>((std::numeric_limits<boost::long_long_type>::max)())); | |
196 | check_within_half(static_cast<T>((std::numeric_limits<boost::long_long_type>::max)()), j); | |
197 | j = llround(static_cast<T>((std::numeric_limits<boost::long_long_type>::min)())); | |
198 | check_within_half(static_cast<T>((std::numeric_limits<boost::long_long_type>::min)()), j); | |
199 | j = lltrunc(static_cast<T>((std::numeric_limits<boost::long_long_type>::max)())); | |
92f5a8d4 | 200 | check_trunc_result(static_cast<T>((std::numeric_limits<boost::long_long_type>::max)()), T(j)); |
7c673cae | 201 | j = lltrunc(static_cast<T>((std::numeric_limits<boost::long_long_type>::min)())); |
92f5a8d4 | 202 | check_trunc_result(static_cast<T>((std::numeric_limits<boost::long_long_type>::min)()), T(j)); |
7c673cae FG |
203 | } |
204 | #endif | |
205 | } | |
206 | ||
207 | template <class T> | |
208 | void test_round(T, const char* name ) | |
209 | { | |
210 | BOOST_MATH_STD_USING | |
211 | #ifdef BOOST_HAS_LONG_LONG | |
212 | using boost::math::llround; using boost::math::lltrunc; | |
213 | #endif | |
214 | ||
215 | std::cout << "Testing rounding with type " << name << std::endl; | |
216 | ||
217 | for(int i = 0; i < 1000; ++i) | |
218 | { | |
219 | T arg = get_random<T>(); | |
220 | test_round_number<T>(arg); | |
221 | } | |
222 | // | |
223 | // Finish off by testing the error handlers: | |
224 | // | |
225 | BOOST_MATH_CHECK_THROW(iround(static_cast<T>(1e20)), boost::math::rounding_error); | |
226 | BOOST_MATH_CHECK_THROW(iround(static_cast<T>(-1e20)), boost::math::rounding_error); | |
227 | BOOST_MATH_CHECK_THROW(lround(static_cast<T>(1e20)), boost::math::rounding_error); | |
228 | BOOST_MATH_CHECK_THROW(lround(static_cast<T>(-1e20)), boost::math::rounding_error); | |
229 | #ifdef BOOST_HAS_LONG_LONG | |
230 | BOOST_MATH_CHECK_THROW(llround(static_cast<T>(1e20)), boost::math::rounding_error); | |
231 | BOOST_MATH_CHECK_THROW(llround(static_cast<T>(-1e20)), boost::math::rounding_error); | |
232 | #endif | |
233 | if(std::numeric_limits<T>::has_infinity) | |
234 | { | |
235 | BOOST_MATH_CHECK_THROW(round(std::numeric_limits<T>::infinity()), boost::math::rounding_error); | |
236 | BOOST_MATH_CHECK_THROW(iround(std::numeric_limits<T>::infinity()), boost::math::rounding_error); | |
237 | BOOST_MATH_CHECK_THROW(iround(-std::numeric_limits<T>::infinity()), boost::math::rounding_error); | |
238 | BOOST_MATH_CHECK_THROW(lround(std::numeric_limits<T>::infinity()), boost::math::rounding_error); | |
239 | BOOST_MATH_CHECK_THROW(lround(-std::numeric_limits<T>::infinity()), boost::math::rounding_error); | |
240 | #ifdef BOOST_HAS_LONG_LONG | |
241 | BOOST_MATH_CHECK_THROW(llround(std::numeric_limits<T>::infinity()), boost::math::rounding_error); | |
242 | BOOST_MATH_CHECK_THROW(llround(-std::numeric_limits<T>::infinity()), boost::math::rounding_error); | |
243 | #endif | |
244 | } | |
245 | if(std::numeric_limits<T>::has_quiet_NaN) | |
246 | { | |
247 | BOOST_MATH_CHECK_THROW(round(std::numeric_limits<T>::quiet_NaN()), boost::math::rounding_error); | |
248 | BOOST_MATH_CHECK_THROW(iround(std::numeric_limits<T>::quiet_NaN()), boost::math::rounding_error); | |
249 | BOOST_MATH_CHECK_THROW(lround(std::numeric_limits<T>::quiet_NaN()), boost::math::rounding_error); | |
250 | #ifdef BOOST_HAS_LONG_LONG | |
251 | BOOST_MATH_CHECK_THROW(llround(std::numeric_limits<T>::quiet_NaN()), boost::math::rounding_error); | |
252 | #endif | |
253 | } | |
254 | BOOST_MATH_CHECK_THROW(itrunc(static_cast<T>(1e20)), boost::math::rounding_error); | |
255 | BOOST_MATH_CHECK_THROW(itrunc(static_cast<T>(-1e20)), boost::math::rounding_error); | |
256 | BOOST_MATH_CHECK_THROW(ltrunc(static_cast<T>(1e20)), boost::math::rounding_error); | |
257 | BOOST_MATH_CHECK_THROW(ltrunc(static_cast<T>(-1e20)), boost::math::rounding_error); | |
258 | #ifdef BOOST_HAS_LONG_LONG | |
259 | BOOST_MATH_CHECK_THROW(lltrunc(static_cast<T>(1e20)), boost::math::rounding_error); | |
260 | BOOST_MATH_CHECK_THROW(lltrunc(static_cast<T>(-1e20)), boost::math::rounding_error); | |
261 | #endif | |
262 | if(std::numeric_limits<T>::has_infinity) | |
263 | { | |
264 | BOOST_MATH_CHECK_THROW(trunc(std::numeric_limits<T>::infinity()), boost::math::rounding_error); | |
265 | BOOST_MATH_CHECK_THROW(itrunc(std::numeric_limits<T>::infinity()), boost::math::rounding_error); | |
266 | BOOST_MATH_CHECK_THROW(itrunc(-std::numeric_limits<T>::infinity()), boost::math::rounding_error); | |
267 | BOOST_MATH_CHECK_THROW(ltrunc(std::numeric_limits<T>::infinity()), boost::math::rounding_error); | |
268 | BOOST_MATH_CHECK_THROW(ltrunc(-std::numeric_limits<T>::infinity()), boost::math::rounding_error); | |
269 | #ifdef BOOST_HAS_LONG_LONG | |
270 | BOOST_MATH_CHECK_THROW(lltrunc(std::numeric_limits<T>::infinity()), boost::math::rounding_error); | |
271 | BOOST_MATH_CHECK_THROW(lltrunc(-std::numeric_limits<T>::infinity()), boost::math::rounding_error); | |
272 | #endif | |
273 | } | |
274 | if(std::numeric_limits<T>::has_quiet_NaN) | |
275 | { | |
276 | BOOST_MATH_CHECK_THROW(trunc(std::numeric_limits<T>::quiet_NaN()), boost::math::rounding_error); | |
277 | BOOST_MATH_CHECK_THROW(itrunc(std::numeric_limits<T>::quiet_NaN()), boost::math::rounding_error); | |
278 | BOOST_MATH_CHECK_THROW(ltrunc(std::numeric_limits<T>::quiet_NaN()), boost::math::rounding_error); | |
279 | #ifdef BOOST_HAS_LONG_LONG | |
280 | BOOST_MATH_CHECK_THROW(lltrunc(std::numeric_limits<T>::quiet_NaN()), boost::math::rounding_error); | |
281 | #endif | |
282 | } | |
283 | if(std::numeric_limits<T>::digits >= std::numeric_limits<int>::digits) | |
284 | { | |
285 | BOOST_MATH_CHECK_THROW(itrunc(static_cast<T>((std::numeric_limits<int>::max)()) + 1), boost::math::rounding_error); | |
286 | BOOST_MATH_CHECK_THROW(itrunc(static_cast<T>((std::numeric_limits<int>::min)()) - 1), boost::math::rounding_error); | |
287 | } | |
288 | if(std::numeric_limits<T>::digits >= std::numeric_limits<long>::digits) | |
289 | { | |
290 | BOOST_MATH_CHECK_THROW(ltrunc(static_cast<T>((std::numeric_limits<long>::max)()) + 1), boost::math::rounding_error); | |
291 | BOOST_MATH_CHECK_THROW(ltrunc(static_cast<T>((std::numeric_limits<long>::min)()) - 1), boost::math::rounding_error); | |
292 | } | |
293 | #ifndef BOOST_NO_LONG_LONG | |
294 | if(std::numeric_limits<T>::digits >= std::numeric_limits<boost::long_long_type>::digits) | |
295 | { | |
296 | BOOST_MATH_CHECK_THROW(lltrunc(static_cast<T>((std::numeric_limits<boost::long_long_type>::max)()) + 1), boost::math::rounding_error); | |
297 | BOOST_MATH_CHECK_THROW(lltrunc(static_cast<T>((std::numeric_limits<boost::long_long_type>::min)()) - 1), boost::math::rounding_error); | |
298 | } | |
299 | #endif | |
300 | if(std::numeric_limits<T>::digits >= std::numeric_limits<int>::digits) | |
301 | { | |
302 | BOOST_MATH_CHECK_THROW(iround(static_cast<T>((std::numeric_limits<int>::max)()) + 1), boost::math::rounding_error); | |
303 | BOOST_MATH_CHECK_THROW(iround(static_cast<T>((std::numeric_limits<int>::min)()) - 1), boost::math::rounding_error); | |
304 | } | |
305 | if(std::numeric_limits<T>::digits >= std::numeric_limits<long>::digits) | |
306 | { | |
307 | BOOST_MATH_CHECK_THROW(lround(static_cast<T>((std::numeric_limits<long>::max)()) + 1), boost::math::rounding_error); | |
308 | BOOST_MATH_CHECK_THROW(lround(static_cast<T>((std::numeric_limits<long>::min)()) - 1), boost::math::rounding_error); | |
309 | } | |
310 | #ifndef BOOST_NO_LONG_LONG | |
311 | if(std::numeric_limits<T>::digits >= std::numeric_limits<boost::long_long_type>::digits) | |
312 | { | |
313 | BOOST_MATH_CHECK_THROW(llround(static_cast<T>((std::numeric_limits<boost::long_long_type>::max)()) + 1), boost::math::rounding_error); | |
314 | BOOST_MATH_CHECK_THROW(llround(static_cast<T>((std::numeric_limits<boost::long_long_type>::min)()) - 1), boost::math::rounding_error); | |
315 | } | |
316 | #endif | |
317 | // | |
318 | // try non-throwing error handlers: | |
319 | // | |
320 | boost::math::policies::policy<boost::math::policies::rounding_error<boost::math::policies::ignore_error> > pol; | |
321 | ||
322 | if(std::numeric_limits<T>::digits >= std::numeric_limits<int>::digits) | |
323 | { | |
324 | BOOST_CHECK_EQUAL(iround((std::numeric_limits<int>::max)() + T(1.0), pol), (std::numeric_limits<int>::max)()); | |
325 | BOOST_CHECK_EQUAL(iround((std::numeric_limits<int>::min)() - T(1.0), pol), (std::numeric_limits<int>::min)()); | |
326 | BOOST_CHECK_EQUAL(itrunc((std::numeric_limits<int>::max)() + T(1.0), pol), (std::numeric_limits<int>::max)()); | |
327 | BOOST_CHECK_EQUAL(itrunc((std::numeric_limits<int>::min)() - T(1.0), pol), (std::numeric_limits<int>::min)()); | |
328 | } | |
329 | if(std::numeric_limits<T>::digits >= std::numeric_limits<long>::digits) | |
330 | { | |
331 | BOOST_CHECK_EQUAL(lround((std::numeric_limits<long>::max)() + T(1.0), pol), (std::numeric_limits<long>::max)()); | |
332 | BOOST_CHECK_EQUAL(lround((std::numeric_limits<long>::min)() - T(1.0), pol), (std::numeric_limits<long>::min)()); | |
333 | BOOST_CHECK_EQUAL(ltrunc((std::numeric_limits<long>::max)() + T(1.0), pol), (std::numeric_limits<long>::max)()); | |
334 | BOOST_CHECK_EQUAL(ltrunc((std::numeric_limits<long>::min)() - T(1.0), pol), (std::numeric_limits<long>::min)()); | |
335 | } | |
336 | #ifndef BOOST_NO_LONG_LONG | |
337 | if(std::numeric_limits<T>::digits >= std::numeric_limits<long long>::digits) | |
338 | { | |
339 | BOOST_CHECK_EQUAL(llround((std::numeric_limits<long long>::max)() + T(1.0), pol), (std::numeric_limits<long long>::max)()); | |
340 | BOOST_CHECK_EQUAL(llround((std::numeric_limits<long long>::min)() - T(1.0), pol), (std::numeric_limits<long long>::min)()); | |
341 | BOOST_CHECK_EQUAL(lltrunc((std::numeric_limits<long long>::max)() + T(1.0), pol), (std::numeric_limits<long long>::max)()); | |
342 | BOOST_CHECK_EQUAL(lltrunc((std::numeric_limits<long long>::min)() - T(1.0), pol), (std::numeric_limits<long long>::min)()); | |
343 | } | |
344 | #endif | |
345 | // Again with bigger value: | |
346 | T big = 1e20f; | |
347 | BOOST_CHECK_EQUAL(iround(big, pol), (std::numeric_limits<int>::max)()); | |
348 | BOOST_CHECK_EQUAL(lround(big, pol), (std::numeric_limits<long>::max)()); | |
349 | BOOST_CHECK_EQUAL(iround(-big, pol), (std::numeric_limits<int>::min)()); | |
350 | BOOST_CHECK_EQUAL(lround(-big, pol), (std::numeric_limits<long>::min)()); | |
351 | BOOST_CHECK_EQUAL(itrunc(big, pol), (std::numeric_limits<int>::max)()); | |
352 | BOOST_CHECK_EQUAL(ltrunc(big, pol), (std::numeric_limits<long>::max)()); | |
353 | BOOST_CHECK_EQUAL(itrunc(-big, pol), (std::numeric_limits<int>::min)()); | |
354 | BOOST_CHECK_EQUAL(ltrunc(-big, pol), (std::numeric_limits<long>::min)()); | |
355 | #ifndef BOOST_NO_LONG_LONG | |
356 | BOOST_CHECK_EQUAL(llround(big, pol), (std::numeric_limits<long long>::max)()); | |
357 | BOOST_CHECK_EQUAL(llround(-big, pol), (std::numeric_limits<long long>::min)()); | |
358 | BOOST_CHECK_EQUAL(lltrunc(big, pol), (std::numeric_limits<long long>::max)()); | |
359 | BOOST_CHECK_EQUAL(lltrunc(-big, pol), (std::numeric_limits<long long>::min)()); | |
360 | #endif | |
361 | ||
362 | // | |
363 | // Special cases that we know can go bad: | |
364 | // | |
365 | T half = 0.5f; | |
366 | half = boost::math::float_prior(half); | |
367 | test_round_number(half); | |
368 | half = -0.5f; | |
369 | half = boost::math::float_next(half); | |
370 | test_round_number(half); | |
371 | ||
372 | if(std::numeric_limits<T>::is_specialized) | |
373 | { | |
374 | // | |
375 | // Odd and even integer values: | |
376 | // | |
377 | T val; | |
378 | for(int i = 2; i < std::numeric_limits<T>::max_exponent; ++i) | |
379 | { | |
380 | val = ldexp(T(1), i); | |
381 | test_round_number(val); | |
382 | ++val; | |
383 | test_round_number(val); | |
384 | val = -val; | |
385 | test_round_number(val); | |
386 | ++val; | |
387 | test_round_number(val); | |
388 | } | |
389 | } | |
390 | } | |
391 | ||
392 | BOOST_AUTO_TEST_CASE( test_main ) | |
393 | { | |
394 | test_round(0.1F, "float"); | |
395 | test_round(0.1, "double"); | |
396 | #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS | |
397 | test_round(0.1L, "long double"); | |
398 | test_round(boost::math::concepts::real_concept(0.1), "real_concept"); | |
399 | #else | |
400 | std::cout << "<note>The long double tests have been disabled on this platform " | |
401 | "either because the long double overloads of the usual math functions are " | |
402 | "not available at all, or because they are too inaccurate for these tests " | |
403 | "to pass.</note>" << std::endl; | |
404 | #endif | |
405 | ||
406 | // test rounding of direct predecessor/successor of 0.5/-0.5 for float and double | |
407 | test_round_number(-0.4999999701976776123046875f); | |
408 | BOOST_CHECK_EQUAL(boost::math::round(-0.4999999701976776123046875f), 0.0f); | |
409 | ||
410 | test_round_number(0.4999999701976776123046875f); | |
411 | BOOST_CHECK_EQUAL(boost::math::round(0.4999999701976776123046875f), 0.0f); | |
412 | ||
413 | BOOST_CHECK_EQUAL(boost::math::round(-0.499999999999999944488848768742172978818416595458984375), 0.0); | |
414 | test_round_number(-0.499999999999999944488848768742172978818416595458984375); | |
415 | ||
416 | BOOST_CHECK_EQUAL(boost::math::round(0.499999999999999944488848768742172978818416595458984375), 0.0); | |
417 | test_round_number(0.499999999999999944488848768742172978818416595458984375); | |
418 | ||
419 | // test rounding of integer numbers on the edge of the float/double mantissa width | |
420 | BOOST_CHECK_EQUAL(boost::math::round(-16777215.0f), -16777215.0f); | |
421 | test_round_number(-16777215.0f); | |
422 | ||
423 | BOOST_CHECK_EQUAL(boost::math::round(-16777213.0f), -16777213.0f); | |
424 | test_round_number(-16777213.0f); | |
425 | ||
426 | BOOST_CHECK_EQUAL(boost::math::round(-8388611.0f), -8388611.0f); | |
427 | test_round_number(-8388611.0f); | |
428 | ||
429 | BOOST_CHECK_EQUAL(boost::math::round(-8388609.0f), -8388609.0f); | |
430 | test_round_number(-8388609.0f); | |
431 | ||
432 | BOOST_CHECK_EQUAL(boost::math::round(8388609.0f), 8388609.0f); | |
433 | test_round_number(8388609.0f); | |
434 | ||
435 | BOOST_CHECK_EQUAL(boost::math::round(8388611.0f), 8388611.0f); | |
436 | test_round_number(8388611.0f); | |
437 | ||
438 | BOOST_CHECK_EQUAL(boost::math::round(16777213.0f), 16777213.0f); | |
439 | test_round_number(16777213.0f); | |
440 | ||
441 | BOOST_CHECK_EQUAL(boost::math::round(16777215.0f), 16777215.0f); | |
442 | test_round_number(16777215.0f); | |
443 | ||
444 | BOOST_CHECK_EQUAL(boost::math::round(-9007199254740993.0), -9007199254740993.0); | |
445 | test_round_number(-9007199254740993.0); | |
446 | ||
447 | BOOST_CHECK_EQUAL(boost::math::round(-9007199254740991.0), -9007199254740991.0); | |
448 | test_round_number(-9007199254740991.0); | |
449 | ||
450 | BOOST_CHECK_EQUAL(boost::math::round(-4503599627370499.0), -4503599627370499.0); | |
451 | test_round_number(-4503599627370499.0); | |
452 | ||
453 | BOOST_CHECK_EQUAL(boost::math::round(-4503599627370497.0), -4503599627370497.0); | |
454 | test_round_number(-4503599627370497.0); | |
455 | ||
456 | BOOST_CHECK_EQUAL(boost::math::round(4503599627370497.0), 4503599627370497.0); | |
457 | test_round_number(4503599627370497.0); | |
458 | ||
459 | BOOST_CHECK_EQUAL(boost::math::round(4503599627370499.0), 4503599627370499.0); | |
460 | test_round_number(4503599627370499.0); | |
461 | ||
462 | BOOST_CHECK_EQUAL(boost::math::round(9007199254740991.0), 9007199254740991.0); | |
463 | test_round_number(9007199254740991.0); | |
464 | ||
465 | BOOST_CHECK_EQUAL(boost::math::round(9007199254740993.0), 9007199254740993.0); | |
466 | test_round_number(9007199254740993.0); | |
467 | } |