Boost logo

Boost-Commit :

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();
 }


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