precision.hpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  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. #ifndef BOOST_MATH_TOOLS_PRECISION_INCLUDED
  6. #define BOOST_MATH_TOOLS_PRECISION_INCLUDED
  7. #ifdef _MSC_VER
  8. #pragma once
  9. #endif
  10. #include <boost/limits.hpp>
  11. #include <boost/assert.hpp>
  12. #include <boost/static_assert.hpp>
  13. #include <boost/mpl/int.hpp>
  14. #include <boost/mpl/bool.hpp>
  15. #include <boost/mpl/if.hpp>
  16. #include <boost/math/policies/policy.hpp>
  17. // These two are for LDBL_MAN_DIG:
  18. #include <limits.h>
  19. #include <math.h>
  20. namespace boost{ namespace math
  21. {
  22. namespace tools
  23. {
  24. // If T is not specialized, the functions digits, max_value and min_value,
  25. // all get synthesised automatically from std::numeric_limits.
  26. // However, if numeric_limits is not specialised for type RealType,
  27. // for example with NTL::RR type, then you will get a compiler error
  28. // when code tries to use these functions, unless you explicitly specialise them.
  29. // For example if the precision of RealType varies at runtime,
  30. // then numeric_limits support may not be appropriate,
  31. // see boost/math/tools/ntl.hpp for examples like
  32. // template <> NTL::RR max_value<NTL::RR> ...
  33. // See Conceptual Requirements for Real Number Types.
  34. template <class T>
  35. inline int digits(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(T))
  36. {
  37. #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
  38. BOOST_STATIC_ASSERT( ::std::numeric_limits<T>::is_specialized);
  39. BOOST_STATIC_ASSERT( ::std::numeric_limits<T>::radix == 2 || ::std::numeric_limits<T>::radix == 10);
  40. #else
  41. BOOST_ASSERT(::std::numeric_limits<T>::is_specialized);
  42. BOOST_ASSERT(::std::numeric_limits<T>::radix == 2 || ::std::numeric_limits<T>::radix == 10);
  43. #endif
  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. template <class T>
  49. inline T max_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE(T))
  50. {
  51. #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
  52. BOOST_STATIC_ASSERT( ::std::numeric_limits<T>::is_specialized);
  53. #else
  54. BOOST_ASSERT(::std::numeric_limits<T>::is_specialized);
  55. #endif
  56. return (std::numeric_limits<T>::max)();
  57. } // Also used as a finite 'infinite' value for - and +infinity, for example:
  58. // -max_value<double> = -1.79769e+308, max_value<double> = 1.79769e+308.
  59. template <class T>
  60. inline T min_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE(T))
  61. {
  62. #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
  63. BOOST_STATIC_ASSERT( ::std::numeric_limits<T>::is_specialized);
  64. #else
  65. BOOST_ASSERT(::std::numeric_limits<T>::is_specialized);
  66. #endif
  67. return (std::numeric_limits<T>::min)();
  68. }
  69. namespace detail{
  70. //
  71. // Logarithmic limits come next, note that although
  72. // we can compute these from the log of the max value
  73. // that is not in general thread safe (if we cache the value)
  74. // so it's better to specialise these:
  75. //
  76. // For type float first:
  77. //
  78. template <class T>
  79. inline T log_max_value(const mpl::int_<128>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T))
  80. {
  81. return 88.0f;
  82. }
  83. template <class T>
  84. inline T log_min_value(const mpl::int_<128>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T))
  85. {
  86. return -87.0f;
  87. }
  88. //
  89. // Now double:
  90. //
  91. template <class T>
  92. inline T log_max_value(const mpl::int_<1024>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T))
  93. {
  94. return 709.0;
  95. }
  96. template <class T>
  97. inline T log_min_value(const mpl::int_<1024>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T))
  98. {
  99. return -708.0;
  100. }
  101. //
  102. // 80 and 128-bit long doubles:
  103. //
  104. template <class T>
  105. inline T log_max_value(const mpl::int_<16384>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T))
  106. {
  107. return 11356.0L;
  108. }
  109. template <class T>
  110. inline T log_min_value(const mpl::int_<16384>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T))
  111. {
  112. return -11355.0L;
  113. }
  114. template <class T>
  115. inline T log_max_value(const mpl::int_<0>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T))
  116. {
  117. #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
  118. BOOST_STATIC_ASSERT( ::std::numeric_limits<T>::is_specialized);
  119. #else
  120. BOOST_ASSERT(::std::numeric_limits<T>::is_specialized);
  121. #endif
  122. BOOST_MATH_STD_USING
  123. static const T val = log((std::numeric_limits<T>::max)());
  124. return val;
  125. }
  126. template <class T>
  127. inline T log_min_value(const mpl::int_<0>& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T))
  128. {
  129. #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
  130. BOOST_STATIC_ASSERT( ::std::numeric_limits<T>::is_specialized);
  131. #else
  132. BOOST_ASSERT(::std::numeric_limits<T>::is_specialized);
  133. #endif
  134. BOOST_MATH_STD_USING
  135. static const T val = log((std::numeric_limits<T>::min)());
  136. return val;
  137. }
  138. template <class T>
  139. inline T epsilon(const mpl::true_& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T))
  140. {
  141. return std::numeric_limits<T>::epsilon();
  142. }
  143. #if (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)) && ((LDBL_MANT_DIG == 106) || (__LDBL_MANT_DIG__ == 106))
  144. template <>
  145. inline long double epsilon<long double>(const mpl::true_& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(long double))
  146. {
  147. // numeric_limits on Darwin tells lies here.
  148. // This static assert fails for some unknown reason, so
  149. // disabled for now...
  150. // BOOST_STATIC_ASSERT(std::numeric_limits<long double>::digits == 106);
  151. return 2.4651903288156618919116517665087e-32L;
  152. }
  153. #endif
  154. template <class T>
  155. inline T epsilon(const mpl::false_& BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(T))
  156. {
  157. BOOST_MATH_STD_USING // for ADL of std names
  158. static const T eps = ldexp(static_cast<T>(1), 1-policies::digits<T, policies::policy<> >());
  159. return eps;
  160. }
  161. } // namespace detail
  162. #ifdef BOOST_MSVC
  163. #pragma warning(push)
  164. #pragma warning(disable:4309)
  165. #endif
  166. template <class T>
  167. inline T log_max_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE(T))
  168. {
  169. #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
  170. typedef typename mpl::if_c<
  171. (std::numeric_limits<T>::radix == 2) &&
  172. (std::numeric_limits<T>::max_exponent == 128
  173. || std::numeric_limits<T>::max_exponent == 1024
  174. || std::numeric_limits<T>::max_exponent == 16384),
  175. mpl::int_<(std::numeric_limits<T>::max_exponent > INT_MAX ? INT_MAX : static_cast<int>(std::numeric_limits<T>::max_exponent))>,
  176. mpl::int_<0>
  177. >::type tag_type;
  178. BOOST_STATIC_ASSERT( ::std::numeric_limits<T>::is_specialized);
  179. return detail::log_max_value<T>(tag_type());
  180. #else
  181. BOOST_ASSERT(::std::numeric_limits<T>::is_specialized);
  182. BOOST_MATH_STD_USING
  183. static const T val = log((std::numeric_limits<T>::max)());
  184. return val;
  185. #endif
  186. }
  187. template <class T>
  188. inline T log_min_value(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE(T))
  189. {
  190. #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
  191. typedef typename mpl::if_c<
  192. (std::numeric_limits<T>::radix == 2) &&
  193. (std::numeric_limits<T>::max_exponent == 128
  194. || std::numeric_limits<T>::max_exponent == 1024
  195. || std::numeric_limits<T>::max_exponent == 16384),
  196. mpl::int_<(std::numeric_limits<T>::max_exponent > INT_MAX ? INT_MAX : static_cast<int>(std::numeric_limits<T>::max_exponent))>,
  197. mpl::int_<0>
  198. >::type tag_type;
  199. BOOST_STATIC_ASSERT( ::std::numeric_limits<T>::is_specialized);
  200. return detail::log_min_value<T>(tag_type());
  201. #else
  202. BOOST_ASSERT(::std::numeric_limits<T>::is_specialized);
  203. BOOST_MATH_STD_USING
  204. static const T val = log((std::numeric_limits<T>::min)());
  205. return val;
  206. #endif
  207. }
  208. #ifdef BOOST_MSVC
  209. #pragma warning(pop)
  210. #endif
  211. template <class T>
  212. inline T epsilon(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(T))
  213. {
  214. #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
  215. return detail::epsilon<T>(mpl::bool_< ::std::numeric_limits<T>::is_specialized>());
  216. #else
  217. return ::std::numeric_limits<T>::is_specialized ?
  218. detail::epsilon<T>(mpl::true_()) :
  219. detail::epsilon<T>(mpl::false_());
  220. #endif
  221. }
  222. namespace detail{
  223. template <class T>
  224. inline T root_epsilon_imp(const mpl::int_<24>&)
  225. {
  226. return static_cast<T>(0.00034526698300124390839884978618400831996329879769945L);
  227. }
  228. template <class T>
  229. inline T root_epsilon_imp(const T*, const mpl::int_<53>&)
  230. {
  231. return static_cast<T>(0.1490116119384765625e-7L);
  232. }
  233. template <class T>
  234. inline T root_epsilon_imp(const T*, const mpl::int_<64>&)
  235. {
  236. return static_cast<T>(0.32927225399135962333569506281281311031656150598474e-9L);
  237. }
  238. template <class T>
  239. inline T root_epsilon_imp(const T*, const mpl::int_<113>&)
  240. {
  241. return static_cast<T>(0.1387778780781445675529539585113525390625e-16L);
  242. }
  243. template <class T, class Tag>
  244. inline T root_epsilon_imp(const T*, const Tag&)
  245. {
  246. BOOST_MATH_STD_USING
  247. static const T r_eps = sqrt(tools::epsilon<T>());
  248. return r_eps;
  249. }
  250. template <class T>
  251. inline T forth_root_epsilon_imp(const T*, const mpl::int_<24>&)
  252. {
  253. return static_cast<T>(0.018581361171917516667460937040007436176452688944747L);
  254. }
  255. template <class T>
  256. inline T forth_root_epsilon_imp(const T*, const mpl::int_<53>&)
  257. {
  258. return static_cast<T>(0.0001220703125L);
  259. }
  260. template <class T>
  261. inline T forth_root_epsilon_imp(const T*, const mpl::int_<64>&)
  262. {
  263. return static_cast<T>(0.18145860519450699870567321328132261891067079047605e-4L);
  264. }
  265. template <class T>
  266. inline T forth_root_epsilon_imp(const T*, const mpl::int_<113>&)
  267. {
  268. return static_cast<T>(0.37252902984619140625e-8L);
  269. }
  270. template <class T, class Tag>
  271. inline T forth_root_epsilon_imp(const T*, const Tag&)
  272. {
  273. BOOST_MATH_STD_USING
  274. static const T r_eps = sqrt(sqrt(tools::epsilon<T>()));
  275. return r_eps;
  276. }
  277. }
  278. template <class T>
  279. inline T root_epsilon()
  280. {
  281. typedef mpl::int_< (::std::numeric_limits<T>::radix == 2) ? std::numeric_limits<T>::digits : 0> tag_type;
  282. return detail::root_epsilon_imp(static_cast<T const*>(0), tag_type());
  283. }
  284. template <class T>
  285. inline T forth_root_epsilon()
  286. {
  287. typedef mpl::int_< (::std::numeric_limits<T>::radix == 2) ? std::numeric_limits<T>::digits : 0> tag_type;
  288. return detail::forth_root_epsilon_imp(static_cast<T const*>(0), tag_type());
  289. }
  290. } // namespace tools
  291. } // namespace math
  292. } // namespace boost
  293. #endif // BOOST_MATH_TOOLS_PRECISION_INCLUDED