brintos

brintos / llvm-project-archived public Read only

0
0
Text · 17.2 KiB · 015ea9c Raw
581 lines · plain
1// fp_traits.hpp2 3#ifndef BOOST_MATH_FP_TRAITS_HPP4#define BOOST_MATH_FP_TRAITS_HPP5 6// Copyright (c) 2006 Johan Rade7// Copyright (c) 2024 Matt Borland8 9// Distributed under the Boost Software License, Version 1.0.10// (See accompanying file LICENSE_1_0.txt11// or copy at http://www.boost.org/LICENSE_1_0.txt)12 13/*14To support old compilers, care has been taken to avoid partial template15specialization and meta function forwarding.16With these techniques, the code could be simplified.17*/18 19#if defined(__vms) && defined(__DECCXX) && !__IEEE_FLOAT20// The VAX floating point formats are used (for float and double)21#   define BOOST_FPCLASSIFY_VAX_FORMAT22#endif23 24#include <cstring>25#include <cstdint>26#include <limits>27#include <type_traits>28#include <boost/math/tools/config.hpp>29#include <boost/math/tools/is_standalone.hpp>30#include <boost/math/tools/assert.hpp>31 32// Determine endianness33#ifndef BOOST_MATH_STANDALONE34 35#include <boost/predef/other/endian.h>36#define BOOST_MATH_ENDIAN_BIG_BYTE BOOST_ENDIAN_BIG_BYTE37#define BOOST_MATH_ENDIAN_LITTLE_BYTE BOOST_ENDIAN_LITTLE_BYTE38 39#elif defined(_WIN32)40 41#define BOOST_MATH_ENDIAN_BIG_BYTE 042#define BOOST_MATH_ENDIAN_LITTLE_BYTE 143 44#elif defined(__BYTE_ORDER__)45 46#define BOOST_MATH_ENDIAN_BIG_BYTE (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)47#define BOOST_MATH_ENDIAN_LITTLE_BYTE (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)48 49#else50#error Could not determine endian type. Please disable standalone mode, and file an issue at https://github.com/boostorg/math51#endif // Determine endianness52 53static_assert((BOOST_MATH_ENDIAN_BIG_BYTE || BOOST_MATH_ENDIAN_LITTLE_BYTE)54    && !(BOOST_MATH_ENDIAN_BIG_BYTE && BOOST_MATH_ENDIAN_LITTLE_BYTE),55    "Inconsistent endianness detected. Please disable standalone mode, and file an issue at https://github.com/boostorg/math");56 57#ifdef BOOST_NO_STDC_NAMESPACE58  namespace std{ using ::memcpy; }59#endif60 61#ifndef FP_NORMAL62 63#define FP_ZERO        064#define FP_NORMAL      165#define FP_INFINITE    266#define FP_NAN         367#define FP_SUBNORMAL   468 69#else70 71#define BOOST_HAS_FPCLASSIFY72 73#ifndef fpclassify74#  if (defined(__GLIBCPP__) || defined(__GLIBCXX__)) \75         && defined(_GLIBCXX_USE_C99_MATH) \76         && !(defined(_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC) \77         && (_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC != 0))78#     ifdef _STLP_VENDOR_CSTD79#        if _STLPORT_VERSION >= 0x52080#           define BOOST_FPCLASSIFY_PREFIX ::__std_alias::81#        else82#           define BOOST_FPCLASSIFY_PREFIX ::_STLP_VENDOR_CSTD::83#        endif84#     else85#        define BOOST_FPCLASSIFY_PREFIX ::std::86#     endif87#  else88#     undef BOOST_HAS_FPCLASSIFY89#     define BOOST_FPCLASSIFY_PREFIX90#  endif91#elif (defined(__HP_aCC) && !defined(__hppa))92// aCC 6 appears to do "#define fpclassify fpclassify" which messes us up a bit!93#  define BOOST_FPCLASSIFY_PREFIX ::94#else95#  define BOOST_FPCLASSIFY_PREFIX96#endif97 98#ifdef __MINGW32__99#  undef BOOST_HAS_FPCLASSIFY100#endif101 102#endif103 104 105//------------------------------------------------------------------------------106 107namespace boost {108namespace math {109namespace detail {110 111//------------------------------------------------------------------------------112 113/*114The following classes are used to tag the different methods that are used115for floating point classification116*/117 118struct native_tag {};119template <bool has_limits>120struct generic_tag {};121struct ieee_tag {};122struct ieee_copy_all_bits_tag : public ieee_tag {};123struct ieee_copy_leading_bits_tag : public ieee_tag {};124 125#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS126//127// These helper functions are used only when numeric_limits<>128// members are not compile time constants:129//130inline bool is_generic_tag_false(const generic_tag<false>*)131{132   return true;133}134inline bool is_generic_tag_false(const void*)135{136   return false;137}138#endif139 140//------------------------------------------------------------------------------141 142/*143Most processors support three different floating point precisions:144single precision (32 bits), double precision (64 bits)145and extended double precision (80 - 128 bits, depending on the processor)146 147Note that the C++ type long double can be implemented148both as double precision and extended double precision.149*/150 151struct unknown_precision{};152struct single_precision {};153struct double_precision {};154struct extended_double_precision {};155 156// native_tag version --------------------------------------------------------------157 158template<class T> struct fp_traits_native159{160    typedef native_tag method;161};162 163// generic_tag version -------------------------------------------------------------164 165template<class T, class U> struct fp_traits_non_native166{167#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS168   typedef generic_tag<std::numeric_limits<T>::is_specialized> method;169#else170   typedef generic_tag<false> method;171#endif172};173 174// ieee_tag versions ---------------------------------------------------------------175 176/*177These specializations of fp_traits_non_native contain information needed178to "parse" the binary representation of a floating point number.179 180Typedef members:181 182  bits -- the target type when copying the leading bytes of a floating183      point number. It is a typedef for uint32_t or uint64_t.184 185  method -- tells us whether all bytes are copied or not.186      It is a typedef for ieee_copy_all_bits_tag or ieee_copy_leading_bits_tag.187 188Static data members:189 190  sign, exponent, flag, significand -- bit masks that give the meaning of the191  bits in the leading bytes.192 193Static function members:194 195  get_bits(), set_bits() -- provide access to the leading bytes.196 197*/198 199// ieee_tag version, float (32 bits) -----------------------------------------------200 201#ifndef BOOST_FPCLASSIFY_VAX_FORMAT202 203template<> struct fp_traits_non_native<float, single_precision>204{205    typedef ieee_copy_all_bits_tag method;206 207    BOOST_MATH_STATIC constexpr uint32_t sign        = 0x80000000u;208    BOOST_MATH_STATIC constexpr uint32_t exponent    = 0x7f800000;209    BOOST_MATH_STATIC constexpr uint32_t flag        = 0x00000000;210    BOOST_MATH_STATIC constexpr uint32_t significand = 0x007fffff;211 212    typedef uint32_t bits;213    BOOST_MATH_GPU_ENABLED static void get_bits(float x, uint32_t& a) { std::memcpy(&a, &x, 4); }214    BOOST_MATH_GPU_ENABLED static void set_bits(float& x, uint32_t a) { std::memcpy(&x, &a, 4); }215};216 217// ieee_tag version, double (64 bits) ----------------------------------------------218 219#if defined(BOOST_NO_INT64_T) || defined(BOOST_NO_INCLASS_MEMBER_INITIALIZATION) \220   || defined(BOOST_BORLANDC) || defined(__CODEGEAR__)221 222template<> struct fp_traits_non_native<double, double_precision>223{224    typedef ieee_copy_leading_bits_tag method;225 226    static constexpr uint32_t sign        = 0x80000000u;227    static constexpr uint32_t exponent    = 0x7ff00000;228    static constexpr uint32_t flag        = 0;229    static constexpr uint32_t significand = 0x000fffff;230 231    typedef uint32_t bits;232 233    static void get_bits(double x, uint32_t& a)234    {235        std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);236    }237 238    static void set_bits(double& x, uint32_t a)239    {240        std::memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4);241    }242 243private:244    static constexpr int offset_ = BOOST_MATH_ENDIAN_BIG_BYTE ? 0 : 4;245};246 247//..............................................................................248 249#else250 251template<> struct fp_traits_non_native<double, double_precision>252{253    typedef ieee_copy_all_bits_tag method;254 255    BOOST_MATH_STATIC constexpr uint64_t sign     = static_cast<uint64_t>(0x80000000u) << 32;256    BOOST_MATH_STATIC constexpr uint64_t exponent = static_cast<uint64_t>(0x7ff00000) << 32;257    BOOST_MATH_STATIC constexpr uint64_t flag     = 0;258    BOOST_MATH_STATIC constexpr uint64_t significand259        = (static_cast<uint64_t>(0x000fffff) << 32) + static_cast<uint64_t>(0xffffffffu);260 261    typedef uint64_t bits;262    BOOST_MATH_GPU_ENABLED static void get_bits(double x, uint64_t& a) { std::memcpy(&a, &x, 8); }263    BOOST_MATH_GPU_ENABLED static void set_bits(double& x, uint64_t a) { std::memcpy(&x, &a, 8); }264};265 266#endif267 268#endif  // #ifndef BOOST_FPCLASSIFY_VAX_FORMAT269 270// long double (64 bits) -------------------------------------------------------271 272#if defined(BOOST_NO_INT64_T) || defined(BOOST_NO_INCLASS_MEMBER_INITIALIZATION)\273   || defined(BOOST_BORLANDC) || defined(__CODEGEAR__)274 275template<> struct fp_traits_non_native<long double, double_precision>276{277    typedef ieee_copy_leading_bits_tag method;278 279    static constexpr uint32_t sign        = 0x80000000u;280    static constexpr uint32_t exponent    = 0x7ff00000;281    static constexpr uint32_t flag        = 0;282    static constexpr uint32_t significand = 0x000fffff;283 284    typedef uint32_t bits;285 286    static void get_bits(long double x, uint32_t& a)287    {288        std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);289    }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 296private:297    static constexpr int offset_ = BOOST_MATH_ENDIAN_BIG_BYTE ? 0 : 4;298};299 300//..............................................................................301 302#else303 304template<> struct fp_traits_non_native<long double, double_precision>305{306    typedef ieee_copy_all_bits_tag method;307 308    static const uint64_t sign     = static_cast<uint64_t>(0x80000000u) << 32;309    static const uint64_t exponent = static_cast<uint64_t>(0x7ff00000) << 32;310    static const uint64_t flag     = 0;311    static const uint64_t significand312        = (static_cast<uint64_t>(0x000fffff) << 32) + static_cast<uint64_t>(0xffffffffu);313 314    typedef uint64_t bits;315    static void get_bits(long double x, uint64_t& a) { std::memcpy(&a, &x, 8); }316    static void set_bits(long double& x, uint64_t a) { std::memcpy(&x, &a, 8); }317};318 319#endif320 321 322// long double (>64 bits), x86 and x64 -----------------------------------------323 324#if defined(__i386) || defined(__i386__) || defined(_M_IX86) \325    || defined(__amd64) || defined(__amd64__)  || defined(_M_AMD64) \326    || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64)327 328// Intel extended double precision format (80 bits)329 330template<>331struct fp_traits_non_native<long double, extended_double_precision>332{333    typedef ieee_copy_leading_bits_tag method;334 335    BOOST_MATH_STATIC constexpr uint32_t sign        = 0x80000000u;336    BOOST_MATH_STATIC constexpr uint32_t exponent    = 0x7fff0000;337    BOOST_MATH_STATIC constexpr uint32_t flag        = 0x00008000;338    BOOST_MATH_STATIC constexpr uint32_t significand = 0x00007fff;339 340    typedef uint32_t bits;341 342    static void get_bits(long double x, uint32_t& a)343    {344        std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + 6, 4);345    }346 347    static void set_bits(long double& x, uint32_t a)348    {349        std::memcpy(reinterpret_cast<unsigned char*>(&x) + 6, &a, 4);350    }351};352 353 354// long double (>64 bits), Itanium ---------------------------------------------355 356#elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64)357 358// The floating point format is unknown at compile time359// No template specialization is provided.360// The generic_tag definition is used.361 362// The Itanium supports both363// the Intel extended double precision format (80 bits) and364// the IEEE extended double precision format with 15 exponent bits (128 bits).365 366#elif defined(__GNUC__) && (LDBL_MANT_DIG == 106)367 368//369// Define nothing here and fall though to generic_tag:370// We have GCC's "double double" in effect, and any attempt371// to handle it via bit-fiddling is pretty much doomed to fail...372//373 374// long double (>64 bits), PowerPC ---------------------------------------------375 376#elif defined(__powerpc) || defined(__powerpc__) || defined(__POWERPC__) \377    || defined(__ppc) || defined(__ppc__) || defined(__PPC__)378 379// PowerPC extended double precision format (128 bits)380 381template<>382struct fp_traits_non_native<long double, extended_double_precision>383{384    typedef ieee_copy_leading_bits_tag method;385 386    BOOST_MATH_STATIC constexpr uint32_t sign        = 0x80000000u;387    BOOST_MATH_STATIC constexpr uint32_t exponent    = 0x7ff00000;388    BOOST_MATH_STATIC constexpr uint32_t flag        = 0x00000000;389    BOOST_MATH_STATIC constexpr uint32_t significand = 0x000fffff;390 391    typedef uint32_t bits;392 393    static void get_bits(long double x, uint32_t& a)394    {395        std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);396    }397 398    static void set_bits(long double& x, uint32_t a)399    {400        std::memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4);401    }402 403private:404    BOOST_MATH_STATIC constexpr int offset_ = BOOST_MATH_ENDIAN_BIG_BYTE ? 0 : 12;405};406 407 408// long double (>64 bits), Motorola 68K ----------------------------------------409 410#elif defined(__m68k) || defined(__m68k__) \411    || defined(__mc68000) || defined(__mc68000__) \412 413// Motorola extended double precision format (96 bits)414 415// It is the same format as the Intel extended double precision format,416// except that 1) it is big-endian, 2) the 3rd and 4th byte are padding, and417// 3) the flag bit is not set for infinity418 419template<>420struct fp_traits_non_native<long double, extended_double_precision>421{422    typedef ieee_copy_leading_bits_tag method;423 424    BOOST_MATH_STATIC constexpr uint32_t sign        = 0x80000000u;425    BOOST_MATH_STATIC constexpr uint32_t exponent    = 0x7fff0000;426    BOOST_MATH_STATIC constexpr uint32_t flag        = 0x00008000;427    BOOST_MATH_STATIC constexpr uint32_t significand = 0x00007fff;428 429    // copy 1st, 2nd, 5th and 6th byte. 3rd and 4th byte are padding.430 431    typedef uint32_t bits;432 433    static void get_bits(long double x, uint32_t& a)434    {435        std::memcpy(&a, &x, 2);436        std::memcpy(reinterpret_cast<unsigned char*>(&a) + 2,437               reinterpret_cast<const unsigned char*>(&x) + 4, 2);438    }439 440    static void set_bits(long double& x, uint32_t a)441    {442        std::memcpy(&x, &a, 2);443        std::memcpy(reinterpret_cast<unsigned char*>(&x) + 4,444               reinterpret_cast<const unsigned char*>(&a) + 2, 2);445    }446};447 448 449// long double (>64 bits), All other processors --------------------------------450 451#else452 453// IEEE extended double precision format with 15 exponent bits (128 bits)454 455template<>456struct fp_traits_non_native<long double, extended_double_precision>457{458    typedef ieee_copy_leading_bits_tag method;459 460    BOOST_MATH_STATIC constexpr uint32_t sign        = 0x80000000u;461    BOOST_MATH_STATIC constexpr uint32_t exponent    = 0x7fff0000;462    BOOST_MATH_STATIC constexpr uint32_t flag        = 0x00000000;463    BOOST_MATH_STATIC constexpr uint32_t significand = 0x0000ffff;464 465    typedef uint32_t bits;466 467    static void get_bits(long double x, uint32_t& a)468    {469        std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);470    }471 472    static void set_bits(long double& x, uint32_t a)473    {474        std::memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4);475    }476 477private:478    BOOST_MATH_STATIC constexpr int offset_ = BOOST_MATH_ENDIAN_BIG_BYTE ? 0 : 12;479};480 481#endif482 483//------------------------------------------------------------------------------484 485// size_to_precision is a type switch for converting a C++ floating point type486// to the corresponding precision type.487 488template<size_t n, bool fp> struct size_to_precision489{490   typedef unknown_precision type;491};492 493template<> struct size_to_precision<4, true>494{495    typedef single_precision type;496};497 498template<> struct size_to_precision<8, true>499{500    typedef double_precision type;501};502 503template<> struct size_to_precision<10, true>504{505    typedef extended_double_precision type;506};507 508template<> struct size_to_precision<12, true>509{510    typedef extended_double_precision type;511};512 513template<> struct size_to_precision<16, true>514{515    typedef extended_double_precision type;516};517 518//------------------------------------------------------------------------------519//520// Figure out whether to use native classification functions based on521// whether T is a built in floating point type or not:522//523template <class T>524struct select_native525{526    typedef typename size_to_precision<sizeof(T), ::std::is_floating_point<T>::value>::type precision;527    typedef fp_traits_non_native<T, precision> type;528};529template<>530struct select_native<float>531{532    typedef fp_traits_native<float> type;533};534template<>535struct select_native<double>536{537    typedef fp_traits_native<double> type;538};539template<>540struct select_native<long double>541{542    typedef fp_traits_native<long double> type;543};544 545//------------------------------------------------------------------------------546 547// fp_traits is a type switch that selects the right fp_traits_non_native548 549#if (defined(BOOST_MATH_USE_C99) && !(defined(__GNUC__) && (__GNUC__ < 4))) \550   && !defined(__hpux) \551   && !defined(__DECCXX)\552   && !defined(__osf__) \553   && !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION)\554   && !defined(__FAST_MATH__)\555   && !defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY)\556   && !defined(__INTEL_COMPILER)\557   && !defined(sun)\558   && !defined(__VXWORKS__)\559   && !defined(BOOST_MATH_HAS_GPU_SUPPORT)560#  define BOOST_MATH_USE_STD_FPCLASSIFY561#endif562 563template<class T> struct fp_traits564{565    typedef typename size_to_precision<sizeof(T), ::std::is_floating_point<T>::value>::type precision;566#if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && !defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY)567    typedef typename select_native<T>::type type;568#else569    typedef fp_traits_non_native<T, precision> type;570#endif571    typedef fp_traits_non_native<T, precision> sign_change_type;572};573 574//------------------------------------------------------------------------------575 576}   // namespace detail577}   // namespace math578}   // namespace boost579 580#endif581