Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r76128 - in sandbox/big_number: boost/multiprecision libs/multiprecision/test
From: john_at_[hidden]
Date: 2011-12-24 05:07:35


Author: johnmaddock
Date: 2011-12-24 05:07:32 EST (Sat, 24 Dec 2011)
New Revision: 76128
URL: http://svn.boost.org/trac/boost/changeset/76128

Log:
Fix modulus operations for negative numbers that should yield zero results (and update tests to match).
Fix boost::rational comparison operator support.
Fix GCC failures in test_rational_io.cpp.
Add adapter for rational types.
Added:
   sandbox/big_number/boost/multiprecision/rational_adapter.hpp (contents, props changed)
Text files modified:
   sandbox/big_number/boost/multiprecision/gmp.hpp | 12 ++++++------
   sandbox/big_number/boost/multiprecision/mp_number.hpp | 24 ++++++++++++++++++++++++
   sandbox/big_number/boost/multiprecision/tommath.hpp | 12 ++++++++++--
   sandbox/big_number/libs/multiprecision/test/test_arithmetic.cpp | 22 +++++++++++++---------
   sandbox/big_number/libs/multiprecision/test/test_rational_io.cpp | 6 +++---
   5 files changed, 56 insertions(+), 20 deletions(-)

Modified: sandbox/big_number/boost/multiprecision/gmp.hpp
==============================================================================
--- sandbox/big_number/boost/multiprecision/gmp.hpp (original)
+++ sandbox/big_number/boost/multiprecision/gmp.hpp 2011-12-24 05:07:32 EST (Sat, 24 Dec 2011)
@@ -1114,7 +1114,7 @@
    bool neg = mpz_sgn(t.data()) < 0;
    bool neg2 = mpz_sgn(o.data()) < 0;
    mpz_mod(t.data(), t.data(), o.data());
- if(neg)
+ if(neg && mpz_sgn(t.data()) != 0)
    {
       if(!neg2)
          t.negate();
@@ -1139,7 +1139,7 @@
 {
    bool neg = mpz_sgn(t.data()) < 0;
    mpz_mod_ui(t.data(), t.data(), i);
- if(neg)
+ if(neg && mpz_sgn(t.data()) != 0)
    {
       t.negate();
       mpz_add_ui(t.data(), t.data(), i);
@@ -1175,7 +1175,7 @@
    bool neg = mpz_sgn(t.data()) < 0;
    bool neg2 = i < 0;
    mpz_mod_ui(t.data(), t.data(), std::abs(i));
- if(neg)
+ if(neg && mpz_sgn(t.data()) != 0)
    {
       if(!neg2)
       {
@@ -1252,7 +1252,7 @@
    bool neg = mpz_sgn(p.data()) < 0;
    bool neg2 = mpz_sgn(o.data()) < 0;
    mpz_mod(t.data(), p.data(), o.data());
- if(neg)
+ if(neg && mpz_sgn(t.data()) != 0)
    {
       if(!neg2)
          t.negate();
@@ -1277,7 +1277,7 @@
 {
    bool neg = mpz_sgn(p.data()) < 0;
    mpz_mod_ui(t.data(), p.data(), i);
- if(neg)
+ if(neg && mpz_sgn(t.data()) != 0)
    {
       t.negate();
       mpz_add_ui(t.data(), t.data(), i);
@@ -1313,7 +1313,7 @@
    bool neg = mpz_sgn(p.data()) < 0;
    bool neg2 = i < 0;
    mpz_mod_ui(t.data(), p.data(), std::abs(i));
- if(neg)
+ if(neg && mpz_sgn(t.data()) != 0)
    {
       if(!neg2)
       {

Modified: sandbox/big_number/boost/multiprecision/mp_number.hpp
==============================================================================
--- sandbox/big_number/boost/multiprecision/mp_number.hpp (original)
+++ sandbox/big_number/boost/multiprecision/mp_number.hpp 2011-12-24 05:07:32 EST (Sat, 24 Dec 2011)
@@ -1611,6 +1611,30 @@
    return is;
 }
 
+template <class T, class Arithmetic>
+typename enable_if<boost::is_arithmetic<Arithmetic>, bool>::type operator == (const rational<multiprecision::mp_number<T> >& a, const Arithmetic& b)
+{
+ return a == multiprecision::mp_number<T>(b);
+}
+
+template <class T, class Arithmetic>
+typename enable_if<boost::is_arithmetic<Arithmetic>, bool>::type operator == (const Arithmetic& b, const rational<multiprecision::mp_number<T> >& a)
+{
+ return a == multiprecision::mp_number<T>(b);
+}
+
+template <class T, class Arithmetic>
+typename enable_if<boost::is_arithmetic<Arithmetic>, bool>::type operator != (const rational<multiprecision::mp_number<T> >& a, const Arithmetic& b)
+{
+ return a != multiprecision::mp_number<T>(b);
+}
+
+template <class T, class Arithmetic>
+typename enable_if<boost::is_arithmetic<Arithmetic>, bool>::type operator != (const Arithmetic& b, const rational<multiprecision::mp_number<T> >& a)
+{
+ return a != multiprecision::mp_number<T>(b);
+}
+
 } // namespaces
 
 #endif

Added: sandbox/big_number/boost/multiprecision/rational_adapter.hpp
==============================================================================
--- (empty file)
+++ sandbox/big_number/boost/multiprecision/rational_adapter.hpp 2011-12-24 05:07:32 EST (Sat, 24 Dec 2011)
@@ -0,0 +1,161 @@
+///////////////////////////////////////////////////////////////
+// Copyright 2011 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_
+
+#ifndef BOOST_MATH_RATIONAL_ADAPTER_HPP
+#define BOOST_MATH_RATIONAL_ADAPTER_HPP
+
+#include <iostream>
+#include <iomanip>
+#include <sstream>
+#include <boost/cstdint.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/multiprecision/mp_number.hpp>
+#include <boost/rational.hpp>
+
+namespace boost{
+namespace multiprecision{
+
+template <class IntBackend>
+struct rational_adapter
+{
+ typedef mp_number<IntBackend> integer_type;
+ typedef boost::rational<integer_type> rational_type;
+
+ typedef typename IntBackend::signed_types signed_types;
+ typedef typename IntBackend::unsigned_types unsigned_types;
+ typedef typename IntBackend::float_types float_types;
+
+ rational_adapter(){}
+ rational_adapter(const rational_adapter& o)
+ {
+ m_value = o.m_value;
+ }
+ rational_adapter(const IntBackend& o) : m_value(o) {}
+#ifndef BOOST_NO_RVALUE_REFERENCES
+ rational_adapter(rational_adapter&& o) : m_value(o.m_value) {}
+ rational_adapter(IntBackend&& o) : m_value(o) {}
+#endif
+ rational_adapter& operator = (const rational_adapter& o)
+ {
+ m_value = o.m_value;
+ return *this;
+ }
+ template <class Arithmetic>
+ typename enable_if<is_arithmetic<Arithmetic>, rational_adapter&>::type operator = (Arithmetic i)
+ {
+ m_value = i;
+ return *this;
+ }
+ rational_adapter& operator = (const char* s)
+ {
+ m_value = s;
+ return *this;
+ }
+ void swap(rational_adapter& o)
+ {
+ std::swap(m_value, o.m_value);
+ }
+ std::string str(std::streamsize digits, std::ios_base::fmtflags f)const
+ {
+ //
+ // We format the string ourselves so we can match what GMP's mpq type does:
+ //
+ std::string result = data().numerator().str(digits, f);
+ if(data().denominator() != 1)
+ {
+ result.append(1, ',');
+ result.append(data().denominator().str(digits, f));
+ }
+ return result;
+ }
+ void negate()
+ {
+ m_value = -m_value;
+ }
+ int compare(const rational_adapter& o)const
+ {
+ return m_value > o.m_value ? 1 : (m_value < o.m_value ? -1 : 0);
+ }
+ template <class Arithmatic>
+ typename enable_if<is_arithmetic<Arithmatic>, int>::type compare(Arithmatic i)const
+ {
+ return m_value > i ? 1 : (m_value < i ? -1 : 0);
+ }
+ rational_type& data() { return m_value; }
+ const rational_type& data()const { return m_value; }
+private:
+ rational_type m_value;
+};
+
+template <class IntBackend>
+inline void add(rational_adapter<IntBackend>& result, const rational_adapter<IntBackend>& o)
+{
+ result.data() += o.data();
+}
+template <class IntBackend>
+inline void subtract(rational_adapter<IntBackend>& result, const rational_adapter<IntBackend>& o)
+{
+ result.data() -= o.data();
+}
+template <class IntBackend>
+inline void multiply(rational_adapter<IntBackend>& result, const rational_adapter<IntBackend>& o)
+{
+ result.data() *= o.data();
+}
+template <class IntBackend>
+inline void divide(rational_adapter<IntBackend>& result, const rational_adapter<IntBackend>& o)
+{
+ result.data() /= o.data();
+}
+
+template <class R, class IntBackend>
+inline void convert_to(R* result, const rational_adapter<IntBackend>& backend)
+{
+ *result = backend.data().numerator().template convert_to<R>();
+ *result /= backend.data().denominator().template convert_to<R>();
+}
+
+template <class IntBackend>
+inline bool is_zero(const rational_adapter<IntBackend>& val)
+{
+ return is_zero(val.data().numerator().backend());
+}
+template <class IntBackend>
+inline int get_sign(const rational_adapter<IntBackend>& val)
+{
+ return get_sign(val.data().numerator().backend());
+}
+
+
+template<class IntBackend>
+struct number_category<rational_adapter<IntBackend> > : public mpl::int_<number_kind_rational>{};
+
+}} // namespaces
+
+
+namespace std{
+
+template <class IntBackend>
+class numeric_limits<boost::multiprecision::mp_number<boost::multiprecision::rational_adapter<IntBackend> > > : public std::numeric_limits<IntBackend>
+{
+ typedef std::numeric_limits<IntBackend> base_type;
+ typedef boost::multiprecision::mp_number<boost::multiprecision::rational_adapter<IntBackend> > number_type;
+public:
+ BOOST_STATIC_CONSTEXPR bool is_integer = false;
+ BOOST_STATIC_CONSTEXPR bool is_exact = true;
+ BOOST_STATIC_CONSTEXPR number_type (min)() BOOST_MP_NOEXCEPT { return (base_type::min)(); }
+ BOOST_STATIC_CONSTEXPR number_type (max)() BOOST_MP_NOEXCEPT { return (base_type::max)(); }
+ BOOST_STATIC_CONSTEXPR number_type lowest() BOOST_MP_NOEXCEPT { return -(max)(); }
+ BOOST_STATIC_CONSTEXPR number_type epsilon() BOOST_MP_NOEXCEPT { return base_type::epsilon(); }
+ BOOST_STATIC_CONSTEXPR number_type round_error() BOOST_MP_NOEXCEPT { return epsilon() / 2; }
+ BOOST_STATIC_CONSTEXPR number_type infinity() BOOST_MP_NOEXCEPT { return base_type::infinity(); }
+ BOOST_STATIC_CONSTEXPR number_type quiet_NaN() BOOST_MP_NOEXCEPT { return base_type::quiet_NaN(); }
+ BOOST_STATIC_CONSTEXPR number_type signaling_NaN() BOOST_MP_NOEXCEPT { return base_type::signaling_NaN(); }
+ BOOST_STATIC_CONSTEXPR number_type denorm_min() BOOST_MP_NOEXCEPT { return base_type::denorm_min(); }
+};
+
+}
+
+#endif

Modified: sandbox/big_number/boost/multiprecision/tommath.hpp
==============================================================================
--- sandbox/big_number/boost/multiprecision/tommath.hpp (original)
+++ sandbox/big_number/boost/multiprecision/tommath.hpp 2011-12-24 05:07:32 EST (Sat, 24 Dec 2011)
@@ -258,12 +258,16 @@
    bool neg = get_sign(t) < 0;
    bool neg2 = get_sign(o) < 0;
    detail::check_tommath_result(mp_mod(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
- if(neg != neg2)
+ if((neg != neg2) && (get_sign(t) != 0))
    {
       t.negate();
       detail::check_tommath_result(mp_add(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
       t.negate();
    }
+ else if(neg && (t.compare(o) == 0))
+ {
+ mp_zero(&t.data());
+ }
 }
 template <class UI>
 inline void left_shift(tommath_int& t, UI i)
@@ -331,12 +335,16 @@
    bool neg = get_sign(p) < 0;
    bool neg2 = get_sign(o) < 0;
    detail::check_tommath_result(mp_mod(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data()));
- if(neg != neg2)
+ if((neg != neg2) && (get_sign(t) != 0))
    {
       t.negate();
       detail::check_tommath_result(mp_add(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
       t.negate();
    }
+ else if(neg && (t.compare(o) == 0))
+ {
+ mp_zero(&t.data());
+ }
 }
 
 inline void bitwise_and(tommath_int& result, const tommath_int& u, const tommath_int& v)

Modified: sandbox/big_number/libs/multiprecision/test/test_arithmetic.cpp
==============================================================================
--- sandbox/big_number/libs/multiprecision/test/test_arithmetic.cpp (original)
+++ sandbox/big_number/libs/multiprecision/test/test_arithmetic.cpp 2011-12-24 05:07:32 EST (Sat, 24 Dec 2011)
@@ -34,6 +34,7 @@
 
 #if defined(TEST_MPF_50) || defined(TEST_MPF) || defined(TEST_MPZ) || defined(TEST_MPQ) || defined(TEST_MPZ_BOOST_RATIONAL)
 #include <boost/multiprecision/gmp.hpp>
+#include <boost/multiprecision/rational_adapter.hpp>
 #endif
 #ifdef TEST_BACKEND
 #include <boost/multiprecision/concepts/mp_number_architypes.hpp>
@@ -46,6 +47,7 @@
 #endif
 #if defined(TEST_TOMMATH) || defined(TEST_TOMMATH_BOOST_RATIONAL)
 #include <boost/multiprecision/tommath.hpp>
+#include <boost/multiprecision/rational_adapter.hpp>
 #endif
 #if defined(TEST_TOMMATH_BOOST_RATIONAL) || defined(TEST_MPZ_BOOST_RATIONAL)
 #include <boost/rational.hpp>
@@ -133,7 +135,7 @@
 {
    Real a(20);
    Real b(7);
- Real c;
+ Real c(5);
    BOOST_TEST(a % b == 20 % 7);
    BOOST_TEST(a % 7 == 20 % 7);
    BOOST_TEST(a % 7u == 20 % 7);
@@ -144,6 +146,14 @@
    BOOST_TEST(-a % -7 == -20 % -7);
    BOOST_TEST(a % -7 == 20 % -7);
    BOOST_TEST(-a % 7u == -20 % 7);
+ BOOST_TEST(-a % a == 0);
+ BOOST_TEST(a % a == 0);
+ BOOST_TEST(-a % c == 0);
+ BOOST_TEST(a % c == 0);
+ BOOST_TEST(-a % 5 == 0);
+ BOOST_TEST(a % 5 == 0);
+ BOOST_TEST(-a % -5 == 0);
+ BOOST_TEST(a % -5 == 0);
 
    b = -b;
    BOOST_TEST(a % b == 20 % -7);
@@ -658,9 +668,7 @@
    BOOST_TEST(ac == 64 * 2);
    ac = a;
    ac = b - ac * a;
-#ifndef NO_MIXED_OPS
    BOOST_TEST(ac == 0);
-#endif
    ac = a;
    ac = b * (ac + a);
    BOOST_TEST(ac == 64 * (16));
@@ -678,9 +686,7 @@
    BOOST_TEST(ac == 8 - 64);
    ac = a;
    ac = a - ac;
-#ifndef NO_MIXED_OPS
    BOOST_TEST(ac == 0);
-#endif
    ac = a;
    ac += a + b;
    BOOST_TEST(ac == 80);
@@ -706,9 +712,7 @@
    BOOST_TEST(ac == 16);
    ac = a;
    ac += -a;
-#ifndef NO_MIXED_OPS
    BOOST_TEST(ac == 0);
-#endif
    ac = a;
    ac += b - a;
    BOOST_TEST(ac == 8 + 64-8);
@@ -718,9 +722,7 @@
    ac = a;
    ac = a;
    ac -= +a;
-#ifndef NO_MIXED_OPS
    BOOST_TEST(ac == 0);
-#endif
    ac = a;
    ac -= -a;
    BOOST_TEST(ac == 16);
@@ -917,6 +919,7 @@
 #endif
 #ifdef TEST_MPZ
    test<boost::multiprecision::mpz_int>();
+ test<boost::multiprecision::mp_number<boost::multiprecision::rational_adapter<boost::multiprecision::gmp_int> > >();
 #endif
 #ifdef TEST_MPQ
    test<boost::multiprecision::mpq_rational>();
@@ -932,6 +935,7 @@
 #endif
 #ifdef TEST_TOMMATH
    test<boost::multiprecision::mp_int>();
+ test<boost::multiprecision::mp_number<boost::multiprecision::rational_adapter<boost::multiprecision::tommath_int> > >();
 #endif
 #ifdef TEST_TOMMATH_BOOST_RATIONAL
    test<boost::rational<boost::multiprecision::mp_int> >();

Modified: sandbox/big_number/libs/multiprecision/test/test_rational_io.cpp
==============================================================================
--- sandbox/big_number/libs/multiprecision/test/test_rational_io.cpp (original)
+++ sandbox/big_number/libs/multiprecision/test/test_rational_io.cpp 2011-12-24 05:07:32 EST (Sat, 24 Dec 2011)
@@ -42,14 +42,14 @@
 {
    static boost::random::uniform_int_distribution<unsigned> ui(0, 20);
    static boost::random::mt19937 gen;
- T val = gen();
+ T val = T(gen());
    unsigned lim = ui(gen);
    for(unsigned i = 0; i < lim; ++i)
    {
       val *= (gen.max)();
       val += gen();
    }
- T denom = gen();
+ T denom = T(gen());
    lim = ui(gen);
    for(unsigned i = 0; i < lim; ++i)
    {
@@ -76,7 +76,7 @@
 void do_round_trip(const T& val, std::ios_base::fmtflags f, const boost::mpl::false_&)
 {
    std::stringstream ss;
- ss << std::setprecision(std::numeric_limits<T>::max_digits10);
+ ss << std::setprecision(std::numeric_limits<T>::digits10 + 4);
    ss.flags(f);
    ss << val;
    T new_val;


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