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