Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r74024 - in sandbox/big_number: boost/math boost/math/big_number libs/math/test
From: john_at_[hidden]
Date: 2011-08-23 14:31:04


Author: johnmaddock
Date: 2011-08-23 14:31:03 EDT (Tue, 23 Aug 2011)
New Revision: 74024
URL: http://svn.boost.org/trac/boost/changeset/74024

Log:
Add increment, decrement and bitwise-shift operators.
Text files modified:
   sandbox/big_number/boost/math/big_number.hpp | 154 +++++++++++++++++++++++++++++++++++++++
   sandbox/big_number/boost/math/big_number/big_number_base.hpp | 2
   sandbox/big_number/boost/math/big_number/default_ops.hpp | 28 +++++++
   sandbox/big_number/boost/math/big_number/gmp.hpp | 24 +++++
   sandbox/big_number/boost/math/big_number/mpfr.hpp | 4
   sandbox/big_number/libs/math/test/test_arithmetic.cpp | 40 ++++++++++
   6 files changed, 248 insertions(+), 4 deletions(-)

Modified: sandbox/big_number/boost/math/big_number.hpp
==============================================================================
--- sandbox/big_number/boost/math/big_number.hpp (original)
+++ sandbox/big_number/boost/math/big_number.hpp 2011-08-23 14:31:03 EDT (Tue, 23 Aug 2011)
@@ -17,6 +17,9 @@
 #include <boost/type_traits/is_signed.hpp>
 #include <boost/type_traits/is_unsigned.hpp>
 #include <boost/type_traits/is_floating_point.hpp>
+#include <boost/type_traits/is_integral.hpp>
+#include <boost/type_traits/make_unsigned.hpp>
+#include <boost/throw_exception.hpp>
 #include <boost/math/big_number/default_ops.hpp>
 
 namespace boost{ namespace math{
@@ -201,6 +204,65 @@
       }
       return *this;
    }
+ //
+ // These operators are *not* proto-ized.
+ // The issue is that the increment/decrement must happen
+ // even if the result of the operator *is never used*.
+ // Possibly we could modify our expression wrapper to
+ // execute the increment/decrement on destruction, but
+ // correct implemetation will be tricky, so defered for now...
+ //
+ big_number& operator++()
+ {
+ BOOST_STATIC_ASSERT_MSG(is_extended_integer<Backend>::value, "The increment operation is only valid for integer types");
+ using big_num_default_ops::increment;
+ increment(m_backend);
+ return *this;
+ }
+
+ big_number& operator--()
+ {
+ BOOST_STATIC_ASSERT_MSG(is_extended_integer<Backend>::value, "The increment operation is only valid for integer types");
+ using big_num_default_ops::decrement;
+ decrement(m_backend);
+ return *this;
+ }
+
+ big_number operator++(int)
+ {
+ BOOST_STATIC_ASSERT_MSG(is_extended_integer<Backend>::value, "The increment operation is only valid for integer types");
+ using big_num_default_ops::increment;
+ self_type temp(*this);
+ increment(m_backend);
+ return temp;
+ }
+
+ big_number operator--(int)
+ {
+ BOOST_STATIC_ASSERT_MSG(is_extended_integer<Backend>::value, "The increment operation is only valid for integer types");
+ using big_num_default_ops::decrement;
+ self_type temp(*this);
+ decrement(m_backend);
+ return temp;
+ }
+
+ template <class V>
+ typename enable_if<is_integral<V>, big_number&>::type operator <<= (V val)
+ {
+ BOOST_STATIC_ASSERT_MSG(is_extended_integer<Backend>::value, "The left-shift operation is only valid for integer types");
+ check_shift_range(val, mpl::bool_<(sizeof(V) > sizeof(std::size_t))>(), is_signed<V>());
+ left_shift(m_backend, canonical_value(val));
+ return *this;
+ }
+
+ template <class V>
+ typename enable_if<is_integral<V>, big_number&>::type operator >>= (V val)
+ {
+ BOOST_STATIC_ASSERT_MSG(is_extended_integer<Backend>::value, "The right-shift operation is only valid for integer types");
+ check_shift_range(val, mpl::bool_<(sizeof(V) > sizeof(std::size_t))>(), is_signed<V>());
+ right_shift(m_backend, canonical_value(val));
+ return *this;
+ }
 
    template <class V>
    typename enable_if<boost::is_arithmetic<V>, big_number<Backend>& >::type
@@ -238,6 +300,14 @@
    }
 
    //
+ // swap:
+ //
+ void swap(self_type& other)
+ {
+ m_backend.swap(other.backend());
+ }
+
+ //
    // String conversion functions:
    //
    std::string str(unsigned digits = 0, bool scientific = true)const
@@ -284,6 +354,29 @@
       return m_backend;
    }
 private:
+ template <class V>
+ void check_shift_range(V val, const mpl::true_&, const mpl::true_&)
+ {
+ if(val > std::numeric_limits<std::size_t>::max())
+ BOOST_THROW_EXCEPTION(std::out_of_range("Can not shift by a value greater than std::numeric_limits<std::size_t>::max()."));
+ if(val < 0)
+ BOOST_THROW_EXCEPTION(std::out_of_range("Can not shift by a negative value."));
+ }
+ template <class V>
+ void check_shift_range(V val, const mpl::false_&, const mpl::true_&)
+ {
+ if(val < 0)
+ BOOST_THROW_EXCEPTION(std::out_of_range("Can not shift by a negative value."));
+ }
+ template <class V>
+ void check_shift_range(V val, const mpl::true_&, const mpl::false_&)
+ {
+ if(val > std::numeric_limits<std::size_t>::max())
+ BOOST_THROW_EXCEPTION(std::out_of_range("Can not shift by a value greater than std::numeric_limits<std::size_t>::max()."));
+ }
+ template <class V>
+ void check_shift_range(V val, const mpl::false_&, const mpl::false_&){}
+
    template <class Exp>
    void do_assign(const Exp& e, const detail::add_immediates&)
    {
@@ -363,6 +456,7 @@
    template <class Exp>
    void do_assign(const Exp& e, const detail::modulus_immediates&)
    {
+ BOOST_STATIC_ASSERT_MSG(is_extended_integer<Backend>::value, "The modulus operation is only valid for integer types");
       using big_num_default_ops::modulus;
       typedef typename proto::tag_of<typename proto::result_of::left<Exp>::type>::type left_tag;
       typedef typename proto::tag_of<typename proto::result_of::right<Exp>::type>::type right_tag;
@@ -576,6 +670,64 @@
       do_assign_function(e, tag_type());
    }
    template <class Exp>
+ void do_assign(const Exp& e, const proto::tag::shift_left&)
+ {
+ // We can only shift by an integer value, not an arbitrary expression:
+ typedef typename proto::result_of::left<Exp>::type left_type;
+ typedef typename proto::result_of::right<Exp>::type right_type;
+ typedef typename proto::arity_of<right_type>::type right_arity;
+ BOOST_STATIC_ASSERT_MSG(right_arity::value == 0, "The left shift operator requires an integer value for the shift operand.");
+ typedef typename proto::result_of::value<right_type>::type right_value_type;
+ BOOST_STATIC_ASSERT_MSG(is_integral<right_value_type>::value, "The left shift operator requires an integer value for the shift operand.");
+ typedef typename proto::tag_of<left_type>::type tag_type;
+ do_assign_left_shift(proto::left(e), canonical_value(proto::value(proto::right(e))), tag_type());
+ }
+
+ template <class Exp>
+ void do_assign(const Exp& e, const proto::tag::shift_right&)
+ {
+ // We can only shift by an integer value, not an arbitrary expression:
+ typedef typename proto::result_of::left<Exp>::type left_type;
+ typedef typename proto::result_of::right<Exp>::type right_type;
+ typedef typename proto::arity_of<right_type>::type right_arity;
+ BOOST_STATIC_ASSERT_MSG(right_arity::value == 0, "The left shift operator requires an integer value for the shift operand.");
+ typedef typename proto::result_of::value<right_type>::type right_value_type;
+ BOOST_STATIC_ASSERT_MSG(is_integral<right_value_type>::value, "The left shift operator requires an integer value for the shift operand.");
+ typedef typename proto::tag_of<left_type>::type tag_type;
+ do_assign_right_shift(proto::left(e), canonical_value(proto::value(proto::right(e))), tag_type());
+ }
+
+ template <class Exp, class Val>
+ void do_assign_right_shift(const Exp& e, const Val& val, const proto::tag::terminal&)
+ {
+ using big_num_default_ops::right_shift;
+ right_shift(m_backend, canonical_value(proto::value(e)), val);
+ }
+
+ template <class Exp, class Val>
+ void do_assign_left_shift(const Exp& e, const Val& val, const proto::tag::terminal&)
+ {
+ using big_num_default_ops::left_shift;
+ left_shift(m_backend, canonical_value(proto::value(e)), val);
+ }
+
+ template <class Exp, class Val, class Tag>
+ void do_assign_right_shift(const Exp& e, const Val& val, const Tag&)
+ {
+ using big_num_default_ops::right_shift;
+ self_type temp(e);
+ right_shift(m_backend, temp.backend(), val);
+ }
+
+ template <class Exp, class Val, class Tag>
+ void do_assign_left_shift(const Exp& e, const Val& val, const Tag&)
+ {
+ using big_num_default_ops::left_shift;
+ self_type temp(e);
+ left_shift(m_backend, temp.backend(), val);
+ }
+
+ template <class Exp>
    void do_assign_function(const Exp& e, const mpl::long_<1>&)
    {
       proto::value(proto::left(e))(&m_backend);
@@ -804,6 +956,7 @@
    template <class Exp>
    void do_modulus(const Exp& e, const proto::tag::terminal&)
    {
+ BOOST_STATIC_ASSERT_MSG(is_extended_integer<Backend>::value, "The modulus operation is only valid for integer types");
       using big_num_default_ops::modulus;
       modulus(m_backend, canonical_value(proto::value(e)));
    }
@@ -811,6 +964,7 @@
    template <class Exp, class Unknown>
    void do_modulus(const Exp& e, const Unknown&)
    {
+ BOOST_STATIC_ASSERT_MSG(is_extended_integer<Backend>::value, "The modulus operation is only valid for integer types");
       using big_num_default_ops::modulus;
       self_type temp(e);
       modulus(m_backend, canonical_value(proto::value(temp)));

Modified: sandbox/big_number/boost/math/big_number/big_number_base.hpp
==============================================================================
--- sandbox/big_number/boost/math/big_number/big_number_base.hpp (original)
+++ sandbox/big_number/boost/math/big_number/big_number_base.hpp 2011-08-23 14:31:03 EDT (Tue, 23 Aug 2011)
@@ -29,6 +29,8 @@
       , proto::unary_plus< big_number_grammar >
       , proto::negate< big_number_grammar >
       , proto::modulus<big_number_grammar, big_number_grammar>
+ , proto::shift_left<big_number_grammar, big_number_grammar>
+ , proto::shift_right<big_number_grammar, big_number_grammar>
>
 {};
 

Modified: sandbox/big_number/boost/math/big_number/default_ops.hpp
==============================================================================
--- sandbox/big_number/boost/math/big_number/default_ops.hpp (original)
+++ sandbox/big_number/boost/math/big_number/default_ops.hpp 2011-08-23 14:31:03 EDT (Tue, 23 Aug 2011)
@@ -146,6 +146,34 @@
    }
 }
 
+template <class T>
+inline void increment(T& val)
+{
+ typedef typename mpl::front<typename T::unsigned_types>::type ui_type;
+ add(val, static_cast<ui_type>(1u));
+}
+
+template <class T>
+inline void decrement(T& val)
+{
+ typedef typename mpl::front<typename T::unsigned_types>::type ui_type;
+ subtract(val, static_cast<ui_type>(1u));
+}
+
+template <class T, class V>
+inline void left_shift(T& result, const T& arg, const V val)
+{
+ result = arg;
+ left_shift(result, val);
+}
+
+template <class T, class V>
+inline void right_shift(T& result, const T& arg, const V val)
+{
+ result = arg;
+ right_shift(result, val);
+}
+
 //
 // Functions:
 //

Modified: sandbox/big_number/boost/math/big_number/gmp.hpp
==============================================================================
--- sandbox/big_number/boost/math/big_number/gmp.hpp (original)
+++ sandbox/big_number/boost/math/big_number/gmp.hpp 2011-08-23 14:31:03 EDT (Tue, 23 Aug 2011)
@@ -862,6 +862,26 @@
    if(i < 0)
       mpz_neg(t.data(), t.data());
 }
+template <class UI>
+inline void left_shift(gmp_int& t, UI i)
+{
+ mpz_mul_2exp(t.data(), t.data(), static_cast<mp_bitcnt_t>(i));
+}
+template <class UI>
+inline void right_shift(gmp_int& t, UI i)
+{
+ mpz_fdiv_q_2exp(t.data(), t.data(), static_cast<mp_bitcnt_t>(i));
+}
+template <class UI>
+inline void left_shift(gmp_int& t, const gmp_int& v, UI i)
+{
+ mpz_mul_2exp(t.data(), v.data(), static_cast<mp_bitcnt_t>(i));
+}
+template <class UI>
+inline void right_shift(gmp_int& t, const gmp_int& v, UI i)
+{
+ mpz_fdiv_q_2exp(t.data(), v.data(), static_cast<mp_bitcnt_t>(i));
+}
 
 inline void add(gmp_int& t, const gmp_int& p, const gmp_int& o)
 {
@@ -1087,8 +1107,8 @@
       {
          std::numeric_limits<boost::math::big_number<boost::math::gmp_real<digits10> > >::epsilon();
          std::numeric_limits<boost::math::big_number<boost::math::gmp_real<digits10> > >::round_error();
- std::numeric_limits<boost::math::big_number<boost::math::gmp_real<digits10> > >::min();
- std::numeric_limits<boost::math::big_number<boost::math::gmp_real<digits10> > >::max();
+ (std::numeric_limits<boost::math::big_number<boost::math::gmp_real<digits10> > >::min)();
+ (std::numeric_limits<boost::math::big_number<boost::math::gmp_real<digits10> > >::max)();
       }
       void do_nothing()const{}
    };

Modified: sandbox/big_number/boost/math/big_number/mpfr.hpp
==============================================================================
--- sandbox/big_number/boost/math/big_number/mpfr.hpp (original)
+++ sandbox/big_number/boost/math/big_number/mpfr.hpp 2011-08-23 14:31:03 EDT (Tue, 23 Aug 2011)
@@ -741,8 +741,8 @@
       {
          std::numeric_limits<boost::math::big_number<boost::math::mpfr_real_backend<digits10> > >::epsilon();
          std::numeric_limits<boost::math::big_number<boost::math::mpfr_real_backend<digits10> > >::round_error();
- std::numeric_limits<boost::math::big_number<boost::math::mpfr_real_backend<digits10> > >::min();
- std::numeric_limits<boost::math::big_number<boost::math::mpfr_real_backend<digits10> > >::max();
+ (std::numeric_limits<boost::math::big_number<boost::math::mpfr_real_backend<digits10> > >::min)();
+ (std::numeric_limits<boost::math::big_number<boost::math::mpfr_real_backend<digits10> > >::max)();
          std::numeric_limits<boost::math::big_number<boost::math::mpfr_real_backend<digits10> > >::infinity();
          std::numeric_limits<boost::math::big_number<boost::math::mpfr_real_backend<digits10> > >::quiet_NaN();
       }

Modified: sandbox/big_number/libs/math/test/test_arithmetic.cpp
==============================================================================
--- sandbox/big_number/libs/math/test/test_arithmetic.cpp (original)
+++ sandbox/big_number/libs/math/test/test_arithmetic.cpp 2011-08-23 14:31:03 EDT (Tue, 23 Aug 2011)
@@ -36,6 +36,11 @@
 #include <boost/math/big_number/mpfr.hpp>
 #endif
 
+#define BOOST_TEST_THROW(x, EX)\
+ try { x; BOOST_ERROR("Expected exception not thrown"); } \
+ catch(const EX&){}\
+ catch(...){ BOOST_ERROR("Incorrect exception type thrown"); }
+
 template <class Real>
 void test_integer_ops(const boost::mpl::false_&){}
 
@@ -104,6 +109,41 @@
    a %= -7LL;
    BOOST_TEST(a == -20 % -7);
 #endif
+ a = 20;
+ BOOST_TEST(++a == 21);
+ BOOST_TEST(--a == 20);
+ BOOST_TEST(a++ == 20);
+ BOOST_TEST(a == 21);
+ BOOST_TEST(a-- == 21);
+ BOOST_TEST(a == 20);
+ a = 2000;
+ a <<= 20;
+ BOOST_TEST(a == 2000L << 20);
+ a >>= 20;
+ BOOST_TEST(a == 2000);
+ a <<= 20u;
+ BOOST_TEST(a == 2000L << 20);
+ a >>= 20u;
+ BOOST_TEST(a == 2000);
+ BOOST_TEST_THROW(a <<= -20, std::out_of_range);
+ BOOST_TEST_THROW(a >>= -20, std::out_of_range);
+#ifndef BOOST_NO_LONG_LONG
+ if(sizeof(long long) > sizeof(std::size_t))
+ {
+ // extreme values should trigger an exception:
+ BOOST_TEST_THROW(a >>= (1uLL << (sizeof(long long) * CHAR_BIT - 2)), std::out_of_range);
+ BOOST_TEST_THROW(a <<= (1uLL << (sizeof(long long) * CHAR_BIT - 2)), std::out_of_range);
+ }
+#endif
+ a = 20;
+ b = a << 20;
+ BOOST_TEST(b == (20 << 20));
+ b = a >> 2;
+ BOOST_TEST(b == (20 >> 2));
+ b = (a + 2) << 10;
+ BOOST_TEST(b == (22 << 10));
+ b = (a + 3) >> 3;
+ BOOST_TEST(b == (23 >> 3));
    //
    // Non-member functions:
    //


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