]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/boost/libs/multiprecision/test/test_sf_import_c99.cpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / libs / multiprecision / test / test_sf_import_c99.cpp
index 3d088a1bec547a5319ef90aebfb603b449573871..2e45b5e74a554760bd0e741c463f4e06e4b41861 100644 (file)
@@ -9,11 +9,16 @@
 
 #if !defined(TEST_MPF_50) && !defined(TEST_MPF) && !defined(TEST_BACKEND) && !defined(TEST_CPP_DEC_FLOAT)\
    && !defined(TEST_MPFR) && !defined(TEST_MPFR_50) && !defined(TEST_MPFI_50) && !defined(TEST_FLOAT128)\
-   && !defined(TEST_CPP_BIN_FLOAT)
+   && !defined(TEST_CPP_BIN_FLOAT) && !defined(TEST_CPP_DEC_FLOAT_2) && !defined(TEST_CPP_DEC_FLOAT_3)\
+  && !defined(TEST_CPP_DEC_FLOAT_4) && !defined(TEST_CPP_DEC_FLOAT_5)
 #  define TEST_MPF_50
 #  define TEST_MPFR_50
 #  define TEST_MPFI_50
 #  define TEST_CPP_DEC_FLOAT
+#  define TEST_CPP_DEC_FLOAT_2
+#  define TEST_CPP_DEC_FLOAT_3
+#  define TEST_CPP_DEC_FLOAT_4
+#  define TEST_CPP_DEC_FLOAT_5
 #  define TEST_FLOAT128
 #  define TEST_CPP_BIN_FLOAT
 
 #ifdef TEST_MPFI_50
 #include <boost/multiprecision/mpfi.hpp>
 #endif
-#ifdef TEST_CPP_DEC_FLOAT
+#if defined(TEST_CPP_DEC_FLOAT) || defined(TEST_CPP_DEC_FLOAT_2) || defined(TEST_CPP_DEC_FLOAT_3) || defined(TEST_CPP_DEC_FLOAT_4) || defined(TEST_CPP_DEC_FLOAT_5)
 #include <boost/multiprecision/cpp_dec_float.hpp>
 #endif
 #ifdef TEST_CPP_BIN_FLOAT
 #include <boost/multiprecision/cpp_bin_float.hpp>
+#include <boost/multiprecision/debug_adaptor.hpp>
 #endif
 #ifdef TEST_FLOAT128
 #include <boost/multiprecision/float128.hpp>
 #endif
 
+#include <boost/math/constants/constants.hpp>
 #include "test.hpp"
 
 #ifdef signbit
 #undef isnormal
 #endif
 
+#ifdef MPFR_VERSION_MAJOR
+#define BOOST_MPFR_VERSION MPFR_VERSION_MAJOR * 10000 + MPFR_VERSION_MINOR * 100 + MPFR_VERSION_PATCHLEVEL
+#endif
+
 template <class T, class U>
 void test_less(T a, U b)
 {
@@ -583,6 +594,1447 @@ void test_poison()
 #endif
 }
 
+template <class T>
+bool type_sets_errno(const T&)
+{
+   return true;
+}
+#ifdef TEST_MPFR_50
+template<unsigned Digits10, boost::multiprecision::mpfr_allocation_type AllocateType, boost::multiprecision::expression_template_option ExpressionTemplates>
+bool type_sets_errno(const boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<Digits10, AllocateType>, ExpressionTemplates> &)
+{
+   return false;
+}
+#endif
+#ifdef TEST_FLOAT128
+bool type_sets_errno(const boost::multiprecision::float128 &)
+{
+   return false;
+}
+#endif
+
+template <class T>
+typename boost::enable_if_c<std::numeric_limits<T>::is_specialized>::type check_invalid(const T& val)
+{
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      BOOST_CHECK(isnan(val));
+   }
+   else
+   {
+      BOOST_CHECK_EQUAL(val, 0);
+   }
+   if(type_sets_errno(val))
+      BOOST_CHECK_EQUAL(errno, EDOM);
+   errno = 0;
+}
+
+template <class T>
+typename boost::disable_if_c<std::numeric_limits<T>::is_specialized>::type check_invalid(const T& val)
+{
+   check_invalid(static_cast<typename T::result_type>(val));
+}
+
+template <class T>
+void check_erange(const T& val)
+{
+   if(type_sets_errno(val))
+      BOOST_CHECK_EQUAL(errno, ERANGE);
+   errno = 0;
+}
+
+template <class T>
+void test_c99_appendix_F()
+{
+   //
+   // Tests conformance to non-normative appendix F.9.1 of C99, basically how to handle
+   // special cases, infinities and NaN's.
+   //
+   errno = 0;
+   T tol = std::numeric_limits<T>::epsilon();
+   // F.9.1.1:
+   T arg = 1;
+   T val = acos(arg);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   arg = 2;
+   check_invalid(acos(arg));
+   arg = -2;
+   check_invalid(acos(arg));
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = std::numeric_limits<T>::infinity();
+      check_invalid(acos(arg));
+      arg = -std::numeric_limits<T>::infinity();
+      check_invalid(acos(arg));
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(acos(arg));
+      arg = -std::numeric_limits<T>::quiet_NaN();
+      check_invalid(acos(arg));
+   }
+   // F.9.1.2:
+   arg = 0;
+   val = asin(arg);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   arg = -arg;
+   if(signbit(arg))
+   {
+      val = asin(arg);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val));
+   }
+   arg = 2;
+   check_invalid(asin(arg));
+   arg = -2;
+   check_invalid(asin(arg));
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = std::numeric_limits<T>::infinity();
+      check_invalid(asin(arg));
+      arg = -std::numeric_limits<T>::infinity();
+      check_invalid(asin(arg));
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(asin(arg));
+      arg = -std::numeric_limits<T>::quiet_NaN();
+      check_invalid(asin(arg));
+   }
+   // F.9.1.3:
+   arg = 0;
+   val = atan(arg);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   arg = -arg;
+   if(signbit(arg))
+   {
+      val = atan(arg);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val));
+   }
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = std::numeric_limits<T>::infinity();
+      val = atan(arg);
+      BOOST_CHECK_EQUAL(val, boost::math::constants::half_pi<T>());
+      arg = -std::numeric_limits<T>::infinity();
+      val = atan(arg);
+      BOOST_CHECK_EQUAL(val, -boost::math::constants::half_pi<T>());
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(asin(arg));
+      arg = -std::numeric_limits<T>::quiet_NaN();
+      check_invalid(asin(arg));
+   }
+   // F.9.1.4:
+   arg = 0;
+   T arg2 = 0;
+   val = atan2(arg, arg2);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   arg = -arg;
+   if(signbit(arg))
+   {
+      val = atan2(arg, arg2);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val));
+   }
+   arg2 = -arg2;
+   if(signbit(arg2))
+   {
+      arg = 0;
+      val = atan2(arg, arg2);
+      BOOST_CHECK_EQUAL(val, boost::math::constants::pi<T>());
+      BOOST_CHECK(signbit(val) == 0);
+      arg = -arg;
+      val = atan2(arg, arg2);
+      BOOST_CHECK_EQUAL(val, -boost::math::constants::pi<T>());
+      BOOST_CHECK(signbit(val));
+   }
+   arg = 0;
+   arg2 = -2;
+   val = atan2(arg, arg2);
+   BOOST_CHECK_EQUAL(val, boost::math::constants::pi<T>());
+   arg = -arg;
+   if(signbit(arg))
+   {
+      val = atan2(arg, arg2);
+      BOOST_CHECK_EQUAL(val, -boost::math::constants::pi<T>());
+   }
+   arg = 0;
+   arg2 = 2;
+   val = atan2(arg, arg2);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   arg = -arg;
+   if(signbit(arg))
+   {
+      val = atan2(arg, arg2);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val));
+   }
+   arg = -2;
+   arg2 = 0;
+   val = atan2(arg, arg2);
+   BOOST_CHECK_EQUAL(val, -boost::math::constants::half_pi<T>());
+   arg2 = -arg2;
+   if(signbit(arg2))
+   {
+      val = atan2(arg, arg2);
+      BOOST_CHECK_EQUAL(val, -boost::math::constants::half_pi<T>());
+   }
+   arg = 2;
+   arg2 = 0;
+   val = atan2(arg, arg2);
+   BOOST_CHECK_EQUAL(val, boost::math::constants::half_pi<T>());
+   arg2 = -arg2;
+   if(signbit(arg2))
+   {
+      val = atan2(arg, arg2);
+      BOOST_CHECK_EQUAL(val, boost::math::constants::half_pi<T>());
+   }
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = 2;
+      arg2 = -std::numeric_limits<T>::infinity();
+      val = atan2(arg, arg2);
+      BOOST_CHECK_EQUAL(val, boost::math::constants::pi<T>());
+      arg = -arg;
+      val = atan2(arg, arg2);
+      BOOST_CHECK_EQUAL(val, -boost::math::constants::pi<T>());
+      arg = 2;
+      arg2 = std::numeric_limits<T>::infinity();
+      val = atan2(arg, arg2);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val) == 0);
+      arg = -arg;
+      if(signbit(-T(0)))
+      {
+         val = atan2(arg, arg2);
+         BOOST_CHECK_EQUAL(val, 0);
+         BOOST_CHECK(signbit(val));
+      }
+      arg = std::numeric_limits<T>::infinity();
+      arg2 = 2;
+      val = atan2(arg, arg2);
+      BOOST_CHECK_EQUAL(val, boost::math::constants::half_pi<T>());
+      arg = -arg;
+      val = atan2(arg, arg2);
+      BOOST_CHECK_EQUAL(val, -boost::math::constants::half_pi<T>());
+      arg = std::numeric_limits<T>::infinity();
+      arg2 = -2;
+      val = atan2(arg, arg2);
+      BOOST_CHECK_EQUAL(val, boost::math::constants::half_pi<T>());
+      arg = -arg;
+      val = atan2(arg, arg2);
+      BOOST_CHECK_EQUAL(val, -boost::math::constants::half_pi<T>());
+      arg = std::numeric_limits<T>::infinity();
+      arg2 = -std::numeric_limits<T>::infinity();
+      val = atan2(arg, arg2);
+      BOOST_CHECK_CLOSE_FRACTION(val, boost::math::constants::three_quarters_pi<T>(), tol);
+      arg = -arg;
+      val = atan2(arg, arg2);
+      BOOST_CHECK_CLOSE_FRACTION(val, -boost::math::constants::three_quarters_pi<T>(), tol);
+      arg = std::numeric_limits<T>::infinity();
+      arg2 = std::numeric_limits<T>::infinity();
+      val = atan2(arg, arg2);
+      BOOST_CHECK_CLOSE_FRACTION(val, ldexp(boost::math::constants::pi<T>(), -2), tol);
+      arg = -arg;
+      val = atan2(arg, arg2);
+      BOOST_CHECK_CLOSE_FRACTION(val, -ldexp(boost::math::constants::pi<T>(), -2), tol);
+      if(std::numeric_limits<T>::has_quiet_NaN)
+      {
+         arg = std::numeric_limits<T>::quiet_NaN();
+         arg2 = 2;
+         check_invalid(atan2(arg, arg2));
+         std::swap(arg, arg2);
+         check_invalid(atan2(arg, arg2));
+         arg = std::numeric_limits<T>::quiet_NaN();
+         check_invalid(atan2(arg, arg2));
+      }
+   }
+   // F.9.1.5:
+   arg = 0;
+   val = cos(arg);
+   BOOST_CHECK_EQUAL(val, 1);
+   arg = -arg;
+   BOOST_CHECK_EQUAL(val, 1);
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = std::numeric_limits<T>::infinity();
+      check_invalid(cos(arg));
+      arg = -std::numeric_limits<T>::infinity();
+      check_invalid(cos(arg));
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(cos(arg));
+      arg = -std::numeric_limits<T>::quiet_NaN();
+      check_invalid(cos(arg));
+   }
+   // F.9.1.6:
+   arg = 0;
+   val = sin(arg);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   arg = -arg;
+   if(signbit(arg))
+   {
+      val = sin(arg);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val));
+   }
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = std::numeric_limits<T>::infinity();
+      check_invalid(sin(arg));
+      arg = -std::numeric_limits<T>::infinity();
+      check_invalid(sin(arg));
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(sin(arg));
+      arg = -std::numeric_limits<T>::quiet_NaN();
+      check_invalid(sin(arg));
+   }
+   // F.9.1.7:
+   arg = 0;
+   val = tan(arg);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   arg = -arg;
+   if(signbit(arg))
+   {
+      val = tan(arg);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val));
+   }
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = std::numeric_limits<T>::infinity();
+      check_invalid(tan(arg));
+      arg = -std::numeric_limits<T>::infinity();
+      check_invalid(tan(arg));
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(tan(arg));
+      arg = -std::numeric_limits<T>::quiet_NaN();
+      check_invalid(tan(arg));
+   }
+   // F.9.2.1:
+   arg = 1;
+   val = acosh(arg);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   arg = -arg;
+   check_invalid(acosh(arg));
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = std::numeric_limits<T>::infinity();
+      val = acosh(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+
+      arg = -std::numeric_limits<T>::infinity();
+      check_invalid(acosh(arg));
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(acosh(arg));
+      arg = -std::numeric_limits<T>::quiet_NaN();
+      check_invalid(acosh(arg));
+   }
+   // F.9.2.2:
+   arg = 0;
+   val = asinh(arg);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   arg = -arg;
+   if(signbit(arg))
+   {
+      val = asinh(arg);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val));
+   }
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = std::numeric_limits<T>::infinity();
+      val = asinh(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+
+      arg = -std::numeric_limits<T>::infinity();
+      val = asinh(arg);
+      BOOST_CHECK_EQUAL(val, -std::numeric_limits<T>::infinity());
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(asinh(arg));
+      arg = -std::numeric_limits<T>::quiet_NaN();
+      check_invalid(asinh(arg));
+   }
+   // F.9.2.3:
+   arg = 0;
+   val = atanh(arg);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   arg = -arg;
+   if(signbit(arg))
+   {
+      val = atanh(arg);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val));
+   }
+   arg = 2;
+   check_invalid(atanh(arg));
+   arg = -3;
+   check_invalid(atanh(arg));
+
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = 1;
+      val = atanh(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      BOOST_CHECK(signbit(val) == 0);
+      check_erange(val);
+      arg = -arg;
+      val = atanh(arg);
+      BOOST_CHECK_EQUAL(val, -std::numeric_limits<T>::infinity());
+      BOOST_CHECK(signbit(val));
+      check_erange(val);
+
+      arg = std::numeric_limits<T>::infinity();
+      check_invalid(atanh(arg));
+      arg = -std::numeric_limits<T>::infinity();
+      check_invalid(atanh(arg));
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(atanh(arg));
+      arg = -std::numeric_limits<T>::quiet_NaN();
+      check_invalid(atanh(arg));
+   }
+   // F.9.2.4:
+   arg = 0;
+   val = cosh(arg);
+   BOOST_CHECK_EQUAL(val, 1);
+   arg = -arg;
+   if(signbit(arg))
+   {
+      val = cosh(arg);
+      BOOST_CHECK_EQUAL(val, 1);
+   }
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = (std::numeric_limits<T>::max)();
+      val = cosh(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      arg = -arg;
+      val = cosh(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      arg = std::numeric_limits<T>::infinity();
+      val = cosh(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      arg = -arg;
+      val = cosh(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(cosh(arg));
+      arg = -std::numeric_limits<T>::quiet_NaN();
+      check_invalid(cosh(arg));
+   }
+   // F.9.2.5:
+   arg = 0;
+   val = sinh(arg);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   arg = -arg;
+   if(signbit(arg))
+   {
+      val = sinh(arg);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val));
+   }
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = (std::numeric_limits<T>::max)();
+      val = sinh(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      arg = -arg;
+      val = sinh(arg);
+      BOOST_CHECK_EQUAL(val, -std::numeric_limits<T>::infinity());
+      arg = std::numeric_limits<T>::infinity();
+      val = sinh(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      arg = -arg;
+      val = sinh(arg);
+      BOOST_CHECK_EQUAL(val, -std::numeric_limits<T>::infinity());
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(sinh(arg));
+      arg = -std::numeric_limits<T>::quiet_NaN();
+      check_invalid(sinh(arg));
+   }
+   // F.9.2.6:
+   arg = 0;
+   val = tanh(arg);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   arg = -arg;
+   if(signbit(arg))
+   {
+      val = tanh(arg);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val));
+   }
+   arg = (std::numeric_limits<T>::max)();
+   val = tanh(arg);
+   BOOST_CHECK_EQUAL(val, 1);
+   arg = -arg;
+   val = tanh(arg);
+   BOOST_CHECK_EQUAL(val, -1);
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = std::numeric_limits<T>::infinity();
+      val = tanh(arg);
+      BOOST_CHECK_EQUAL(val, 1);
+      arg = -arg;
+      val = tanh(arg);
+      BOOST_CHECK_EQUAL(val, -1);
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(tanh(arg));
+      arg = -std::numeric_limits<T>::quiet_NaN();
+      check_invalid(tanh(arg));
+   }
+   // F.9.3.1:
+   arg = 0;
+   val = exp(arg);
+   BOOST_CHECK_EQUAL(val, 1);
+   arg = -arg;
+   if(signbit(arg))
+   {
+      val = exp(arg);
+      BOOST_CHECK_EQUAL(val, 1);
+   }
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = std::numeric_limits<T>::infinity();
+      val = exp(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      arg = -arg;
+      val = exp(arg);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val) == 0);
+      arg = (std::numeric_limits<T>::max)();
+      val = exp(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      arg = -arg;
+      val = exp(arg);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val) == 0);
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(exp(arg));
+      arg = -std::numeric_limits<T>::quiet_NaN();
+      check_invalid(exp(arg));
+   }
+   // F.9.3.2:
+   arg = 0;
+   val = exp2(arg);
+   BOOST_CHECK_EQUAL(val, 1);
+   arg = -arg;
+   if(signbit(arg))
+   {
+      val = exp2(arg);
+      BOOST_CHECK_EQUAL(val, 1);
+   }
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = std::numeric_limits<T>::infinity();
+      val = exp2(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      arg = -arg;
+      val = exp2(arg);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val) == 0);
+      arg = (std::numeric_limits<T>::max)();
+      val = exp2(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      arg = -arg;
+      val = exp2(arg);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val) == 0);
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(exp2(arg));
+      arg = -std::numeric_limits<T>::quiet_NaN();
+      check_invalid(exp2(arg));
+   }
+   // F.9.3.3:
+   arg = 0;
+   val = expm1(arg);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   arg = -arg;
+   if(signbit(arg))
+   {
+      val = expm1(arg);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val));
+   }
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = std::numeric_limits<T>::infinity();
+      val = expm1(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      arg = -arg;
+      val = expm1(arg);
+      BOOST_CHECK_EQUAL(val, -1);
+      arg = (std::numeric_limits<T>::max)();
+      val = expm1(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      arg = -arg;
+      val = expm1(arg);
+      BOOST_CHECK_EQUAL(val, -1);
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(expm1(arg));
+      arg = -std::numeric_limits<T>::quiet_NaN();
+      check_invalid(expm1(arg));
+   }
+   // F.9.3.4:
+   arg = 0;
+   int ival;
+   val = frexp(arg, &ival);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK_EQUAL(ival, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   arg = -arg;
+   if(signbit(arg))
+   {
+      val = frexp(arg, &ival);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val));
+      BOOST_CHECK(signbit(val));
+   }
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = std::numeric_limits<T>::infinity();
+      val = frexp(arg, &ival);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      arg = -arg;
+      val = frexp(arg, &ival);
+      BOOST_CHECK_EQUAL(val, -std::numeric_limits<T>::infinity());
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      val = frexp(arg, &ival);
+      BOOST_CHECK(isnan(val));
+   }
+   // F.9.3.5:
+   typename T::backend_type::exponent_type eval;
+   typename T::backend_type::exponent_type fp_ilogb0 = (std::numeric_limits<typename T::backend_type::exponent_type>::min)();
+   typename T::backend_type::exponent_type fp_ilogbnan =
+#ifdef FP_ILOGBNAN
+      FP_ILOGBNAN < 0 ? (std::numeric_limits<typename T::backend_type::exponent_type>::min)() : (std::numeric_limits<typename T::backend_type::exponent_type>::max)();
+#else
+      INT_MAX;
+#endif
+
+   arg = 0;
+   eval = ilogb(arg);
+   BOOST_CHECK_EQUAL(eval, fp_ilogb0);
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = std::numeric_limits<T>::infinity();
+      eval = ilogb(arg);
+      BOOST_CHECK_EQUAL(eval, (std::numeric_limits<typename T::backend_type::exponent_type>::max)());
+      arg = -arg;
+      eval = ilogb(arg);
+      BOOST_CHECK_EQUAL(eval, (std::numeric_limits<typename T::backend_type::exponent_type>::max)());
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      eval = ilogb(arg);
+      BOOST_CHECK_EQUAL(eval, fp_ilogbnan);
+   }
+   // F.9.3.7:
+   arg = 1;
+   val = log(arg);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = 0;
+      val = log(arg);
+      BOOST_CHECK_EQUAL(val, -std::numeric_limits<T>::infinity());
+      check_erange(val);
+      arg = -arg;
+      if(signbit(arg))
+      {
+         val = log(arg);
+         BOOST_CHECK_EQUAL(val, -std::numeric_limits<T>::infinity());
+         check_erange(val);
+      }
+      arg = -1;
+      check_invalid(log(arg));
+      arg = -std::numeric_limits<T>::infinity();
+      check_invalid(log(arg));
+      arg = std::numeric_limits<T>::infinity();
+      val = log(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(log(arg));
+      arg = -std::numeric_limits<T>::quiet_NaN();
+      check_invalid(log(arg));
+   }
+   // F.9.3.8:
+   arg = 1;
+   val = log10(arg);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = 0;
+      val = log10(arg);
+      BOOST_CHECK_EQUAL(val, -std::numeric_limits<T>::infinity());
+      check_erange(val);
+      arg = -arg;
+      if(signbit(arg))
+      {
+         val = log10(arg);
+         BOOST_CHECK_EQUAL(val, -std::numeric_limits<T>::infinity());
+         check_erange(val);
+      }
+      arg = -1;
+      check_invalid(log10(arg));
+      arg = -std::numeric_limits<T>::infinity();
+      check_invalid(log10(arg));
+      arg = std::numeric_limits<T>::infinity();
+      val = log10(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(log10(arg));
+      arg = -std::numeric_limits<T>::quiet_NaN();
+      check_invalid(log10(arg));
+   }
+   // F.9.3.9:
+   arg = 0;
+   val = log1p(arg);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   arg = -arg;
+   if(signbit(arg))
+   {
+      val = log1p(arg);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val));
+   }
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = -1;
+      val = log1p(arg);
+      BOOST_CHECK_EQUAL(val, -std::numeric_limits<T>::infinity());
+      check_erange(val);
+      arg = -2;
+      check_invalid(log1p(arg));
+      arg = -std::numeric_limits<T>::infinity();
+      check_invalid(log1p(arg));
+      arg = std::numeric_limits<T>::infinity();
+      val = log1p(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(log1p(arg));
+      arg = -std::numeric_limits<T>::quiet_NaN();
+      check_invalid(log1p(arg));
+   }
+   // F.9.3.10:
+   arg = 1;
+   val = log2(arg);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = 0;
+      val = log2(arg);
+      BOOST_CHECK_EQUAL(val, -std::numeric_limits<T>::infinity());
+      check_erange(val);
+      arg = -arg;
+      if(signbit(arg))
+      {
+         val = log2(arg);
+         BOOST_CHECK_EQUAL(val, -std::numeric_limits<T>::infinity());
+         check_erange(val);
+      }
+      arg = -1;
+      check_invalid(log2(arg));
+      arg = -std::numeric_limits<T>::infinity();
+      check_invalid(log2(arg));
+      arg = std::numeric_limits<T>::infinity();
+      val = log2(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(log2(arg));
+      arg = -std::numeric_limits<T>::quiet_NaN();
+      check_invalid(log2(arg));
+   }
+   // F.9.3.11:
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = 0;
+      val = logb(arg);
+      BOOST_CHECK_EQUAL(val, -std::numeric_limits<T>::infinity());
+      check_erange(val);
+      arg = -arg;
+      if(signbit(arg))
+      {
+         val = logb(arg);
+         BOOST_CHECK_EQUAL(val, -std::numeric_limits<T>::infinity());
+         check_erange(val);
+      }
+      arg = std::numeric_limits<T>::infinity();
+      val = logb(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      arg = -std::numeric_limits<T>::infinity();
+      val = logb(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(logb(arg));
+      arg = -std::numeric_limits<T>::quiet_NaN();
+      check_invalid(logb(arg));
+   }
+   // F.9.3.13:
+   arg = 0;
+   val = scalbn(arg, 2);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   arg = -arg;
+   if(signbit(arg))
+   {
+      val = scalbn(arg, 2);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val));
+   }
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = std::numeric_limits<T>::infinity();
+      val = scalbn(arg, -100);
+      BOOST_CHECK_EQUAL(val, arg);
+      arg = -arg;
+      val = scalbn(arg, -100);
+      BOOST_CHECK_EQUAL(val, arg);
+   }
+   // F.9.4.1:
+   arg = 0;
+   val = cbrt(arg);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   arg = -arg;
+   if(signbit(arg))
+   {
+      val = cbrt(arg);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val));
+   }
+#if !(defined(TEST_FLOAT128) && defined(BOOST_GCC_VERSION) && (BOOST_GCC_VERSION < 40800))
+   //
+   // This test fails with early implementations of libquadmath - not our issue!
+   //
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = std::numeric_limits<T>::infinity();
+      val = cbrt(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      arg = -std::numeric_limits<T>::infinity();
+      val = cbrt(arg);
+      BOOST_CHECK_EQUAL(val, -std::numeric_limits<T>::infinity());
+   }
+#endif
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(cbrt(arg));
+      arg = -std::numeric_limits<T>::quiet_NaN();
+      check_invalid(cbrt(arg));
+   }
+   // F.9.4.2:
+   arg = 0;
+   val = fabs(arg);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   arg = -arg;
+   if(signbit(arg))
+   {
+      val = fabs(arg);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val) == 0);
+   }
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = std::numeric_limits<T>::infinity();
+      val = fabs(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      arg = -std::numeric_limits<T>::infinity();
+      val = fabs(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+   }
+   // F.9.4.3:
+   arg = 2;
+   arg2 = 0;
+   val = hypot(arg, arg2);
+   BOOST_CHECK_EQUAL(val, arg);
+   arg2 = -arg2;
+   val = hypot(arg, arg2);
+   BOOST_CHECK_EQUAL(val, arg);
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = std::numeric_limits<T>::infinity();
+      arg2 = 2;
+      val = hypot(arg, arg2);
+      BOOST_CHECK_EQUAL(val, arg);
+      arg = -arg;
+      val = hypot(arg, arg2);
+      BOOST_CHECK_EQUAL(val, -arg);
+      arg2 = std::numeric_limits<T>::quiet_NaN();
+      val = hypot(arg, arg2);
+      BOOST_CHECK_EQUAL(val, -arg);
+      arg = -arg;
+      val = hypot(arg, arg2);
+      BOOST_CHECK_EQUAL(val, arg);
+   }
+   // F.9.4.4:
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = 0;
+      arg2 = -3;
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      check_erange(val);
+      arg = -arg;
+      if(signbit(arg))
+      {
+         val = pow(arg, arg2);
+         BOOST_CHECK_EQUAL(val, -std::numeric_limits<T>::infinity());
+         check_erange(val);
+      }
+      arg = 0;
+      arg2 = -2;
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      check_erange(val);
+      arg = -arg;
+      if(signbit(arg))
+      {
+         val = pow(arg, arg2);
+         BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+         check_erange(val);
+      }
+      arg = 0;
+      arg2 = 3;
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val) == 0);
+      arg = -arg;
+      if(signbit(arg))
+      {
+         val = pow(arg, arg2);
+         BOOST_CHECK_EQUAL(val, 0);
+         BOOST_CHECK(signbit(val));
+      }
+      arg = 0;
+      arg2 = 2;
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val) == 0);
+      arg = -arg;
+      if(signbit(arg))
+      {
+         val = pow(arg, arg2);
+         BOOST_CHECK_EQUAL(val, 0);
+         BOOST_CHECK(signbit(val) == 0);
+      }
+      arg = -1;
+      arg2 = std::numeric_limits<T>::infinity();
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, 1);
+      arg2 = -std::numeric_limits<T>::infinity();
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, 1);
+      arg = 1;
+      arg2 = 0;
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, 1);
+      arg2 = std::numeric_limits<T>::infinity();
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, 1);
+      arg2 = -std::numeric_limits<T>::infinity();
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, 1);
+      arg2 = std::numeric_limits<T>::quiet_NaN();
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, 1);
+      arg = 0;
+      arg2 = 0;
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, 1);
+      arg2 = -arg2;
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, 1);
+      arg = std::numeric_limits<T>::infinity();
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, 1);
+      arg2 = -arg2;
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, 1);
+      arg = std::numeric_limits<T>::quiet_NaN();
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, 1);
+      arg2 = -arg2;
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, 1);
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = -2.5;
+      arg2 = 2.5;
+      check_invalid(pow(arg, arg2));
+   }
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = 0.5;
+      arg2 = -std::numeric_limits<T>::infinity();
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      arg = -0.25;
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      arg = 2.5;
+      arg2 = -std::numeric_limits<T>::infinity();
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, 0);
+      arg = -arg;
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, 0);
+      arg = 2.5;
+      arg2 = std::numeric_limits<T>::infinity();
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      arg = -arg;
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      arg = -std::numeric_limits<T>::infinity();
+      arg2 = -3;
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, 0);
+      if(signbit(-T(0)))
+         BOOST_CHECK(signbit(val));
+      arg2 = -2;
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val) == 0);
+      arg2 = -2.5;
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val) == 0);
+      arg2 = 3;
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, -std::numeric_limits<T>::infinity());
+      arg2 = 2;
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      arg2 = 2.5;
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      arg = -arg; // +INF
+      arg2 = -2;
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val) == 0);
+      arg2 = -3;
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val) == 0);
+      arg2 = -3.5;
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val) == 0);
+      arg2 = 2;
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      arg2 = 3;
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      arg2 = 3.5;
+      val = pow(arg, arg2);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+   }
+   // F.9.4.5:
+   arg = 0;
+   val = sqrt(arg);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   arg = -arg;
+   if(signbit(arg))
+   {
+      val = sqrt(arg);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val));
+   }
+#if !(defined(TEST_FLOAT128) && defined(BOOST_GCC_VERSION) && (BOOST_GCC_VERSION < 40800))
+   //
+   // This test fails with early implementations of libquadmath - not our issue!
+   //
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = std::numeric_limits<T>::infinity();
+      val = sqrt(arg);
+      BOOST_CHECK_EQUAL(val, arg);
+      arg = -arg;
+      check_invalid(sqrt(arg));
+   }
+#endif
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(sqrt(arg));
+   }
+   // F.9.5.1:
+   arg = 0;
+   val = erf(arg);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   arg = -arg;
+   if(signbit(arg))
+   {
+      val = erf(arg);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val));
+   }
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = std::numeric_limits<T>::infinity();
+      val = erf(arg);
+      BOOST_CHECK_EQUAL(val, 1);
+      arg = -arg;
+      val = erf(arg);
+      BOOST_CHECK_EQUAL(val, -1);
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(erf(arg));
+   }
+   // F.9.5.2:
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = std::numeric_limits<T>::infinity();
+      val = erfc(arg);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val) == 0);
+      arg = -arg;
+      val = erfc(arg);
+      BOOST_CHECK_EQUAL(val, 2);
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(erfc(arg));
+   }
+   // F.9.5.3:
+   arg = 1;
+   val = lgamma(arg);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   arg = 2;
+   val = lgamma(arg);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+#if !defined(BOOST_MPFR_VERSION) || (BOOST_MPFR_VERSION > 30103)
+   arg = 0;
+   val = lgamma(arg);
+   BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+   check_erange(val);
+   arg = -1;
+   val = lgamma(arg);
+   BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+   check_erange(val);
+   arg = -2;
+   val = lgamma(arg);
+   BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+   check_erange(val);
+   arg = -std::numeric_limits<T>::infinity();
+   val = lgamma(arg);
+   BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+#endif
+   arg = std::numeric_limits<T>::infinity();
+   val = lgamma(arg);
+   BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(lgamma(arg));
+   }
+   // F.9.5.4:
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = 0;
+      val = tgamma(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      check_erange(val);
+      arg = -arg;
+      if(signbit(arg))
+      {
+         val = tgamma(arg);
+         BOOST_CHECK_EQUAL(val, -std::numeric_limits<T>::infinity());
+         check_erange(val);
+      }
+      arg = -1;
+      check_invalid(tgamma(arg));
+      arg = -std::numeric_limits<T>::infinity();
+      check_invalid(tgamma(arg));
+      arg = std::numeric_limits<T>::infinity();
+      val = tgamma(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(tgamma(arg));
+   }
+   // F.9.6.1:
+   arg = 0;
+   val = ceil(arg);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   arg = -arg;
+   if(signbit(arg))
+   {
+      val = ceil(arg);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val));
+   }
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = std::numeric_limits<T>::infinity();
+      val = ceil(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      arg = -arg;
+      val = ceil(arg);
+      BOOST_CHECK_EQUAL(val, -std::numeric_limits<T>::infinity());
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(ceil(arg));
+   }
+   // F.9.6.2:
+   arg = 0;
+   val = floor(arg);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   arg = -arg;
+   if(signbit(arg))
+   {
+      val = floor(arg);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val));
+   }
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = std::numeric_limits<T>::infinity();
+      val = floor(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      arg = -arg;
+      val = floor(arg);
+      BOOST_CHECK_EQUAL(val, -std::numeric_limits<T>::infinity());
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(floor(arg));
+   }
+   // F.9.6.3:
+   arg = 0;
+   val = nearbyint(arg);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   arg = -arg;
+   if(signbit(arg))
+   {
+      val = nearbyint(arg);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val));
+   }
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = std::numeric_limits<T>::infinity();
+      val = nearbyint(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      arg = -arg;
+      val = nearbyint(arg);
+      BOOST_CHECK_EQUAL(val, -std::numeric_limits<T>::infinity());
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(nearbyint(arg));
+   }
+   // F.9.6.4:
+   arg = 0;
+   val = rint(arg);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   arg = -arg;
+   if(signbit(arg))
+   {
+      val = rint(arg);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val));
+   }
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = std::numeric_limits<T>::infinity();
+      val = rint(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      arg = -arg;
+      val = rint(arg);
+      BOOST_CHECK_EQUAL(val, -std::numeric_limits<T>::infinity());
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(rint(arg));
+   }
+   // F.9.6.6:
+   arg = 0;
+   val = round(arg);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   arg = -arg;
+   if(signbit(arg))
+   {
+      val = round(arg);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val));
+   }
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = std::numeric_limits<T>::infinity();
+      val = round(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      arg = -arg;
+      val = round(arg);
+      BOOST_CHECK_EQUAL(val, -std::numeric_limits<T>::infinity());
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(round(arg));
+   }
+   // F.9.6.8:
+   arg = 0;
+   val = trunc(arg);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   arg = -arg;
+   if(signbit(arg))
+   {
+      val = trunc(arg);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val));
+   }
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = std::numeric_limits<T>::infinity();
+      val = trunc(arg);
+      BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+      arg = -arg;
+      val = trunc(arg);
+      BOOST_CHECK_EQUAL(val, -std::numeric_limits<T>::infinity());
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      check_invalid(trunc(arg));
+   }
+   // F.9.7.1:
+   arg = 0;
+   arg2 = 2;
+   val = fmod(arg, arg2);
+   BOOST_CHECK_EQUAL(val, 0);
+   BOOST_CHECK(signbit(val) == 0);
+   arg = -arg;
+   if(signbit(arg))
+   {
+      val = fmod(arg, arg2);
+      BOOST_CHECK_EQUAL(val, 0);
+      BOOST_CHECK(signbit(val));
+   }
+   if(std::numeric_limits<T>::has_infinity)
+   {
+      arg = std::numeric_limits<T>::infinity();
+      check_invalid(fmod(arg, arg2));
+      arg = -arg;
+      check_invalid(fmod(arg, arg2));
+      arg = 2;
+      arg2 = 0;
+      check_invalid(fmod(arg, arg2));
+      check_invalid(fmod(arg, -arg2));
+   }
+   if(std::numeric_limits<T>::has_quiet_NaN)
+   {
+      arg = std::numeric_limits<T>::quiet_NaN();
+      arg2 = 2;
+      check_invalid(fmod(arg, arg2));
+      swap(arg, arg2);
+      check_invalid(fmod(arg, arg2));
+      check_invalid(fmod(arg2, arg2));
+   }
+}
+
 int main()
 {
    test_poison<float>();
@@ -592,8 +2044,10 @@ int main()
    test<boost::multiprecision::mpf_float_100>();
 #endif
 #ifdef TEST_MPFR_50
+   std::cout << "Testing MPFR: " << MPFR_VERSION_STRING << std::endl;
    test<boost::multiprecision::mpfr_float_50>();
    test<boost::multiprecision::mpfr_float_100>();
+   test_c99_appendix_F<boost::multiprecision::mpfr_float_50>();
 #endif
 #ifdef TEST_MPFI_50
    test<boost::multiprecision::mpfi_float_50>();
@@ -601,25 +2055,45 @@ int main()
 #endif
 #ifdef TEST_CPP_DEC_FLOAT
    test<boost::multiprecision::cpp_dec_float_50>();
+#if !(defined(CI_SUPPRESS_KNOWN_ISSUES) && defined(__GNUC__) && defined(_WIN32)) // Object file too large otherwise
    test<boost::multiprecision::cpp_dec_float_100>();
-#ifndef SLOW_COMPLER
+#endif
+   test_c99_appendix_F<boost::multiprecision::cpp_dec_float_50>();
+#endif
+#ifdef TEST_CPP_DEC_FLOAT_2
    // Some "peculiar" digit counts which stress our code:
    test<boost::multiprecision::number<boost::multiprecision::cpp_dec_float<65> > >();
+#if !(defined(CI_SUPPRESS_KNOWN_ISSUES) && defined(__GNUC__) && defined(_WIN32)) // Object file too large otherwise
    test<boost::multiprecision::number<boost::multiprecision::cpp_dec_float<64> > >();
+#endif
+#endif
+#ifdef TEST_CPP_DEC_FLOAT_3
    test<boost::multiprecision::number<boost::multiprecision::cpp_dec_float<63> > >();
+#if !(defined(CI_SUPPRESS_KNOWN_ISSUES) && defined(__GNUC__) && defined(_WIN32)) // Object file too large otherwise
    test<boost::multiprecision::number<boost::multiprecision::cpp_dec_float<62> > >();
+#endif
+#endif
+#ifdef TEST_CPP_DEC_FLOAT_4
    test<boost::multiprecision::number<boost::multiprecision::cpp_dec_float<61, long long> > >();
+#if !(defined(CI_SUPPRESS_KNOWN_ISSUES) && defined(__GNUC__) && defined(_WIN32)) // Object file too large otherwise
    test<boost::multiprecision::number<boost::multiprecision::cpp_dec_float<60, long long> > >();
+#endif
+#endif
+#ifdef TEST_CPP_DEC_FLOAT_5
    test<boost::multiprecision::number<boost::multiprecision::cpp_dec_float<59, long long, std::allocator<void> > > >();
+#if !(defined(CI_SUPPRESS_KNOWN_ISSUES) && defined(__GNUC__) && defined(_WIN32)) // Object file too large otherwise
    test<boost::multiprecision::number<boost::multiprecision::cpp_dec_float<58, long long, std::allocator<void> > > >();
 #endif
 #endif
 #ifdef TEST_CPP_BIN_FLOAT
    test<boost::multiprecision::cpp_bin_float_50>();
    test<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<100>, boost::multiprecision::et_on> >();
+   test_c99_appendix_F<boost::multiprecision::cpp_bin_float_50>();
+   test_c99_appendix_F<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<100>, boost::multiprecision::et_on> >();
 #endif
 #ifdef TEST_FLOAT128
    test<boost::multiprecision::float128>();
+   test_c99_appendix_F<boost::multiprecision::float128>();
 #endif
 
    return boost::report_errors();