mirror of
https://github.com/boostorg/safe_numerics.git
synced 2026-02-10 11:42:29 +00:00
Implemented divide operations
updated test_add
This commit is contained in:
@@ -381,7 +381,7 @@ namespace checked {
|
||||
const T & t,
|
||||
const U & u
|
||||
) {
|
||||
static_assert(! is_safe<T>::value, "should only be a base type here!");
|
||||
static_assert(! is_safe<T>::value, "should not be a base type here!");
|
||||
return
|
||||
detail::cast<R>(t) != checked_result<R>::exception_type::no_exception ?
|
||||
detail::cast<R>(t)
|
||||
@@ -410,134 +410,88 @@ namespace checked {
|
||||
;
|
||||
}
|
||||
|
||||
/*
|
||||
////////////////////////////////
|
||||
// safe division on unsafe types
|
||||
namespace detail {
|
||||
|
||||
////////////////////////////////
|
||||
// multiplication implementation
|
||||
|
||||
template<class T, class U>
|
||||
decltype(T() * U())
|
||||
check_multiplication_overflow(const T & t, const U & u){
|
||||
typedef decltype(T() * U()) result_type;
|
||||
char const * const msg = "safe range multiplication overflow";
|
||||
// presume that size of uintmax_t and intmax_t are the same
|
||||
typedef bits<boost::uintmax_t> available_bits;
|
||||
|
||||
if(multiply_result_bits<T, U>::value
|
||||
<= boost::numeric::bits<result_type>::value)
|
||||
return t * u;
|
||||
|
||||
if(multiply_result_bits<T, U>::value <= available_bits::value){
|
||||
typedef typename multiply_result_type<T, U>::type temp_type;
|
||||
temp_type tmp = static_cast<temp_type>(t) * temp_type(u);
|
||||
// the following works for both positive and negative results
|
||||
// and for both signed and unsigned numbers
|
||||
if(tmp > boost::integer_traits<result_type>::const_max)
|
||||
boost::numeric::overflow(msg);
|
||||
if(tmp < boost::integer_traits<result_type>::const_min)
|
||||
boost::numeric::overflow(msg);
|
||||
return static_cast<result_type>(tmp);
|
||||
}
|
||||
|
||||
// when the there is no native type which can hold the product
|
||||
// use multible precision
|
||||
|
||||
// t is factored as (a << temp_bits) + b
|
||||
// u is factored as (c << temp_bits) + d
|
||||
// so we use multi-precision:
|
||||
// a + b
|
||||
// c + d
|
||||
// -----
|
||||
// bd
|
||||
// ad
|
||||
// cb
|
||||
// ac
|
||||
// -----
|
||||
// ..
|
||||
|
||||
if(boost::numeric::is_unsigned<result_type>::value
|
||||
&& (t < 0 || u < 0))
|
||||
overflow("conversion of negative value to unsigned");
|
||||
|
||||
if(t == 1)
|
||||
return u;
|
||||
if(u == 1)
|
||||
return t;
|
||||
|
||||
result_type rt = t;
|
||||
if(rt < 0){
|
||||
rt = ~rt + 1;
|
||||
// address
|
||||
if(rt < 0)
|
||||
overflow("overflow of negative value");
|
||||
}
|
||||
result_type ru = u;
|
||||
if(ru < 0){
|
||||
ru = ~ru + 1;
|
||||
// address
|
||||
if(ru < 0)
|
||||
overflow("overflow of negative value");
|
||||
}
|
||||
|
||||
// check positive values for overflow
|
||||
|
||||
// t is factored as (a << temp_bits) + b
|
||||
// u is factored as (c << temp_bits) + d
|
||||
// so we use multi-precision:
|
||||
// a + b
|
||||
// c + d
|
||||
// -----
|
||||
// bd
|
||||
// ad
|
||||
// cb
|
||||
// ac
|
||||
// -----
|
||||
// ..
|
||||
|
||||
typedef boost::uintmax_t accumulator_type;
|
||||
const int temp_bits = bits<accumulator_type>::value / 2;
|
||||
typedef typename boost::uint_t<temp_bits>::least temp_type;
|
||||
|
||||
temp_type a = (static_cast<accumulator_type>(rt) >> temp_bits);
|
||||
temp_type c = (static_cast<accumulator_type>(ru) >> temp_bits);
|
||||
if(0 != a && 0 != c)
|
||||
overflow(msg);
|
||||
|
||||
temp_type b = static_cast<temp_type>(rt);
|
||||
if((static_cast<accumulator_type>(b) * static_cast<accumulator_type>(c) >> temp_bits) > 0)
|
||||
overflow(msg);
|
||||
|
||||
temp_type d = static_cast<const temp_type>(ru);
|
||||
if(0 != (static_cast<accumulator_type>(a) * static_cast<accumulator_type>(d) >> temp_bits))
|
||||
overflow(msg);
|
||||
|
||||
return t * u;
|
||||
template<class R>
|
||||
typename boost::enable_if_c<
|
||||
std::is_unsigned<R>::value,
|
||||
checked_result<R>
|
||||
>::type
|
||||
SAFE_NUMERIC_CONSTEXPR divide(
|
||||
const R & minr,
|
||||
const R & maxr,
|
||||
const R t,
|
||||
const R u
|
||||
) {
|
||||
return checked_result<R>(t / u);
|
||||
}
|
||||
template<class T, class U>
|
||||
decltype(T() / U())
|
||||
check_division_overflow(const T & t, const U & u){
|
||||
if(0 == u)
|
||||
overflow("divide by zero");
|
||||
|
||||
if(boost::numeric::is_signed<U>::value){
|
||||
// t unsigned, u signed
|
||||
if(boost::numeric::is_unsigned<T>::value){
|
||||
if(u < 0){
|
||||
overflow("conversion of negative value to unsigned");
|
||||
}
|
||||
}
|
||||
else{
|
||||
// both signed
|
||||
// pathological case: change sign on negative number so it overflows
|
||||
if(t == boost::integer_traits<T>::const_min && u == -1)
|
||||
overflow("overflow in result");
|
||||
}
|
||||
}
|
||||
// both unsigned
|
||||
// t signed, u unsigned
|
||||
return t / u;
|
||||
template<class R>
|
||||
typename boost::enable_if_c<
|
||||
std::is_signed<R>::value,
|
||||
checked_result<R>
|
||||
>::type
|
||||
SAFE_NUMERIC_CONSTEXPR divide(
|
||||
const R & minr,
|
||||
const R & maxr,
|
||||
const R t,
|
||||
const R u
|
||||
){
|
||||
return
|
||||
// note presumption of two's complement arithmetic
|
||||
(u < 0 && t == std::numeric_limits<R>::min()) ?
|
||||
checked_result<R>(
|
||||
checked_result<R>::exception_type::domain_error,
|
||||
"divide by zero"
|
||||
)
|
||||
:
|
||||
checked_result<R>(t / u)
|
||||
;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<class R, class T, class U>
|
||||
SAFE_NUMERIC_CONSTEXPR checked_result<R> divide(
|
||||
const R & minr,
|
||||
const R & maxr,
|
||||
const T & t,
|
||||
const U & u
|
||||
) {
|
||||
static_assert(! is_safe<T>::value, "should not be a base type here!");
|
||||
return
|
||||
detail::cast<R>(t) != checked_result<R>::exception_type::no_exception ?
|
||||
detail::cast<R>(t)
|
||||
:
|
||||
detail::cast<R>(u) != checked_result<R>::exception_type::no_exception ?
|
||||
detail::cast<R>(u)
|
||||
:
|
||||
u == 0 ?
|
||||
checked_result<R>(
|
||||
checked_result<R>::exception_type::domain_error,
|
||||
"divide by zero"
|
||||
)
|
||||
:
|
||||
detail::divide<R>(minr, maxr, t, u)
|
||||
;
|
||||
}
|
||||
template<class R, class T, class U>
|
||||
SAFE_NUMERIC_CONSTEXPR checked_result<R> divide(
|
||||
const T & t,
|
||||
const U & u
|
||||
) {
|
||||
return
|
||||
divide<R, T, U>(
|
||||
std::numeric_limits<R>::min(),
|
||||
std::numeric_limits<R>::max(),
|
||||
t,
|
||||
u
|
||||
)
|
||||
;
|
||||
}
|
||||
/*
|
||||
template<class T, class U>
|
||||
decltype(T() / U())
|
||||
check_modulus_overflow(const T & t, const U & u){
|
||||
@@ -562,8 +516,7 @@ namespace checked {
|
||||
// t signed, u unsigned
|
||||
return t % u;
|
||||
}
|
||||
} // detail
|
||||
*/
|
||||
*/
|
||||
} // checked
|
||||
} // numeric
|
||||
} // boost
|
||||
|
||||
@@ -23,7 +23,8 @@ struct checked_result {
|
||||
no_exception,
|
||||
overflow_error,
|
||||
underflow_error,
|
||||
range_error
|
||||
range_error,
|
||||
domain_error
|
||||
};
|
||||
exception_type m_e;
|
||||
union {
|
||||
@@ -103,6 +104,9 @@ struct checked_result {
|
||||
case checked_result<R>::exception_type::range_error:
|
||||
EP::range_error(m_msg);
|
||||
break;
|
||||
case checked_result<R>::exception_type::domain_error:
|
||||
EP::domain_error(m_msg);
|
||||
break;
|
||||
case checked_result<R>::exception_type::no_exception:
|
||||
break;
|
||||
default:
|
||||
@@ -112,7 +116,7 @@ struct checked_result {
|
||||
};
|
||||
|
||||
template<typename R>
|
||||
SAFE_NUMERIC_CONSTEXPR inline const checked_result<R> minxx(const checked_result<R> & t, const checked_result<R> & u){
|
||||
SAFE_NUMERIC_CONSTEXPR inline const checked_result<R> min(const checked_result<R> & t, const checked_result<R> & u){
|
||||
return
|
||||
(t.m_e == checked_result<R>::exception_type::no_exception
|
||||
&& u.m_e == checked_result<R>::exception_type::no_exception) ?
|
||||
@@ -127,8 +131,9 @@ SAFE_NUMERIC_CONSTEXPR inline const checked_result<R> minxx(const checked_result
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
template<typename R>
|
||||
SAFE_NUMERIC_CONSTEXPR inline const checked_result<R> maxxx(const checked_result<R> & t, const checked_result<R> & u){
|
||||
SAFE_NUMERIC_CONSTEXPR inline const checked_result<R> max(const checked_result<R> & t, const checked_result<R> & u){
|
||||
return
|
||||
(t.m_e == checked_result<R>::exception_type::no_exception
|
||||
&& u.m_e == checked_result<R>::exception_type::no_exception) ?
|
||||
|
||||
@@ -24,6 +24,7 @@ struct ExceptionPolicy {
|
||||
EP::overflow_error(message);
|
||||
EP::underflow_error(message);
|
||||
EP::range_error(message);
|
||||
EP::domain_error(message);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ struct ignore_exception {
|
||||
static void overflow_error(const char * message) {}
|
||||
static void underflow_error(const char * message) {}
|
||||
static void range_error(const char * message) {}
|
||||
static void domain_error(const char * message) {}
|
||||
};
|
||||
|
||||
// If an exceptional condition is detected at runtime throw the exception.
|
||||
@@ -45,6 +46,9 @@ struct throw_exception {
|
||||
static void range_error(const char * message) {
|
||||
throw std::domain_error(message);
|
||||
}
|
||||
static void domain_error(const char * message) {
|
||||
throw std::domain_error(message);
|
||||
}
|
||||
};
|
||||
|
||||
// example - if you want to specify specific behavior for particular exception
|
||||
@@ -54,7 +58,8 @@ struct throw_exception {
|
||||
template<
|
||||
void (*OVERFLOW)(const char *),
|
||||
void (*UNDERFLOW)(const char *),
|
||||
void (*RANGE)(const char *)
|
||||
void (*RANGE)(const char *),
|
||||
void (*DOMAIN)(const char *)
|
||||
>
|
||||
struct no_exception_support {
|
||||
BOOST_CONCEPT_ASSERT((boost::numeric::ExceptionPolicy<no_exception_support>));
|
||||
@@ -67,6 +72,9 @@ struct no_exception_support {
|
||||
static void range_error(const char * message) {
|
||||
RANGE(message);
|
||||
}
|
||||
static void domain_error(const char * message) {
|
||||
DOMAIN(message);
|
||||
}
|
||||
};
|
||||
|
||||
// use this policy to trap at compile time any operation which
|
||||
@@ -90,6 +98,10 @@ struct trap_exception {
|
||||
static void range_error(const T *) {
|
||||
static_assert(std::is_void<T>::value, "range_error");
|
||||
}
|
||||
template<class T>
|
||||
static void domain_error(const T *) {
|
||||
static_assert(std::is_void<T>::value, "domain_error");
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace numeric
|
||||
|
||||
@@ -54,11 +54,11 @@ SAFE_NUMERIC_CONSTEXPR interval<R> operator*(const interval<T> & t, const interv
|
||||
(u.l < 0) ?
|
||||
(u.u > 0) ? // M * M
|
||||
interval<R>(
|
||||
boost::numeric::minxx(
|
||||
min(
|
||||
checked::multiply<R>(t.l, u.u),
|
||||
checked::multiply<R>(t.u, u.l)
|
||||
),
|
||||
boost::numeric::maxxx(
|
||||
max(
|
||||
checked::multiply<R>(t.l, u.u),
|
||||
checked::multiply<R>(t.u, u.l)
|
||||
)
|
||||
@@ -119,6 +119,102 @@ SAFE_NUMERIC_CONSTEXPR interval<R> operator*(const interval<T> & t, const interv
|
||||
;
|
||||
}
|
||||
|
||||
template<typename R, typename T, typename U>
|
||||
SAFE_NUMERIC_CONSTEXPR interval<R> operator/(const interval<T> & t, const interval<U> & u){
|
||||
// adapted from https://en.wikipedia.org/wiki/Interval_arithmetic
|
||||
return
|
||||
(u.l <= 0) ?
|
||||
interval<R>(
|
||||
0,
|
||||
checked_result<R>(
|
||||
checked_result<R>::exception_type::domain_error,
|
||||
"interval divisor includes zero"
|
||||
)
|
||||
)
|
||||
:
|
||||
interval<R>(
|
||||
min(
|
||||
min(
|
||||
checked::divide<R>(t.l, u.l),
|
||||
checked::divide<R>(t.l, u.u)
|
||||
),
|
||||
min(
|
||||
checked::divide<R>(t.u, u.l),
|
||||
checked::divide<R>(t.u, u.u)
|
||||
)
|
||||
),
|
||||
max(
|
||||
max(
|
||||
checked::divide<R>(t.l, u.l),
|
||||
checked::divide<R>(t.l, u.u)
|
||||
),
|
||||
max(
|
||||
checked::divide<R>(t.u, u.l),
|
||||
checked::divide<R>(t.u, u.u)
|
||||
)
|
||||
)
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/*
|
||||
template<typename R, typename T, typename U>
|
||||
SAFE_NUMERIC_CONSTEXPR interval<R> operator/(const interval<T> & t, const interval<U> & u){
|
||||
// adapted from boost interval library
|
||||
return
|
||||
(t.u < 0) ?
|
||||
(u.u < 0) ?
|
||||
interval<R>(
|
||||
checked_result<R>(t.u, u.l),
|
||||
checked_result<R>(t.l, u.u)
|
||||
)
|
||||
:
|
||||
interval<R>(
|
||||
checked_result<R>(t.l, u.l),
|
||||
checked_result<R>(t.u, u.u)
|
||||
)
|
||||
:
|
||||
(t.l < 0) ?
|
||||
(u.u < 0) ?
|
||||
interval<R>(
|
||||
checked_result<R>(t.u, u.u),
|
||||
checked_result<R>(t.l, u.u)
|
||||
)
|
||||
:
|
||||
interval<R>(
|
||||
checked_result<R>(t.l, u.l),
|
||||
checked_result<R>(t.u, u.l)
|
||||
)
|
||||
:
|
||||
(u.u < 0) ?
|
||||
interval<R>(
|
||||
checked_result<R>(t.u, u.u),
|
||||
checked_result<R>(t.l, u.l)
|
||||
)
|
||||
:
|
||||
interval<R>(
|
||||
checked_result<R>(t.l, u.u),
|
||||
checked_result<R>(t.u, u.l)
|
||||
)
|
||||
;
|
||||
}
|
||||
if (::boost::numeric::interval_lib::user::is_neg(xu))
|
||||
if (::boost::numeric::interval_lib::user::is_neg(yu))
|
||||
return I(rnd.div_down(xu, yl), rnd.div_up(xl, yu), true);
|
||||
else
|
||||
return I(rnd.div_down(xl, yl), rnd.div_up(xu, yu), true);
|
||||
else if (::boost::numeric::interval_lib::user::is_neg(xl))
|
||||
if (::boost::numeric::interval_lib::user::is_neg(yu))
|
||||
return I(rnd.div_down(xu, yu), rnd.div_up(xl, yu), true);
|
||||
else
|
||||
return I(rnd.div_down(xl, yl), rnd.div_up(xu, yl), true);
|
||||
else
|
||||
if (::boost::numeric::interval_lib::user::is_neg(yu))
|
||||
return I(rnd.div_down(xu, yu), rnd.div_up(xl, yl), true);
|
||||
else
|
||||
return I(rnd.div_down(xl, yu), rnd.div_up(xu, yl), true);
|
||||
*/
|
||||
|
||||
} // numeric
|
||||
} // boost
|
||||
|
||||
|
||||
@@ -30,42 +30,34 @@ template<
|
||||
struct safe;
|
||||
|
||||
struct native {
|
||||
template<
|
||||
typename T,
|
||||
typename U,
|
||||
typename P,
|
||||
typename E
|
||||
>
|
||||
template<typename T, typename U, typename P, typename E>
|
||||
struct addition_result {
|
||||
typedef typename base_type<T>::type base_type_t;
|
||||
typedef typename base_type<U>::type base_type_u;
|
||||
typedef decltype(base_type_t() + base_type_u()) result_base_type;
|
||||
typedef safe<result_base_type, P, E> type;
|
||||
};
|
||||
template<
|
||||
typename T,
|
||||
typename U,
|
||||
typename P,
|
||||
typename E
|
||||
>
|
||||
template<typename T, typename U, typename P, typename E>
|
||||
struct subtraction_result {
|
||||
typedef typename base_type<T>::type base_type_t;
|
||||
typedef typename base_type<U>::type base_type_u;
|
||||
typedef decltype(base_type_t() - base_type_u()) result_base_type;
|
||||
typedef safe<result_base_type, P, E> type;
|
||||
};
|
||||
template<
|
||||
typename T,
|
||||
typename U,
|
||||
typename P,
|
||||
typename E
|
||||
>
|
||||
template<typename T, typename U, typename P, typename E>
|
||||
struct multiplication_result {
|
||||
typedef typename base_type<T>::type base_type_t;
|
||||
typedef typename base_type<U>::type base_type_u;
|
||||
typedef decltype(base_type_t() * base_type_u()) result_base_type;
|
||||
typedef safe<result_base_type, P, E> type;
|
||||
};
|
||||
template<typename T, typename U, typename P, typename E>
|
||||
struct division_result {
|
||||
typedef typename base_type<T>::type base_type_t;
|
||||
typedef typename base_type<U>::type base_type_u;
|
||||
typedef decltype(base_type_t() / base_type_u()) result_base_type;
|
||||
typedef safe<result_base_type, P, E> type;
|
||||
};
|
||||
};
|
||||
|
||||
} // numeric
|
||||
|
||||
@@ -310,22 +310,74 @@ inline operator*(const T & t, const U & u){
|
||||
return static_cast<result_type>(r);
|
||||
}
|
||||
|
||||
/*
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// division
|
||||
// special case - possible overflow
|
||||
template<class T, class Stored, class Derived, class Policies>
|
||||
typename boost::enable_if<
|
||||
std::is_integral<T>,
|
||||
decltype(T() / Stored())
|
||||
|
||||
template<class T, class U>
|
||||
struct division_result {
|
||||
typedef common_policies<T, U> P;
|
||||
typedef typename P::promotion_policy::template division_result<
|
||||
T,
|
||||
U,
|
||||
typename P::promotion_policy,
|
||||
typename P::exception_policy
|
||||
>::type type;
|
||||
};
|
||||
|
||||
template<class T, class U>
|
||||
typename boost::lazy_enable_if<
|
||||
boost::mpl::or_<
|
||||
boost::numeric::is_safe<T>,
|
||||
boost::numeric::is_safe<U>
|
||||
>,
|
||||
division_result<T, U>
|
||||
>::type
|
||||
inline operator/(const T & lhs, const safe_base<Stored, Derived, Policies> & rhs) {
|
||||
if(safe_compare::equal(0, rhs))
|
||||
throw std::domain_error("Divide by zero");
|
||||
return static_cast<
|
||||
decltype(T() / Stored())
|
||||
>(lhs / static_cast<const Stored &>(rhs));
|
||||
inline operator/(const T & t, const U & u){
|
||||
// argument dependent lookup should guarentee that we only get here
|
||||
// only if one of the types is a safe type. Verify this here
|
||||
typedef division_result<T, U> ar;
|
||||
typedef typename ar::type result_type;
|
||||
static_assert(
|
||||
boost::numeric::is_safe<result_type>::value,
|
||||
"Promotion failed to return safe type"
|
||||
);
|
||||
|
||||
typedef typename base_type<result_type>::type result_base_type;
|
||||
typedef typename base_type<T>::type t_base_type;
|
||||
typedef typename base_type<U>::type u_base_type;
|
||||
|
||||
// filter out case were overflow cannot occur
|
||||
SAFE_NUMERIC_CONSTEXPR const interval<t_base_type> t_interval = {
|
||||
base_value(std::numeric_limits<t_base_type>::min()),
|
||||
base_value(std::numeric_limits<t_base_type>::max())
|
||||
};
|
||||
SAFE_NUMERIC_CONSTEXPR const interval<u_base_type> u_interval = {
|
||||
base_value(std::numeric_limits<u_base_type>::min()),
|
||||
base_value(std::numeric_limits<u_base_type>::max())
|
||||
};
|
||||
|
||||
SAFE_NUMERIC_CONSTEXPR const interval<result_base_type> r_interval
|
||||
= operator/<result_base_type>(t_interval, u_interval);
|
||||
|
||||
// if no over/under flow possible
|
||||
if(r_interval.no_exception())
|
||||
return result_type(base_value(t) / base_value(u));
|
||||
|
||||
// otherwise do the multiplication checking for overflow
|
||||
checked_result<result_base_type> r = checked::divide(
|
||||
base_value(std::numeric_limits<result_type>::min()),
|
||||
base_value(std::numeric_limits<result_type>::max()),
|
||||
base_value(t),
|
||||
base_value(u)
|
||||
);
|
||||
|
||||
r.template dispatch<typename ar::P::exception_policy>();
|
||||
|
||||
return static_cast<result_type>(r);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
// comparison operators
|
||||
template<class T, class Stored, class Derived, class Policies>
|
||||
typename boost::enable_if<
|
||||
|
||||
@@ -27,10 +27,12 @@ bool test_add(
|
||||
|
||||
try{
|
||||
result = t1 + v2;
|
||||
|
||||
static_assert(
|
||||
boost::numeric::is_safe<decltype(t1 + v2)>::value,
|
||||
"Expression failed to return safe type"
|
||||
);
|
||||
|
||||
if(expected_result == 'x'){
|
||||
std::cout
|
||||
<< "failed to detect error in addition "
|
||||
@@ -66,14 +68,6 @@ bool test_add(
|
||||
// presuming native policy
|
||||
boost::numeric::safe<decltype(v1 + v2)> result;
|
||||
|
||||
static_assert(
|
||||
std::is_same<
|
||||
boost::numeric::safe<decltype(v1 + v2)>,
|
||||
decltype(t1 + t2)
|
||||
>::value,
|
||||
"unexpected result type"
|
||||
);
|
||||
|
||||
try{
|
||||
result = t1 + t2;
|
||||
|
||||
@@ -81,6 +75,7 @@ bool test_add(
|
||||
boost::numeric::is_safe<decltype(t1 + t2)>::value,
|
||||
"Expression failed to return safe type"
|
||||
);
|
||||
|
||||
if(expected_result == 'x'){
|
||||
std::cout
|
||||
<< "failed to detect error in addition "
|
||||
|
||||
@@ -27,74 +27,86 @@ bool test_divide(
|
||||
<< "testing "
|
||||
<< av1 << " / " << av2
|
||||
<< std::endl;
|
||||
{
|
||||
boost::numeric::safe<T1> t1 = v1;
|
||||
// presuming native policy
|
||||
boost::numeric::safe<decltype(v1 / v2)> result;
|
||||
|
||||
boost::numeric::safe<T1> t1 = v1;
|
||||
BOOST_TYPEOF_TPL(T1() / T2()) result;
|
||||
|
||||
try{
|
||||
result = t1 / v2;
|
||||
|
||||
if(expected_result != '.'){
|
||||
//if(expected_result == 'x'){
|
||||
std::cout
|
||||
<< "failed to detect error in division "
|
||||
<< std::hex << result << "(" << std::dec << result << ")"
|
||||
<< " ! = "<< av1 << " / " << av2
|
||||
<< std::endl;
|
||||
try{
|
||||
result = t1 / v2;
|
||||
try{
|
||||
result = t1 / v2;
|
||||
static_assert(
|
||||
boost::numeric::is_safe<decltype(t1 + v2)>::value,
|
||||
"Expression failed to return safe type"
|
||||
);
|
||||
if(expected_result == 'x'){
|
||||
std::cout
|
||||
<< "failed to detect error in division "
|
||||
<< std::hex << result << "(" << std::dec << result << ")"
|
||||
<< " ! = "<< av1 << " / " << av2
|
||||
<< std::endl;
|
||||
try{
|
||||
t1 / v2;
|
||||
}
|
||||
catch(...){}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch(std::exception & e){
|
||||
if(expected_result == '.'){
|
||||
std::cout
|
||||
<< "erroneously detected error in division "
|
||||
<< std::hex << result << "(" << std::dec << result << ")"
|
||||
<< " == "<< av1 << " / " << av2
|
||||
<< std::endl;
|
||||
try{
|
||||
t1 / v2;
|
||||
}
|
||||
catch(...){}
|
||||
return false;
|
||||
}
|
||||
catch(...){}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch(std::range_error){
|
||||
if(expected_result != 'x'){
|
||||
//if(expected_result == '.'){
|
||||
std::cout
|
||||
<< "erroneously detected error in division "
|
||||
<< std::hex << result << "(" << std::dec << result << ")"
|
||||
<< " == "<< av1 << " / " << av2
|
||||
<< std::endl;
|
||||
try{
|
||||
result = t1 / v2;
|
||||
}
|
||||
catch(...){}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
boost::numeric::safe<T2> t2 = v2;
|
||||
{
|
||||
boost::numeric::safe<T1> t1 = v1;
|
||||
boost::numeric::safe<T2> t2 = v2;
|
||||
|
||||
try{
|
||||
result = t1 / t2;
|
||||
// presuming native policy
|
||||
boost::numeric::safe<decltype(v1 + v2)> result;
|
||||
|
||||
if(expected_result != '.'){
|
||||
//if(expected_result == 'x'){
|
||||
std::cout
|
||||
<< "failed to detect error in division "
|
||||
<< std::hex << result << "(" << std::dec << result << ")"
|
||||
<< " ! = "<< av1 << " / " << av2
|
||||
<< std::endl;
|
||||
try{
|
||||
result = t1 / t2;
|
||||
try{
|
||||
result = t1 / t2;
|
||||
|
||||
static_assert(
|
||||
boost::numeric::is_safe<decltype(t1 + t2)>::value,
|
||||
"Expression failed to return safe type"
|
||||
);
|
||||
|
||||
if(expected_result == 'x'){
|
||||
std::cout
|
||||
<< "failed to detect error in division "
|
||||
<< std::hex << result << "(" << std::dec << result << ")"
|
||||
<< " ! = "<< av1 << " / " << av2
|
||||
<< std::endl;
|
||||
try{
|
||||
t1 / t2;
|
||||
}
|
||||
catch(...){}
|
||||
return false;
|
||||
}
|
||||
catch(...){}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch(std::range_error){
|
||||
if(expected_result != 'x'){
|
||||
//if(expected_result == '.'){
|
||||
std::cout
|
||||
<< "erroneously detected error in division "
|
||||
<< std::hex << result << "(" << std::dec << result << ")"
|
||||
<< " == "<< av1 << " / " << av2
|
||||
<< std::endl;
|
||||
try{
|
||||
result = t1 / t2;
|
||||
catch(std::exception & e){
|
||||
if(expected_result == '.'){
|
||||
std::cout
|
||||
<< "erroneously detected error in division "
|
||||
<< std::hex << result << "(" << std::dec << result << ")"
|
||||
<< " == "<< av1 << " / " << av2
|
||||
<< std::endl;
|
||||
try{
|
||||
t1 / t2;
|
||||
}
|
||||
catch(...){}
|
||||
return false;
|
||||
}
|
||||
catch(...){}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -113,38 +125,38 @@ const char *test_division_result[VALUE_ARRAY_SIZE] = {
|
||||
// 01234567890123456789012345678901
|
||||
/* 0*/ "................................",
|
||||
/* 1*/ "................................",
|
||||
/* 2*/ "...x...x...x...x................",
|
||||
/* 3*/ "................................",
|
||||
/* 2*/ "........................xxxxxxxx",
|
||||
/* 3*/ "........................xxxxxxxx",
|
||||
/* 4*/ ".................................",
|
||||
/* 5*/ "................................",
|
||||
/* 6*/ "...x...x...x...x................",
|
||||
/* 7*/ "................................",
|
||||
/* 6*/ "........................xxxxxxxx",
|
||||
/* 7*/ "........................xxxxxxxx",
|
||||
|
||||
/* 8*/ "................................",
|
||||
/* 9*/ "................................",
|
||||
/*10*/ "...x...x...x...x................",
|
||||
/*11*/ "................................",
|
||||
/*10*/ "..xx..xx..xx............xxxxxxxx",
|
||||
/*11*/ "........................xxxxxxxx",
|
||||
/*12*/ "................................",
|
||||
/*13*/ "................................",
|
||||
/*14*/ "...x...x...x...x................",
|
||||
/*15*/ "................................",
|
||||
/*14*/ "..xx..xx..xx..xx............xxxx",
|
||||
/*15*/ "............................xxxx",
|
||||
|
||||
// 0 0 0 0
|
||||
// 01234567012345670123456701234567
|
||||
// 01234567890123456789012345678901
|
||||
/*16*/ "..xx..xx..xx..xx................",
|
||||
/*17*/ "..xx..xx..xx..xx................",
|
||||
/*18*/ "..xx..xx..xx..xx................",
|
||||
/*19*/ "..xx..xx..xx..xx................",
|
||||
/*20*/ "..xx..xx..xx..xx................",
|
||||
/*21*/ "..xx..xx..xx..xx................",
|
||||
/*22*/ "..xx..xx..xx..xx................",
|
||||
/*23*/ "..xx..xx..xx..xx................",
|
||||
/*16*/ "................................",
|
||||
/*17*/ "................................",
|
||||
/*18*/ "................................",
|
||||
/*19*/ "................................",
|
||||
/*20*/ "................................",
|
||||
/*21*/ "................................",
|
||||
/*22*/ "................................",
|
||||
/*23*/ "................................",
|
||||
|
||||
/*24*/ "..xx..xx..xx..xx................",
|
||||
/*25*/ "..xx..xx..xx..xx................",
|
||||
/*26*/ "..xx..xx..xx..xx................",
|
||||
/*27*/ "..xx..xx..xx..xx................",
|
||||
/*24*/ "..xx..xx..xx....................",
|
||||
/*25*/ "..xx..xx..xx....................",
|
||||
/*26*/ "..xx..xx..xx....................",
|
||||
/*27*/ "..xx..xx..xx....................",
|
||||
/*28*/ "..xx..xx..xx..xx................",
|
||||
/*29*/ "..xx..xx..xx..xx................",
|
||||
/*30*/ "..xx..xx..xx..xx................",
|
||||
|
||||
Reference in New Issue
Block a user