Chris@16: // fp_traits.hpp Chris@16: Chris@16: #ifndef BOOST_MATH_FP_TRAITS_HPP Chris@16: #define BOOST_MATH_FP_TRAITS_HPP Chris@16: Chris@16: // Copyright (c) 2006 Johan Rade Chris@16: Chris@16: // Distributed under the Boost Software License, Version 1.0. Chris@16: // (See accompanying file LICENSE_1_0.txt Chris@16: // or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: /* Chris@16: To support old compilers, care has been taken to avoid partial template Chris@16: specialization and meta function forwarding. Chris@16: With these techniques, the code could be simplified. Chris@16: */ Chris@16: Chris@16: #if defined(__vms) && defined(__DECCXX) && !__IEEE_FLOAT Chris@16: // The VAX floating point formats are used (for float and double) Chris@16: # define BOOST_FPCLASSIFY_VAX_FORMAT Chris@16: #endif Chris@16: Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #ifdef BOOST_NO_STDC_NAMESPACE Chris@16: namespace std{ using ::memcpy; } Chris@16: #endif Chris@16: Chris@16: #ifndef FP_NORMAL Chris@16: Chris@16: #define FP_ZERO 0 Chris@16: #define FP_NORMAL 1 Chris@16: #define FP_INFINITE 2 Chris@16: #define FP_NAN 3 Chris@16: #define FP_SUBNORMAL 4 Chris@16: Chris@16: #else Chris@16: Chris@16: #define BOOST_HAS_FPCLASSIFY Chris@16: Chris@16: #ifndef fpclassify Chris@16: # if (defined(__GLIBCPP__) || defined(__GLIBCXX__)) \ Chris@16: && defined(_GLIBCXX_USE_C99_MATH) \ Chris@16: && !(defined(_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC) \ Chris@16: && (_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC != 0)) Chris@16: # ifdef _STLP_VENDOR_CSTD Chris@16: # if _STLPORT_VERSION >= 0x520 Chris@16: # define BOOST_FPCLASSIFY_PREFIX ::__std_alias:: Chris@16: # else Chris@16: # define BOOST_FPCLASSIFY_PREFIX ::_STLP_VENDOR_CSTD:: Chris@16: # endif Chris@16: # else Chris@16: # define BOOST_FPCLASSIFY_PREFIX ::std:: Chris@16: # endif Chris@16: # else Chris@16: # undef BOOST_HAS_FPCLASSIFY Chris@16: # define BOOST_FPCLASSIFY_PREFIX Chris@16: # endif Chris@16: #elif (defined(__HP_aCC) && !defined(__hppa)) Chris@16: // aCC 6 appears to do "#define fpclassify fpclassify" which messes us up a bit! Chris@16: # define BOOST_FPCLASSIFY_PREFIX :: Chris@16: #else Chris@16: # define BOOST_FPCLASSIFY_PREFIX Chris@16: #endif Chris@16: Chris@16: #ifdef __MINGW32__ Chris@16: # undef BOOST_HAS_FPCLASSIFY Chris@16: #endif Chris@16: Chris@16: #endif Chris@16: Chris@16: Chris@16: //------------------------------------------------------------------------------ Chris@16: Chris@16: namespace boost { Chris@16: namespace math { Chris@16: namespace detail { Chris@16: Chris@16: //------------------------------------------------------------------------------ Chris@16: Chris@16: /* Chris@16: The following classes are used to tag the different methods that are used Chris@16: for floating point classification Chris@16: */ Chris@16: Chris@16: struct native_tag {}; Chris@16: template Chris@16: struct generic_tag {}; Chris@16: struct ieee_tag {}; Chris@16: struct ieee_copy_all_bits_tag : public ieee_tag {}; Chris@16: struct ieee_copy_leading_bits_tag : public ieee_tag {}; Chris@16: Chris@16: #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS Chris@16: // Chris@16: // These helper functions are used only when numeric_limits<> Chris@16: // members are not compile time constants: Chris@16: // Chris@16: inline bool is_generic_tag_false(const generic_tag*) Chris@16: { Chris@16: return true; Chris@16: } Chris@16: inline bool is_generic_tag_false(const void*) Chris@16: { Chris@16: return false; Chris@16: } Chris@16: #endif Chris@16: Chris@16: //------------------------------------------------------------------------------ Chris@16: Chris@16: /* Chris@16: Most processors support three different floating point precisions: Chris@16: single precision (32 bits), double precision (64 bits) Chris@16: and extended double precision (80 - 128 bits, depending on the processor) Chris@16: Chris@16: Note that the C++ type long double can be implemented Chris@16: both as double precision and extended double precision. Chris@16: */ Chris@16: Chris@16: struct unknown_precision{}; Chris@16: struct single_precision {}; Chris@16: struct double_precision {}; Chris@16: struct extended_double_precision {}; Chris@16: Chris@16: // native_tag version -------------------------------------------------------------- Chris@16: Chris@16: template struct fp_traits_native Chris@16: { Chris@16: typedef native_tag method; Chris@16: }; Chris@16: Chris@16: // generic_tag version ------------------------------------------------------------- Chris@16: Chris@16: template struct fp_traits_non_native Chris@16: { Chris@16: #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS Chris@16: typedef generic_tag::is_specialized> method; Chris@16: #else Chris@16: typedef generic_tag method; Chris@16: #endif Chris@16: }; Chris@16: Chris@16: // ieee_tag versions --------------------------------------------------------------- Chris@16: Chris@16: /* Chris@16: These specializations of fp_traits_non_native contain information needed Chris@16: to "parse" the binary representation of a floating point number. Chris@16: Chris@16: Typedef members: Chris@16: Chris@16: bits -- the target type when copying the leading bytes of a floating Chris@16: point number. It is a typedef for uint32_t or uint64_t. Chris@16: Chris@16: method -- tells us whether all bytes are copied or not. Chris@16: It is a typedef for ieee_copy_all_bits_tag or ieee_copy_leading_bits_tag. Chris@16: Chris@16: Static data members: Chris@16: Chris@16: sign, exponent, flag, significand -- bit masks that give the meaning of the Chris@16: bits in the leading bytes. Chris@16: Chris@16: Static function members: Chris@16: Chris@16: get_bits(), set_bits() -- provide access to the leading bytes. Chris@16: Chris@16: */ Chris@16: Chris@16: // ieee_tag version, float (32 bits) ----------------------------------------------- Chris@16: Chris@16: #ifndef BOOST_FPCLASSIFY_VAX_FORMAT Chris@16: Chris@16: template<> struct fp_traits_non_native Chris@16: { Chris@16: typedef ieee_copy_all_bits_tag method; Chris@16: Chris@16: BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u); Chris@16: BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7f800000); Chris@16: BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00000000); Chris@16: BOOST_STATIC_CONSTANT(uint32_t, significand = 0x007fffff); Chris@16: Chris@16: typedef uint32_t bits; Chris@16: static void get_bits(float x, uint32_t& a) { std::memcpy(&a, &x, 4); } Chris@16: static void set_bits(float& x, uint32_t a) { std::memcpy(&x, &a, 4); } Chris@16: }; Chris@16: Chris@16: // ieee_tag version, double (64 bits) ---------------------------------------------- Chris@16: Chris@16: #if defined(BOOST_NO_INT64_T) || defined(BOOST_NO_INCLASS_MEMBER_INITIALIZATION) \ Chris@16: || defined(__BORLANDC__) || defined(__CODEGEAR__) Chris@16: Chris@16: template<> struct fp_traits_non_native Chris@16: { Chris@16: typedef ieee_copy_leading_bits_tag method; Chris@16: Chris@16: BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u); Chris@16: BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7ff00000); Chris@16: BOOST_STATIC_CONSTANT(uint32_t, flag = 0); Chris@16: BOOST_STATIC_CONSTANT(uint32_t, significand = 0x000fffff); Chris@16: Chris@16: typedef uint32_t bits; Chris@16: Chris@16: static void get_bits(double x, uint32_t& a) Chris@16: { Chris@16: std::memcpy(&a, reinterpret_cast(&x) + offset_, 4); Chris@16: } Chris@16: Chris@16: static void set_bits(double& x, uint32_t a) Chris@16: { Chris@16: std::memcpy(reinterpret_cast(&x) + offset_, &a, 4); Chris@16: } Chris@16: Chris@16: private: Chris@16: Chris@16: #if defined(BOOST_BIG_ENDIAN) Chris@16: BOOST_STATIC_CONSTANT(int, offset_ = 0); Chris@16: #elif defined(BOOST_LITTLE_ENDIAN) Chris@16: BOOST_STATIC_CONSTANT(int, offset_ = 4); Chris@16: #else Chris@16: BOOST_STATIC_ASSERT(false); Chris@16: #endif Chris@16: }; Chris@16: Chris@16: //.............................................................................. Chris@16: Chris@16: #else Chris@16: Chris@16: template<> struct fp_traits_non_native Chris@16: { Chris@16: typedef ieee_copy_all_bits_tag method; Chris@16: Chris@16: static const uint64_t sign = ((uint64_t)0x80000000u) << 32; Chris@16: static const uint64_t exponent = ((uint64_t)0x7ff00000) << 32; Chris@16: static const uint64_t flag = 0; Chris@16: static const uint64_t significand Chris@16: = (((uint64_t)0x000fffff) << 32) + ((uint64_t)0xffffffffu); Chris@16: Chris@16: typedef uint64_t bits; Chris@16: static void get_bits(double x, uint64_t& a) { std::memcpy(&a, &x, 8); } Chris@16: static void set_bits(double& x, uint64_t a) { std::memcpy(&x, &a, 8); } Chris@16: }; Chris@16: Chris@16: #endif Chris@16: Chris@16: #endif // #ifndef BOOST_FPCLASSIFY_VAX_FORMAT Chris@16: Chris@16: // long double (64 bits) ------------------------------------------------------- Chris@16: Chris@16: #if defined(BOOST_NO_INT64_T) || defined(BOOST_NO_INCLASS_MEMBER_INITIALIZATION)\ Chris@16: || defined(__BORLANDC__) || defined(__CODEGEAR__) Chris@16: Chris@16: template<> struct fp_traits_non_native Chris@16: { Chris@16: typedef ieee_copy_leading_bits_tag method; Chris@16: Chris@16: BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u); Chris@16: BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7ff00000); Chris@16: BOOST_STATIC_CONSTANT(uint32_t, flag = 0); Chris@16: BOOST_STATIC_CONSTANT(uint32_t, significand = 0x000fffff); Chris@16: Chris@16: typedef uint32_t bits; Chris@16: Chris@16: static void get_bits(long double x, uint32_t& a) Chris@16: { Chris@16: std::memcpy(&a, reinterpret_cast(&x) + offset_, 4); Chris@16: } Chris@16: Chris@16: static void set_bits(long double& x, uint32_t a) Chris@16: { Chris@16: std::memcpy(reinterpret_cast(&x) + offset_, &a, 4); Chris@16: } Chris@16: Chris@16: private: Chris@16: Chris@16: #if defined(BOOST_BIG_ENDIAN) Chris@16: BOOST_STATIC_CONSTANT(int, offset_ = 0); Chris@16: #elif defined(BOOST_LITTLE_ENDIAN) Chris@16: BOOST_STATIC_CONSTANT(int, offset_ = 4); Chris@16: #else Chris@16: BOOST_STATIC_ASSERT(false); Chris@16: #endif Chris@16: }; Chris@16: Chris@16: //.............................................................................. Chris@16: Chris@16: #else Chris@16: Chris@16: template<> struct fp_traits_non_native Chris@16: { Chris@16: typedef ieee_copy_all_bits_tag method; Chris@16: Chris@16: static const uint64_t sign = (uint64_t)0x80000000u << 32; Chris@16: static const uint64_t exponent = (uint64_t)0x7ff00000 << 32; Chris@16: static const uint64_t flag = 0; Chris@16: static const uint64_t significand Chris@16: = ((uint64_t)0x000fffff << 32) + (uint64_t)0xffffffffu; Chris@16: Chris@16: typedef uint64_t bits; Chris@16: static void get_bits(long double x, uint64_t& a) { std::memcpy(&a, &x, 8); } Chris@16: static void set_bits(long double& x, uint64_t a) { std::memcpy(&x, &a, 8); } Chris@16: }; Chris@16: Chris@16: #endif Chris@16: Chris@16: Chris@16: // long double (>64 bits), x86 and x64 ----------------------------------------- Chris@16: Chris@16: #if defined(__i386) || defined(__i386__) || defined(_M_IX86) \ Chris@16: || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) \ Chris@16: || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) Chris@16: Chris@16: // Intel extended double precision format (80 bits) Chris@16: Chris@16: template<> Chris@16: struct fp_traits_non_native Chris@16: { Chris@16: typedef ieee_copy_leading_bits_tag method; Chris@16: Chris@16: BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u); Chris@16: BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7fff0000); Chris@16: BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00008000); Chris@16: BOOST_STATIC_CONSTANT(uint32_t, significand = 0x00007fff); Chris@16: Chris@16: typedef uint32_t bits; Chris@16: Chris@16: static void get_bits(long double x, uint32_t& a) Chris@16: { Chris@16: std::memcpy(&a, reinterpret_cast(&x) + 6, 4); Chris@16: } Chris@16: Chris@16: static void set_bits(long double& x, uint32_t a) Chris@16: { Chris@16: std::memcpy(reinterpret_cast(&x) + 6, &a, 4); Chris@16: } Chris@16: }; Chris@16: Chris@16: Chris@16: // long double (>64 bits), Itanium --------------------------------------------- Chris@16: Chris@16: #elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64) Chris@16: Chris@16: // The floating point format is unknown at compile time Chris@16: // No template specialization is provided. Chris@16: // The generic_tag definition is used. Chris@16: Chris@16: // The Itanium supports both Chris@16: // the Intel extended double precision format (80 bits) and Chris@16: // the IEEE extended double precision format with 15 exponent bits (128 bits). Chris@16: Chris@101: #elif defined(__GNUC__) && (LDBL_MANT_DIG == 106) Chris@101: Chris@101: // Chris@101: // Define nothing here and fall though to generic_tag: Chris@101: // We have GCC's "double double" in effect, and any attempt Chris@101: // to handle it via bit-fiddling is pretty much doomed to fail... Chris@101: // Chris@16: Chris@16: // long double (>64 bits), PowerPC --------------------------------------------- Chris@16: Chris@16: #elif defined(__powerpc) || defined(__powerpc__) || defined(__POWERPC__) \ Chris@16: || defined(__ppc) || defined(__ppc__) || defined(__PPC__) Chris@16: Chris@16: // PowerPC extended double precision format (128 bits) Chris@16: Chris@16: template<> Chris@16: struct fp_traits_non_native Chris@16: { Chris@16: typedef ieee_copy_leading_bits_tag method; Chris@16: Chris@16: BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u); Chris@16: BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7ff00000); Chris@16: BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00000000); Chris@16: BOOST_STATIC_CONSTANT(uint32_t, significand = 0x000fffff); Chris@16: Chris@16: typedef uint32_t bits; Chris@16: Chris@16: static void get_bits(long double x, uint32_t& a) Chris@16: { Chris@16: std::memcpy(&a, reinterpret_cast(&x) + offset_, 4); Chris@16: } Chris@16: Chris@16: static void set_bits(long double& x, uint32_t a) Chris@16: { Chris@16: std::memcpy(reinterpret_cast(&x) + offset_, &a, 4); Chris@16: } Chris@16: Chris@16: private: Chris@16: Chris@16: #if defined(BOOST_BIG_ENDIAN) Chris@16: BOOST_STATIC_CONSTANT(int, offset_ = 0); Chris@16: #elif defined(BOOST_LITTLE_ENDIAN) Chris@16: BOOST_STATIC_CONSTANT(int, offset_ = 12); Chris@16: #else Chris@16: BOOST_STATIC_ASSERT(false); Chris@16: #endif Chris@16: }; Chris@16: Chris@16: Chris@16: // long double (>64 bits), Motorola 68K ---------------------------------------- Chris@16: Chris@16: #elif defined(__m68k) || defined(__m68k__) \ Chris@16: || defined(__mc68000) || defined(__mc68000__) \ Chris@16: Chris@16: // Motorola extended double precision format (96 bits) Chris@16: Chris@16: // It is the same format as the Intel extended double precision format, Chris@16: // except that 1) it is big-endian, 2) the 3rd and 4th byte are padding, and Chris@16: // 3) the flag bit is not set for infinity Chris@16: Chris@16: template<> Chris@16: struct fp_traits_non_native Chris@16: { Chris@16: typedef ieee_copy_leading_bits_tag method; Chris@16: Chris@16: BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u); Chris@16: BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7fff0000); Chris@16: BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00008000); Chris@16: BOOST_STATIC_CONSTANT(uint32_t, significand = 0x00007fff); Chris@16: Chris@16: // copy 1st, 2nd, 5th and 6th byte. 3rd and 4th byte are padding. Chris@16: Chris@16: typedef uint32_t bits; Chris@16: Chris@16: static void get_bits(long double x, uint32_t& a) Chris@16: { Chris@16: std::memcpy(&a, &x, 2); Chris@16: std::memcpy(reinterpret_cast(&a) + 2, Chris@16: reinterpret_cast(&x) + 4, 2); Chris@16: } Chris@16: Chris@16: static void set_bits(long double& x, uint32_t a) Chris@16: { Chris@16: std::memcpy(&x, &a, 2); Chris@16: std::memcpy(reinterpret_cast(&x) + 4, Chris@16: reinterpret_cast(&a) + 2, 2); Chris@16: } Chris@16: }; Chris@16: Chris@16: Chris@16: // long double (>64 bits), All other processors -------------------------------- Chris@16: Chris@16: #else Chris@16: Chris@16: // IEEE extended double precision format with 15 exponent bits (128 bits) Chris@16: Chris@16: template<> Chris@16: struct fp_traits_non_native Chris@16: { Chris@16: typedef ieee_copy_leading_bits_tag method; Chris@16: Chris@16: BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u); Chris@16: BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7fff0000); Chris@16: BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00000000); Chris@16: BOOST_STATIC_CONSTANT(uint32_t, significand = 0x0000ffff); Chris@16: Chris@16: typedef uint32_t bits; Chris@16: Chris@16: static void get_bits(long double x, uint32_t& a) Chris@16: { Chris@16: std::memcpy(&a, reinterpret_cast(&x) + offset_, 4); Chris@16: } Chris@16: Chris@16: static void set_bits(long double& x, uint32_t a) Chris@16: { Chris@16: std::memcpy(reinterpret_cast(&x) + offset_, &a, 4); Chris@16: } Chris@16: Chris@16: private: Chris@16: Chris@16: #if defined(BOOST_BIG_ENDIAN) Chris@16: BOOST_STATIC_CONSTANT(int, offset_ = 0); Chris@16: #elif defined(BOOST_LITTLE_ENDIAN) Chris@16: BOOST_STATIC_CONSTANT(int, offset_ = 12); Chris@16: #else Chris@16: BOOST_STATIC_ASSERT(false); Chris@16: #endif Chris@16: }; Chris@16: Chris@16: #endif Chris@16: Chris@16: //------------------------------------------------------------------------------ Chris@16: Chris@16: // size_to_precision is a type switch for converting a C++ floating point type Chris@16: // to the corresponding precision type. Chris@16: Chris@16: template struct size_to_precision Chris@16: { Chris@16: typedef unknown_precision type; Chris@16: }; Chris@16: Chris@16: template<> struct size_to_precision<4, true> Chris@16: { Chris@16: typedef single_precision type; Chris@16: }; Chris@16: Chris@16: template<> struct size_to_precision<8, true> Chris@16: { Chris@16: typedef double_precision type; Chris@16: }; Chris@16: Chris@16: template<> struct size_to_precision<10, true> Chris@16: { Chris@16: typedef extended_double_precision type; Chris@16: }; Chris@16: Chris@16: template<> struct size_to_precision<12, true> Chris@16: { Chris@16: typedef extended_double_precision type; Chris@16: }; Chris@16: Chris@16: template<> struct size_to_precision<16, true> Chris@16: { Chris@16: typedef extended_double_precision type; Chris@16: }; Chris@16: Chris@16: //------------------------------------------------------------------------------ Chris@16: // Chris@16: // Figure out whether to use native classification functions based on Chris@16: // whether T is a built in floating point type or not: Chris@16: // Chris@16: template Chris@16: struct select_native Chris@16: { Chris@16: typedef BOOST_DEDUCED_TYPENAME size_to_precision::value>::type precision; Chris@16: typedef fp_traits_non_native type; Chris@16: }; Chris@16: template<> Chris@16: struct select_native Chris@16: { Chris@16: typedef fp_traits_native type; Chris@16: }; Chris@16: template<> Chris@16: struct select_native Chris@16: { Chris@16: typedef fp_traits_native type; Chris@16: }; Chris@16: template<> Chris@16: struct select_native Chris@16: { Chris@16: typedef fp_traits_native type; Chris@16: }; Chris@16: Chris@16: //------------------------------------------------------------------------------ Chris@16: Chris@16: // fp_traits is a type switch that selects the right fp_traits_non_native Chris@16: Chris@16: #if (defined(BOOST_MATH_USE_C99) && !(defined(__GNUC__) && (__GNUC__ < 4))) \ Chris@16: && !defined(__hpux) \ Chris@16: && !defined(__DECCXX)\ Chris@16: && !defined(__osf__) \ Chris@16: && !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION)\ Chris@101: && !defined(__FAST_MATH__)\ Chris@101: && !defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY)\ Chris@101: && !defined(BOOST_INTEL)\ Chris@101: && !defined(sun) Chris@16: # define BOOST_MATH_USE_STD_FPCLASSIFY Chris@16: #endif Chris@16: Chris@16: template struct fp_traits Chris@16: { Chris@16: typedef BOOST_DEDUCED_TYPENAME size_to_precision::value>::type precision; Chris@16: #if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && !defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY) Chris@16: typedef typename select_native::type type; Chris@16: #else Chris@16: typedef fp_traits_non_native type; Chris@16: #endif Chris@16: typedef fp_traits_non_native sign_change_type; Chris@16: }; Chris@16: Chris@16: //------------------------------------------------------------------------------ Chris@16: Chris@16: } // namespace detail Chris@16: } // namespace math Chris@16: } // namespace boost Chris@16: Chris@16: #endif