Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:40:04

0001 // fp_traits.hpp
0002 
0003 #ifndef BOOST_MATH_FP_TRAITS_HPP
0004 #define BOOST_MATH_FP_TRAITS_HPP
0005 
0006 // Copyright (c) 2006 Johan Rade
0007 
0008 // Distributed under the Boost Software License, Version 1.0.
0009 // (See accompanying file LICENSE_1_0.txt
0010 // or copy at http://www.boost.org/LICENSE_1_0.txt)
0011 
0012 /*
0013 To support old compilers, care has been taken to avoid partial template
0014 specialization and meta function forwarding.
0015 With these techniques, the code could be simplified.
0016 */
0017 
0018 #if defined(__vms) && defined(__DECCXX) && !__IEEE_FLOAT
0019 // The VAX floating point formats are used (for float and double)
0020 #   define BOOST_FPCLASSIFY_VAX_FORMAT
0021 #endif
0022 
0023 #include <cstring>
0024 #include <cstdint>
0025 #include <limits>
0026 #include <type_traits>
0027 #include <boost/math/tools/is_standalone.hpp>
0028 #include <boost/math/tools/assert.hpp>
0029 
0030 // Determine endianness
0031 #ifndef BOOST_MATH_STANDALONE
0032 
0033 #include <boost/predef/other/endian.h>
0034 #define BOOST_MATH_ENDIAN_BIG_BYTE BOOST_ENDIAN_BIG_BYTE
0035 #define BOOST_MATH_ENDIAN_LITTLE_BYTE BOOST_ENDIAN_LITTLE_BYTE
0036 
0037 #elif (__cplusplus >= 202002L || _MSVC_LANG >= 202002L)
0038 
0039 #if __has_include(<bit>)
0040 #include <bit>
0041 #define BOOST_MATH_ENDIAN_BIG_BYTE (std::endian::native == std::endian::big)
0042 #define BOOST_MATH_ENDIAN_LITTLE_BYTE (std::endian::native == std::endian::little)
0043 #else
0044 #error Missing <bit> header. Please disable standalone mode, and file an issue at https://github.com/boostorg/math
0045 #endif
0046 
0047 #elif defined(_WIN32)
0048 
0049 #define BOOST_MATH_ENDIAN_BIG_BYTE 0
0050 #define BOOST_MATH_ENDIAN_LITTLE_BYTE 1
0051 
0052 #elif defined(__BYTE_ORDER__)
0053 
0054 #define BOOST_MATH_ENDIAN_BIG_BYTE (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
0055 #define BOOST_MATH_ENDIAN_LITTLE_BYTE (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
0056 
0057 #else
0058 #error Could not determine endian type. Please disable standalone mode, and file an issue at https://github.com/boostorg/math
0059 #endif // Determine endianness
0060 
0061 static_assert((BOOST_MATH_ENDIAN_BIG_BYTE || BOOST_MATH_ENDIAN_LITTLE_BYTE)
0062     && !(BOOST_MATH_ENDIAN_BIG_BYTE && BOOST_MATH_ENDIAN_LITTLE_BYTE),
0063     "Inconsistent endianness detected. Please disable standalone mode, and file an issue at https://github.com/boostorg/math");
0064 
0065 #ifdef BOOST_NO_STDC_NAMESPACE
0066   namespace std{ using ::memcpy; }
0067 #endif
0068 
0069 #ifndef FP_NORMAL
0070 
0071 #define FP_ZERO        0
0072 #define FP_NORMAL      1
0073 #define FP_INFINITE    2
0074 #define FP_NAN         3
0075 #define FP_SUBNORMAL   4
0076 
0077 #else
0078 
0079 #define BOOST_HAS_FPCLASSIFY
0080 
0081 #ifndef fpclassify
0082 #  if (defined(__GLIBCPP__) || defined(__GLIBCXX__)) \
0083          && defined(_GLIBCXX_USE_C99_MATH) \
0084          && !(defined(_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC) \
0085          && (_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC != 0))
0086 #     ifdef _STLP_VENDOR_CSTD
0087 #        if _STLPORT_VERSION >= 0x520
0088 #           define BOOST_FPCLASSIFY_PREFIX ::__std_alias::
0089 #        else
0090 #           define BOOST_FPCLASSIFY_PREFIX ::_STLP_VENDOR_CSTD::
0091 #        endif
0092 #     else
0093 #        define BOOST_FPCLASSIFY_PREFIX ::std::
0094 #     endif
0095 #  else
0096 #     undef BOOST_HAS_FPCLASSIFY
0097 #     define BOOST_FPCLASSIFY_PREFIX
0098 #  endif
0099 #elif (defined(__HP_aCC) && !defined(__hppa))
0100 // aCC 6 appears to do "#define fpclassify fpclassify" which messes us up a bit!
0101 #  define BOOST_FPCLASSIFY_PREFIX ::
0102 #else
0103 #  define BOOST_FPCLASSIFY_PREFIX
0104 #endif
0105 
0106 #ifdef __MINGW32__
0107 #  undef BOOST_HAS_FPCLASSIFY
0108 #endif
0109 
0110 #endif
0111 
0112 
0113 //------------------------------------------------------------------------------
0114 
0115 namespace boost {
0116 namespace math {
0117 namespace detail {
0118 
0119 //------------------------------------------------------------------------------
0120 
0121 /*
0122 The following classes are used to tag the different methods that are used
0123 for floating point classification
0124 */
0125 
0126 struct native_tag {};
0127 template <bool has_limits>
0128 struct generic_tag {};
0129 struct ieee_tag {};
0130 struct ieee_copy_all_bits_tag : public ieee_tag {};
0131 struct ieee_copy_leading_bits_tag : public ieee_tag {};
0132 
0133 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
0134 //
0135 // These helper functions are used only when numeric_limits<>
0136 // members are not compile time constants:
0137 //
0138 inline bool is_generic_tag_false(const generic_tag<false>*)
0139 {
0140    return true;
0141 }
0142 inline bool is_generic_tag_false(const void*)
0143 {
0144    return false;
0145 }
0146 #endif
0147 
0148 //------------------------------------------------------------------------------
0149 
0150 /*
0151 Most processors support three different floating point precisions:
0152 single precision (32 bits), double precision (64 bits)
0153 and extended double precision (80 - 128 bits, depending on the processor)
0154 
0155 Note that the C++ type long double can be implemented
0156 both as double precision and extended double precision.
0157 */
0158 
0159 struct unknown_precision{};
0160 struct single_precision {};
0161 struct double_precision {};
0162 struct extended_double_precision {};
0163 
0164 // native_tag version --------------------------------------------------------------
0165 
0166 template<class T> struct fp_traits_native
0167 {
0168     typedef native_tag method;
0169 };
0170 
0171 // generic_tag version -------------------------------------------------------------
0172 
0173 template<class T, class U> struct fp_traits_non_native
0174 {
0175 #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
0176    typedef generic_tag<std::numeric_limits<T>::is_specialized> method;
0177 #else
0178    typedef generic_tag<false> method;
0179 #endif
0180 };
0181 
0182 // ieee_tag versions ---------------------------------------------------------------
0183 
0184 /*
0185 These specializations of fp_traits_non_native contain information needed
0186 to "parse" the binary representation of a floating point number.
0187 
0188 Typedef members:
0189 
0190   bits -- the target type when copying the leading bytes of a floating
0191       point number. It is a typedef for uint32_t or uint64_t.
0192 
0193   method -- tells us whether all bytes are copied or not.
0194       It is a typedef for ieee_copy_all_bits_tag or ieee_copy_leading_bits_tag.
0195 
0196 Static data members:
0197 
0198   sign, exponent, flag, significand -- bit masks that give the meaning of the
0199   bits in the leading bytes.
0200 
0201 Static function members:
0202 
0203   get_bits(), set_bits() -- provide access to the leading bytes.
0204 
0205 */
0206 
0207 // ieee_tag version, float (32 bits) -----------------------------------------------
0208 
0209 #ifndef BOOST_FPCLASSIFY_VAX_FORMAT
0210 
0211 template<> struct fp_traits_non_native<float, single_precision>
0212 {
0213     typedef ieee_copy_all_bits_tag method;
0214 
0215     static constexpr uint32_t sign        = 0x80000000u;
0216     static constexpr uint32_t exponent    = 0x7f800000;
0217     static constexpr uint32_t flag        = 0x00000000;
0218     static constexpr uint32_t significand = 0x007fffff;
0219 
0220     typedef uint32_t bits;
0221     static void get_bits(float x, uint32_t& a) { std::memcpy(&a, &x, 4); }
0222     static void set_bits(float& x, uint32_t a) { std::memcpy(&x, &a, 4); }
0223 };
0224 
0225 // ieee_tag version, double (64 bits) ----------------------------------------------
0226 
0227 #if defined(BOOST_NO_INT64_T) || defined(BOOST_NO_INCLASS_MEMBER_INITIALIZATION) \
0228    || defined(BOOST_BORLANDC) || defined(__CODEGEAR__)
0229 
0230 template<> struct fp_traits_non_native<double, double_precision>
0231 {
0232     typedef ieee_copy_leading_bits_tag method;
0233 
0234     static constexpr uint32_t sign        = 0x80000000u;
0235     static constexpr uint32_t exponent    = 0x7ff00000;
0236     static constexpr uint32_t flag        = 0;
0237     static constexpr uint32_t significand = 0x000fffff;
0238 
0239     typedef uint32_t bits;
0240 
0241     static void get_bits(double x, uint32_t& a)
0242     {
0243         std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);
0244     }
0245 
0246     static void set_bits(double& x, uint32_t a)
0247     {
0248         std::memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4);
0249     }
0250 
0251 private:
0252     static constexpr int offset_ = BOOST_MATH_ENDIAN_BIG_BYTE ? 0 : 4;
0253 };
0254 
0255 //..............................................................................
0256 
0257 #else
0258 
0259 template<> struct fp_traits_non_native<double, double_precision>
0260 {
0261     typedef ieee_copy_all_bits_tag method;
0262 
0263     static constexpr uint64_t sign     = static_cast<uint64_t>(0x80000000u) << 32;
0264     static constexpr uint64_t exponent = static_cast<uint64_t>(0x7ff00000) << 32;
0265     static constexpr uint64_t flag     = 0;
0266     static constexpr uint64_t significand
0267         = (static_cast<uint64_t>(0x000fffff) << 32) + static_cast<uint64_t>(0xffffffffu);
0268 
0269     typedef uint64_t bits;
0270     static void get_bits(double x, uint64_t& a) { std::memcpy(&a, &x, 8); }
0271     static void set_bits(double& x, uint64_t a) { std::memcpy(&x, &a, 8); }
0272 };
0273 
0274 #endif
0275 
0276 #endif  // #ifndef BOOST_FPCLASSIFY_VAX_FORMAT
0277 
0278 // long double (64 bits) -------------------------------------------------------
0279 
0280 #if defined(BOOST_NO_INT64_T) || defined(BOOST_NO_INCLASS_MEMBER_INITIALIZATION)\
0281    || defined(BOOST_BORLANDC) || defined(__CODEGEAR__)
0282 
0283 template<> struct fp_traits_non_native<long double, double_precision>
0284 {
0285     typedef ieee_copy_leading_bits_tag method;
0286 
0287     static constexpr uint32_t sign        = 0x80000000u;
0288     static constexpr uint32_t exponent    = 0x7ff00000;
0289     static constexpr uint32_t flag        = 0;
0290     static constexpr uint32_t significand = 0x000fffff;
0291 
0292     typedef uint32_t bits;
0293 
0294     static void get_bits(long double x, uint32_t& a)
0295     {
0296         std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);
0297     }
0298 
0299     static void set_bits(long double& x, uint32_t a)
0300     {
0301         std::memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4);
0302     }
0303 
0304 private:
0305     static constexpr int offset_ = BOOST_MATH_ENDIAN_BIG_BYTE ? 0 : 4;
0306 };
0307 
0308 //..............................................................................
0309 
0310 #else
0311 
0312 template<> struct fp_traits_non_native<long double, double_precision>
0313 {
0314     typedef ieee_copy_all_bits_tag method;
0315 
0316     static const uint64_t sign     = static_cast<uint64_t>(0x80000000u) << 32;
0317     static const uint64_t exponent = static_cast<uint64_t>(0x7ff00000) << 32;
0318     static const uint64_t flag     = 0;
0319     static const uint64_t significand
0320         = (static_cast<uint64_t>(0x000fffff) << 32) + static_cast<uint64_t>(0xffffffffu);
0321 
0322     typedef uint64_t bits;
0323     static void get_bits(long double x, uint64_t& a) { std::memcpy(&a, &x, 8); }
0324     static void set_bits(long double& x, uint64_t a) { std::memcpy(&x, &a, 8); }
0325 };
0326 
0327 #endif
0328 
0329 
0330 // long double (>64 bits), x86 and x64 -----------------------------------------
0331 
0332 #if defined(__i386) || defined(__i386__) || defined(_M_IX86) \
0333     || defined(__amd64) || defined(__amd64__)  || defined(_M_AMD64) \
0334     || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64)
0335 
0336 // Intel extended double precision format (80 bits)
0337 
0338 template<>
0339 struct fp_traits_non_native<long double, extended_double_precision>
0340 {
0341     typedef ieee_copy_leading_bits_tag method;
0342 
0343     static constexpr uint32_t sign        = 0x80000000u;
0344     static constexpr uint32_t exponent    = 0x7fff0000;
0345     static constexpr uint32_t flag        = 0x00008000;
0346     static constexpr uint32_t significand = 0x00007fff;
0347 
0348     typedef uint32_t bits;
0349 
0350     static void get_bits(long double x, uint32_t& a)
0351     {
0352         std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + 6, 4);
0353     }
0354 
0355     static void set_bits(long double& x, uint32_t a)
0356     {
0357         std::memcpy(reinterpret_cast<unsigned char*>(&x) + 6, &a, 4);
0358     }
0359 };
0360 
0361 
0362 // long double (>64 bits), Itanium ---------------------------------------------
0363 
0364 #elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
0365 
0366 // The floating point format is unknown at compile time
0367 // No template specialization is provided.
0368 // The generic_tag definition is used.
0369 
0370 // The Itanium supports both
0371 // the Intel extended double precision format (80 bits) and
0372 // the IEEE extended double precision format with 15 exponent bits (128 bits).
0373 
0374 #elif defined(__GNUC__) && (LDBL_MANT_DIG == 106)
0375 
0376 //
0377 // Define nothing here and fall though to generic_tag:
0378 // We have GCC's "double double" in effect, and any attempt
0379 // to handle it via bit-fiddling is pretty much doomed to fail...
0380 //
0381 
0382 // long double (>64 bits), PowerPC ---------------------------------------------
0383 
0384 #elif defined(__powerpc) || defined(__powerpc__) || defined(__POWERPC__) \
0385     || defined(__ppc) || defined(__ppc__) || defined(__PPC__)
0386 
0387 // PowerPC extended double precision format (128 bits)
0388 
0389 template<>
0390 struct fp_traits_non_native<long double, extended_double_precision>
0391 {
0392     typedef ieee_copy_leading_bits_tag method;
0393 
0394     static constexpr uint32_t sign        = 0x80000000u;
0395     static constexpr uint32_t exponent    = 0x7ff00000;
0396     static constexpr uint32_t flag        = 0x00000000;
0397     static constexpr uint32_t significand = 0x000fffff;
0398 
0399     typedef uint32_t bits;
0400 
0401     static void get_bits(long double x, uint32_t& a)
0402     {
0403         std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);
0404     }
0405 
0406     static void set_bits(long double& x, uint32_t a)
0407     {
0408         std::memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4);
0409     }
0410 
0411 private:
0412     static constexpr int offset_ = BOOST_MATH_ENDIAN_BIG_BYTE ? 0 : 12;
0413 };
0414 
0415 
0416 // long double (>64 bits), Motorola 68K ----------------------------------------
0417 
0418 #elif defined(__m68k) || defined(__m68k__) \
0419     || defined(__mc68000) || defined(__mc68000__) \
0420 
0421 // Motorola extended double precision format (96 bits)
0422 
0423 // It is the same format as the Intel extended double precision format,
0424 // except that 1) it is big-endian, 2) the 3rd and 4th byte are padding, and
0425 // 3) the flag bit is not set for infinity
0426 
0427 template<>
0428 struct fp_traits_non_native<long double, extended_double_precision>
0429 {
0430     typedef ieee_copy_leading_bits_tag method;
0431 
0432     static constexpr uint32_t sign        = 0x80000000u;
0433     static constexpr uint32_t exponent    = 0x7fff0000;
0434     static constexpr uint32_t flag        = 0x00008000;
0435     static constexpr uint32_t significand = 0x00007fff;
0436 
0437     // copy 1st, 2nd, 5th and 6th byte. 3rd and 4th byte are padding.
0438 
0439     typedef uint32_t bits;
0440 
0441     static void get_bits(long double x, uint32_t& a)
0442     {
0443         std::memcpy(&a, &x, 2);
0444         std::memcpy(reinterpret_cast<unsigned char*>(&a) + 2,
0445                reinterpret_cast<const unsigned char*>(&x) + 4, 2);
0446     }
0447 
0448     static void set_bits(long double& x, uint32_t a)
0449     {
0450         std::memcpy(&x, &a, 2);
0451         std::memcpy(reinterpret_cast<unsigned char*>(&x) + 4,
0452                reinterpret_cast<const unsigned char*>(&a) + 2, 2);
0453     }
0454 };
0455 
0456 
0457 // long double (>64 bits), All other processors --------------------------------
0458 
0459 #else
0460 
0461 // IEEE extended double precision format with 15 exponent bits (128 bits)
0462 
0463 template<>
0464 struct fp_traits_non_native<long double, extended_double_precision>
0465 {
0466     typedef ieee_copy_leading_bits_tag method;
0467 
0468     static constexpr uint32_t sign        = 0x80000000u;
0469     static constexpr uint32_t exponent    = 0x7fff0000;
0470     static constexpr uint32_t flag        = 0x00000000;
0471     static constexpr uint32_t significand = 0x0000ffff;
0472 
0473     typedef uint32_t bits;
0474 
0475     static void get_bits(long double x, uint32_t& a)
0476     {
0477         std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);
0478     }
0479 
0480     static void set_bits(long double& x, uint32_t a)
0481     {
0482         std::memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4);
0483     }
0484 
0485 private:
0486     static constexpr int offset_ = BOOST_MATH_ENDIAN_BIG_BYTE ? 0 : 12;
0487 };
0488 
0489 #endif
0490 
0491 //------------------------------------------------------------------------------
0492 
0493 // size_to_precision is a type switch for converting a C++ floating point type
0494 // to the corresponding precision type.
0495 
0496 template<size_t n, bool fp> struct size_to_precision
0497 {
0498    typedef unknown_precision type;
0499 };
0500 
0501 template<> struct size_to_precision<4, true>
0502 {
0503     typedef single_precision type;
0504 };
0505 
0506 template<> struct size_to_precision<8, true>
0507 {
0508     typedef double_precision type;
0509 };
0510 
0511 template<> struct size_to_precision<10, true>
0512 {
0513     typedef extended_double_precision type;
0514 };
0515 
0516 template<> struct size_to_precision<12, true>
0517 {
0518     typedef extended_double_precision type;
0519 };
0520 
0521 template<> struct size_to_precision<16, true>
0522 {
0523     typedef extended_double_precision type;
0524 };
0525 
0526 //------------------------------------------------------------------------------
0527 //
0528 // Figure out whether to use native classification functions based on
0529 // whether T is a built in floating point type or not:
0530 //
0531 template <class T>
0532 struct select_native
0533 {
0534     typedef typename size_to_precision<sizeof(T), ::std::is_floating_point<T>::value>::type precision;
0535     typedef fp_traits_non_native<T, precision> type;
0536 };
0537 template<>
0538 struct select_native<float>
0539 {
0540     typedef fp_traits_native<float> type;
0541 };
0542 template<>
0543 struct select_native<double>
0544 {
0545     typedef fp_traits_native<double> type;
0546 };
0547 template<>
0548 struct select_native<long double>
0549 {
0550     typedef fp_traits_native<long double> type;
0551 };
0552 
0553 //------------------------------------------------------------------------------
0554 
0555 // fp_traits is a type switch that selects the right fp_traits_non_native
0556 
0557 #if (defined(BOOST_MATH_USE_C99) && !(defined(__GNUC__) && (__GNUC__ < 4))) \
0558    && !defined(__hpux) \
0559    && !defined(__DECCXX)\
0560    && !defined(__osf__) \
0561    && !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION)\
0562    && !defined(__FAST_MATH__)\
0563    && !defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY)\
0564    && !defined(__INTEL_COMPILER)\
0565    && !defined(sun)\
0566    && !defined(__VXWORKS__)
0567 #  define BOOST_MATH_USE_STD_FPCLASSIFY
0568 #endif
0569 
0570 template<class T> struct fp_traits
0571 {
0572     typedef typename size_to_precision<sizeof(T), ::std::is_floating_point<T>::value>::type precision;
0573 #if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && !defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY)
0574     typedef typename select_native<T>::type type;
0575 #else
0576     typedef fp_traits_non_native<T, precision> type;
0577 #endif
0578     typedef fp_traits_non_native<T, precision> sign_change_type;
0579 };
0580 
0581 //------------------------------------------------------------------------------
0582 
0583 }   // namespace detail
0584 }   // namespace math
0585 }   // namespace boost
0586 
0587 #endif