📄 fp_traits.hpp
字号:
// fp_traits.hpp#ifndef BOOST_MATH_FP_TRAITS_HPP#define BOOST_MATH_FP_TRAITS_HPP// Copyright (c) 2006 Johan Rade// Distributed under the Boost Software License, Version 1.0.// (See accompanying file LICENSE_1_0.txt// or copy at http://www.boost.org/LICENSE_1_0.txt)#if defined(__vms) && defined(__DECCXX) && !__IEEE_FLOAT# error The VAX floating point mode on VMS is not supported.#endif#include <cstring>#include <boost/assert.hpp>#include <boost/cstdint.hpp>#include <boost/detail/endian.hpp>#include <boost/static_assert.hpp>#include <boost/type_traits/is_floating_point.hpp>//------------------------------------------------------------------------------namespace boost {namespace math {namespace detail {//------------------------------------------------------------------------------/*Most processors support three different floating point precisions:single precision (32 bits), double precision (64 bits)and extended double precision (>64 bits)Note that the C++ type long double can be implementedboth as double precision and extended double precision.*/struct single_precision_tag {};struct double_precision_tag {};struct extended_double_precision_tag {};//------------------------------------------------------------------------------/*template<class T, class U> struct fp_traits_impl; This is traits class that describes the binary structure of floating point numbers of C++ type T and precision URequirements: T = float, double or long double U = single_precision_tag, double_precision_tag or extended_double_precision_tagTypedef members: bits -- the target type when copying the leading bytes of a floating point number. It is a typedef for uint32_t or uint64_t. coverage -- tells us whether all bytes are copied or not. It is a typedef for all_bits or not_all_bits.Static data members: sign, exponent, flag, mantissa -- bit masks that give the meaning of the bits in the leading bytes.Static function members: init() -- initializes the static data members, if needed. (Is a no-op in the specialized versions of the template.) get_bits(), set_bits() -- provide access to the leading bytes.*/struct all_bits {};struct not_all_bits {};// Generic version -------------------------------------------------------------// The generic version uses run time initialization to determine the floating// point format. It is capable of handling most formats,// but not the Motorola 68K extended double precision format.// Currently the generic version is used only for extended double precision// on Itanium. In all other cases there are specializations of the template// that use compile time initialization.template<class T> struct uint32_t_coverage{ typedef not_all_bits type;};template<> struct uint32_t_coverage<single_precision_tag>{ typedef all_bits type;};template<class T, class U> struct fp_traits_impl{ typedef uint32_t bits; typedef BOOST_DEDUCED_TYPENAME uint32_t_coverage<U>::type coverage; BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000); static uint32_t exponent; static uint32_t flag; static uint32_t mantissa; static void init() { if(is_init_) return; do_init_(); is_init_ = true; } static void get_bits(T x, uint32_t& a) { memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4); } static void set_bits(T& x, uint32_t a) { memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4); }private: static size_t offset_; static bool is_init_; static void do_init_();};//..............................................................................template<class T, class U> uint32_t fp_traits_impl<T,U>::exponent;template<class T, class U> uint32_t fp_traits_impl<T,U>::flag;template<class T, class U> uint32_t fp_traits_impl<T,U>::mantissa;template<class T, class U> size_t fp_traits_impl<T,U>::offset_;template<class T, class U> bool fp_traits_impl<T,U>::is_init_;// In a single-threaded program, do_init will be called exactly once.// In a multi-threaded program, do_init may be called simultaneously// by more then one thread. That should not be a problem.//..............................................................................template<class T, class U> void fp_traits_impl<T,U>::do_init_(){ T x = static_cast<T>(3) / static_cast<T>(4); // sign bit = 0 // exponent: first and last bit = 0, all other bits = 1 // flag bit (if present) = 1 // mantissa: first bit = 1, all other bits = 0 uint32_t a; for(size_t k = 0; k <= sizeof(T) - 4; ++k) { memcpy(&a, reinterpret_cast<unsigned char*>(&x) + k, 4); switch(a) { case 0x3f400000: // IEEE single precision format offset_ = k; exponent = 0x7f800000; flag = 0x00000000; mantissa = 0x007fffff; return; case 0x3fe80000: // IEEE double precision format // and PowerPC extended double precision format offset_ = k; exponent = 0x7ff00000; flag = 0x00000000; mantissa = 0x000fffff; return; case 0x3ffe0000: // Motorola extended double precision format // Must not get here. Must be handled by specialization. // To get accurate cutoff between normals and subnormals // we must use the flag bit that is in the 5th byte. // Otherwise this cutoff will be off by a factor 2. // If we do get here, then we have failed to detect the Motorola // processor at compile time. BOOST_ASSERT(false); return; case 0x3ffe8000: // IEEE extended double precision format // with 15 exponent bits offset_ = k; exponent = 0x7fff0000; flag = 0x00000000; mantissa = 0x0000ffff; return; case 0x3ffec000: // Intel extended double precision format offset_ = k; exponent = 0x7fff0000; flag = 0x00008000; mantissa = 0x00007fff; return; default: continue; } } BOOST_ASSERT(false); // Unknown format.}// float (32 bits) -------------------------------------------------------------template<> struct fp_traits_impl<float, single_precision_tag>{ typedef uint32_t bits; typedef all_bits coverage; BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000); BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7f800000); BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00000000); BOOST_STATIC_CONSTANT(uint32_t, mantissa = 0x007fffff); static void init() {} static void get_bits(float x, uint32_t& a) { memcpy(&a, &x, 4); } static void set_bits(float& x, uint32_t a) { memcpy(&x, &a, 4); }};// double (64 bits) ------------------------------------------------------------#if defined(BOOST_NO_INT64_T) || defined(BOOST_NO_INCLASS_MEMBER_INITIALIZATION)template<> struct fp_traits_impl<double, double_precision_tag>{ typedef uint32_t bits; typedef not_all_bits coverage; BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000); BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7ff00000); BOOST_STATIC_CONSTANT(uint32_t, flag = 0); BOOST_STATIC_CONSTANT(uint32_t, mantissa = 0x000fffff); static void init() {} static void get_bits(double x, uint32_t& a) { memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4); } static void set_bits(double& x, uint32_t a) { memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4); }private:#if defined(BOOST_BIG_ENDIAN) BOOST_STATIC_CONSTANT(int, offset_ = 0);#elif defined(BOOST_LITTLE_ENDIAN) BOOST_STATIC_CONSTANT(int, offset_ = 4);#else BOOST_STATIC_ASSERT(false);#endif};//..............................................................................#elsetemplate<> struct fp_traits_impl<double, double_precision_tag>{ typedef uint64_t bits; typedef all_bits coverage; static const uint64_t sign = (uint64_t)0x80000000 << 32; static const uint64_t exponent = (uint64_t)0x7ff00000 << 32; static const uint64_t flag = 0; static const uint64_t mantissa = ((uint64_t)0x000fffff << 32) + (uint64_t)0xffffffff;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -