$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r86191 - in sandbox/multiprecision.cpp_bin_float: boost/multiprecision libs/multiprecision/performance libs/multiprecision/test
From: john_at_[hidden]
Date: 2013-10-07 13:27:43
Author: johnmaddock
Date: 2013-10-07 13:27:42 EDT (Mon, 07 Oct 2013)
New Revision: 86191
URL: http://svn.boost.org/trac/boost/changeset/86191
Log:
Add some performance tests and optimize multiplication/divide by integer.
Added:
   sandbox/multiprecision.cpp_bin_float/libs/multiprecision/performance/
      - copied from r86126, trunk/libs/multiprecision/performance/
Text files modified: 
   sandbox/multiprecision.cpp_bin_float/boost/multiprecision/cpp_bin_float.hpp               |   175 ++++++++++++++++++++++++++++++++++++++++
   sandbox/multiprecision.cpp_bin_float/libs/multiprecision/performance/performance_test.cpp |    20 ++--                                    
   sandbox/multiprecision.cpp_bin_float/libs/multiprecision/test/test_cpp_bin_float.cpp      |    18 ++++                                    
   3 files changed, 203 insertions(+), 10 deletions(-)
Modified: sandbox/multiprecision.cpp_bin_float/boost/multiprecision/cpp_bin_float.hpp
==============================================================================
--- sandbox/multiprecision.cpp_bin_float/boost/multiprecision/cpp_bin_float.hpp	Sun Oct  6 20:24:26 2013	(r86190)
+++ sandbox/multiprecision.cpp_bin_float/boost/multiprecision/cpp_bin_float.hpp	2013-10-07 13:27:42 EDT (Mon, 07 Oct 2013)	(r86191)
@@ -616,6 +616,59 @@
    eval_multiply(res, res, a);
 }
 
+template <unsigned bits, class U>
+inline typename enable_if_c<is_unsigned<U>::value>::type eval_multiply(cpp_bin_float<bits> &res, const cpp_bin_float<bits> &a, const U &b)
+{
+   using default_ops::eval_bit_test;
+   using default_ops::eval_multiply;
+
+   // Special cases first:
+   switch(a.exponent())
+   {
+   case cpp_bin_float<bits>::exponent_zero:
+      res = a;
+      return;
+   case cpp_bin_float<bits>::exponent_infinity:
+      if(b == 0)
+         res = std::numeric_limits<number<cpp_bin_float<bits> > >::quiet_NaN().backend();
+      else
+         res = a;
+      return;
+   case cpp_bin_float<bits>::exponent_nan:
+      res = a;
+      return;
+   }
+
+   typename cpp_bin_float<bits>::double_rep_type dt;
+   typedef typename boost::multiprecision::detail::canonical<U, typename cpp_bin_float<bits>::double_rep_type>::type canon_ui_type;
+   eval_multiply(dt, a.bits(), static_cast<canon_ui_type>(b));
+   res.exponent() = a.exponent();
+   copy_and_round(res, dt);
+   res.check_invariants();
+   res.sign() = a.sign();
+}
+
+template <unsigned bits, class U>
+inline typename enable_if_c<is_unsigned<U>::value>::type eval_multiply(cpp_bin_float<bits> &res, const U &b)
+{
+   eval_multiply(res, res, b);
+}
+
+template <unsigned bits, class S>
+inline typename enable_if_c<is_signed<S>::value>::type eval_multiply(cpp_bin_float<bits> &res, const cpp_bin_float<bits> &a, const S &b)
+{
+   typedef typename make_unsigned<S>::type ui_type;
+   eval_multiply(res, a, static_cast<ui_type>(boost::multiprecision::detail::abs(b)));
+   if(b < 0)
+      res.negate();
+}
+
+template <unsigned bits, class S>
+inline typename enable_if_c<is_signed<S>::value>::type eval_multiply(cpp_bin_float<bits> &res, const S &b)
+{
+   eval_multiply(res, res, b);
+}
+
 template <unsigned bits>
 inline void eval_divide(cpp_bin_float<bits> &res, const cpp_bin_float<bits> &u, const cpp_bin_float<bits> &v)
 {
@@ -742,6 +795,128 @@
    eval_divide(res, res, arg);
 }
 
+template <unsigned bits, class U>
+inline typename enable_if_c<is_unsigned<U>::value>::type eval_divide(cpp_bin_float<bits> &res, const cpp_bin_float<bits> &u, const U &v)
+{
+   using default_ops::eval_subtract;
+   using default_ops::eval_qr;
+   using default_ops::eval_bit_test;
+   using default_ops::eval_get_sign;
+
+   //
+   // Special cases first:
+   //
+   switch(u.exponent())
+   {
+   case cpp_bin_float<bits>::exponent_zero:
+      if(v == 0)
+      {
+         res = std::numeric_limits<number<cpp_bin_float<bits> > >::quiet_NaN().backend();
+         return;
+      }
+      res = u;
+      return;
+   case cpp_bin_float<bits>::exponent_infinity:
+      res = u;
+      return;
+   case cpp_bin_float<bits>::exponent_nan:
+      res = std::numeric_limits<number<cpp_bin_float<bits> > >::quiet_NaN().backend();
+      return;
+   }
+   if(v == 0)
+   {
+      bool s = u.sign();
+      res = std::numeric_limits<number<cpp_bin_float<bits> > >::infinity().backend();
+      res.sign() = s;
+      return;
+   }
+
+   // We can scale u and v so that both are integers, then perform integer
+   // division to obtain quotient q and remainder r, such that:
+   //
+   // q * v + r = u
+   //
+   // and hense:
+   //
+   // q + r/v = u/v
+   //
+   // From this, assuming q has "bits" bits, we only need to determine whether
+   // r/v is less than, equal to, or greater than 0.5 to determine rounding - 
+   // this we can do with a shift and comparison.
+   //
+   // We can set the exponent and sign of the result up front:
+   //
+   int gb = msb(v);
+   res.exponent() = u.exponent() - gb - 1;
+   res.sign() = u.sign();
+   //
+   // Now get the quotient and remainder:
+   //
+   typename cpp_bin_float<bits>::double_rep_type t(u.bits()), q, r;
+   eval_left_shift(t, gb + 1);
+   eval_qr(t, number<typename cpp_bin_float<bits>::double_rep_type>::canonical_value(v), q, r);
+   //
+   // We now have either "bits" or "bits+1" significant bits in q.
+   //
+   static const unsigned limb_bits = sizeof(limb_type) * CHAR_BIT;
+   if(eval_bit_test(q, bits))
+   {
+      //
+      // OK we have bits+1 bits, so we already have rounding info,
+      // we just need to changes things if the last bit is 1 and the
+      // remainder is non-zero (ie we do not have a tie).
+      //
+      BOOST_ASSERT(eval_msb(q) == bits);
+      if((q.limbs()[0] & 1u) && eval_get_sign(r))
+      {
+         eval_left_shift(q, limb_bits);
+         q.limbs()[0] = 1;
+         res.exponent() -= limb_bits;
+      }
+   }
+   else
+   {
+      //
+      // We have exactly "bits" bits in q.
+      // Get rounding info, which we can get by comparing 2r with v.
+      // We want to call copy_and_round to handle rounding and general cleanup,
+      // so we'll left shift q and add some fake bits on the end to represent
+      // how we'll be rounding.
+      //
+      BOOST_ASSERT(eval_msb(q) == bits - 1);
+      eval_left_shift(q, limb_bits);
+      res.exponent() -= limb_bits;
+      eval_left_shift(r, 1u);
+      int c = r.compare(number<typename cpp_bin_float<bits>::double_rep_type>::canonical_value(v));
+      if(c == 0)
+         q.limbs()[0] = static_cast<limb_type>(1u) << (limb_bits - 1);
+      else if(c > 0)
+         q.limbs()[0] = (static_cast<limb_type>(1u) << (limb_bits - 1)) + static_cast<limb_type>(1u);
+   }
+   copy_and_round(res, q);
+}
+
+template <unsigned bits, class U>
+inline typename enable_if_c<is_unsigned<U>::value>::type eval_divide(cpp_bin_float<bits> &res, const U &v)
+{
+   eval_divide(res, res, v);
+}
+
+template <unsigned bits, class S>
+inline typename enable_if_c<is_signed<S>::value>::type eval_divide(cpp_bin_float<bits> &res, const cpp_bin_float<bits> &u, const S &v)
+{
+   typedef typename make_unsigned<S>::type ui_type;
+   eval_divide(res, u, static_cast<ui_type>(boost::multiprecision::detail::abs(v)));
+   if(v < 0)
+      res.negate();
+}
+
+template <unsigned bits, class S>
+inline typename enable_if_c<is_signed<S>::value>::type eval_divide(cpp_bin_float<bits> &res, const S &v)
+{
+   eval_divide(res, res, v);
+}
+
 template <unsigned bits>
 inline void eval_convert_to(long long *res, const cpp_bin_float<bits> &arg)
 {
Modified: sandbox/multiprecision.cpp_bin_float/libs/multiprecision/performance/performance_test.cpp
==============================================================================
--- trunk/libs/multiprecision/performance/performance_test.cpp	Tue Oct  1 14:12:50 2013	(r86126)
+++ sandbox/multiprecision.cpp_bin_float/libs/multiprecision/performance/performance_test.cpp	2013-10-07 13:27:42 EDT (Mon, 07 Oct 2013)	(r86191)
@@ -12,7 +12,7 @@
 #if !defined(TEST_MPF) && !defined(TEST_MPZ) && \
    !defined(TEST_CPP_DEC_FLOAT) && !defined(TEST_MPFR) && !defined(TEST_MPQ) \
    && !defined(TEST_TOMMATH) && !defined(TEST_TOMMATH_BOOST_RATIONAL) && !defined(TEST_MPZ_BOOST_RATIONAL)\
-   && !defined(TEST_CPP_INT) && !defined(TEST_CPP_INT_RATIONAL)
+   && !defined(TEST_CPP_INT) && !defined(TEST_CPP_INT_RATIONAL) && !defined(TEST_CPP_BIN_FLOAT)
 #  define TEST_MPF
 #  define TEST_MPZ
 #  define TEST_MPQ
@@ -22,6 +22,7 @@
 #  define TEST_TOMMATH
 #  define TEST_CPP_INT
 #  define TEST_CPP_INT_RATIONAL
+#  define TEST_CPP_BIN_FLOAT
 
 #ifdef _MSC_VER
 #pragma message("CAUTION!!: No backend type specified so testing everything.... this will take some time!!")
@@ -39,6 +40,9 @@
 #ifdef TEST_CPP_DEC_FLOAT
 #include <boost/multiprecision/cpp_dec_float.hpp>
 #endif
+#ifdef TEST_CPP_BIN_FLOAT
+#include <boost/multiprecision/cpp_bin_float.hpp>
+#endif
 #if defined(TEST_MPFR)
 #include <boost/multiprecision/mpfr.hpp>
 #endif
@@ -84,15 +88,6 @@
 
 unsigned bits_wanted; // for integer types
 
-namespace boost{ namespace multiprecision{
-
-template<>
-class number_category<boost::int64_t> : public mpl::int_<number_kind_integer>{};
-template<>
-class number_category<boost::uint64_t> : public mpl::int_<number_kind_integer>{};
-
-}}
-
 template <class T, int Type>
 struct tester
 {
@@ -841,6 +836,11 @@
    test<boost::multiprecision::cpp_dec_float_100>("cpp_dec_float", 100);
    test<boost::multiprecision::number<boost::multiprecision::cpp_dec_float<500> > >("cpp_dec_float", 500);
 #endif
+#ifdef TEST_CPP_BIN_FLOAT
+   test<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<std::numeric_limits<boost::multiprecision::mpfr_float_50>::digits> > >("cpp_bin_float", 50);
+   test<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<std::numeric_limits<boost::multiprecision::mpfr_float_100>::digits> > >("cpp_bin_float", 100);
+   test<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<std::numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_dec_float<500> > >::digits> > >("cpp_bin_float", 500);
+#endif
 #ifdef TEST_MPFR
    test<boost::multiprecision::mpfr_float_50>("mpfr_float", 50);
    test<boost::multiprecision::mpfr_float_100>("mpfr_float", 100);
Modified: sandbox/multiprecision.cpp_bin_float/libs/multiprecision/test/test_cpp_bin_float.cpp
==============================================================================
--- sandbox/multiprecision.cpp_bin_float/libs/multiprecision/test/test_cpp_bin_float.cpp	Sun Oct  6 20:24:26 2013	(r86190)
+++ sandbox/multiprecision.cpp_bin_float/libs/multiprecision/test/test_cpp_bin_float.cpp	2013-10-07 13:27:42 EDT (Mon, 07 Oct 2013)	(r86191)
@@ -182,6 +182,24 @@
       BOOST_CHECK_EQUAL(test_type(ceil(a)), ceil(ta));
       BOOST_CHECK_EQUAL(test_type(ceil(-a)), ceil(-ta));
 
+      static boost::random::mt19937 i_gen;
+
+      int si = i_gen();
+      BOOST_CHECK_EQUAL(test_type(a * si), ta * si);
+      BOOST_CHECK_EQUAL(test_type(-a * si), -ta * si);
+      BOOST_CHECK_EQUAL(test_type(-a * -si), -ta * -si);
+      BOOST_CHECK_EQUAL(test_type(a * -si), ta * -si);
+      unsigned ui = std::abs(si);
+      BOOST_CHECK_EQUAL(test_type(a * ui), ta * ui);
+      BOOST_CHECK_EQUAL(test_type(-a * ui), -ta * ui);
+
+      // Divide:
+      BOOST_CHECK_EQUAL(test_type(a / si), ta / si);
+      BOOST_CHECK_EQUAL(test_type(-a / si), -ta / si);
+      BOOST_CHECK_EQUAL(test_type(-a / -si), -ta / -si);
+      BOOST_CHECK_EQUAL(test_type(a / -si), ta / -si);
+      BOOST_CHECK_EQUAL(test_type(a / ui), ta / ui);
+      BOOST_CHECK_EQUAL(test_type(-a / ui), -ta / ui);
    }
    return boost::report_errors();
 }