Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-16 08:38:32

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