]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Copyright John Maddock 2005-2006. |
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 | #ifndef BOOST_MATH_TOOLS_PRECISION_INCLUDED | |
7 | #define BOOST_MATH_TOOLS_PRECISION_INCLUDED | |
8 | ||
9 | #ifdef _MSC_VER | |
10 | #pragma once | |
11 | #endif | |
12 | ||
1e59de90 | 13 | #include <boost/math/tools/assert.hpp> |
7c673cae | 14 | #include <boost/math/policies/policy.hpp> |
1e59de90 TL |
15 | #include <type_traits> |
16 | #include <limits> | |
17 | #include <climits> | |
18 | #include <cmath> | |
19 | #include <cstdint> | |
20 | #include <cfloat> // LDBL_MANT_DIG | |
7c673cae FG |
21 | |
22 | namespace boost{ namespace math | |
23 | { | |
24 | namespace tools | |
25 | { | |
26 | // If T is not specialized, the functions digits, max_value and min_value, | |
27 | // all get synthesised automatically from std::numeric_limits. | |
28 | // However, if numeric_limits is not specialised for type RealType, | |
29 | // for example with NTL::RR type, then you will get a compiler error | |
30 | // when code tries to use these functions, unless you explicitly specialise them. | |
31 | ||
32 | // For example if the precision of RealType varies at runtime, | |
33 | // then numeric_limits support may not be appropriate, | |
34 | // see boost/math/tools/ntl.hpp for examples like | |
35 | // template <> NTL::RR max_value<NTL::RR> ... | |
36 | // See Conceptual Requirements for Real Number Types. | |
37 | ||
38 | template <class T> | |
1e59de90 | 39 | inline constexpr int digits(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(T)) noexcept |
7c673cae | 40 | { |
1e59de90 TL |
41 | static_assert( ::std::numeric_limits<T>::is_specialized, "Type T must be specialized"); |
42 | static_assert( ::std::numeric_limits<T>::radix == 2 || ::std::numeric_limits<T>::radix == 10, "Type T must have a radix of 2 or 10"); | |
43 | ||
7c673cae FG |
44 | return std::numeric_limits<T>::radix == 2 |
45 | ? std::numeric_limits<T>::digits | |
46 | : ((std::numeric_limits<T>::digits + 1) * 1000L) / 301L; | |
47 | } | |
48 | ||
49 | template <class T> | |
1e59de90 | 50 | inline constexpr T max_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE(T)) noexcept(std::is_floating_point<T>::value) |
7c673cae | 51 | { |
1e59de90 | 52 | static_assert( ::std::numeric_limits<T>::is_specialized, "Type T must be specialized"); |
7c673cae FG |
53 | return (std::numeric_limits<T>::max)(); |
54 | } // Also used as a finite 'infinite' value for - and +infinity, for example: | |
55 | // -max_value<double> = -1.79769e+308, max_value<double> = 1.79769e+308. | |
56 | ||
57 | template <class T> | |
1e59de90 | 58 | inline constexpr T min_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE(T)) noexcept(std::is_floating_point<T>::value) |
7c673cae | 59 | { |
1e59de90 TL |
60 | static_assert( ::std::numeric_limits<T>::is_specialized, "Type T must be specialized"); |
61 | ||
7c673cae FG |
62 | return (std::numeric_limits<T>::min)(); |
63 | } | |
64 | ||
65 | namespace detail{ | |
66 | // | |
67 | // Logarithmic limits come next, note that although | |
68 | // we can compute these from the log of the max value | |
69 | // that is not in general thread safe (if we cache the value) | |
70 | // so it's better to specialise these: | |
71 | // | |
72 | // For type float first: | |
73 | // | |
74 | template <class T> | |
1e59de90 | 75 | inline constexpr T log_max_value(const std::integral_constant<int, 128>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T)) noexcept(std::is_floating_point<T>::value) |
7c673cae FG |
76 | { |
77 | return 88.0f; | |
78 | } | |
79 | ||
80 | template <class T> | |
1e59de90 | 81 | inline constexpr T log_min_value(const std::integral_constant<int, 128>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T)) noexcept(std::is_floating_point<T>::value) |
7c673cae FG |
82 | { |
83 | return -87.0f; | |
84 | } | |
85 | // | |
86 | // Now double: | |
87 | // | |
88 | template <class T> | |
1e59de90 | 89 | inline constexpr T log_max_value(const std::integral_constant<int, 1024>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T)) noexcept(std::is_floating_point<T>::value) |
7c673cae FG |
90 | { |
91 | return 709.0; | |
92 | } | |
93 | ||
94 | template <class T> | |
1e59de90 | 95 | inline constexpr T log_min_value(const std::integral_constant<int, 1024>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T)) noexcept(std::is_floating_point<T>::value) |
7c673cae FG |
96 | { |
97 | return -708.0; | |
98 | } | |
99 | // | |
100 | // 80 and 128-bit long doubles: | |
101 | // | |
102 | template <class T> | |
1e59de90 | 103 | inline constexpr T log_max_value(const std::integral_constant<int, 16384>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T)) noexcept(std::is_floating_point<T>::value) |
7c673cae FG |
104 | { |
105 | return 11356.0L; | |
106 | } | |
107 | ||
108 | template <class T> | |
1e59de90 | 109 | inline constexpr T log_min_value(const std::integral_constant<int, 16384>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T)) noexcept(std::is_floating_point<T>::value) |
7c673cae FG |
110 | { |
111 | return -11355.0L; | |
112 | } | |
113 | ||
114 | template <class T> | |
1e59de90 | 115 | inline T log_max_value(const std::integral_constant<int, 0>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T)) |
7c673cae FG |
116 | { |
117 | BOOST_MATH_STD_USING | |
118 | #ifdef __SUNPRO_CC | |
119 | static const T m = boost::math::tools::max_value<T>(); | |
120 | static const T val = log(m); | |
121 | #else | |
122 | static const T val = log(boost::math::tools::max_value<T>()); | |
123 | #endif | |
124 | return val; | |
125 | } | |
126 | ||
127 | template <class T> | |
1e59de90 | 128 | inline T log_min_value(const std::integral_constant<int, 0>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T)) |
7c673cae FG |
129 | { |
130 | BOOST_MATH_STD_USING | |
131 | #ifdef __SUNPRO_CC | |
132 | static const T m = boost::math::tools::min_value<T>(); | |
133 | static const T val = log(m); | |
134 | #else | |
135 | static const T val = log(boost::math::tools::min_value<T>()); | |
136 | #endif | |
137 | return val; | |
138 | } | |
139 | ||
140 | template <class T> | |
1e59de90 | 141 | inline constexpr T epsilon(const std::true_type& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T)) noexcept(std::is_floating_point<T>::value) |
7c673cae FG |
142 | { |
143 | return std::numeric_limits<T>::epsilon(); | |
144 | } | |
145 | ||
146 | #if defined(__GNUC__) && ((LDBL_MANT_DIG == 106) || (__LDBL_MANT_DIG__ == 106)) | |
147 | template <> | |
1e59de90 | 148 | inline constexpr long double epsilon<long double>(const std::true_type& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(long double)) noexcept(std::is_floating_point<long double>::value) |
7c673cae FG |
149 | { |
150 | // numeric_limits on Darwin (and elsewhere) tells lies here: | |
151 | // the issue is that long double on a few platforms is | |
152 | // really a "double double" which has a non-contiguous | |
153 | // mantissa: 53 bits followed by an unspecified number of | |
154 | // zero bits, followed by 53 more bits. Thus the apparent | |
155 | // precision of the type varies depending where it's been. | |
156 | // Set epsilon to the value that a 106 bit fixed mantissa | |
157 | // type would have, as that will give us sensible behaviour everywhere. | |
158 | // | |
159 | // This static assert fails for some unknown reason, so | |
160 | // disabled for now... | |
1e59de90 | 161 | // static_assert(std::numeric_limits<long double>::digits == 106); |
7c673cae FG |
162 | return 2.4651903288156618919116517665087e-32L; |
163 | } | |
164 | #endif | |
165 | ||
166 | template <class T> | |
1e59de90 | 167 | inline T epsilon(const std::false_type& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T)) |
7c673cae FG |
168 | { |
169 | // Note: don't cache result as precision may vary at runtime: | |
170 | BOOST_MATH_STD_USING // for ADL of std names | |
171 | return ldexp(static_cast<T>(1), 1-policies::digits<T, policies::policy<> >()); | |
172 | } | |
173 | ||
174 | template <class T> | |
175 | struct log_limit_traits | |
176 | { | |
1e59de90 | 177 | typedef typename std::conditional< |
7c673cae FG |
178 | (std::numeric_limits<T>::radix == 2) && |
179 | (std::numeric_limits<T>::max_exponent == 128 | |
180 | || std::numeric_limits<T>::max_exponent == 1024 | |
181 | || std::numeric_limits<T>::max_exponent == 16384), | |
1e59de90 TL |
182 | std::integral_constant<int, (std::numeric_limits<T>::max_exponent > INT_MAX ? INT_MAX : static_cast<int>(std::numeric_limits<T>::max_exponent))>, |
183 | std::integral_constant<int, 0> | |
7c673cae | 184 | >::type tag_type; |
1e59de90 TL |
185 | static constexpr bool value = tag_type::value ? true : false; |
186 | static_assert(::std::numeric_limits<T>::is_specialized || (value == 0), "Type T must be specialized or equal to 0"); | |
7c673cae FG |
187 | }; |
188 | ||
189 | template <class T, bool b> struct log_limit_noexcept_traits_imp : public log_limit_traits<T> {}; | |
1e59de90 | 190 | template <class T> struct log_limit_noexcept_traits_imp<T, false> : public std::integral_constant<bool, false> {}; |
7c673cae FG |
191 | |
192 | template <class T> | |
1e59de90 | 193 | struct log_limit_noexcept_traits : public log_limit_noexcept_traits_imp<T, std::is_floating_point<T>::value> {}; |
7c673cae FG |
194 | |
195 | } // namespace detail | |
196 | ||
1e59de90 | 197 | #ifdef _MSC_VER |
7c673cae FG |
198 | #pragma warning(push) |
199 | #pragma warning(disable:4309) | |
200 | #endif | |
201 | ||
202 | template <class T> | |
1e59de90 | 203 | inline constexpr T log_max_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE(T)) noexcept(detail::log_limit_noexcept_traits<T>::value) |
7c673cae FG |
204 | { |
205 | #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS | |
206 | return detail::log_max_value<T>(typename detail::log_limit_traits<T>::tag_type()); | |
207 | #else | |
1e59de90 | 208 | BOOST_MATH_ASSERT(::std::numeric_limits<T>::is_specialized); |
7c673cae FG |
209 | BOOST_MATH_STD_USING |
210 | static const T val = log((std::numeric_limits<T>::max)()); | |
211 | return val; | |
212 | #endif | |
213 | } | |
214 | ||
215 | template <class T> | |
1e59de90 | 216 | inline constexpr T log_min_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE(T)) noexcept(detail::log_limit_noexcept_traits<T>::value) |
7c673cae FG |
217 | { |
218 | #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS | |
219 | return detail::log_min_value<T>(typename detail::log_limit_traits<T>::tag_type()); | |
220 | #else | |
1e59de90 | 221 | BOOST_MATH_ASSERT(::std::numeric_limits<T>::is_specialized); |
7c673cae FG |
222 | BOOST_MATH_STD_USING |
223 | static const T val = log((std::numeric_limits<T>::min)()); | |
224 | return val; | |
225 | #endif | |
226 | } | |
227 | ||
1e59de90 | 228 | #ifdef _MSC_VER |
7c673cae FG |
229 | #pragma warning(pop) |
230 | #endif | |
231 | ||
232 | template <class T> | |
1e59de90 | 233 | inline constexpr T epsilon(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(T)) noexcept(std::is_floating_point<T>::value) |
7c673cae FG |
234 | { |
235 | #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS | |
1e59de90 | 236 | return detail::epsilon<T>(std::integral_constant<bool, ::std::numeric_limits<T>::is_specialized>()); |
7c673cae FG |
237 | #else |
238 | return ::std::numeric_limits<T>::is_specialized ? | |
1e59de90 TL |
239 | detail::epsilon<T>(std::true_type()) : |
240 | detail::epsilon<T>(std::false_type()); | |
7c673cae FG |
241 | #endif |
242 | } | |
243 | ||
244 | namespace detail{ | |
245 | ||
246 | template <class T> | |
1e59de90 | 247 | inline constexpr T root_epsilon_imp(const std::integral_constant<int, 24>&) noexcept(std::is_floating_point<T>::value) |
7c673cae FG |
248 | { |
249 | return static_cast<T>(0.00034526698300124390839884978618400831996329879769945L); | |
250 | } | |
251 | ||
252 | template <class T> | |
1e59de90 | 253 | inline constexpr T root_epsilon_imp(const T*, const std::integral_constant<int, 53>&) noexcept(std::is_floating_point<T>::value) |
7c673cae FG |
254 | { |
255 | return static_cast<T>(0.1490116119384765625e-7L); | |
256 | } | |
257 | ||
258 | template <class T> | |
1e59de90 | 259 | inline constexpr T root_epsilon_imp(const T*, const std::integral_constant<int, 64>&) noexcept(std::is_floating_point<T>::value) |
7c673cae FG |
260 | { |
261 | return static_cast<T>(0.32927225399135962333569506281281311031656150598474e-9L); | |
262 | } | |
263 | ||
264 | template <class T> | |
1e59de90 | 265 | inline constexpr T root_epsilon_imp(const T*, const std::integral_constant<int, 113>&) noexcept(std::is_floating_point<T>::value) |
7c673cae FG |
266 | { |
267 | return static_cast<T>(0.1387778780781445675529539585113525390625e-16L); | |
268 | } | |
269 | ||
270 | template <class T, class Tag> | |
271 | inline T root_epsilon_imp(const T*, const Tag&) | |
272 | { | |
273 | BOOST_MATH_STD_USING | |
274 | static const T r_eps = sqrt(tools::epsilon<T>()); | |
275 | return r_eps; | |
276 | } | |
277 | ||
278 | template <class T> | |
1e59de90 | 279 | inline T root_epsilon_imp(const T*, const std::integral_constant<int, 0>&) |
7c673cae FG |
280 | { |
281 | BOOST_MATH_STD_USING | |
282 | return sqrt(tools::epsilon<T>()); | |
283 | } | |
284 | ||
285 | template <class T> | |
1e59de90 | 286 | inline constexpr T cbrt_epsilon_imp(const std::integral_constant<int, 24>&) noexcept(std::is_floating_point<T>::value) |
7c673cae FG |
287 | { |
288 | return static_cast<T>(0.0049215666011518482998719164346805794944150447839903L); | |
289 | } | |
290 | ||
291 | template <class T> | |
1e59de90 | 292 | inline constexpr T cbrt_epsilon_imp(const T*, const std::integral_constant<int, 53>&) noexcept(std::is_floating_point<T>::value) |
7c673cae FG |
293 | { |
294 | return static_cast<T>(6.05545445239333906078989272793696693569753008995e-6L); | |
295 | } | |
296 | ||
297 | template <class T> | |
1e59de90 | 298 | inline constexpr T cbrt_epsilon_imp(const T*, const std::integral_constant<int, 64>&) noexcept(std::is_floating_point<T>::value) |
7c673cae FG |
299 | { |
300 | return static_cast<T>(4.76837158203125e-7L); | |
301 | } | |
302 | ||
303 | template <class T> | |
1e59de90 | 304 | inline constexpr T cbrt_epsilon_imp(const T*, const std::integral_constant<int, 113>&) noexcept(std::is_floating_point<T>::value) |
7c673cae FG |
305 | { |
306 | return static_cast<T>(5.7749313854154005630396773604745549542403508090496e-12L); | |
307 | } | |
308 | ||
309 | template <class T, class Tag> | |
310 | inline T cbrt_epsilon_imp(const T*, const Tag&) | |
311 | { | |
312 | BOOST_MATH_STD_USING; | |
313 | static const T cbrt_eps = pow(tools::epsilon<T>(), T(1) / 3); | |
314 | return cbrt_eps; | |
315 | } | |
316 | ||
317 | template <class T> | |
1e59de90 | 318 | inline T cbrt_epsilon_imp(const T*, const std::integral_constant<int, 0>&) |
7c673cae FG |
319 | { |
320 | BOOST_MATH_STD_USING; | |
321 | return pow(tools::epsilon<T>(), T(1) / 3); | |
322 | } | |
323 | ||
324 | template <class T> | |
1e59de90 | 325 | inline constexpr T forth_root_epsilon_imp(const T*, const std::integral_constant<int, 24>&) noexcept(std::is_floating_point<T>::value) |
7c673cae FG |
326 | { |
327 | return static_cast<T>(0.018581361171917516667460937040007436176452688944747L); | |
328 | } | |
329 | ||
330 | template <class T> | |
1e59de90 | 331 | inline constexpr T forth_root_epsilon_imp(const T*, const std::integral_constant<int, 53>&) noexcept(std::is_floating_point<T>::value) |
7c673cae FG |
332 | { |
333 | return static_cast<T>(0.0001220703125L); | |
334 | } | |
335 | ||
336 | template <class T> | |
1e59de90 | 337 | inline constexpr T forth_root_epsilon_imp(const T*, const std::integral_constant<int, 64>&) noexcept(std::is_floating_point<T>::value) |
7c673cae FG |
338 | { |
339 | return static_cast<T>(0.18145860519450699870567321328132261891067079047605e-4L); | |
340 | } | |
341 | ||
342 | template <class T> | |
1e59de90 | 343 | inline constexpr T forth_root_epsilon_imp(const T*, const std::integral_constant<int, 113>&) noexcept(std::is_floating_point<T>::value) |
7c673cae FG |
344 | { |
345 | return static_cast<T>(0.37252902984619140625e-8L); | |
346 | } | |
347 | ||
348 | template <class T, class Tag> | |
349 | inline T forth_root_epsilon_imp(const T*, const Tag&) | |
350 | { | |
351 | BOOST_MATH_STD_USING | |
352 | static const T r_eps = sqrt(sqrt(tools::epsilon<T>())); | |
353 | return r_eps; | |
354 | } | |
355 | ||
356 | template <class T> | |
1e59de90 | 357 | inline T forth_root_epsilon_imp(const T*, const std::integral_constant<int, 0>&) |
7c673cae FG |
358 | { |
359 | BOOST_MATH_STD_USING | |
360 | return sqrt(sqrt(tools::epsilon<T>())); | |
361 | } | |
362 | ||
363 | template <class T> | |
364 | struct root_epsilon_traits | |
365 | { | |
1e59de90 TL |
366 | typedef std::integral_constant<int, (::std::numeric_limits<T>::radix == 2) && (::std::numeric_limits<T>::digits != INT_MAX) ? std::numeric_limits<T>::digits : 0> tag_type; |
367 | static constexpr bool has_noexcept = (tag_type::value == 113) || (tag_type::value == 64) || (tag_type::value == 53) || (tag_type::value == 24); | |
7c673cae FG |
368 | }; |
369 | ||
370 | } | |
371 | ||
372 | template <class T> | |
1e59de90 | 373 | inline constexpr T root_epsilon() noexcept(std::is_floating_point<T>::value && detail::root_epsilon_traits<T>::has_noexcept) |
7c673cae FG |
374 | { |
375 | return detail::root_epsilon_imp(static_cast<T const*>(0), typename detail::root_epsilon_traits<T>::tag_type()); | |
376 | } | |
377 | ||
378 | template <class T> | |
1e59de90 | 379 | inline constexpr T cbrt_epsilon() noexcept(std::is_floating_point<T>::value && detail::root_epsilon_traits<T>::has_noexcept) |
7c673cae FG |
380 | { |
381 | return detail::cbrt_epsilon_imp(static_cast<T const*>(0), typename detail::root_epsilon_traits<T>::tag_type()); | |
382 | } | |
383 | ||
384 | template <class T> | |
1e59de90 | 385 | inline constexpr T forth_root_epsilon() noexcept(std::is_floating_point<T>::value && detail::root_epsilon_traits<T>::has_noexcept) |
7c673cae FG |
386 | { |
387 | return detail::forth_root_epsilon_imp(static_cast<T const*>(0), typename detail::root_epsilon_traits<T>::tag_type()); | |
388 | } | |
389 | ||
390 | } // namespace tools | |
391 | } // namespace math | |
392 | } // namespace boost | |
393 | ||
394 | #endif // BOOST_MATH_TOOLS_PRECISION_INCLUDED | |
395 |