fp_traits.hpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  1. // fp_traits.hpp
  2. #ifndef BOOST_MATH_FP_TRAITS_HPP
  3. #define BOOST_MATH_FP_TRAITS_HPP
  4. // Copyright (c) 2006 Johan Rade
  5. // Distributed under the Boost Software License, Version 1.0.
  6. // (See accompanying file LICENSE_1_0.txt
  7. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  8. /*
  9. To support old compilers, care has been taken to avoid partial template
  10. specialization and meta function forwarding.
  11. With these techniques, the code could be simplified.
  12. */
  13. #if defined(__vms) && defined(__DECCXX) && !__IEEE_FLOAT
  14. // The VAX floating point formats are used (for float and double)
  15. # define BOOST_FPCLASSIFY_VAX_FORMAT
  16. #endif
  17. #include <cstring>
  18. #include <boost/assert.hpp>
  19. #include <boost/cstdint.hpp>
  20. #include <boost/predef/other/endian.h>
  21. #include <boost/static_assert.hpp>
  22. #include <boost/type_traits/is_floating_point.hpp>
  23. #ifdef BOOST_NO_STDC_NAMESPACE
  24. namespace std{ using ::memcpy; }
  25. #endif
  26. #ifndef FP_NORMAL
  27. #define FP_ZERO 0
  28. #define FP_NORMAL 1
  29. #define FP_INFINITE 2
  30. #define FP_NAN 3
  31. #define FP_SUBNORMAL 4
  32. #else
  33. #define BOOST_HAS_FPCLASSIFY
  34. #ifndef fpclassify
  35. # if (defined(__GLIBCPP__) || defined(__GLIBCXX__)) \
  36. && defined(_GLIBCXX_USE_C99_MATH) \
  37. && !(defined(_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC) \
  38. && (_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC != 0))
  39. # ifdef _STLP_VENDOR_CSTD
  40. # if _STLPORT_VERSION >= 0x520
  41. # define BOOST_FPCLASSIFY_PREFIX ::__std_alias::
  42. # else
  43. # define BOOST_FPCLASSIFY_PREFIX ::_STLP_VENDOR_CSTD::
  44. # endif
  45. # else
  46. # define BOOST_FPCLASSIFY_PREFIX ::std::
  47. # endif
  48. # else
  49. # undef BOOST_HAS_FPCLASSIFY
  50. # define BOOST_FPCLASSIFY_PREFIX
  51. # endif
  52. #elif (defined(__HP_aCC) && !defined(__hppa))
  53. // aCC 6 appears to do "#define fpclassify fpclassify" which messes us up a bit!
  54. # define BOOST_FPCLASSIFY_PREFIX ::
  55. #else
  56. # define BOOST_FPCLASSIFY_PREFIX
  57. #endif
  58. #ifdef __MINGW32__
  59. # undef BOOST_HAS_FPCLASSIFY
  60. #endif
  61. #endif
  62. //------------------------------------------------------------------------------
  63. namespace boost {
  64. namespace math {
  65. namespace detail {
  66. //------------------------------------------------------------------------------
  67. /*
  68. The following classes are used to tag the different methods that are used
  69. for floating point classification
  70. */
  71. struct native_tag {};
  72. template <bool has_limits>
  73. struct generic_tag {};
  74. struct ieee_tag {};
  75. struct ieee_copy_all_bits_tag : public ieee_tag {};
  76. struct ieee_copy_leading_bits_tag : public ieee_tag {};
  77. #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
  78. //
  79. // These helper functions are used only when numeric_limits<>
  80. // members are not compile time constants:
  81. //
  82. inline bool is_generic_tag_false(const generic_tag<false>*)
  83. {
  84. return true;
  85. }
  86. inline bool is_generic_tag_false(const void*)
  87. {
  88. return false;
  89. }
  90. #endif
  91. //------------------------------------------------------------------------------
  92. /*
  93. Most processors support three different floating point precisions:
  94. single precision (32 bits), double precision (64 bits)
  95. and extended double precision (80 - 128 bits, depending on the processor)
  96. Note that the C++ type long double can be implemented
  97. both as double precision and extended double precision.
  98. */
  99. struct unknown_precision{};
  100. struct single_precision {};
  101. struct double_precision {};
  102. struct extended_double_precision {};
  103. // native_tag version --------------------------------------------------------------
  104. template<class T> struct fp_traits_native
  105. {
  106. typedef native_tag method;
  107. };
  108. // generic_tag version -------------------------------------------------------------
  109. template<class T, class U> struct fp_traits_non_native
  110. {
  111. #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
  112. typedef generic_tag<std::numeric_limits<T>::is_specialized> method;
  113. #else
  114. typedef generic_tag<false> method;
  115. #endif
  116. };
  117. // ieee_tag versions ---------------------------------------------------------------
  118. /*
  119. These specializations of fp_traits_non_native contain information needed
  120. to "parse" the binary representation of a floating point number.
  121. Typedef members:
  122. bits -- the target type when copying the leading bytes of a floating
  123. point number. It is a typedef for uint32_t or uint64_t.
  124. method -- tells us whether all bytes are copied or not.
  125. It is a typedef for ieee_copy_all_bits_tag or ieee_copy_leading_bits_tag.
  126. Static data members:
  127. sign, exponent, flag, significand -- bit masks that give the meaning of the
  128. bits in the leading bytes.
  129. Static function members:
  130. get_bits(), set_bits() -- provide access to the leading bytes.
  131. */
  132. // ieee_tag version, float (32 bits) -----------------------------------------------
  133. #ifndef BOOST_FPCLASSIFY_VAX_FORMAT
  134. template<> struct fp_traits_non_native<float, single_precision>
  135. {
  136. typedef ieee_copy_all_bits_tag method;
  137. BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u);
  138. BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7f800000);
  139. BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00000000);
  140. BOOST_STATIC_CONSTANT(uint32_t, significand = 0x007fffff);
  141. typedef uint32_t bits;
  142. static void get_bits(float x, uint32_t& a) { std::memcpy(&a, &x, 4); }
  143. static void set_bits(float& x, uint32_t a) { std::memcpy(&x, &a, 4); }
  144. };
  145. // ieee_tag version, double (64 bits) ----------------------------------------------
  146. #if defined(BOOST_NO_INT64_T) || defined(BOOST_NO_INCLASS_MEMBER_INITIALIZATION) \
  147. || defined(__BORLANDC__) || defined(__CODEGEAR__)
  148. template<> struct fp_traits_non_native<double, double_precision>
  149. {
  150. typedef ieee_copy_leading_bits_tag method;
  151. BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u);
  152. BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7ff00000);
  153. BOOST_STATIC_CONSTANT(uint32_t, flag = 0);
  154. BOOST_STATIC_CONSTANT(uint32_t, significand = 0x000fffff);
  155. typedef uint32_t bits;
  156. static void get_bits(double x, uint32_t& a)
  157. {
  158. std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);
  159. }
  160. static void set_bits(double& x, uint32_t a)
  161. {
  162. std::memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4);
  163. }
  164. private:
  165. #if BOOST_ENDIAN_BIG_BYTE
  166. BOOST_STATIC_CONSTANT(int, offset_ = 0);
  167. #elif BOOST_ENDIAN_LITTLE_BYTE
  168. BOOST_STATIC_CONSTANT(int, offset_ = 4);
  169. #else
  170. BOOST_STATIC_ASSERT(false);
  171. #endif
  172. };
  173. //..............................................................................
  174. #else
  175. template<> struct fp_traits_non_native<double, double_precision>
  176. {
  177. typedef ieee_copy_all_bits_tag method;
  178. static const uint64_t sign = ((uint64_t)0x80000000u) << 32;
  179. static const uint64_t exponent = ((uint64_t)0x7ff00000) << 32;
  180. static const uint64_t flag = 0;
  181. static const uint64_t significand
  182. = (((uint64_t)0x000fffff) << 32) + ((uint64_t)0xffffffffu);
  183. typedef uint64_t bits;
  184. static void get_bits(double x, uint64_t& a) { std::memcpy(&a, &x, 8); }
  185. static void set_bits(double& x, uint64_t a) { std::memcpy(&x, &a, 8); }
  186. };
  187. #endif
  188. #endif // #ifndef BOOST_FPCLASSIFY_VAX_FORMAT
  189. // long double (64 bits) -------------------------------------------------------
  190. #if defined(BOOST_NO_INT64_T) || defined(BOOST_NO_INCLASS_MEMBER_INITIALIZATION)\
  191. || defined(__BORLANDC__) || defined(__CODEGEAR__)
  192. template<> struct fp_traits_non_native<long double, double_precision>
  193. {
  194. typedef ieee_copy_leading_bits_tag method;
  195. BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u);
  196. BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7ff00000);
  197. BOOST_STATIC_CONSTANT(uint32_t, flag = 0);
  198. BOOST_STATIC_CONSTANT(uint32_t, significand = 0x000fffff);
  199. typedef uint32_t bits;
  200. static void get_bits(long double x, uint32_t& a)
  201. {
  202. std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);
  203. }
  204. static void set_bits(long double& x, uint32_t a)
  205. {
  206. std::memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4);
  207. }
  208. private:
  209. #if BOOST_ENDIAN_BIG_BYTE
  210. BOOST_STATIC_CONSTANT(int, offset_ = 0);
  211. #elif BOOST_ENDIAN_LITTLE_BYTE
  212. BOOST_STATIC_CONSTANT(int, offset_ = 4);
  213. #else
  214. BOOST_STATIC_ASSERT(false);
  215. #endif
  216. };
  217. //..............................................................................
  218. #else
  219. template<> struct fp_traits_non_native<long double, double_precision>
  220. {
  221. typedef ieee_copy_all_bits_tag method;
  222. static const uint64_t sign = (uint64_t)0x80000000u << 32;
  223. static const uint64_t exponent = (uint64_t)0x7ff00000 << 32;
  224. static const uint64_t flag = 0;
  225. static const uint64_t significand
  226. = ((uint64_t)0x000fffff << 32) + (uint64_t)0xffffffffu;
  227. typedef uint64_t bits;
  228. static void get_bits(long double x, uint64_t& a) { std::memcpy(&a, &x, 8); }
  229. static void set_bits(long double& x, uint64_t a) { std::memcpy(&x, &a, 8); }
  230. };
  231. #endif
  232. // long double (>64 bits), x86 and x64 -----------------------------------------
  233. #if defined(__i386) || defined(__i386__) || defined(_M_IX86) \
  234. || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) \
  235. || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64)
  236. // Intel extended double precision format (80 bits)
  237. template<>
  238. struct fp_traits_non_native<long double, extended_double_precision>
  239. {
  240. typedef ieee_copy_leading_bits_tag method;
  241. BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u);
  242. BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7fff0000);
  243. BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00008000);
  244. BOOST_STATIC_CONSTANT(uint32_t, significand = 0x00007fff);
  245. typedef uint32_t bits;
  246. static void get_bits(long double x, uint32_t& a)
  247. {
  248. std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + 6, 4);
  249. }
  250. static void set_bits(long double& x, uint32_t a)
  251. {
  252. std::memcpy(reinterpret_cast<unsigned char*>(&x) + 6, &a, 4);
  253. }
  254. };
  255. // long double (>64 bits), Itanium ---------------------------------------------
  256. #elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
  257. // The floating point format is unknown at compile time
  258. // No template specialization is provided.
  259. // The generic_tag definition is used.
  260. // The Itanium supports both
  261. // the Intel extended double precision format (80 bits) and
  262. // the IEEE extended double precision format with 15 exponent bits (128 bits).
  263. #elif defined(__GNUC__) && (LDBL_MANT_DIG == 106)
  264. //
  265. // Define nothing here and fall though to generic_tag:
  266. // We have GCC's "double double" in effect, and any attempt
  267. // to handle it via bit-fiddling is pretty much doomed to fail...
  268. //
  269. // long double (>64 bits), PowerPC ---------------------------------------------
  270. #elif defined(__powerpc) || defined(__powerpc__) || defined(__POWERPC__) \
  271. || defined(__ppc) || defined(__ppc__) || defined(__PPC__)
  272. // PowerPC extended double precision format (128 bits)
  273. template<>
  274. struct fp_traits_non_native<long double, extended_double_precision>
  275. {
  276. typedef ieee_copy_leading_bits_tag method;
  277. BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u);
  278. BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7ff00000);
  279. BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00000000);
  280. BOOST_STATIC_CONSTANT(uint32_t, significand = 0x000fffff);
  281. typedef uint32_t bits;
  282. static void get_bits(long double x, uint32_t& a)
  283. {
  284. std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);
  285. }
  286. static void set_bits(long double& x, uint32_t a)
  287. {
  288. std::memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4);
  289. }
  290. private:
  291. #if BOOST_ENDIAN_BIG_BYTE
  292. BOOST_STATIC_CONSTANT(int, offset_ = 0);
  293. #elif BOOST_ENDIAN_LITTLE_BYTE
  294. BOOST_STATIC_CONSTANT(int, offset_ = 12);
  295. #else
  296. BOOST_STATIC_ASSERT(false);
  297. #endif
  298. };
  299. // long double (>64 bits), Motorola 68K ----------------------------------------
  300. #elif defined(__m68k) || defined(__m68k__) \
  301. || defined(__mc68000) || defined(__mc68000__) \
  302. // Motorola extended double precision format (96 bits)
  303. // It is the same format as the Intel extended double precision format,
  304. // except that 1) it is big-endian, 2) the 3rd and 4th byte are padding, and
  305. // 3) the flag bit is not set for infinity
  306. template<>
  307. struct fp_traits_non_native<long double, extended_double_precision>
  308. {
  309. typedef ieee_copy_leading_bits_tag method;
  310. BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u);
  311. BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7fff0000);
  312. BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00008000);
  313. BOOST_STATIC_CONSTANT(uint32_t, significand = 0x00007fff);
  314. // copy 1st, 2nd, 5th and 6th byte. 3rd and 4th byte are padding.
  315. typedef uint32_t bits;
  316. static void get_bits(long double x, uint32_t& a)
  317. {
  318. std::memcpy(&a, &x, 2);
  319. std::memcpy(reinterpret_cast<unsigned char*>(&a) + 2,
  320. reinterpret_cast<const unsigned char*>(&x) + 4, 2);
  321. }
  322. static void set_bits(long double& x, uint32_t a)
  323. {
  324. std::memcpy(&x, &a, 2);
  325. std::memcpy(reinterpret_cast<unsigned char*>(&x) + 4,
  326. reinterpret_cast<const unsigned char*>(&a) + 2, 2);
  327. }
  328. };
  329. // long double (>64 bits), All other processors --------------------------------
  330. #else
  331. // IEEE extended double precision format with 15 exponent bits (128 bits)
  332. template<>
  333. struct fp_traits_non_native<long double, extended_double_precision>
  334. {
  335. typedef ieee_copy_leading_bits_tag method;
  336. BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u);
  337. BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7fff0000);
  338. BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00000000);
  339. BOOST_STATIC_CONSTANT(uint32_t, significand = 0x0000ffff);
  340. typedef uint32_t bits;
  341. static void get_bits(long double x, uint32_t& a)
  342. {
  343. std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);
  344. }
  345. static void set_bits(long double& x, uint32_t a)
  346. {
  347. std::memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4);
  348. }
  349. private:
  350. #if BOOST_ENDIAN_BIG_BYTE
  351. BOOST_STATIC_CONSTANT(int, offset_ = 0);
  352. #elif BOOST_ENDIAN_LITTLE_BYTE
  353. BOOST_STATIC_CONSTANT(int, offset_ = 12);
  354. #else
  355. BOOST_STATIC_ASSERT(false);
  356. #endif
  357. };
  358. #endif
  359. //------------------------------------------------------------------------------
  360. // size_to_precision is a type switch for converting a C++ floating point type
  361. // to the corresponding precision type.
  362. template<int n, bool fp> struct size_to_precision
  363. {
  364. typedef unknown_precision type;
  365. };
  366. template<> struct size_to_precision<4, true>
  367. {
  368. typedef single_precision type;
  369. };
  370. template<> struct size_to_precision<8, true>
  371. {
  372. typedef double_precision type;
  373. };
  374. template<> struct size_to_precision<10, true>
  375. {
  376. typedef extended_double_precision type;
  377. };
  378. template<> struct size_to_precision<12, true>
  379. {
  380. typedef extended_double_precision type;
  381. };
  382. template<> struct size_to_precision<16, true>
  383. {
  384. typedef extended_double_precision type;
  385. };
  386. //------------------------------------------------------------------------------
  387. //
  388. // Figure out whether to use native classification functions based on
  389. // whether T is a built in floating point type or not:
  390. //
  391. template <class T>
  392. struct select_native
  393. {
  394. typedef BOOST_DEDUCED_TYPENAME size_to_precision<sizeof(T), ::boost::is_floating_point<T>::value>::type precision;
  395. typedef fp_traits_non_native<T, precision> type;
  396. };
  397. template<>
  398. struct select_native<float>
  399. {
  400. typedef fp_traits_native<float> type;
  401. };
  402. template<>
  403. struct select_native<double>
  404. {
  405. typedef fp_traits_native<double> type;
  406. };
  407. template<>
  408. struct select_native<long double>
  409. {
  410. typedef fp_traits_native<long double> type;
  411. };
  412. //------------------------------------------------------------------------------
  413. // fp_traits is a type switch that selects the right fp_traits_non_native
  414. #if (defined(BOOST_MATH_USE_C99) && !(defined(__GNUC__) && (__GNUC__ < 4))) \
  415. && !defined(__hpux) \
  416. && !defined(__DECCXX)\
  417. && !defined(__osf__) \
  418. && !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION)\
  419. && !defined(__FAST_MATH__)\
  420. && !defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY)\
  421. && !defined(BOOST_INTEL)\
  422. && !defined(sun)\
  423. && !defined(__VXWORKS__)
  424. # define BOOST_MATH_USE_STD_FPCLASSIFY
  425. #endif
  426. template<class T> struct fp_traits
  427. {
  428. typedef BOOST_DEDUCED_TYPENAME size_to_precision<sizeof(T), ::boost::is_floating_point<T>::value>::type precision;
  429. #if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && !defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY)
  430. typedef typename select_native<T>::type type;
  431. #else
  432. typedef fp_traits_non_native<T, precision> type;
  433. #endif
  434. typedef fp_traits_non_native<T, precision> sign_change_type;
  435. };
  436. //------------------------------------------------------------------------------
  437. } // namespace detail
  438. } // namespace math
  439. } // namespace boost
  440. #endif