Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-02 08:17:03

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