fp_traits.hpp 17 KB

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