Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r81151 - in sandbox/big_number: boost/multiprecision boost/multiprecision/detail libs/multiprecision/test
From: john_at_[hidden]
Date: 2012-11-02 15:13:51


Author: johnmaddock
Date: 2012-11-02 15:13:50 EDT (Fri, 02 Nov 2012)
New Revision: 81151
URL: http://svn.boost.org/trac/boost/changeset/81151

Log:
Add non-member functions for mixed precision arithmetic + tests for same.
Fix a couple of bugs discovered along the way.
Added:
   sandbox/big_number/libs/multiprecision/test/test_mixed_cpp_int.cpp (contents, props changed)
   sandbox/big_number/libs/multiprecision/test/test_mixed_float.cpp (contents, props changed)
Text files modified:
   sandbox/big_number/boost/multiprecision/cpp_dec_float.hpp | 6 ++-
   sandbox/big_number/boost/multiprecision/cpp_int.hpp | 4 +-
   sandbox/big_number/boost/multiprecision/detail/default_ops.hpp | 74 ++++++++++++++++++++++++++++++++++++---
   sandbox/big_number/libs/multiprecision/test/Jamfile.v2 | 11 +++++
   4 files changed, 83 insertions(+), 12 deletions(-)

Modified: sandbox/big_number/boost/multiprecision/cpp_dec_float.hpp
==============================================================================
--- sandbox/big_number/boost/multiprecision/cpp_dec_float.hpp (original)
+++ sandbox/big_number/boost/multiprecision/cpp_dec_float.hpp 2012-11-02 15:13:50 EDT (Fri, 02 Nov 2012)
@@ -376,8 +376,10 @@
       exp = f.exp;
       neg = f.neg;
       fpclass = static_cast<enum_fpclass_type>(static_cast<int>(f.fpclass));
- std::copy(f.data.begin(), f.data.begin() + (std::min)(f.prec_elem, prec_elem), data.begin());
- precision((std::min)(f.prec_elem, prec_elem));
+ unsigned elems = (std::min)(f.prec_elem, cpp_dec_float_elem_number);
+ std::copy(f.data.begin(), f.data.begin() + elems, data.begin());
+ std::fill(data.begin() + elems, data.end(), 0);
+ prec_elem = cpp_dec_float_elem_number;
       return *this;
    }
    cpp_dec_float& operator= (long long v) BOOST_NOEXCEPT

Modified: sandbox/big_number/boost/multiprecision/cpp_int.hpp
==============================================================================
--- sandbox/big_number/boost/multiprecision/cpp_int.hpp (original)
+++ sandbox/big_number/boost/multiprecision/cpp_int.hpp 2012-11-02 15:13:50 EDT (Fri, 02 Nov 2012)
@@ -690,7 +690,7 @@
          BOOST_THROW_EXCEPTION(std::range_error("The argument to a cpp_int constructor exceeded the largest value it can represent."));
    }
    template <class T, int C>
- void check_in_range(T val, const mpl::int_<C>&){}
+ void check_in_range(T, const mpl::int_<C>&){}
 
    template <class T>
    void check_in_range(T val)
@@ -817,7 +817,7 @@
          BOOST_THROW_EXCEPTION(std::range_error("The argument to an unsigned cpp_int constructor was negative."));
    }
    template <class T, int C, bool B>
- BOOST_FORCEINLINE void check_in_range(T val, const mpl::int_<C>&, const mpl::bool_<B>&){}
+ BOOST_FORCEINLINE void check_in_range(T, const mpl::int_<C>&, const mpl::bool_<B>&){}
 
    template <class T>
    BOOST_FORCEINLINE void check_in_range(T val)

Modified: sandbox/big_number/boost/multiprecision/detail/default_ops.hpp
==============================================================================
--- sandbox/big_number/boost/multiprecision/detail/default_ops.hpp (original)
+++ sandbox/big_number/boost/multiprecision/detail/default_ops.hpp 2012-11-02 15:13:50 EDT (Fri, 02 Nov 2012)
@@ -253,7 +253,7 @@
 inline void eval_add_default(T& t, const U& u, const V& v)
 {
    t = u;
- eval_add(t, u);
+ eval_add(t, v);
 }
 template <class T, class U, class V>
 inline void eval_add(T& t, const U& u, const V& v)
@@ -358,7 +358,7 @@
 inline void eval_multiply_default(T& t, const U& u, const V& v)
 {
    t = u;
- eval_multiply(t, u);
+ eval_multiply(t, v);
 }
 template <class T, class U, class V>
 inline void eval_multiply(T& t, const U& u, const V& v)
@@ -457,7 +457,7 @@
 inline void eval_divide_default(T& t, const U& u, const V& v)
 {
    t = u;
- eval_divide(t, u);
+ eval_divide(t, v);
 }
 template <class T, class U, class V>
 inline void eval_divide(T& t, const U& u, const V& v)
@@ -515,7 +515,7 @@
 inline void eval_modulus_default(T& t, const U& u, const V& v)
 {
    t = u;
- eval_modulus(t, u);
+ eval_modulus(t, v);
 }
 template <class T, class U, class V>
 inline void eval_modulus(T& t, const U& u, const V& v)
@@ -565,7 +565,7 @@
 inline void eval_bitwise_and_default(T& t, const U& u, const V& v)
 {
    t = u;
- eval_bitwise_and(t, u);
+ eval_bitwise_and(t, v);
 }
 template <class T, class U, class V>
 inline void eval_bitwise_and(T& t, const U& u, const V& v)
@@ -615,7 +615,7 @@
 inline void eval_bitwise_or_default(T& t, const U& u, const V& v)
 {
    t = u;
- eval_bitwise_or(t, u);
+ eval_bitwise_or(t, v);
 }
 template <class T, class U, class V>
 inline void eval_bitwise_or(T& t, const U& u, const V& v)
@@ -665,7 +665,7 @@
 inline void eval_bitwise_xor_default(T& t, const U& u, const V& v)
 {
    t = u;
- eval_bitwise_xor(t, u);
+ eval_bitwise_xor(t, v);
 }
 template <class T, class U, class V>
 inline void eval_bitwise_xor(T& t, const U& u, const V& v)
@@ -1108,6 +1108,66 @@
 } // namespace math
 namespace multiprecision{
 
+template <class B1, class B2, class B3, expression_template_option ET1, expression_template_option ET2, expression_template_option ET3>
+inline number<B1, ET1>& add(number<B1, ET1>& result, const number<B2, ET2>& a, const number<B3, ET3>& b)
+{
+ BOOST_STATIC_ASSERT_MSG((is_convertible<B2, B1>::value), "No conversion to the target of a mixed precision addition exists");
+ BOOST_STATIC_ASSERT_MSG((is_convertible<B3, B1>::value), "No conversion to the target of a mixed precision addition exists");
+ using default_ops::eval_add;
+ eval_add(result.backend(), a.backend(), b.backend());
+ return result;
+}
+
+template <class B1, class B2, class B3, expression_template_option ET1, expression_template_option ET2, expression_template_option ET3>
+inline number<B1, ET1>& subtract(number<B1, ET1>& result, const number<B2, ET2>& a, const number<B3, ET3>& b)
+{
+ BOOST_STATIC_ASSERT_MSG((is_convertible<B2, B1>::value), "No conversion to the target of a mixed precision addition exists");
+ BOOST_STATIC_ASSERT_MSG((is_convertible<B3, B1>::value), "No conversion to the target of a mixed precision addition exists");
+ using default_ops::eval_subtract;
+ eval_subtract(result.backend(), a.backend(), b.backend());
+ return result;
+}
+
+template <class B1, class B2, class B3, expression_template_option ET1, expression_template_option ET2, expression_template_option ET3>
+inline number<B1, ET1>& multiply(number<B1, ET1>& result, const number<B2, ET2>& a, const number<B3, ET3>& b)
+{
+ BOOST_STATIC_ASSERT_MSG((is_convertible<B2, B1>::value), "No conversion to the target of a mixed precision addition exists");
+ BOOST_STATIC_ASSERT_MSG((is_convertible<B3, B1>::value), "No conversion to the target of a mixed precision addition exists");
+ using default_ops::eval_multiply;
+ eval_multiply(result.backend(), a.backend(), b.backend());
+ return result;
+}
+
+template <class B, expression_template_option ET, class I>
+inline typename enable_if_c<is_integral<I>::value, number<B, ET>&>::type
+ add(number<B, ET>& result, const I& a, const I& b)
+{
+ using default_ops::eval_add;
+ typedef typename detail::canonical<I, B>::type canonical_type;
+ eval_add(result.backend(), static_cast<canonical_type>(a), static_cast<canonical_type>(b));
+ return result;
+}
+
+template <class B, expression_template_option ET, class I>
+inline typename enable_if_c<is_integral<I>::value, number<B, ET>&>::type
+ subtract(number<B, ET>& result, const I& a, const I& b)
+{
+ using default_ops::eval_subtract;
+ typedef typename detail::canonical<I, B>::type canonical_type;
+ eval_subtract(result.backend(), static_cast<canonical_type>(a), static_cast<canonical_type>(b));
+ return result;
+}
+
+template <class B, expression_template_option ET, class I>
+inline typename enable_if_c<is_integral<I>::value, number<B, ET>&>::type
+ multiply(number<B, ET>& result, const I& a, const I& b)
+{
+ using default_ops::eval_multiply;
+ typedef typename detail::canonical<I, B>::type canonical_type;
+ eval_multiply(result.backend(), static_cast<canonical_type>(a), static_cast<canonical_type>(b));
+ return result;
+}
+
 template <class tag, class A1, class A2, class A3, class A4, class Policy>
 inline typename detail::expression<tag, A1, A2, A3, A4>::result_type trunc(const detail::expression<tag, A1, A2, A3, A4>& v, const Policy& pol)
 {

Modified: sandbox/big_number/libs/multiprecision/test/Jamfile.v2
==============================================================================
--- sandbox/big_number/libs/multiprecision/test/Jamfile.v2 (original)
+++ sandbox/big_number/libs/multiprecision/test/Jamfile.v2 2012-11-02 15:13:50 EDT (Fri, 02 Nov 2012)
@@ -820,7 +820,16 @@
         : # requirements
          [ check-target-builds ../config//has_tommath : : <build>no ] ;
 run ../example/floating_point_examples.cpp : : : <toolset>gcc:<cxxflags>-std=c++0x ;
-run test_cpp_int_conv.cpp ;
+run test_cpp_int_conv.cpp;
+
+run test_mixed_cpp_int.cpp ;
+run test_mixed_float.cpp
+ : # command line
+ : # input files
+ : # requirements
+ [ check-target-builds ../config//has_gmp : <define>TEST_GMP <library>gmp : ]
+ [ check-target-builds ../config//has_mpfr : <define>TEST_MPFR <library>mpfr <library>gmp : ] ;
+
 
 compile include_test/mpfr_include_test.cpp
               : # requirements

Added: sandbox/big_number/libs/multiprecision/test/test_mixed_cpp_int.cpp
==============================================================================
--- (empty file)
+++ sandbox/big_number/libs/multiprecision/test/test_mixed_cpp_int.cpp 2012-11-02 15:13:50 EDT (Fri, 02 Nov 2012)
@@ -0,0 +1,85 @@
+///////////////////////////////////////////////////////////////
+// Copyright 2012 John Maddock. 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_
+
+//
+// Compare arithmetic results using fixed_int to GMP results.
+//
+
+#ifdef _MSC_VER
+# define _SCL_SECURE_NO_WARNINGS
+#endif
+
+#include <boost/multiprecision/cpp_int.hpp>
+#include "test.hpp"
+
+template <class Number, class BigNumber>
+void test()
+{
+ using namespace boost::multiprecision;
+ typedef Number test_type;
+
+ test_type h = (std::numeric_limits<test_type>::max)();
+ test_type l = (std::numeric_limits<test_type>::max)();
+ BigNumber r;
+
+ add(r, h, h);
+ BOOST_CHECK_EQUAL(r, cpp_int(h) + cpp_int(h));
+
+ multiply(r, h, h);
+ BOOST_CHECK_EQUAL(r, cpp_int(h) * cpp_int(h));
+
+ if(std::numeric_limits<test_type>::is_signed)
+ {
+ subtract(r, l, h);
+ BOOST_CHECK_EQUAL(r, cpp_int(l) - cpp_int(h));
+ subtract(r, h, l);
+ BOOST_CHECK_EQUAL(r, cpp_int(h) - cpp_int(l));
+ multiply(r, l, l);
+ BOOST_CHECK_EQUAL(r, cpp_int(l) * cpp_int(l));
+ }
+
+ //
+ // Try again with integer types as the source:
+ //
+ static const unsigned max_digits = std::numeric_limits<test_type>::is_signed ? std::numeric_limits<long long>::digits : std::numeric_limits<unsigned long long>::digits;
+ static const unsigned require_digits = std::numeric_limits<test_type>::digits <= 2 * max_digits ? std::numeric_limits<test_type>::digits / 2 : max_digits;
+ typedef typename boost::mpl::if_c<std::numeric_limits<test_type>::is_signed, typename boost::int_t<require_digits>::least, typename boost::uint_t<require_digits>::least>::type i_type;
+
+ i_type ih = (std::numeric_limits<i_type>::max)();
+ i_type il = (std::numeric_limits<i_type>::max)();
+
+ add(r, ih, ih);
+ BOOST_CHECK_EQUAL(r, cpp_int(ih) + cpp_int(ih));
+
+ multiply(r, ih, ih);
+ BOOST_CHECK_EQUAL(r, cpp_int(ih) * cpp_int(ih));
+
+ if(std::numeric_limits<test_type>::is_signed)
+ {
+ subtract(r, il, ih);
+ BOOST_CHECK_EQUAL(r, cpp_int(il) - cpp_int(ih));
+ subtract(r, ih, il);
+ BOOST_CHECK_EQUAL(r, cpp_int(ih) - cpp_int(il));
+ multiply(r, il, il);
+ BOOST_CHECK_EQUAL(r, cpp_int(il) * cpp_int(il));
+ }
+}
+
+int main()
+{
+ using namespace boost::multiprecision;
+
+ test<checked_int512_t, checked_int1024_t>();
+ test<checked_int256_t, checked_int512_t>();
+ test<number<cpp_int_backend<64, 64, signed_magnitude, checked, void>, et_off>, checked_int512_t>();
+
+ test<checked_uint512_t, checked_uint1024_t>();
+ test<checked_uint256_t, checked_uint512_t>();
+ test<number<cpp_int_backend<64, 64, unsigned_magnitude, checked, void>, et_off>, checked_uint512_t>();
+ return boost::report_errors();
+}
+
+
+

Added: sandbox/big_number/libs/multiprecision/test/test_mixed_float.cpp
==============================================================================
--- (empty file)
+++ sandbox/big_number/libs/multiprecision/test/test_mixed_float.cpp 2012-11-02 15:13:50 EDT (Fri, 02 Nov 2012)
@@ -0,0 +1,57 @@
+///////////////////////////////////////////////////////////////
+// Copyright 2012 John Maddock. 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_
+
+//
+// Compare arithmetic results using fixed_int to GMP results.
+//
+
+#ifdef _MSC_VER
+# define _SCL_SECURE_NO_WARNINGS
+#endif
+
+#ifdef TEST_GMP
+#include <boost/multiprecision/gmp.hpp>
+#endif
+#ifdef TEST_MPFR
+#include <boost/multiprecision/mpfr.hpp>
+#endif
+#include <boost/multiprecision/cpp_dec_float.hpp>
+#include "test.hpp"
+
+template <class Number, class BigNumber>
+void test()
+{
+ using namespace boost::multiprecision;
+ typedef Number test_type;
+
+ test_type a = 1;
+ a /= 3;
+ test_type b = -a;
+
+ BigNumber r;
+ BOOST_CHECK_EQUAL(add(r, a, a), BigNumber(a) + BigNumber(a));
+ BOOST_CHECK_EQUAL(subtract(r, a, b), BigNumber(a) - BigNumber(b));
+ BOOST_CHECK_EQUAL(subtract(r, b, a), BigNumber(b) - BigNumber(a));
+ BOOST_CHECK_EQUAL(multiply(r, a, a), BigNumber(a) * BigNumber(a));
+}
+
+int main()
+{
+ using namespace boost::multiprecision;
+
+ test<cpp_dec_float_50, cpp_dec_float_100>();
+
+#ifdef TEST_GMP
+ test<mpf_float_50, mpf_float_100>();
+#endif
+#ifdef TEST_MPFR
+ test<mpfr_float_50, mpfr_float_100>();
+#endif
+
+ 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