|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r86473 - in sandbox/multiprecision.cpp_bin_float: boost/multiprecision boost/multiprecision/cpp_bin_float libs/multiprecision/doc libs/multiprecision/test/math libs/multiprecision/test/math/instances
From: john_at_[hidden]
Date: 2013-10-27 05:27:01
Author: johnmaddock
Date: 2013-10-27 05:27:01 EDT (Sun, 27 Oct 2013)
New Revision: 86473
URL: http://svn.boost.org/trac/boost/changeset/86473
Log:
Lots of small fixes for better overflow/underflow handling.
Add some optimised sign manipulation routines.
Add a new version of exp optimised for binary floating point types.
Tweak test types.
Added:
sandbox/multiprecision.cpp_bin_float/boost/multiprecision/cpp_bin_float/transcendental.hpp (contents, props changed)
Text files modified:
sandbox/multiprecision.cpp_bin_float/boost/multiprecision/cpp_bin_float.hpp | 54 ++++++++++++++++---
sandbox/multiprecision.cpp_bin_float/boost/multiprecision/cpp_bin_float/io.hpp | 70 +++++++++++++++++++++++---
sandbox/multiprecision.cpp_bin_float/boost/multiprecision/cpp_bin_float/transcendental.hpp | 106 ++++++++++++++++++++++++++++++++++++++++
sandbox/multiprecision.cpp_bin_float/libs/multiprecision/doc/multiprecision.qbk | 2
sandbox/multiprecision.cpp_bin_float/libs/multiprecision/test/math/instances/instances.cpp | 14 ++++
sandbox/multiprecision.cpp_bin_float/libs/multiprecision/test/math/setup.hpp | 4
6 files changed, 227 insertions(+), 23 deletions(-)
Modified: sandbox/multiprecision.cpp_bin_float/boost/multiprecision/cpp_bin_float.hpp
==============================================================================
--- sandbox/multiprecision.cpp_bin_float/boost/multiprecision/cpp_bin_float.hpp Sun Oct 27 05:23:16 2013 (r86472)
+++ sandbox/multiprecision.cpp_bin_float/boost/multiprecision/cpp_bin_float.hpp 2013-10-27 05:27:01 EDT (Sun, 27 Oct 2013) (r86473)
@@ -163,7 +163,7 @@
m_exponent += bits;
eval_add(*this, ipart);
}
- m_exponent += e;
+ m_exponent += static_cast<Exponent>(e);
return *this;
}
@@ -263,12 +263,12 @@
unsigned shift = msb(fi);
if(shift >= bit_count)
{
- m_exponent = shift;
+ m_exponent = static_cast<Exponent>(shift);
m_data = static_cast<limb_type>(fi >> (shift + 1 - bit_count));
}
else
{
- m_exponent = shift;
+ m_exponent = static_cast<Exponent>(shift);
eval_left_shift(m_data, bit_count - shift - 1);
}
BOOST_ASSERT(eval_bit_test(m_data, bit_count-1));
@@ -370,12 +370,12 @@
res.bits() = static_cast<limb_type>(0u);
return;
}
- unsigned msb = eval_msb(arg);
+ int msb = eval_msb(arg);
if(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count > msb + 1)
{
// Must have had cancellation in subtraction, shift left and copy:
eval_left_shift(arg, cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - msb - 1);
- res.exponent() -= cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - msb - 1;
+ res.exponent() -= static_cast<Exponent>(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - msb - 1);
}
else if(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count < msb + 1)
{
@@ -391,7 +391,7 @@
}
// Shift off the cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count we don't need:
eval_right_shift(arg, msb - cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count + 1);
- res.exponent() += msb - cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count + 1;
+ res.exponent() += static_cast<Exponent>(msb - (int)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count + 1);
if(roundup)
{
eval_increment(arg);
@@ -912,7 +912,7 @@
// We can set the exponent and sign of the result up front:
//
int gb = msb(v);
- res.exponent() = u.exponent() - gb - 1;
+ res.exponent() = u.exponent() - static_cast<Exponent>(gb) - static_cast<Exponent>(1);
res.sign() = u.sign();
//
// Now get the quotient and remainder:
@@ -982,6 +982,27 @@
}
template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE>
+inline int eval_get_sign(const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> &arg)
+{
+ return arg.exponent() == cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero ? 0 : arg.sign() ? -1 : 1;
+}
+
+template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE>
+inline bool eval_is_zero(const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> &arg)
+{
+ return arg.exponent() == cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero;
+}
+
+template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE>
+inline bool eval_eq(const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> &a, cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> &b)
+{
+ return (a.exponent() == b.exponent())
+ && (a.sign() == b.sign())
+ && (a.bits().compare(b.bits()) == 0)
+ && (a.exponent() != cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_nan);
+}
+
+template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE>
inline void eval_convert_to(long long *res, const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> &arg)
{
switch(arg.exponent())
@@ -1120,8 +1141,22 @@
res = arg;
return;
}
- res = arg;
- res.exponent() += e;
+ if((e > 0) && (cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent - e < arg.exponent()))
+ {
+ // Overflow:
+ res = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::infinity().backend();
+ res.sign() = arg.sign();
+ }
+ else if((e < 0) && (cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::min_exponent - e > arg.exponent()))
+ {
+ // Underflow:
+ res = limb_type(0);
+ }
+ else
+ {
+ res = arg;
+ res.exponent() += e;
+ }
}
template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, class I>
@@ -1339,6 +1374,7 @@
}} // namespaces
#include <boost/multiprecision/cpp_bin_float/io.hpp>
+#include <boost/multiprecision/cpp_bin_float/transcendental.hpp>
namespace std{
Modified: sandbox/multiprecision.cpp_bin_float/boost/multiprecision/cpp_bin_float/io.hpp
==============================================================================
--- sandbox/multiprecision.cpp_bin_float/boost/multiprecision/cpp_bin_float/io.hpp Sun Oct 27 05:23:16 2013 (r86472)
+++ sandbox/multiprecision.cpp_bin_float/boost/multiprecision/cpp_bin_float/io.hpp 2013-10-27 05:27:01 EDT (Sun, 27 Oct 2013) (r86473)
@@ -286,6 +286,7 @@
#endif
boost::int64_t error = 0;
boost::intmax_t calc_exp = 0;
+ boost::intmax_t final_exponent = 0;
if(decimal_exp >= 0)
{
@@ -300,13 +301,11 @@
}
else
t = n;
- exponent() = (int)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - 1;
- exponent() += static_cast<exponent_type>(decimal_exp);
- exponent() += static_cast<exponent_type>(calc_exp);
+ final_exponent = (boost::int64_t)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - 1 + decimal_exp + calc_exp;
int rshift = msb(t) - cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count + 1;
if(rshift > 0)
{
- exponent() += rshift;
+ final_exponent += rshift;
int roundup = boost::multiprecision::cpp_bf_io_detail::get_round_mode(t, rshift - 1, error);
t >>= rshift;
if((roundup == 2) || ((roundup == 1) && t.backend().limbs()[0] & 1))
@@ -326,6 +325,22 @@
{
BOOST_ASSERT(!error);
}
+ if(final_exponent > cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent)
+ {
+ exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent;
+ final_exponent -= cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent;
+ }
+ else if(final_exponent < cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::min_exponent)
+ {
+ // Underflow:
+ exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::min_exponent;
+ final_exponent -= cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::min_exponent;
+ }
+ else
+ {
+ exponent() = static_cast<Exponent>(final_exponent);
+ final_exponent = 0;
+ }
copy_and_round(*this, t.backend());
break;
}
@@ -345,11 +360,11 @@
cpp_int d;
calc_exp = boost::multiprecision::cpp_bf_io_detail::restricted_pow(d, cpp_int(5), -decimal_exp, max_bits, error);
int shift = (int)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - msb(n) + msb(d);
- exponent() = static_cast<exponent_type>(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - 1 + decimal_exp - calc_exp);
+ final_exponent = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - 1 + decimal_exp - calc_exp;
if(shift > 0)
{
n <<= shift;
- exponent() -= shift;
+ final_exponent -= static_cast<Exponent>(shift);
}
cpp_int q, r;
divide_qr(n, d, q, r);
@@ -371,7 +386,7 @@
// note that the radius of error in r is error/2 * q:
int shift = gb - (int)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count + 1;
q >>= shift;
- exponent() += shift;
+ final_exponent += static_cast<Exponent>(shift);
BOOST_ASSERT((msb(q) >= cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - 1));
if(error && (r < (error / 2) * q))
roundup = -1;
@@ -396,12 +411,29 @@
if(shift > 0)
{
n >>= shift;
- exponent() += shift;
+ final_exponent += static_cast<Exponent>(shift);
}
continue;
}
else if((roundup == 2) || ((roundup == 1) && q.backend().limbs()[0] & 1))
++q;
+ if(final_exponent > cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent)
+ {
+ // Overflow:
+ exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent;
+ final_exponent -= cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent;
+ }
+ else if(final_exponent < cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::min_exponent)
+ {
+ // Underflow:
+ exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::min_exponent;
+ final_exponent -= cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::min_exponent;
+ }
+ else
+ {
+ exponent() = static_cast<Exponent>(final_exponent);
+ final_exponent = 0;
+ }
copy_and_round(*this, q.backend());
if(ss != sign())
negate();
@@ -409,7 +441,27 @@
}
while(true);
}
-
+ //
+ // Check for scaling and/or over/under-flow:
+ //
+ final_exponent += exponent();
+ if(final_exponent > cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent)
+ {
+ // Overflow:
+ exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity;
+ bits() = limb_type(0);
+ }
+ else if(final_exponent < cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::min_exponent)
+ {
+ // Underflow:
+ exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero;
+ bits() = limb_type(0);
+ sign() = 0;
+ }
+ else
+ {
+ exponent() = static_cast<Exponent>(final_exponent);
+ }
return *this;
}
Added: sandbox/multiprecision.cpp_bin_float/boost/multiprecision/cpp_bin_float/transcendental.hpp
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ sandbox/multiprecision.cpp_bin_float/boost/multiprecision/cpp_bin_float/transcendental.hpp 2013-10-27 05:27:01 EDT (Sun, 27 Oct 2013) (r86473)
@@ -0,0 +1,106 @@
+///////////////////////////////////////////////////////////////
+// Copyright 2013 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_MULTIPRECISION_CPP_BIN_FLOAT_TRANSCENDENTAL_HPP
+#define BOOST_MULTIPRECISION_CPP_BIN_FLOAT_TRANSCENDENTAL_HPP
+
+namespace boost{ namespace multiprecision{ namespace backends{
+
+template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE>
+void eval_exp_taylor(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> &res, const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> &arg)
+{
+ static const int bits = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count;
+ //
+ // Taylor series for small argument:
+ //
+ res = limb_type(0);
+ cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> num(arg), denom, t;
+ denom = limb_type(1);
+ eval_add(res, num);
+
+ for(unsigned k = 2; ; ++k)
+ {
+ eval_multiply(denom, k);
+ eval_multiply(num, arg);
+ eval_divide(t, num, denom);
+ eval_add(res, t);
+ if(eval_is_zero(t) || (res.exponent() - bits > t.exponent()))
+ break;
+ }
+}
+
+template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE>
+void eval_exp(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> &res, const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> &arg)
+{
+ using default_ops::eval_multiply;
+ using default_ops::eval_subtract;
+ using default_ops::eval_add;
+ using default_ops::eval_convert_to;
+
+ int type = eval_fpclassify(arg);
+ bool isneg = eval_get_sign(arg) < 0;
+ if(type == FP_NAN)
+ {
+ res = arg;
+ return;
+ }
+ else if(type == FP_INFINITE)
+ {
+ res = arg;
+ if(isneg)
+ res = limb_type(0u);
+ else
+ res = arg;
+ return;
+ }
+ else if(type == FP_ZERO)
+ {
+ res = limb_type(1);
+ return;
+ }
+ cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> t, n;
+ if(isneg)
+ {
+ t = arg;
+ t.negate();
+ eval_exp(res, t);
+ t.swap(res);
+ res = limb_type(1);
+ eval_divide(res, t);
+ return;
+ }
+
+ eval_divide(n, arg, default_ops::get_constant_ln2<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> >());
+ eval_floor(n, n);
+ eval_multiply(t, n, default_ops::get_constant_ln2<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> >());
+ eval_subtract(t, arg);
+ t.negate();
+ BOOST_ASSERT(t.compare(limb_type(0)) >= 0);
+ BOOST_ASSERT(t.compare(default_ops::get_constant_ln2<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> >()) < 0);
+
+ Exponent k, nn;
+ eval_convert_to(&nn, n);
+ k = nn ? Exponent(1) << (msb(nn) / 2) : 0;
+ eval_ldexp(t, t, -k);
+
+ eval_exp_taylor(res, t);
+ //
+ // Square 1 + res k times:
+ //
+ for(int s = 0; s < k; ++s)
+ {
+ t.swap(res);
+ eval_multiply(res, t, t);
+ eval_ldexp(t, t, 1);
+ eval_add(res, t);
+ }
+ eval_add(res, limb_type(1));
+ eval_ldexp(res, res, nn);
+}
+
+}}} // namespaces
+
+#endif
+
Modified: sandbox/multiprecision.cpp_bin_float/libs/multiprecision/doc/multiprecision.qbk
==============================================================================
--- sandbox/multiprecision.cpp_bin_float/libs/multiprecision/doc/multiprecision.qbk Sun Oct 27 05:23:16 2013 (r86472)
+++ sandbox/multiprecision.cpp_bin_float/libs/multiprecision/doc/multiprecision.qbk 2013-10-27 05:27:01 EDT (Sun, 27 Oct 2013) (r86473)
@@ -694,7 +694,7 @@
Normally `cpp_bin_float` allocates no memory: all of the space required for its digits are allocated
directly within the class. As a result care should be taken not to use the class with too high a digit count
as stack space requirements can grow out of control. If that represents a problem then providing an allocator
-as the final template parameter causes `cpp_bin_float` to dynamically allocate the memory it needs: this
+as a template parameter causes `cpp_bin_float` to dynamically allocate the memory it needs: this
significantly reduces the size of `cpp_bin_float` and increases the viable upper limit on the number of digits
at the expense of performance. However, please bear in mind that arithmetic operations rapidly become ['very] expensive
as the digit count grows: the current implementation really isn't optimized or designed for large digit counts.
Modified: sandbox/multiprecision.cpp_bin_float/libs/multiprecision/test/math/instances/instances.cpp
==============================================================================
--- sandbox/multiprecision.cpp_bin_float/libs/multiprecision/test/math/instances/instances.cpp Sun Oct 27 05:23:16 2013 (r86472)
+++ sandbox/multiprecision.cpp_bin_float/libs/multiprecision/test/math/instances/instances.cpp 2013-10-27 05:27:01 EDT (Sun, 27 Oct 2013) (r86473)
@@ -6,9 +6,19 @@
#define BOOST_MATH_OVERFLOW_ERROR_POLICY ignore_error
#include <boost/math/special_functions.hpp>
+#define BOOST_MATH_TEST_TYPE boost::multiprecision::float128_t
+
#include "../setup.hpp"
-//#define BOOST_MATH_TEST_TYPE double
-//#define TEST_GROUP_1
+#define TEST_GROUP_1
+#define TEST_GROUP_2
+#define TEST_GROUP_3
+#define TEST_GROUP_4
+#define TEST_GROUP_5
+#define TEST_GROUP_6
+#define TEST_GROUP_7
+#define TEST_GROUP_8
+#define TEST_GROUP_9
+#define TEST_GROUP_10
#include "libs/math/test/test_instances/test_instances.hpp"
Modified: sandbox/multiprecision.cpp_bin_float/libs/multiprecision/test/math/setup.hpp
==============================================================================
--- sandbox/multiprecision.cpp_bin_float/libs/multiprecision/test/math/setup.hpp Sun Oct 27 05:23:16 2013 (r86472)
+++ sandbox/multiprecision.cpp_bin_float/libs/multiprecision/test/math/setup.hpp 2013-10-27 05:27:01 EDT (Sun, 27 Oct 2013) (r86473)
@@ -95,9 +95,9 @@
#ifdef TEST_CPP_BIN_FLOAT
#include <boost/multiprecision/cpp_bin_float.hpp>
-#define CPP_BIN_FLOAT_TESTS test(cpp_bin_float_50>(), "cpp_bin_float_50");
+#define CPP_BIN_FLOAT_TESTS test(float128_t(), "float128_t");
-typedef boost::multiprecision::cpp_bin_float_50 test_type_1;
+typedef boost::multiprecision::float128_t test_type_1;
#else
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