1 // fp_traits.hpp 2 3 #ifndef BOOST_MATH_FP_TRAITS_HPP 4 #define BOOST_MATH_FP_TRAITS_HPP 5 6 // Copyright (c) 2006 Johan Rade 7 8 // Distributed under the Boost Software License, Version 1.0. 9 // (See accompanying file LICENSE_1_0.txt 10 // or copy at http://www.boost.org/LICENSE_1_0.txt) 11 12 /* 13 To support old compilers, care has been taken to avoid partial template 14 specialization and meta function forwarding. 15 With these techniques, the code could be simplified. 16 */ 17 18 #if defined(__vms) && defined(__DECCXX) && !__IEEE_FLOAT 19 // The VAX floating point formats are used (for float and double) 20 # define BOOST_FPCLASSIFY_VAX_FORMAT 21 #endif 22 23 #include <cstring> 24 25 #include <boost/assert.hpp> 26 #include <boost/cstdint.hpp> 27 #include <boost/detail/endian.hpp> 28 #include <boost/static_assert.hpp> 29 #include <boost/type_traits/is_floating_point.hpp> 30 31 #ifdef BOOST_NO_STDC_NAMESPACE 32 namespace std{ using ::memcpy; } 33 #endif 34 35 #ifndef FP_NORMAL 36 37 #define FP_ZERO 0 38 #define FP_NORMAL 1 39 #define FP_INFINITE 2 40 #define FP_NAN 3 41 #define FP_SUBNORMAL 4 42 43 #else 44 45 #define BOOST_HAS_FPCLASSIFY 46 47 #ifndef fpclassify 48 # if (defined(__GLIBCPP__) || defined(__GLIBCXX__)) \ 49 && defined(_GLIBCXX_USE_C99_MATH) \ 50 && !(defined(_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC) \ 51 && (_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC != 0)) 52 # ifdef _STLP_VENDOR_CSTD 53 # if _STLPORT_VERSION >= 0x520 54 # define BOOST_FPCLASSIFY_PREFIX ::__std_alias:: 55 # else 56 # define BOOST_FPCLASSIFY_PREFIX ::_STLP_VENDOR_CSTD:: 57 # endif 58 # else 59 # define BOOST_FPCLASSIFY_PREFIX ::std:: 60 # endif 61 # else 62 # undef BOOST_HAS_FPCLASSIFY 63 # define BOOST_FPCLASSIFY_PREFIX 64 # endif 65 #elif (defined(__HP_aCC) && !defined(__hppa)) 66 // aCC 6 appears to do "#define fpclassify fpclassify" which messes us up a bit! 67 # define BOOST_FPCLASSIFY_PREFIX :: 68 #else 69 # define BOOST_FPCLASSIFY_PREFIX 70 #endif 71 72 #ifdef __MINGW32__ 73 # undef BOOST_HAS_FPCLASSIFY 74 #endif 75 76 #endif 77 78 79 //------------------------------------------------------------------------------ 80 81 namespace boost { 82 namespace math { 83 namespace detail { 84 85 //------------------------------------------------------------------------------ 86 87 /* 88 The following classes are used to tag the different methods that are used 89 for floating point classification 90 */ 91 92 struct native_tag {}; 93 template <bool has_limits> 94 struct generic_tag {}; 95 struct ieee_tag {}; 96 struct ieee_copy_all_bits_tag : public ieee_tag {}; 97 struct ieee_copy_leading_bits_tag : public ieee_tag {}; 98 99 #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS 100 // 101 // These helper functions are used only when numeric_limits<> 102 // members are not compile time constants: 103 // 104 inline bool is_generic_tag_false(const generic_tag<false>*) 105 { 106 return true; 107 } 108 inline bool is_generic_tag_false(const void*) 109 { 110 return false; 111 } 112 #endif 113 114 //------------------------------------------------------------------------------ 115 116 /* 117 Most processors support three different floating point precisions: 118 single precision (32 bits), double precision (64 bits) 119 and extended double precision (80 - 128 bits, depending on the processor) 120 121 Note that the C++ type long double can be implemented 122 both as double precision and extended double precision. 123 */ 124 125 struct unknown_precision{}; 126 struct single_precision {}; 127 struct double_precision {}; 128 struct extended_double_precision {}; 129 130 // native_tag version -------------------------------------------------------------- 131 132 template<class T> struct fp_traits_native 133 { 134 typedef native_tag method; 135 }; 136 137 // generic_tag version ------------------------------------------------------------- 138 139 template<class T, class U> struct fp_traits_non_native 140 { 141 #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS 142 typedef generic_tag<std::numeric_limits<T>::is_specialized> method; 143 #else 144 typedef generic_tag<false> method; 145 #endif 146 }; 147 148 // ieee_tag versions --------------------------------------------------------------- 149 150 /* 151 These specializations of fp_traits_non_native contain information needed 152 to "parse" the binary representation of a floating point number. 153 154 Typedef members: 155 156 bits -- the target type when copying the leading bytes of a floating 157 point number. It is a typedef for uint32_t or uint64_t. 158 159 method -- tells us whether all bytes are copied or not. 160 It is a typedef for ieee_copy_all_bits_tag or ieee_copy_leading_bits_tag. 161 162 Static data members: 163 164 sign, exponent, flag, significand -- bit masks that give the meaning of the 165 bits in the leading bytes. 166 167 Static function members: 168 169 get_bits(), set_bits() -- provide access to the leading bytes. 170 171 */ 172 173 // ieee_tag version, float (32 bits) ----------------------------------------------- 174 175 #ifndef BOOST_FPCLASSIFY_VAX_FORMAT 176 177 template<> struct fp_traits_non_native<float, single_precision> 178 { 179 typedef ieee_copy_all_bits_tag method; 180 181 BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u); 182 BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7f800000); 183 BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00000000); 184 BOOST_STATIC_CONSTANT(uint32_t, significand = 0x007fffff); 185 186 typedef uint32_t bits; 187 static void get_bits(float x, uint32_t& a) { std::memcpy(&a, &x, 4); } 188 static void set_bits(float& x, uint32_t a) { std::memcpy(&x, &a, 4); } 189 }; 190 191 // ieee_tag version, double (64 bits) ---------------------------------------------- 192 193 #if defined(BOOST_NO_INT64_T) || defined(BOOST_NO_INCLASS_MEMBER_INITIALIZATION) \ 194 || defined(__BORLANDC__) || defined(__CODEGEAR__) 195 196 template<> struct fp_traits_non_native<double, double_precision> 197 { 198 typedef ieee_copy_leading_bits_tag method; 199 200 BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u); 201 BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7ff00000); 202 BOOST_STATIC_CONSTANT(uint32_t, flag = 0); 203 BOOST_STATIC_CONSTANT(uint32_t, significand = 0x000fffff); 204 205 typedef uint32_t bits; 206 207 static void get_bits(double x, uint32_t& a) 208 { 209 std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4); 210 } 211 212 static void set_bits(double& x, uint32_t a) 213 { 214 std::memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4); 215 } 216 217 private: 218 219 #if defined(BOOST_BIG_ENDIAN) 220 BOOST_STATIC_CONSTANT(int, offset_ = 0); 221 #elif defined(BOOST_LITTLE_ENDIAN) 222 BOOST_STATIC_CONSTANT(int, offset_ = 4); 223 #else 224 BOOST_STATIC_ASSERT(false); 225 #endif 226 }; 227 228 //.............................................................................. 229 230 #else 231 232 template<> struct fp_traits_non_native<double, double_precision> 233 { 234 typedef ieee_copy_all_bits_tag method; 235 236 static const uint64_t sign = ((uint64_t)0x80000000u) << 32; 237 static const uint64_t exponent = ((uint64_t)0x7ff00000) << 32; 238 static const uint64_t flag = 0; 239 static const uint64_t significand 240 = (((uint64_t)0x000fffff) << 32) + ((uint64_t)0xffffffffu); 241 242 typedef uint64_t bits; 243 static void get_bits(double x, uint64_t& a) { std::memcpy(&a, &x, 8); } 244 static void set_bits(double& x, uint64_t a) { std::memcpy(&x, &a, 8); } 245 }; 246 247 #endif 248 249 #endif // #ifndef BOOST_FPCLASSIFY_VAX_FORMAT 250 251 // long double (64 bits) ------------------------------------------------------- 252 253 #if defined(BOOST_NO_INT64_T) || defined(BOOST_NO_INCLASS_MEMBER_INITIALIZATION)\ 254 || defined(__BORLANDC__) || defined(__CODEGEAR__) 255 256 template<> struct fp_traits_non_native<long double, double_precision> 257 { 258 typedef ieee_copy_leading_bits_tag method; 259 260 BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u); 261 BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7ff00000); 262 BOOST_STATIC_CONSTANT(uint32_t, flag = 0); 263 BOOST_STATIC_CONSTANT(uint32_t, significand = 0x000fffff); 264 265 typedef uint32_t bits; 266 267 static void get_bits(long double x, uint32_t& a) 268 { 269 std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4); 270 } 271 272 static void set_bits(long double& x, uint32_t a) 273 { 274 std::memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4); 275 } 276 277 private: 278 279 #if defined(BOOST_BIG_ENDIAN) 280 BOOST_STATIC_CONSTANT(int, offset_ = 0); 281 #elif defined(BOOST_LITTLE_ENDIAN) 282 BOOST_STATIC_CONSTANT(int, offset_ = 4); 283 #else 284 BOOST_STATIC_ASSERT(false); 285 #endif 286 }; 287 288 //.............................................................................. 289 290 #else 291 292 template<> struct fp_traits_non_native<long double, double_precision> 293 { 294 typedef ieee_copy_all_bits_tag method; 295 296 static const uint64_t sign = (uint64_t)0x80000000u << 32; 297 static const uint64_t exponent = (uint64_t)0x7ff00000 << 32; 298 static const uint64_t flag = 0; 299 static const uint64_t significand 300 = ((uint64_t)0x000fffff << 32) + (uint64_t)0xffffffffu; 301 302 typedef uint64_t bits; 303 static void get_bits(long double x, uint64_t& a) { std::memcpy(&a, &x, 8); } 304 static void set_bits(long double& x, uint64_t a) { std::memcpy(&x, &a, 8); } 305 }; 306 307 #endif 308 309 310 // long double (>64 bits), x86 and x64 ----------------------------------------- 311 312 #if defined(__i386) || defined(__i386__) || defined(_M_IX86) \ 313 || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) \ 314 || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) 315 316 // Intel extended double precision format (80 bits) 317 318 template<> 319 struct fp_traits_non_native<long double, extended_double_precision> 320 { 321 typedef ieee_copy_leading_bits_tag method; 322 323 BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u); 324 BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7fff0000); 325 BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00008000); 326 BOOST_STATIC_CONSTANT(uint32_t, significand = 0x00007fff); 327 328 typedef uint32_t bits; 329 330 static void get_bits(long double x, uint32_t& a) 331 { 332 std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + 6, 4); 333 } 334 335 static void set_bits(long double& x, uint32_t a) 336 { 337 std::memcpy(reinterpret_cast<unsigned char*>(&x) + 6, &a, 4); 338 } 339 }; 340 341 342 // long double (>64 bits), Itanium --------------------------------------------- 343 344 #elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64) 345 346 // The floating point format is unknown at compile time 347 // No template specialization is provided. 348 // The generic_tag definition is used. 349 350 // The Itanium supports both 351 // the Intel extended double precision format (80 bits) and 352 // the IEEE extended double precision format with 15 exponent bits (128 bits). 353 354 355 // long double (>64 bits), PowerPC --------------------------------------------- 356 357 #elif defined(__powerpc) || defined(__powerpc__) || defined(__POWERPC__) \ 358 || defined(__ppc) || defined(__ppc__) || defined(__PPC__) 359 360 // PowerPC extended double precision format (128 bits) 361 362 template<> 363 struct fp_traits_non_native<long double, extended_double_precision> 364 { 365 typedef ieee_copy_leading_bits_tag method; 366 367 BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u); 368 BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7ff00000); 369 BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00000000); 370 BOOST_STATIC_CONSTANT(uint32_t, significand = 0x000fffff); 371 372 typedef uint32_t bits; 373 374 static void get_bits(long double x, uint32_t& a) 375 { 376 std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4); 377 } 378 379 static void set_bits(long double& x, uint32_t a) 380 { 381 std::memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4); 382 } 383 384 private: 385 386 #if defined(BOOST_BIG_ENDIAN) 387 BOOST_STATIC_CONSTANT(int, offset_ = 0); 388 #elif defined(BOOST_LITTLE_ENDIAN) 389 BOOST_STATIC_CONSTANT(int, offset_ = 12); 390 #else 391 BOOST_STATIC_ASSERT(false); 392 #endif 393 }; 394 395 396 // long double (>64 bits), Motorola 68K ---------------------------------------- 397 398 #elif defined(__m68k) || defined(__m68k__) \ 399 || defined(__mc68000) || defined(__mc68000__) \ 400 401 // Motorola extended double precision format (96 bits) 402 403 // It is the same format as the Intel extended double precision format, 404 // except that 1) it is big-endian, 2) the 3rd and 4th byte are padding, and 405 // 3) the flag bit is not set for infinity 406 407 template<> 408 struct fp_traits_non_native<long double, extended_double_precision> 409 { 410 typedef ieee_copy_leading_bits_tag method; 411 412 BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u); 413 BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7fff0000); 414 BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00008000); 415 BOOST_STATIC_CONSTANT(uint32_t, significand = 0x00007fff); 416 417 // copy 1st, 2nd, 5th and 6th byte. 3rd and 4th byte are padding. 418 419 typedef uint32_t bits; 420 421 static void get_bits(long double x, uint32_t& a) 422 { 423 std::memcpy(&a, &x, 2); 424 std::memcpy(reinterpret_cast<unsigned char*>(&a) + 2, 425 reinterpret_cast<const unsigned char*>(&x) + 4, 2); 426 } 427 428 static void set_bits(long double& x, uint32_t a) 429 { 430 std::memcpy(&x, &a, 2); 431 std::memcpy(reinterpret_cast<unsigned char*>(&x) + 4, 432 reinterpret_cast<const unsigned char*>(&a) + 2, 2); 433 } 434 }; 435 436 437 // long double (>64 bits), All other processors -------------------------------- 438 439 #else 440 441 // IEEE extended double precision format with 15 exponent bits (128 bits) 442 443 template<> 444 struct fp_traits_non_native<long double, extended_double_precision> 445 { 446 typedef ieee_copy_leading_bits_tag method; 447 448 BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u); 449 BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7fff0000); 450 BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00000000); 451 BOOST_STATIC_CONSTANT(uint32_t, significand = 0x0000ffff); 452 453 typedef uint32_t bits; 454 455 static void get_bits(long double x, uint32_t& a) 456 { 457 std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4); 458 } 459 460 static void set_bits(long double& x, uint32_t a) 461 { 462 std::memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4); 463 } 464 465 private: 466 467 #if defined(BOOST_BIG_ENDIAN) 468 BOOST_STATIC_CONSTANT(int, offset_ = 0); 469 #elif defined(BOOST_LITTLE_ENDIAN) 470 BOOST_STATIC_CONSTANT(int, offset_ = 12); 471 #else 472 BOOST_STATIC_ASSERT(false); 473 #endif 474 }; 475 476 #endif 477 478 //------------------------------------------------------------------------------ 479 480 // size_to_precision is a type switch for converting a C++ floating point type 481 // to the corresponding precision type. 482 483 template<int n, bool fp> struct size_to_precision 484 { 485 typedef unknown_precision type; 486 }; 487 488 template<> struct size_to_precision<4, true> 489 { 490 typedef single_precision type; 491 }; 492 493 template<> struct size_to_precision<8, true> 494 { 495 typedef double_precision type; 496 }; 497 498 template<> struct size_to_precision<10, true> 499 { 500 typedef extended_double_precision type; 501 }; 502 503 template<> struct size_to_precision<12, true> 504 { 505 typedef extended_double_precision type; 506 }; 507 508 template<> struct size_to_precision<16, true> 509 { 510 typedef extended_double_precision type; 511 }; 512 513 //------------------------------------------------------------------------------ 514 // 515 // Figure out whether to use native classification functions based on 516 // whether T is a built in floating point type or not: 517 // 518 template <class T> 519 struct select_native 520 { 521 typedef BOOST_DEDUCED_TYPENAME size_to_precision<sizeof(T), ::boost::is_floating_point<T>::value>::type precision; 522 typedef fp_traits_non_native<T, precision> type; 523 }; 524 template<> 525 struct select_native<float> 526 { 527 typedef fp_traits_native<float> type; 528 }; 529 template<> 530 struct select_native<double> 531 { 532 typedef fp_traits_native<double> type; 533 }; 534 template<> 535 struct select_native<long double> 536 { 537 typedef fp_traits_native<long double> type; 538 }; 539 540 //------------------------------------------------------------------------------ 541 542 // fp_traits is a type switch that selects the right fp_traits_non_native 543 544 #if (defined(BOOST_MATH_USE_C99) && !(defined(__GNUC__) && (__GNUC__ < 4))) \ 545 && !defined(__hpux) \ 546 && !defined(__DECCXX)\ 547 && !defined(__osf__) \ 548 && !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION)\ 549 && !defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY) 550 # define BOOST_MATH_USE_STD_FPCLASSIFY 551 #endif 552 553 template<class T> struct fp_traits 554 { 555 typedef BOOST_DEDUCED_TYPENAME size_to_precision<sizeof(T), ::boost::is_floating_point<T>::value>::type precision; 556 #if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && !defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY) 557 typedef typename select_native<T>::type type; 558 #else 559 typedef fp_traits_non_native<T, precision> type; 560 #endif 561 typedef fp_traits_non_native<T, precision> sign_change_type; 562 }; 563 564 //------------------------------------------------------------------------------ 565 566 } // namespace detail 567 } // namespace math 568 } // namespace boost 569 570 #endif 571