summaryrefslogtreecommitdiff
path: root/boost/multiprecision/detail/default_ops.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/multiprecision/detail/default_ops.hpp')
-rw-r--r--boost/multiprecision/detail/default_ops.hpp48
1 files changed, 38 insertions, 10 deletions
diff --git a/boost/multiprecision/detail/default_ops.hpp b/boost/multiprecision/detail/default_ops.hpp
index bfdb8bd368..c45eec447f 100644
--- a/boost/multiprecision/detail/default_ops.hpp
+++ b/boost/multiprecision/detail/default_ops.hpp
@@ -50,8 +50,9 @@ namespace default_ops{
#ifdef BOOST_MSVC
// warning C4127: conditional expression is constant
+// warning C4146: unary minus operator applied to unsigned type, result still unsigned
#pragma warning(push)
-#pragma warning(disable:4127)
+#pragma warning(disable:4127 4146)
#endif
//
// Default versions of mixed arithmetic, these just construct a temporary
@@ -889,29 +890,42 @@ struct calculate_next_larger_type
};
template <class R, class T>
-inline bool check_in_range(const T& t)
+inline typename boost::enable_if_c<boost::is_integral<R>::value, bool>::type check_in_range(const T& t)
{
// Can t fit in an R?
- if(std::numeric_limits<R>::is_specialized && std::numeric_limits<R>::is_bounded && (t > (std::numeric_limits<R>::max)()))
+ if((t > 0) && std::numeric_limits<R>::is_specialized && std::numeric_limits<R>::is_bounded && (t > (std::numeric_limits<R>::max)()))
return true;
+ else
return false;
}
-template <class R, class T>
-inline bool check_in_range(const terminal<T>&)
+template <class R, class B>
+inline typename boost::enable_if_c<boost::is_integral<R>::value>::type eval_convert_to(R* result, const B& backend)
{
- return false;
+ typedef typename calculate_next_larger_type<R, B>::type next_type;
+ next_type n;
+ eval_convert_to(&n, backend);
+ if(std::numeric_limits<R>::is_specialized && std::numeric_limits<R>::is_bounded && (n > (next_type)(std::numeric_limits<R>::max)()))
+ {
+ *result = (std::numeric_limits<R>::max)();
+ }
+ else if (std::numeric_limits<R>::is_specialized && std::numeric_limits<R>::is_bounded && (n < (next_type)(std::numeric_limits<R>::min)()))
+ {
+ *result = (std::numeric_limits<R>::min)();
+ }
+ else
+ *result = static_cast<R>(n);
}
template <class R, class B>
-inline void eval_convert_to(R* result, const B& backend)
+inline typename boost::disable_if_c<boost::is_integral<R>::value>::type eval_convert_to(R* result, const B& backend)
{
typedef typename calculate_next_larger_type<R, B>::type next_type;
next_type n;
eval_convert_to(&n, backend);
- if(check_in_range<R>(n))
+ if(std::numeric_limits<R>::is_specialized && std::numeric_limits<R>::is_bounded && ((n > (next_type)(std::numeric_limits<R>::max)() || (n < (next_type)-(std::numeric_limits<R>::max)()) )))
{
- *result = (std::numeric_limits<R>::max)();
+ *result = n > 0 ? (std::numeric_limits<R>::max)() : -(std::numeric_limits<R>::max)();
}
else
*result = static_cast<R>(n);
@@ -924,7 +938,21 @@ inline void eval_convert_to(terminal<R>* result, const B& backend)
// We ran out of types to try for the conversion, try
// a lexical_cast and hope for the best:
//
- result->value = boost::lexical_cast<R>(backend.str(0, std::ios_base::fmtflags(0)));
+ if (std::numeric_limits<R>::is_integer && !std::numeric_limits<R>::is_signed && (eval_get_sign(backend) < 0))
+ BOOST_THROW_EXCEPTION(std::range_error("Attempt to convert negative value to an unsigned integer results in undefined behaviour"));
+ try
+ {
+ result->value = boost::lexical_cast<R>(backend.str(0, std::ios_base::fmtflags(0)));
+ }
+ catch (const bad_lexical_cast&)
+ {
+ if (eval_get_sign(backend) < 0)
+ {
+ *result = std::numeric_limits<R>::is_integer && std::numeric_limits<R>::is_signed ? (std::numeric_limits<R>::min)() : -(std::numeric_limits<R>::max)();
+ }
+ else
+ *result = (std::numeric_limits<R>::max)();
+ }
}
template <class B1, class B2, expression_template_option et>