fp_traits.hpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  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/detail/endian.hpp>
  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 defined(BOOST_BIG_ENDIAN)
  166. BOOST_STATIC_CONSTANT(int, offset_ = 0);
  167. #elif defined(BOOST_LITTLE_ENDIAN)
  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 defined(BOOST_BIG_ENDIAN)
  210. BOOST_STATIC_CONSTANT(int, offset_ = 0);
  211. #elif defined(BOOST_LITTLE_ENDIAN)
  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. // long double (>64 bits), PowerPC ---------------------------------------------
  264. #elif defined(__powerpc) || defined(__powerpc__) || defined(__POWERPC__) \
  265. || defined(__ppc) || defined(__ppc__) || defined(__PPC__)
  266. // PowerPC extended double precision format (128 bits)
  267. template<>
  268. struct fp_traits_non_native<long double, extended_double_precision>
  269. {
  270. typedef ieee_copy_leading_bits_tag method;
  271. BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u);
  272. BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7ff00000);
  273. BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00000000);
  274. BOOST_STATIC_CONSTANT(uint32_t, significand = 0x000fffff);
  275. typedef uint32_t bits;
  276. static void get_bits(long double x, uint32_t& a)
  277. {
  278. std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);
  279. }
  280. static void set_bits(long double& x, uint32_t a)
  281. {
  282. std::memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4);
  283. }
  284. private:
  285. #if defined(BOOST_BIG_ENDIAN)
  286. BOOST_STATIC_CONSTANT(int, offset_ = 0);
  287. #elif defined(BOOST_LITTLE_ENDIAN)
  288. BOOST_STATIC_CONSTANT(int, offset_ = 12);
  289. #else
  290. BOOST_STATIC_ASSERT(false);
  291. #endif
  292. };
  293. // long double (>64 bits), Motorola 68K ----------------------------------------
  294. #elif defined(__m68k) || defined(__m68k__) \
  295. || defined(__mc68000) || defined(__mc68000__) \
  296. // Motorola extended double precision format (96 bits)
  297. // It is the same format as the Intel extended double precision format,
  298. // except that 1) it is big-endian, 2) the 3rd and 4th byte are padding, and
  299. // 3) the flag bit is not set for infinity
  300. template<>
  301. struct fp_traits_non_native<long double, extended_double_precision>
  302. {
  303. typedef ieee_copy_leading_bits_tag method;
  304. BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u);
  305. BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7fff0000);
  306. BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00008000);
  307. BOOST_STATIC_CONSTANT(uint32_t, significand = 0x00007fff);
  308. // copy 1st, 2nd, 5th and 6th byte. 3rd and 4th byte are padding.
  309. typedef uint32_t bits;
  310. static void get_bits(long double x, uint32_t& a)
  311. {
  312. std::memcpy(&a, &x, 2);
  313. std::memcpy(reinterpret_cast<unsigned char*>(&a) + 2,
  314. reinterpret_cast<const unsigned char*>(&x) + 4, 2);
  315. }
  316. static void set_bits(long double& x, uint32_t a)
  317. {
  318. std::memcpy(&x, &a, 2);
  319. std::memcpy(reinterpret_cast<unsigned char*>(&x) + 4,
  320. reinterpret_cast<const unsigned char*>(&a) + 2, 2);
  321. }
  322. };
  323. // long double (>64 bits), All other processors --------------------------------
  324. #else
  325. // IEEE extended double precision format with 15 exponent bits (128 bits)
  326. template<>
  327. struct fp_traits_non_native<long double, extended_double_precision>
  328. {
  329. typedef ieee_copy_leading_bits_tag method;
  330. BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u);
  331. BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7fff0000);
  332. BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00000000);
  333. BOOST_STATIC_CONSTANT(uint32_t, significand = 0x0000ffff);
  334. typedef uint32_t bits;
  335. static void get_bits(long double x, uint32_t& a)
  336. {
  337. std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);
  338. }
  339. static void set_bits(long double& x, uint32_t a)
  340. {
  341. std::memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4);
  342. }
  343. private:
  344. #if defined(BOOST_BIG_ENDIAN)
  345. BOOST_STATIC_CONSTANT(int, offset_ = 0);
  346. #elif defined(BOOST_LITTLE_ENDIAN)
  347. BOOST_STATIC_CONSTANT(int, offset_ = 12);
  348. #else
  349. BOOST_STATIC_ASSERT(false);
  350. #endif
  351. };
  352. #endif
  353. //------------------------------------------------------------------------------
  354. // size_to_precision is a type switch for converting a C++ floating point type
  355. // to the corresponding precision type.
  356. template<int n, bool fp> struct size_to_precision
  357. {
  358. typedef unknown_precision type;
  359. };
  360. template<> struct size_to_precision<4, true>
  361. {
  362. typedef single_precision type;
  363. };
  364. template<> struct size_to_precision<8, true>
  365. {
  366. typedef double_precision type;
  367. };
  368. template<> struct size_to_precision<10, true>
  369. {
  370. typedef extended_double_precision type;
  371. };
  372. template<> struct size_to_precision<12, true>
  373. {
  374. typedef extended_double_precision type;
  375. };
  376. template<> struct size_to_precision<16, true>
  377. {
  378. typedef extended_double_precision type;
  379. };
  380. //------------------------------------------------------------------------------
  381. //
  382. // Figure out whether to use native classification functions based on
  383. // whether T is a built in floating point type or not:
  384. //
  385. template <class T>
  386. struct select_native
  387. {
  388. typedef BOOST_DEDUCED_TYPENAME size_to_precision<sizeof(T), ::boost::is_floating_point<T>::value>::type precision;
  389. typedef fp_traits_non_native<T, precision> type;
  390. };
  391. template<>
  392. struct select_native<float>
  393. {
  394. typedef fp_traits_native<float> type;
  395. };
  396. template<>
  397. struct select_native<double>
  398. {
  399. typedef fp_traits_native<double> type;
  400. };
  401. template<>
  402. struct select_native<long double>
  403. {
  404. typedef fp_traits_native<long double> type;
  405. };
  406. //------------------------------------------------------------------------------
  407. // fp_traits is a type switch that selects the right fp_traits_non_native
  408. #if (defined(BOOST_MATH_USE_C99) && !(defined(__GNUC__) && (__GNUC__ < 4))) \
  409. && !defined(__hpux) \
  410. && !defined(__DECCXX)\
  411. && !defined(__osf__) \
  412. && !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION)\
  413. && !defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY)
  414. # define BOOST_MATH_USE_STD_FPCLASSIFY
  415. #endif
  416. template<class T> struct fp_traits
  417. {
  418. typedef BOOST_DEDUCED_TYPENAME size_to_precision<sizeof(T), ::boost::is_floating_point<T>::value>::type precision;
  419. #if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && !defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY)
  420. typedef typename select_native<T>::type type;
  421. #else
  422. typedef fp_traits_non_native<T, precision> type;
  423. #endif
  424. typedef fp_traits_non_native<T, precision> sign_change_type;
  425. };
  426. //------------------------------------------------------------------------------
  427. } // namespace detail
  428. } // namespace math
  429. } // namespace boost
  430. #endif