|
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