Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-06 09:00:33

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__) || (defined(__APPLE__) && defined(__aarch64__)) || defined(_MSC_VER)
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 // long double (>64 bits), x86 and x64 -----------------------------------------
0301 
0302 #elif defined(__i386) || defined(__i386__) || defined(_M_IX86) \
0303     || defined(__amd64) || defined(__amd64__)  || defined(_M_AMD64) \
0304     || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64)
0305 
0306 // Intel extended double precision format (80 bits)
0307 
0308 template<>
0309 struct fp_traits_non_native<long double, extended_double_precision>
0310 {
0311     typedef ieee_copy_leading_bits_tag method;
0312 
0313     BOOST_MATH_STATIC constexpr uint32_t sign        = 0x80000000u;
0314     BOOST_MATH_STATIC constexpr uint32_t exponent    = 0x7fff0000;
0315     BOOST_MATH_STATIC constexpr uint32_t flag        = 0x00008000;
0316     BOOST_MATH_STATIC constexpr uint32_t significand = 0x00007fff;
0317 
0318     typedef uint32_t bits;
0319 
0320     static void get_bits(long double x, uint32_t& a)
0321     {
0322         std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + 6, 4);
0323     }
0324 
0325     static void set_bits(long double& x, uint32_t a)
0326     {
0327         std::memcpy(reinterpret_cast<unsigned char*>(&x) + 6, &a, 4);
0328     }
0329 };
0330 
0331 
0332 // long double (>64 bits), Itanium ---------------------------------------------
0333 
0334 #elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
0335 
0336 // The floating point format is unknown at compile time
0337 // No template specialization is provided.
0338 // The generic_tag definition is used.
0339 
0340 // The Itanium supports both
0341 // the Intel extended double precision format (80 bits) and
0342 // the IEEE extended double precision format with 15 exponent bits (128 bits).
0343 
0344 #elif defined(__GNUC__) && (LDBL_MANT_DIG == 106)
0345 
0346 //
0347 // Define nothing here and fall though to generic_tag:
0348 // We have GCC's "double double" in effect, and any attempt
0349 // to handle it via bit-fiddling is pretty much doomed to fail...
0350 //
0351 
0352 // long double (>64 bits), PowerPC ---------------------------------------------
0353 
0354 #elif defined(__powerpc) || defined(__powerpc__) || defined(__POWERPC__) \
0355     || defined(__ppc) || defined(__ppc__) || defined(__PPC__)
0356 
0357 // PowerPC extended double precision format (128 bits)
0358 
0359 template<>
0360 struct fp_traits_non_native<long double, extended_double_precision>
0361 {
0362     typedef ieee_copy_leading_bits_tag method;
0363 
0364     BOOST_MATH_STATIC constexpr uint32_t sign        = 0x80000000u;
0365     BOOST_MATH_STATIC constexpr uint32_t exponent    = 0x7ff00000;
0366     BOOST_MATH_STATIC constexpr uint32_t flag        = 0x00000000;
0367     BOOST_MATH_STATIC constexpr uint32_t significand = 0x000fffff;
0368 
0369     typedef uint32_t bits;
0370 
0371     static void get_bits(long double x, uint32_t& a)
0372     {
0373         std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);
0374     }
0375 
0376     static void set_bits(long double& x, uint32_t a)
0377     {
0378         std::memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4);
0379     }
0380 
0381 private:
0382     BOOST_MATH_STATIC constexpr int offset_ = BOOST_MATH_ENDIAN_BIG_BYTE ? 0 : 12;
0383 };
0384 
0385 
0386 // long double (>64 bits), Motorola 68K ----------------------------------------
0387 
0388 #elif defined(__m68k) || defined(__m68k__) \
0389     || defined(__mc68000) || defined(__mc68000__) \
0390 
0391 // Motorola extended double precision format (96 bits)
0392 
0393 // It is the same format as the Intel extended double precision format,
0394 // except that 1) it is big-endian, 2) the 3rd and 4th byte are padding, and
0395 // 3) the flag bit is not set for infinity
0396 
0397 template<>
0398 struct fp_traits_non_native<long double, extended_double_precision>
0399 {
0400     typedef ieee_copy_leading_bits_tag method;
0401 
0402     BOOST_MATH_STATIC constexpr uint32_t sign        = 0x80000000u;
0403     BOOST_MATH_STATIC constexpr uint32_t exponent    = 0x7fff0000;
0404     BOOST_MATH_STATIC constexpr uint32_t flag        = 0x00008000;
0405     BOOST_MATH_STATIC constexpr uint32_t significand = 0x00007fff;
0406 
0407     // copy 1st, 2nd, 5th and 6th byte. 3rd and 4th byte are padding.
0408 
0409     typedef uint32_t bits;
0410 
0411     static void get_bits(long double x, uint32_t& a)
0412     {
0413         std::memcpy(&a, &x, 2);
0414         std::memcpy(reinterpret_cast<unsigned char*>(&a) + 2,
0415                reinterpret_cast<const unsigned char*>(&x) + 4, 2);
0416     }
0417 
0418     static void set_bits(long double& x, uint32_t a)
0419     {
0420         std::memcpy(&x, &a, 2);
0421         std::memcpy(reinterpret_cast<unsigned char*>(&x) + 4,
0422                reinterpret_cast<const unsigned char*>(&a) + 2, 2);
0423     }
0424 };
0425 
0426 
0427 // long double (>64 bits), All other processors --------------------------------
0428 
0429 #else
0430 
0431 // IEEE extended double precision format with 15 exponent bits (128 bits)
0432 
0433 template<>
0434 struct fp_traits_non_native<long double, extended_double_precision>
0435 {
0436     typedef ieee_copy_leading_bits_tag method;
0437 
0438     BOOST_MATH_STATIC constexpr uint32_t sign        = 0x80000000u;
0439     BOOST_MATH_STATIC constexpr uint32_t exponent    = 0x7fff0000;
0440     BOOST_MATH_STATIC constexpr uint32_t flag        = 0x00000000;
0441     BOOST_MATH_STATIC constexpr uint32_t significand = 0x0000ffff;
0442 
0443     typedef uint32_t bits;
0444 
0445     static void get_bits(long double x, uint32_t& a)
0446     {
0447         std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);
0448     }
0449 
0450     static void set_bits(long double& x, uint32_t a)
0451     {
0452         std::memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4);
0453     }
0454 
0455 private:
0456     BOOST_MATH_STATIC constexpr int offset_ = BOOST_MATH_ENDIAN_BIG_BYTE ? 0 : 12;
0457 };
0458 
0459 #endif
0460 
0461 //------------------------------------------------------------------------------
0462 
0463 // size_to_precision is a type switch for converting a C++ floating point type
0464 // to the corresponding precision type.
0465 
0466 template<size_t n, bool fp> struct size_to_precision
0467 {
0468    typedef unknown_precision type;
0469 };
0470 
0471 template<> struct size_to_precision<4, true>
0472 {
0473     typedef single_precision type;
0474 };
0475 
0476 template<> struct size_to_precision<8, true>
0477 {
0478     typedef double_precision type;
0479 };
0480 
0481 template<> struct size_to_precision<10, true>
0482 {
0483     typedef extended_double_precision type;
0484 };
0485 
0486 template<> struct size_to_precision<12, true>
0487 {
0488     typedef extended_double_precision type;
0489 };
0490 
0491 template<> struct size_to_precision<16, true>
0492 {
0493     typedef extended_double_precision type;
0494 };
0495 
0496 //------------------------------------------------------------------------------
0497 //
0498 // Figure out whether to use native classification functions based on
0499 // whether T is a built in floating point type or not:
0500 //
0501 template <class T>
0502 struct select_native
0503 {
0504     typedef typename size_to_precision<sizeof(T), ::std::is_floating_point<T>::value>::type precision;
0505     typedef fp_traits_non_native<T, precision> type;
0506 };
0507 template<>
0508 struct select_native<float>
0509 {
0510     typedef fp_traits_native<float> type;
0511 };
0512 template<>
0513 struct select_native<double>
0514 {
0515     typedef fp_traits_native<double> type;
0516 };
0517 template<>
0518 struct select_native<long double>
0519 {
0520     typedef fp_traits_native<long double> type;
0521 };
0522 
0523 //------------------------------------------------------------------------------
0524 
0525 // fp_traits is a type switch that selects the right fp_traits_non_native
0526 
0527 #if (defined(BOOST_MATH_USE_C99) && !(defined(__GNUC__) && (__GNUC__ < 4))) \
0528    && !defined(__hpux) \
0529    && !defined(__DECCXX)\
0530    && !defined(__osf__) \
0531    && !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION)\
0532    && !defined(__FAST_MATH__)\
0533    && !defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY)\
0534    && !defined(__INTEL_COMPILER)\
0535    && !defined(sun)\
0536    && !defined(__VXWORKS__)\
0537    && !defined(BOOST_MATH_HAS_GPU_SUPPORT)
0538 #  define BOOST_MATH_USE_STD_FPCLASSIFY
0539 #endif
0540 
0541 template<class T> struct fp_traits
0542 {
0543     typedef typename size_to_precision<sizeof(T), ::std::is_floating_point<T>::value>::type precision;
0544 #if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && !defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY)
0545     typedef typename select_native<T>::type type;
0546 #else
0547     typedef fp_traits_non_native<T, precision> type;
0548 #endif
0549     typedef fp_traits_non_native<T, precision> sign_change_type;
0550 };
0551 
0552 //------------------------------------------------------------------------------
0553 
0554 }   // namespace detail
0555 }   // namespace math
0556 }   // namespace boost
0557 
0558 #endif