Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r50134 - in trunk/boost/math/special_functions: . detail
From: john_at_[hidden]
Date: 2008-12-05 11:05:26


Author: johnmaddock
Date: 2008-12-05 11:05:26 EST (Fri, 05 Dec 2008)
New Revision: 50134
URL: http://svn.boost.org/trac/boost/changeset/50134

Log:
Integrated Johan Rade's floating point utilities code.
Added:
   trunk/boost/math/special_functions/detail/fp_traits.hpp (contents, props changed)
Text files modified:
   trunk/boost/math/special_functions/fpclassify.hpp | 482 ++++++++++++++++++++++++++++++---------
   1 files changed, 368 insertions(+), 114 deletions(-)

Added: trunk/boost/math/special_functions/detail/fp_traits.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/math/special_functions/detail/fp_traits.hpp 2008-12-05 11:05:26 EST (Fri, 05 Dec 2008)
@@ -0,0 +1,556 @@
+// 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)
+
+/*
+To support old compilers, care has been taken to avoid partial template
+specialization and meta function forwarding.
+With these techniques, the code could be simplified.
+*/
+
+#if defined(__vms) && defined(__DECCXX) && !__IEEE_FLOAT
+// The VAX floating point formats are used (for float and double)
+# define BOOST_FPCLASSIFY_VAX_FORMAT
+#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>
+
+#ifdef BOOST_NO_STDC_NAMESPACE
+ namespace std{ using ::memcpy; }
+#endif
+
+#ifndef FP_NORMAL
+
+#define FP_ZERO 0
+#define FP_NORMAL 1
+#define FP_INFINITE 2
+#define FP_NAN 3
+#define FP_SUBNORMAL 4
+
+#else
+
+#define BOOST_HAS_FPCLASSIFY
+
+#ifndef fpclassify
+# if (defined(__GLIBCPP__) || defined(__GLIBCXX__)) \
+ && defined(_GLIBCXX_USE_C99_MATH) \
+ && !(defined(_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC) \
+ && (_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC != 0))
+# ifdef _STLP_VENDOR_CSTD
+# define BOOST_FPCLASSIFY_PREFIX ::_STLP_VENDOR_CSTD::
+# else
+# define BOOST_FPCLASSIFY_PREFIX ::std::
+# endif
+# else
+# undef BOOST_HAS_FPCLASSIFY
+# define BOOST_FPCLASSIFY_PREFIX
+# endif
+#elif (defined(__HP_aCC) && !defined(__hppa))
+// aCC 6 appears to do "#define fpclassify fpclassify" which messes us up a bit!
+# define BOOST_FPCLASSIFY_PREFIX ::
+#else
+# define BOOST_FPCLASSIFY_PREFIX
+#endif
+
+#ifdef __MINGW32__
+# undef BOOST_HAS_FPCLASSIFY
+#endif
+
+#endif
+
+
+//------------------------------------------------------------------------------
+
+namespace boost {
+namespace math {
+namespace detail {
+
+//------------------------------------------------------------------------------
+
+/*
+The following classes are used to tag the different methods that are used
+for floating point classification
+*/
+
+struct native_tag {};
+template <bool has_limits>
+struct generic_tag {};
+struct ieee_tag {};
+struct ieee_copy_all_bits_tag : public ieee_tag {};
+struct ieee_copy_leading_bits_tag : public ieee_tag {};
+
+#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
+//
+// These helper functions are used only when numeric_limits<>
+// members are not compile time constants:
+//
+inline bool is_generic_tag_false(const generic_tag<false>&)
+{
+ return true;
+}
+inline bool is_generic_tag_false(...)
+{
+ return false;
+}
+#endif
+
+//------------------------------------------------------------------------------
+
+/*
+Most processors support three different floating point precisions:
+single precision (32 bits), double precision (64 bits)
+and extended double precision (80 - 128 bits, depending on the processor)
+
+Note that the C++ type long double can be implemented
+both as double precision and extended double precision.
+*/
+
+struct unknown_precision{};
+struct single_precision {};
+struct double_precision {};
+struct extended_double_precision {};
+
+// native_tag version --------------------------------------------------------------
+
+template<class T> struct fp_traits_native
+{
+ typedef native_tag method;
+};
+
+// generic_tag version -------------------------------------------------------------
+
+template<class T, class U> struct fp_traits_non_native
+{
+#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
+ typedef generic_tag<std::numeric_limits<T>::is_specialized> method;
+#else
+ typedef generic_tag<false> method;
+#endif
+};
+
+// ieee_tag versions ---------------------------------------------------------------
+
+/*
+These specializations of fp_traits_non_native contain information needed
+to "parse" the binary representation of a floating point number.
+
+Typedef 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.
+
+ method -- tells us whether all bytes are copied or not.
+ It is a typedef for ieee_copy_all_bits_tag or ieee_copy_leading_bits_tag.
+
+Static data members:
+
+ sign, exponent, flag, significand -- bit masks that give the meaning of the
+ bits in the leading bytes.
+
+Static function members:
+
+ get_bits(), set_bits() -- provide access to the leading bytes.
+
+*/
+
+// ieee_tag version, float (32 bits) -----------------------------------------------
+
+#ifndef BOOST_FPCLASSIFY_VAX_FORMAT
+
+template<> struct fp_traits_non_native<float, single_precision>
+{
+ typedef ieee_copy_all_bits_tag method;
+
+ BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u);
+ BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7f800000);
+ BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00000000);
+ BOOST_STATIC_CONSTANT(uint32_t, significand = 0x007fffff);
+
+ typedef uint32_t bits;
+ static void get_bits(float x, uint32_t& a) { std::memcpy(&a, &x, 4); }
+ static void set_bits(float& x, uint32_t a) { std::memcpy(&x, &a, 4); }
+};
+
+// ieee_tag version, double (64 bits) ----------------------------------------------
+
+#if defined(BOOST_NO_INT64_T) || defined(BOOST_NO_INCLASS_MEMBER_INITIALIZATION) \
+ || defined(__BORLANDC__) || defined(__CODEGEAR__)
+
+template<> struct fp_traits_non_native<double, double_precision>
+{
+ typedef ieee_copy_leading_bits_tag method;
+
+ BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u);
+ BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7ff00000);
+ BOOST_STATIC_CONSTANT(uint32_t, flag = 0);
+ BOOST_STATIC_CONSTANT(uint32_t, significand = 0x000fffff);
+
+ typedef uint32_t bits;
+
+ static void get_bits(double x, uint32_t& a)
+ {
+ std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);
+ }
+
+ static void set_bits(double& x, uint32_t a)
+ {
+ std::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
+};
+
+//..............................................................................
+
+#else
+
+template<> struct fp_traits_non_native<double, double_precision>
+{
+ typedef ieee_copy_all_bits_tag method;
+
+ static const uint64_t sign = ((uint64_t)0x80000000u) << 32;
+ static const uint64_t exponent = ((uint64_t)0x7ff00000) << 32;
+ static const uint64_t flag = 0;
+ static const uint64_t significand
+ = (((uint64_t)0x000fffff) << 32) + ((uint64_t)0xffffffffu);
+
+ typedef uint64_t bits;
+ static void get_bits(double x, uint64_t& a) { std::memcpy(&a, &x, 8); }
+ static void set_bits(double& x, uint64_t a) { std::memcpy(&x, &a, 8); }
+};
+
+#endif
+
+#endif // #ifndef BOOST_FPCLASSIFY_VAX_FORMAT
+
+// long double (64 bits) -------------------------------------------------------
+
+#if defined(BOOST_NO_INT64_T) || defined(BOOST_NO_INCLASS_MEMBER_INITIALIZATION)\
+ || defined(__BORLANDC__) || defined(__CODEGEAR__)
+
+template<> struct fp_traits_non_native<long double, double_precision>
+{
+ typedef ieee_copy_leading_bits_tag method;
+
+ BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u);
+ BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7ff00000);
+ BOOST_STATIC_CONSTANT(uint32_t, flag = 0);
+ BOOST_STATIC_CONSTANT(uint32_t, significand = 0x000fffff);
+
+ typedef uint32_t bits;
+
+ static void get_bits(long double x, uint32_t& a)
+ {
+ std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);
+ }
+
+ static void set_bits(long double& x, uint32_t a)
+ {
+ std::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
+};
+
+//..............................................................................
+
+#else
+
+template<> struct fp_traits_non_native<long double, double_precision>
+{
+ typedef ieee_copy_all_bits_tag method;
+
+ static const uint64_t sign = (uint64_t)0x80000000u << 32;
+ static const uint64_t exponent = (uint64_t)0x7ff00000 << 32;
+ static const uint64_t flag = 0;
+ static const uint64_t significand
+ = ((uint64_t)0x000fffff << 32) + (uint64_t)0xffffffffu;
+
+ typedef uint64_t bits;
+ static void get_bits(long double x, uint64_t& a) { std::memcpy(&a, &x, 8); }
+ static void set_bits(long double& x, uint64_t a) { std::memcpy(&x, &a, 8); }
+};
+
+#endif
+
+
+// long double (>64 bits), x86 and x64 -----------------------------------------
+
+#if defined(__i386) || defined(__i386__) || defined(_M_IX86) \
+ || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) \
+ || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64)
+
+// Intel extended double precision format (80 bits)
+
+template<>
+struct fp_traits_non_native<long double, extended_double_precision>
+{
+ typedef ieee_copy_leading_bits_tag method;
+
+ BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u);
+ BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7fff0000);
+ BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00008000);
+ BOOST_STATIC_CONSTANT(uint32_t, significand = 0x00007fff);
+
+ typedef uint32_t bits;
+
+ static void get_bits(long double x, uint32_t& a)
+ {
+ std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + 6, 4);
+ }
+
+ static void set_bits(long double& x, uint32_t a)
+ {
+ std::memcpy(reinterpret_cast<unsigned char*>(&x) + 6, &a, 4);
+ }
+};
+
+
+// long double (>64 bits), Itanium ---------------------------------------------
+
+#elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
+
+// The floating point format is unknown at compile time
+// No template specialization is provided.
+// The generic_tag definition is used.
+
+// The Itanium supports both
+// the Intel extended double precision format (80 bits) and
+// the IEEE extended double precision format with 15 exponent bits (128 bits).
+
+
+// long double (>64 bits), PowerPC ---------------------------------------------
+
+#elif defined(__powerpc) || defined(__powerpc__) || defined(__POWERPC__) \
+ || defined(__ppc) || defined(__ppc__) || defined(__PPC__)
+
+// PowerPC extended double precision format (128 bits)
+
+template<>
+struct fp_traits_non_native<long double, extended_double_precision>
+{
+ typedef ieee_copy_leading_bits_tag method;
+
+ BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u);
+ BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7ff00000);
+ BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00000000);
+ BOOST_STATIC_CONSTANT(uint32_t, significand = 0x000fffff);
+
+ typedef uint32_t bits;
+
+ static void get_bits(long double x, uint32_t& a)
+ {
+ std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);
+ }
+
+ static void set_bits(long double& x, uint32_t a)
+ {
+ std::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_ = 12);
+#else
+ BOOST_STATIC_ASSERT(false);
+#endif
+};
+
+
+// long double (>64 bits), Motorola 68K ----------------------------------------
+
+#elif defined(__m68k) || defined(__m68k__) \
+ || defined(__mc68000) || defined(__mc68000__) \
+
+// Motorola extended double precision format (96 bits)
+
+// It is the same format as the Intel extended double precision format,
+// except that 1) it is big-endian, 2) the 3rd and 4th byte are padding, and
+// 3) the flag bit is not set for infinity
+
+template<>
+struct fp_traits_non_native<long double, extended_double_precision>
+{
+ typedef ieee_copy_leading_bits_tag method;
+
+ BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u);
+ BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7fff0000);
+ BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00008000);
+ BOOST_STATIC_CONSTANT(uint32_t, significand = 0x00007fff);
+
+ // copy 1st, 2nd, 5th and 6th byte. 3rd and 4th byte are padding.
+
+ typedef uint32_t bits;
+
+ static void get_bits(long double x, uint32_t& a)
+ {
+ std::memcpy(&a, &x, 2);
+ std::memcpy(reinterpret_cast<unsigned char*>(&a) + 2,
+ reinterpret_cast<const unsigned char*>(&x) + 4, 2);
+ }
+
+ static void set_bits(long double& x, uint32_t a)
+ {
+ std::memcpy(&x, &a, 2);
+ std::memcpy(reinterpret_cast<unsigned char*>(&x) + 4,
+ reinterpret_cast<const unsigned char*>(&a) + 2, 2);
+ }
+};
+
+
+// long double (>64 bits), All other processors --------------------------------
+
+#else
+
+// IEEE extended double precision format with 15 exponent bits (128 bits)
+
+template<>
+struct fp_traits_non_native<long double, extended_double_precision>
+{
+ typedef ieee_copy_leading_bits_tag method;
+
+ BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u);
+ BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7fff0000);
+ BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00000000);
+ BOOST_STATIC_CONSTANT(uint32_t, significand = 0x0000ffff);
+
+ typedef uint32_t bits;
+
+ static void get_bits(long double x, uint32_t& a)
+ {
+ std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);
+ }
+
+ static void set_bits(long double& x, uint32_t a)
+ {
+ std::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_ = 12);
+#else
+ BOOST_STATIC_ASSERT(false);
+#endif
+};
+
+#endif
+
+//------------------------------------------------------------------------------
+
+// size_to_precision is a type switch for converting a C++ floating point type
+// to the corresponding precision type.
+
+template<int n, bool fp> struct size_to_precision
+{
+ typedef unknown_precision type;
+};
+
+template<> struct size_to_precision<4, true>
+{
+ typedef single_precision type;
+};
+
+template<> struct size_to_precision<8, true>
+{
+ typedef double_precision type;
+};
+
+template<> struct size_to_precision<10, true>
+{
+ typedef extended_double_precision type;
+};
+
+template<> struct size_to_precision<12, true>
+{
+ typedef extended_double_precision type;
+};
+
+template<> struct size_to_precision<16, true>
+{
+ typedef extended_double_precision type;
+};
+
+//------------------------------------------------------------------------------
+//
+// Figure out whether to use native classification functions based on
+// whether T is a built in floating point type or not:
+//
+template <class T>
+struct select_native
+{
+ typedef BOOST_DEDUCED_TYPENAME size_to_precision<sizeof(T), ::boost::is_floating_point<T>::value>::type precision;
+ typedef fp_traits_non_native<T, precision> type;
+};
+template<>
+struct select_native<float>
+{
+ typedef fp_traits_native<float> type;
+};
+template<>
+struct select_native<double>
+{
+ typedef fp_traits_native<double> type;
+};
+template<>
+struct select_native<long double>
+{
+ typedef fp_traits_native<long double> type;
+};
+
+//------------------------------------------------------------------------------
+
+// fp_traits is a type switch that selects the right fp_traits_non_native
+
+template<class T> struct fp_traits
+{
+#if (defined(BOOST_MATH_USE_C99) && (!defined(__GNUC__) || (__GNUC__ >= 4)))
+ typedef typename select_native<T>::type type;
+#else
+ typedef BOOST_DEDUCED_TYPENAME size_to_precision<sizeof(T), ::boost::is_floating_point<T>::value>::type precision;
+ typedef fp_traits_non_native<T, precision> type;
+#endif
+};
+
+//------------------------------------------------------------------------------
+
+} // namespace detail
+} // namespace math
+} // namespace boost
+
+#endif

Modified: trunk/boost/math/special_functions/fpclassify.hpp
==============================================================================
--- trunk/boost/math/special_functions/fpclassify.hpp (original)
+++ trunk/boost/math/special_functions/fpclassify.hpp 2008-12-05 11:05:26 EST (Fri, 05 Dec 2008)
@@ -1,4 +1,5 @@
-// Copyright John Maddock 2005-2006.
+// Copyright John Maddock 2005-2008.
+// Copyright (c) 2006-2008 Johan Rade
 // Use, modification and distribution are subject to 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)
@@ -16,52 +17,63 @@
 #include <boost/math/tools/real_cast.hpp>
 #include <boost/type_traits/is_floating_point.hpp>
 #include <boost/math/special_functions/math_fwd.hpp>
+#include <boost/math/special_functions/detail/fp_traits.hpp>
 
-#if defined(_MSC_VER) || defined(__BORLANDC__)
-#include <float.h>
-#endif
+/*
 
-#ifdef BOOST_NO_STDC_NAMESPACE
- namespace std{ using ::abs; using ::fabs; }
-#endif
+1. If the platform is C99 compliant, then the native floating point
+classification functions are used.
 
-#ifndef FP_NORMAL
+2. If the platform is not C99 compliant, and the binary format for
+a floating point type (float, double or long double) can be determined
+at compile time, then the following algorithm is used:
 
-#define FP_ZERO 0
-#define FP_NORMAL 1
-#define FP_INFINITE 2
-#define FP_NAN 3
-#define FP_SUBNORMAL 4
+ If all exponent bits, the flag bit (if there is one),
+ and all significand bits are 0, then the number is zero.
 
-#else
+ If all exponent bits and the flag bit (if there is one) are 0,
+ and at least one significand bit is 1, then the number is subnormal.
 
-#define BOOST_HAS_FPCLASSIFY
+ If all exponent bits are 1 and all significand bits are 0,
+ then the number is infinity.
 
-#ifndef fpclassify
-# if (defined(__GLIBCPP__) || defined(__GLIBCXX__)) \
- && defined(_GLIBCXX_USE_C99_MATH) \
- && !(defined(_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC) \
- && (_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC != 0))
-# ifdef _STLP_VENDOR_CSTD
-# define BOOST_FPCLASSIFY_PREFIX ::_STLP_VENDOR_CSTD::
-# else
-# define BOOST_FPCLASSIFY_PREFIX ::std::
-# endif
-# else
-# undef BOOST_HAS_FPCLASSIFY
-# define BOOST_FPCLASSIFY_PREFIX
-# endif
-#elif (defined(__HP_aCC) && !defined(__hppa))
-// aCC 6 appears to do "#define fpclassify fpclassify" which messes us up a bit!
-# define BOOST_FPCLASSIFY_PREFIX ::
-#else
-# define BOOST_FPCLASSIFY_PREFIX
-#endif
+ If all exponent bits are 1 and at least one significand bit is 1,
+ then the number is a not-a-number.
+
+ Otherwise the number is normal.
+
+ This algorithm works for the IEEE 754 representation,
+ and also for several non IEEE 754 formats.
+
+ Most formats have the structure
+ sign bit + exponent bits + significand bits.
+
+ A few have the structure
+ sign bit + exponent bits + flag bit + significand bits.
+ The flag bit is 0 for zero and subnormal numbers,
+ and 1 for normal numbers and NaN.
+ It is 0 (Motorola 68K) or 1 (Intel) for infinity.
 
-#ifdef __MINGW32__
-# undef BOOST_HAS_FPCLASSIFY
+ To get the bits, the four or eight most significant bytes are copied
+ into an uint32_t or uint64_t and bit masks are applied.
+ This covers all the exponent bits and the flag bit (if there is one),
+ but not always all the significand bits.
+ Some of the functions below have two implementations,
+ depending on whether all the significand bits are copied or not.
+
+3. If the platform is not C99 compliant, and the binary format for
+a floating point type (float, double or long double) can not be determined
+at compile time, then comparison with std::numeric_limits values
+is used.
+
+*/
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+#include <float.h>
 #endif
 
+#ifdef BOOST_NO_STDC_NAMESPACE
+ namespace std{ using ::abs; using ::fabs; }
 #endif
 
 namespace boost{
@@ -99,8 +111,16 @@
 namespace detail{
 
 template <class T>
-inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const mpl::true_&)
+inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const native_tag&)
+{
+ return (std::fpclassify)(t);
+}
+
+template <class T>
+inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const generic_tag<true>&)
 {
+ BOOST_MATH_INSTRUMENT_VARIABLE(t);
+
    // whenever possible check for Nan's first:
 #ifdef BOOST_HAS_FPCLASSIFY
    if(::boost::math_detail::is_nan_helper(t, ::boost::is_floating_point<T>()))
@@ -133,117 +153,351 @@
 }
 
 template <class T>
-inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const mpl::false_&)
+inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const generic_tag<false>&)
 {
+#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
+ if(std::numeric_limits<T>::is_specialized)
+ return fp_classify_imp(t, mpl::true_());
+#endif
    //
    // An unknown type with no numeric_limits support,
    // so what are we supposed to do we do here?
    //
+ BOOST_MATH_INSTRUMENT_VARIABLE(t);
+
    return t == 0 ? FP_ZERO : FP_NORMAL;
 }
 
-} // namespace detail
-
-template <class T>
-inline int fpclassify BOOST_NO_MACRO_EXPAND(T t)
+template<class T>
+int fpclassify_imp BOOST_NO_MACRO_EXPAND(T x, ieee_copy_all_bits_tag)
 {
-#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
- if(std::numeric_limits<T>::is_specialized)
- return detail::fpclassify_imp(t, mpl::true_());
- return detail::fpclassify_imp(t, mpl::false_());
-#else
- return detail::fpclassify_imp(t, mpl::bool_< ::std::numeric_limits<T>::is_specialized>());
-#endif
+ typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
+
+ BOOST_MATH_INSTRUMENT_VARIABLE(x);
+
+ BOOST_DEDUCED_TYPENAME traits::bits a;
+ traits::get_bits(x,a);
+ BOOST_MATH_INSTRUMENT_VARIABLE(a);
+ a &= traits::exponent | traits::flag | traits::significand;
+ BOOST_MATH_INSTRUMENT_VARIABLE((traits::exponent | traits::flag | traits::significand));
+ BOOST_MATH_INSTRUMENT_VARIABLE(a);
+
+ if(a <= traits::significand) {
+ if(a == 0)
+ return FP_ZERO;
+ else
+ return FP_SUBNORMAL;
+ }
+
+ if(a < traits::exponent) return FP_NORMAL;
+
+ a &= traits::significand;
+ if(a == 0) return FP_INFINITE;
+
+ return FP_NAN;
 }
 
-#if defined(BOOST_HAS_FPCLASSIFY)
-inline int fpclassify BOOST_NO_MACRO_EXPAND(float t)
+template<class T>
+int fpclassify_imp BOOST_NO_MACRO_EXPAND(T x, ieee_copy_leading_bits_tag)
 {
- return BOOST_FPCLASSIFY_PREFIX fpclassify(t);
+ typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
+
+ BOOST_MATH_INSTRUMENT_VARIABLE(x);
+
+ BOOST_DEDUCED_TYPENAME traits::bits a;
+ traits::get_bits(x,a);
+ a &= traits::exponent | traits::flag | traits::significand;
+
+ if(a <= traits::significand) {
+ if(x == 0)
+ return FP_ZERO;
+ else
+ return FP_SUBNORMAL;
+ }
+
+ if(a < traits::exponent) return FP_NORMAL;
+
+ a &= traits::significand;
+ traits::set_bits(x,a);
+ if(x == 0) return FP_INFINITE;
+
+ return FP_NAN;
 }
-inline int fpclassify BOOST_NO_MACRO_EXPAND(double t)
+
+#if defined(BOOST_HAS_FPCLASSIFY)
+template<class T, class U>
+inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T x, const U&)
 {
- return BOOST_FPCLASSIFY_PREFIX fpclassify(t);
+ return BOOST_FPCLASSIFY_PREFIX fpclassify BOOST_NO_MACRO_EXPAND(x);
 }
-#if !defined(__CYGWIN__) && !defined(__HP_aCC) && !defined(BOOST_INTEL) \
- && !defined(BOOST_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY) \
- && !(defined(__GNUC__) && !defined(BOOST_MATH_USE_C99))
-// The native fpclassify broken for long doubles with aCC
+#if defined(__CYGWIN__) || defined(__HP_aCC) || defined(BOOST_INTEL) \
+ || defined(BOOST_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY) \
+ || (defined(__GNUC__) && !defined(BOOST_MATH_USE_C99))
+// The native fpclassify broken for long doubles
 // use portable one instead....
-inline int fpclassify BOOST_NO_MACRO_EXPAND(long double t)
+template<class U>
+inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(long double t, const U&)
 {
- return BOOST_FPCLASSIFY_PREFIX fpclassify(t);
+#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
+ typedef generic_tag<std::numeric_limits<T>::is_specialized> method;
+#else
+ typedef generic_tag<false> method;
+#endif
+ return fpclassify_imp BOOST_NO_MACRO_EXPAND(t, method(), t);
 }
 #endif
+#endif
+} // namespace detail
 
-#elif defined(_MSC_VER)
-// This only works for type double, for both float
-// and long double it gives misleading answers.
-inline int fpclassify BOOST_NO_MACRO_EXPAND(double t)
+template <class T>
+inline int fpclassify BOOST_NO_MACRO_EXPAND(T t)
 {
- switch(::_fpclass(t))
- {
- case _FPCLASS_SNAN /* Signaling NaN */ :
- case _FPCLASS_QNAN /* Quiet NaN */ :
- return FP_NAN;
- case _FPCLASS_NINF /*Negative infinity ( -INF) */ :
- case _FPCLASS_PINF /* Positive infinity (+INF) */ :
- return FP_INFINITE;
- case _FPCLASS_NN /* Negative normalized non-zero */ :
- case _FPCLASS_PN /* Positive normalized non-zero */ :
- return FP_NORMAL;
- case _FPCLASS_ND /* Negative denormalized */:
- case _FPCLASS_PD /* Positive denormalized */ :
- return FP_SUBNORMAL;
- case _FPCLASS_NZ /* Negative zero ( - 0) */ :
- case _FPCLASS_PZ /* Positive 0 (+0) */ :
- return FP_ZERO;
- default:
- /**/ ;
- }
- return FP_NAN; // should never get here!!!
+ typedef typename detail::fp_traits<T>::type traits;
+ typedef typename traits::method method;
+#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
+ if(std::numeric_limits<T>::is_specialized && detail::is_generic_tag_false(method()))
+ return detail::fpclassify_imp(t, detail::generic_tag<true>());
+ return detail::fpclassify_imp(t, method());
+#else
+ return detail::fpclassify_imp(t, method());
+#endif
 }
+
+namespace detail {
+
+ template<class T>
+ inline bool isfinite_impl(T x, native_tag const&)
+ {
+ return (std::isfinite)(x);
+ }
+
+ template<class T>
+ inline bool isfinite_impl(T x, generic_tag<true> const&)
+ {
+ return x >= -std::numeric_limits<T>::max()
+ && x <= std::numeric_limits<T>::max();
+ }
+
+ template<class T>
+ inline bool isfinite_impl(T x, generic_tag<false> const&)
+ {
+#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
+ if(std::numeric_limits<T>::is_specialized)
+ return isfinite_impl(x, mpl::true_());
 #endif
+ (void)x; // warning supression.
+ return true;
+ }
+
+ template<class T>
+ inline bool isfinite_impl(T x, ieee_tag const&)
+ {
+ typedef BOOST_DEDUCED_TYPENAME detail::fp_traits<T>::type traits;
+ BOOST_DEDUCED_TYPENAME traits::bits a;
+ traits::get_bits(x,a);
+ a &= traits::exponent;
+ return a != traits::exponent;
+ }
 
-template <class T>
-inline bool isfinite BOOST_NO_MACRO_EXPAND(T z)
-{
- int t = (::boost::math::fpclassify)(z);
- return (t != (int)FP_NAN) && (t != (int)FP_INFINITE);
 }
 
-template <class T>
-inline bool isinf BOOST_NO_MACRO_EXPAND(T t)
-{
- return (::boost::math::fpclassify)(t) == (int)FP_INFINITE;
+template<class T>
+inline bool (isfinite)(T x)
+{
+ typedef typename detail::fp_traits<T>::type traits;
+ typedef typename traits::method method;
+ typedef typename boost::is_floating_point<T>::type fp_tag;
+ return detail::isfinite_impl(x, method());
+}
+
+//------------------------------------------------------------------------------
+
+namespace detail {
+
+ template<class T>
+ inline bool isnormal_impl(T x, native_tag const&)
+ {
+ return (std::isnormal)(x);
+ }
+
+ template<class T>
+ inline bool isnormal_impl(T x, generic_tag<true> const&)
+ {
+ if(x < 0) x = -x;
+ return x >= std::numeric_limits<T>::min()
+ && x <= std::numeric_limits<T>::max();
+ }
+
+ template<class T>
+ inline bool isnormal_impl(T x, generic_tag<false> const&)
+ {
+#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
+ if(std::numeric_limits<T>::is_specialized)
+ return isnormal_impl(x, mpl::true_());
+#endif
+ return !(x == 0);
+ }
+
+ template<class T>
+ inline bool isnormal_impl(T x, ieee_tag const&)
+ {
+ typedef BOOST_DEDUCED_TYPENAME detail::fp_traits<T>::type traits;
+ BOOST_DEDUCED_TYPENAME traits::bits a;
+ traits::get_bits(x,a);
+ a &= traits::exponent | traits::flag;
+ return (a != 0) && (a < traits::exponent);
+ }
+
 }
 
-template <class T>
-inline bool isnan BOOST_NO_MACRO_EXPAND(T t)
-{
- return (::boost::math::fpclassify)(t) == (int)FP_NAN;
+template<class T>
+inline bool (isnormal)(T x)
+{
+ typedef typename detail::fp_traits<T>::type traits;
+ typedef typename traits::method method;
+ typedef typename boost::is_floating_point<T>::type fp_tag;
+ return detail::isnormal_impl(x, method());
+}
+
+//------------------------------------------------------------------------------
+
+namespace detail {
+
+ template<class T>
+ inline bool isinf_impl(T x, native_tag const&)
+ {
+ return (std::isinf)(x);
+ }
+
+ template<class T>
+ inline bool isinf_impl(T x, generic_tag<true> const&)
+ {
+ return std::numeric_limits<T>::has_infinity
+ && ( x == std::numeric_limits<T>::infinity()
+ || x == -std::numeric_limits<T>::infinity());
+ }
+
+ template<class T>
+ inline bool isinf_impl(T x, generic_tag<false> const&)
+ {
+#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
+ if(std::numeric_limits<T>::is_specialized)
+ return isinf_impl(x, mpl::true_());
+#endif
+ (void)x; // warning supression.
+ return false;
+ }
+
+ template<class T>
+ inline bool isinf_impl(T x, ieee_copy_all_bits_tag const&)
+ {
+ typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
+
+ BOOST_DEDUCED_TYPENAME traits::bits a;
+ traits::get_bits(x,a);
+ a &= traits::exponent | traits::significand;
+ return a == traits::exponent;
+ }
+
+ template<class T>
+ inline bool isinf_impl(T x, ieee_copy_leading_bits_tag const&)
+ {
+ typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
+
+ BOOST_DEDUCED_TYPENAME traits::bits a;
+ traits::get_bits(x,a);
+ a &= traits::exponent | traits::significand;
+ if(a != traits::exponent)
+ return false;
+
+ traits::set_bits(x,0);
+ return x == 0;
+ }
+
+} // namespace detail
+
+template<class T>
+inline bool (isinf)(T x)
+{
+ typedef typename detail::fp_traits<T>::type traits;
+ typedef typename traits::method method;
+ typedef typename boost::is_floating_point<T>::type fp_tag;
+ return detail::isinf_impl(x, method());
+}
+
+//------------------------------------------------------------------------------
+
+namespace detail {
+
+ template<class T>
+ inline bool isnan_impl(T x, native_tag const&)
+ {
+ return (std::isnan)(x);
+ }
+
+ template<class T>
+ inline bool isnan_impl(T x, generic_tag<true> const&)
+ {
+ return std::numeric_limits<T>::has_infinity
+ ? !(x <= std::numeric_limits<T>::infinity())
+ : x != x;
+ }
+
+ template<class T>
+ inline bool isnan_impl(T x, generic_tag<false> const&)
+ {
+#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
+ if(std::numeric_limits<T>::is_specialized)
+ return isnan_impl(x, mpl::true_());
+#endif
+ (void)x; // warning supression
+ return false;
+ }
+
+ template<class T>
+ inline bool isnan_impl(T x, ieee_copy_all_bits_tag const&)
+ {
+ typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
+
+ BOOST_DEDUCED_TYPENAME traits::bits a;
+ traits::get_bits(x,a);
+ a &= traits::exponent | traits::significand;
+ return a > traits::exponent;
+ }
+
+ template<class T>
+ inline bool isnan_impl(T x, ieee_copy_leading_bits_tag const&)
+ {
+ typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
+
+ BOOST_DEDUCED_TYPENAME traits::bits a;
+ traits::get_bits(x,a);
+
+ a &= traits::exponent | traits::significand;
+ if(a < traits::exponent)
+ return false;
+
+ a &= traits::significand;
+ traits::set_bits(x,a);
+ return x != 0;
+ }
+
+} // namespace detail
+
+template<class T> bool (isnan)(T x)
+{
+ typedef typename detail::fp_traits<T>::type traits;
+ typedef typename traits::method method;
+ typedef typename boost::is_floating_point<T>::type fp_tag;
+ return detail::isnan_impl(x, method());
 }
+
 #ifdef isnan
 template <> inline bool isnan BOOST_NO_MACRO_EXPAND<float>(float t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); }
 template <> inline bool isnan BOOST_NO_MACRO_EXPAND<double>(double t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); }
 template <> inline bool isnan BOOST_NO_MACRO_EXPAND<long double>(long double t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); }
-#elif defined(BOOST_MSVC)
-# pragma warning(push)
-# pragma warning(disable: 4800) // forcing value to bool 'true' or 'false'
-# pragma warning(disable: 4244) // conversion from 'long double' to 'double',
-// No possible loss of data because they are same size.
-template <> inline bool isnan BOOST_NO_MACRO_EXPAND<float>(float t){ return _isnan(t); }
-template <> inline bool isnan BOOST_NO_MACRO_EXPAND<double>(double t){ return _isnan(t); }
-template <> inline bool isnan BOOST_NO_MACRO_EXPAND<long double>(long double t){ return _isnan(t); }
-#pragma warning (pop)
 #endif
 
-template <class T>
-inline bool isnormal BOOST_NO_MACRO_EXPAND(T t)
-{
- return (::boost::math::fpclassify)(t) == (int)FP_NORMAL;
-}
-
 } // namespace math
 } // namespace boost
 


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk