Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r75714 - in sandbox/big_number: boost/multiprecision libs/multiprecision/test
From: john_at_[hidden]
Date: 2011-11-28 11:28:32


Author: johnmaddock
Date: 2011-11-28 11:28:31 EST (Mon, 28 Nov 2011)
New Revision: 75714
URL: http://svn.boost.org/trac/boost/changeset/75714

Log:
Fix IO of infinities and NaN's.
Add IO round trip test and adjust max_digits10 accordingly.
Text files modified:
   sandbox/big_number/boost/multiprecision/cpp_float.hpp | 53 +++++++++++++++++++--
   sandbox/big_number/boost/multiprecision/gmp.hpp | 4
   sandbox/big_number/boost/multiprecision/mpfr.hpp | 17 ++++++
   sandbox/big_number/libs/multiprecision/test/test.hpp | 2
   sandbox/big_number/libs/multiprecision/test/test_float_io.cpp | 98 +++++++++++++++++++++++++++++++++++++++
   5 files changed, 163 insertions(+), 11 deletions(-)

Modified: sandbox/big_number/boost/multiprecision/cpp_float.hpp
==============================================================================
--- sandbox/big_number/boost/multiprecision/cpp_float.hpp (original)
+++ sandbox/big_number/boost/multiprecision/cpp_float.hpp 2011-11-28 11:28:31 EST (Mon, 28 Nov 2011)
@@ -53,6 +53,11 @@
    static const boost::int32_t mp_elem_number = static_cast<boost::int32_t>(cpp_float_digits10_num_base + 2);
    static const boost::int32_t mp_elem_mask = static_cast<boost::int32_t>(100000000);
 
+public:
+ static const boost::int32_t cpp_float_total_digits10 = mp_elem_number * mp_elem_digits10;
+
+private:
+
    typedef enum enum_fpclass
    {
       mp_finite,
@@ -1641,6 +1646,20 @@
 template <unsigned Digits10>
 std::string cpp_float<Digits10>::str(std::streamsize number_of_digits, std::ios_base::fmtflags f) const
 {
+ if(this->isinf())
+ {
+ if(this->isneg())
+ return "-inf";
+ else if(f & std::ios_base::showpos)
+ return "+inf";
+ else
+ return "inf";
+ }
+ else if(this->isnan())
+ {
+ return "nan";
+ }
+
    std::string str;
    std::streamsize org_digits(number_of_digits);
    boost::int64_t my_exp = order();
@@ -1799,17 +1818,39 @@
    // Get a possible +/- sign and remove it.
    neg = false;
 
- if((pos = str.find(static_cast<char>('-'))) != std::string::npos)
+ if(str.size())
    {
- neg = true;
- str.erase(pos, static_cast<std::size_t>(1u));
+ if(str[0] == '-')
+ {
+ neg = true;
+ str.erase(0, 1);
+ }
+ else if(str[0] == '+')
+ {
+ str.erase(0, 1);
+ }
    }
-
- if((pos = str.find(static_cast<char>('+'))) != std::string::npos)
+ //
+ // Special cases for infinities and NaN's:
+ //
+ if((str == "inf") || (str == "INF") || (str == "infinity") || (str == "INFINITY"))
    {
- str.erase(pos, static_cast<std::size_t>(1u));
+ if(neg)
+ {
+ *this = this->inf();
+ this->negate();
+ }
+ else
+ *this = this->inf();
+ return true;
+ }
+ if((str.size() >= 3) && ((str.substr(0, 3) == "nan") || (str.substr(0, 3) == "NAN")))
+ {
+ *this = this->nan();
+ return true;
    }
 
+
    // Remove leading zeros for all input types.
    const std::string::iterator fwd_it_leading_zero = std::find_if(str.begin(), str.end(), char_is_nonzero_predicate);
 

Modified: sandbox/big_number/boost/multiprecision/gmp.hpp
==============================================================================
--- sandbox/big_number/boost/multiprecision/gmp.hpp (original)
+++ sandbox/big_number/boost/multiprecision/gmp.hpp 2011-11-28 11:28:31 EST (Mon, 28 Nov 2011)
@@ -1788,8 +1788,8 @@
    }
    BOOST_STATIC_CONSTEXPR int digits = static_cast<int>(((Digits10 + 1) * 1000L) / 301L);
    BOOST_STATIC_CONSTEXPR int digits10 = Digits10;
- // Is this really correct???
- BOOST_STATIC_CONSTEXPR int max_digits10 = Digits10 + 1;
+ // Have to allow for a possible extra limb inside the gmp data structure:
+ BOOST_STATIC_CONSTEXPR int max_digits10 = Digits10 + 2 + ((GMP_LIMB_BITS * 301L) / 1000L);
    BOOST_STATIC_CONSTEXPR bool is_signed = true;
    BOOST_STATIC_CONSTEXPR bool is_integer = false;
    BOOST_STATIC_CONSTEXPR bool is_exact = false;

Modified: sandbox/big_number/boost/multiprecision/mpfr.hpp
==============================================================================
--- sandbox/big_number/boost/multiprecision/mpfr.hpp (original)
+++ sandbox/big_number/boost/multiprecision/mpfr.hpp 2011-11-28 11:28:31 EST (Mon, 28 Nov 2011)
@@ -168,6 +168,21 @@
 
       std::string result;
       mp_exp_t e;
+ if(mpfr_inf_p(m_data))
+ {
+ if(mpfr_sgn(m_data) < 0)
+ result = "-inf";
+ else if(f & std::ios_base::showpos)
+ result = "+inf";
+ else
+ result = "inf";
+ return result;
+ }
+ if(mpfr_nan_p(m_data))
+ {
+ result = "nan";
+ return result;
+ }
       if(mpfr_zero_p(m_data))
       {
          e = 0;
@@ -1059,7 +1074,7 @@
    BOOST_STATIC_CONSTEXPR int digits = static_cast<int>(((Digits10 + 1) * 1000L) / 301L);
    BOOST_STATIC_CONSTEXPR int digits10 = Digits10;
    // Is this really correct???
- BOOST_STATIC_CONSTEXPR int max_digits10 = Digits10 + 1;
+ BOOST_STATIC_CONSTEXPR int max_digits10 = Digits10 + 2;
    BOOST_STATIC_CONSTEXPR bool is_signed = true;
    BOOST_STATIC_CONSTEXPR bool is_integer = false;
    BOOST_STATIC_CONSTEXPR bool is_exact = false;

Modified: sandbox/big_number/libs/multiprecision/test/test.hpp
==============================================================================
--- sandbox/big_number/libs/multiprecision/test/test.hpp (original)
+++ sandbox/big_number/libs/multiprecision/test/test.hpp 2011-11-28 11:28:31 EST (Mon, 28 Nov 2011)
@@ -63,7 +63,7 @@
 template <class T>
 inline int digits_of(const T&)
 {
- return std::numeric_limits<T>::is_specialized ? std::numeric_limits<T>::digits10 + 2 : std::numeric_limits<long double>::digits10 + 2;
+ return std::numeric_limits<T>::is_specialized ? std::numeric_limits<T>::max_digits10 + 2 : std::numeric_limits<long double>::max_digits10 + 2;
 }
 
 inline std::ostream& report_where(const char* file, int line, const char* function)

Modified: sandbox/big_number/libs/multiprecision/test/test_float_io.cpp
==============================================================================
--- sandbox/big_number/libs/multiprecision/test/test_float_io.cpp (original)
+++ sandbox/big_number/libs/multiprecision/test/test_float_io.cpp 2011-11-28 11:28:31 EST (Mon, 28 Nov 2011)
@@ -33,7 +33,9 @@
 #include <boost/multiprecision/cpp_float.hpp>
 #endif
 
-#include <boost/detail/lightweight_test.hpp>
+#include <boost/random/mersenne_twister.hpp>
+#include <boost/random/uniform_int.hpp>
+#include "test.hpp"
 #include <boost/array.hpp>
 #include <iostream>
 #include <iomanip>
@@ -160,6 +162,85 @@
          }
       }
    }
+
+ if(std::numeric_limits<mp_t>::has_infinity)
+ {
+ T val = std::numeric_limits<T>::infinity();
+ BOOST_CHECK_EQUAL(val.str(), "inf");
+ BOOST_CHECK_EQUAL(val.str(0, std::ios_base::showpos), "+inf");
+ val = -val;
+ BOOST_CHECK_EQUAL(val.str(), "-inf");
+ BOOST_CHECK_EQUAL(val.str(0, std::ios_base::showpos), "-inf");
+
+ val = "inf";
+ BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+ val = "+inf";
+ BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
+ val = "-inf";
+ BOOST_CHECK_EQUAL(val, -std::numeric_limits<T>::infinity());
+ }
+ if(std::numeric_limits<mp_t>::has_quiet_NaN)
+ {
+ T val = std::numeric_limits<T>::quiet_NaN();
+ BOOST_CHECK_EQUAL(val.str(), "nan");
+ val = "nan";
+ BOOST_CHECK(boost::math::isnan(val));
+ }
+}
+
+template <class T>
+T generate_random()
+{
+ static boost::random::mt19937 gen;
+ T val = gen();
+ T prev_val = -1;
+ while(val != prev_val)
+ {
+ val *= (gen.max)();
+ prev_val = val;
+ val += gen();
+ }
+ int e;
+ val = frexp(val, &e);
+
+ typedef typename T::backend_type::exponent_type e_type;
+ static boost::random::uniform_int_distribution<e_type> ui(0, std::numeric_limits<T>::max_exponent - 10);
+ return ldexp(val, ui(gen));
+}
+
+template <class T>
+void do_round_trip(const T& val, std::ios_base::fmtflags f)
+{
+ std::stringstream ss;
+ ss << std::setprecision(std::numeric_limits<T>::max_digits10);
+ ss.flags(f);
+ ss << val;
+ T new_val = ss.str();
+ BOOST_CHECK_EQUAL(new_val, val);
+ new_val = val.str(0, f);
+ BOOST_CHECK_EQUAL(new_val, val);
+}
+
+template <class T>
+void do_round_trip(const T& val)
+{
+ do_round_trip(val, std::ios_base::fmtflags(0));
+ do_round_trip(val, std::ios_base::fmtflags(std::ios_base::scientific));
+ if((fabs(val) > 1) && (fabs(val) < 1e100))
+ do_round_trip(val, std::ios_base::fmtflags(std::ios_base::fixed));
+}
+
+template <class T>
+void test_round_trip()
+{
+ for(unsigned i = 0; i < 1000; ++i)
+ {
+ T val = generate_random<T>();
+ do_round_trip(val);
+ do_round_trip(T(-val));
+ do_round_trip(T(1/val));
+ do_round_trip(T(-1/val));
+ }
 }
 
 int main()
@@ -167,14 +248,29 @@
 #ifdef TEST_MPFR_50
    test<boost::multiprecision::mpfr_float_50>();
    test<boost::multiprecision::mpfr_float_100>();
+
+ test_round_trip<boost::multiprecision::mpfr_float_50>();
+ test_round_trip<boost::multiprecision::mpfr_float_100>();
 #endif
 #ifdef TEST_CPP_FLOAT
    test<boost::multiprecision::cpp_float_50>();
    test<boost::multiprecision::cpp_float_100>();
+
+ /*
+ // cpp_float has extra guard digits that messes this up:
+ test_round_trip<boost::multiprecision::cpp_float_50>();
+ test_round_trip<boost::multiprecision::cpp_float_100>();
+ */
 #endif
 #ifdef TEST_MPF_50
    test<boost::multiprecision::mpf_float_50>();
    test<boost::multiprecision::mpf_float_100>();
+ /*
+ // I can't get this to work with mpf_t - mpf_str appears
+ // not to actually print enough decimal digits:
+ test_round_trip<boost::multiprecision::mpf_float_50>();
+ test_round_trip<boost::multiprecision::mpf_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