]>
Commit | Line | Data |
---|---|---|
b32b8144 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> | |
92f5a8d4 | 12 | #include <boost/test/tools/floating_point_comparison.hpp> |
b32b8144 FG |
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> | |
17 | #include <iostream> | |
18 | #include <iomanip> | |
19 | ||
1e59de90 | 20 | #ifdef _MSC_VER |
b32b8144 FG |
21 | #pragma warning(disable:4127) |
22 | #endif | |
23 | ||
24 | template <class T> | |
25 | bool is_normalized_value(const T& val) | |
26 | { | |
27 | // | |
28 | // Returns false if value has guard digits that are non-zero | |
29 | // | |
1e59de90 | 30 | std::intmax_t shift = std::numeric_limits<T>::digits - ilogb(val) - 1; |
b32b8144 FG |
31 | T shifted = scalbn(val, shift); |
32 | return floor(shifted) == shifted; | |
33 | } | |
34 | ||
35 | template <class T> | |
36 | void test_value(const T& val, const char* name) | |
37 | { | |
38 | using namespace boost::math; | |
39 | T upper = tools::max_value<T>(); | |
40 | T lower = -upper; | |
41 | ||
42 | std::cout << "Testing type " << name << " with initial value " << val << std::endl; | |
43 | ||
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)) | |
58 | { | |
59 | BOOST_CHECK_EQUAL(float_prior(float_next(val)), val); | |
60 | BOOST_CHECK_EQUAL(float_next(float_prior(val)), val); | |
61 | } | |
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)) | |
65 | { | |
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); | |
68 | } | |
69 | if (is_normalized_value(val)) | |
70 | { | |
71 | if (val > 0) | |
72 | { | |
73 | T n = val + ulp(val); | |
74 | T fn = float_next(val); | |
75 | if (n > fn) | |
76 | { | |
77 | BOOST_CHECK_LE(ulp(val), boost::math::tools::min_value<T>()); | |
78 | } | |
79 | else | |
80 | { | |
81 | BOOST_CHECK_EQUAL(fn, n); | |
82 | } | |
83 | } | |
84 | else if (val == 0) | |
85 | { | |
86 | BOOST_CHECK_GE(boost::math::tools::min_value<T>(), ulp(val)); | |
87 | } | |
88 | else | |
89 | { | |
90 | T n = val - ulp(val); | |
91 | T fp = float_prior(val); | |
92 | if (n < fp) | |
93 | { | |
94 | BOOST_CHECK_LE(ulp(val), boost::math::tools::min_value<T>()); | |
95 | } | |
96 | else | |
97 | { | |
98 | BOOST_CHECK_EQUAL(fp, n); | |
99 | } | |
100 | } | |
101 | } | |
102 | } | |
103 | ||
104 | template <class T> | |
105 | void test_values(const T& val, const char* name) | |
106 | { | |
1e59de90 TL |
107 | static const T a = T("1.3456724e22"); |
108 | static const T b = T("1.3456724e-22"); | |
b32b8144 FG |
109 | static const T z = 0; |
110 | static const T one = 1; | |
111 | static const T radix = std::numeric_limits<T>::radix; | |
112 | ||
113 | std::cout << "Testing type " << name << std::endl; | |
114 | ||
115 | T den = (std::numeric_limits<T>::min)() / 4; | |
116 | if(den != 0) | |
117 | { | |
118 | std::cout << "Denormals are active\n"; | |
119 | } | |
120 | else | |
121 | { | |
122 | std::cout << "Denormals are flushed to zero.\n"; | |
123 | } | |
124 | ||
125 | test_value(a, name); | |
126 | test_value(T(-a), name); | |
127 | test_value(b, 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)) | |
136 | { | |
137 | test_value(z, name); | |
138 | test_value(T(-z), name); | |
139 | } | |
140 | test_value(one, name); | |
141 | test_value(T(-one), name); | |
142 | test_value(radix, name); | |
143 | test_value(T(-radix), name); | |
144 | ||
145 | if(std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_denorm == std::denorm_present) && ((std::numeric_limits<T>::min)() / 2 != 0)) | |
146 | { | |
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); | |
151 | } | |
152 | ||
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, | |
163 | }; | |
164 | ||
165 | for(unsigned i = 0; i < sizeof(primes)/sizeof(primes[0]); ++i) | |
166 | { | |
167 | T v1 = val; | |
168 | T v2 = val; | |
169 | for(int j = 0; j < primes[i]; ++j) | |
170 | { | |
171 | v1 = boost::math::float_next(v1); | |
172 | v2 = boost::math::float_prior(v2); | |
173 | } | |
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); | |
178 | } | |
179 | if(std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_infinity)) | |
180 | { | |
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) | |
186 | { | |
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); | |
189 | } | |
190 | else | |
191 | { | |
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()); | |
194 | } | |
195 | } | |
196 | } | |
197 | ||
198 | BOOST_AUTO_TEST_CASE( test_main ) | |
199 | { | |
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"); | |
202 | ||
f67539c2 | 203 | // Faster, but no good for diagnosing the cause of any issues: |
1e59de90 | 204 | #ifndef BOOST_MATH_STANDALONE |
b32b8144 | 205 | test_values(boost::multiprecision::cpp_dec_float_50(0), "cpp_dec_float_50"); |
1e59de90 | 206 | #endif |
b32b8144 FG |
207 | } |
208 | ||
209 |