maths, view: rationalise equal,almost_equal,==
views should not do elementwise comparisons for equality operators. they are pairs of iterators and are only equal if their iterators are equal. instead, use `equal` for elementwise equality. we update the name of exactly_equal to perform this operation too.
This commit is contained in:
parent
5d32408126
commit
35e3f69ad2
@ -909,7 +909,7 @@ json::tree::number::sint (void) const
|
|||||||
return m_value.s;
|
return m_value.s;
|
||||||
|
|
||||||
case REAL:
|
case REAL:
|
||||||
if (!::util::exactly_equal (real_t (sint_t (m_value.r)), m_value.r))
|
if (!::util::equal (real_t (sint_t (m_value.r)), m_value.r))
|
||||||
throw type_error ("number is not a sint");
|
throw type_error ("number is not a sint");
|
||||||
return sint_t (m_value.r);
|
return sint_t (m_value.r);
|
||||||
|
|
||||||
@ -932,7 +932,7 @@ json::tree::number::uint (void) const
|
|||||||
return m_value.u;
|
return m_value.u;
|
||||||
|
|
||||||
case REAL:
|
case REAL:
|
||||||
if (!::util::exactly_equal (real_t (uint_t (m_value.r)), m_value.r))
|
if (!::util::equal (real_t (uint_t (m_value.r)), m_value.r))
|
||||||
throw type_error ("number is not a uint");
|
throw type_error ("number is not a uint");
|
||||||
return uint_t (m_value.r);
|
return uint_t (m_value.r);
|
||||||
|
|
||||||
|
114
maths.hpp
114
maths.hpp
@ -43,67 +43,6 @@
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
namespace util {
|
namespace util {
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Comparisons
|
|
||||||
inline bool
|
|
||||||
almost_equal (const float &a, const float &b)
|
|
||||||
{
|
|
||||||
return ieee_single::almost_equal (a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
inline bool
|
|
||||||
almost_equal (const double &a, const double &b)
|
|
||||||
{
|
|
||||||
return ieee_double::almost_equal (a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
template <typename A, typename B>
|
|
||||||
inline
|
|
||||||
typename std::enable_if_t<
|
|
||||||
std::is_floating_point<A>::value &&
|
|
||||||
std::is_floating_point<B>::value &&
|
|
||||||
!std::is_same<A,B>::value ,
|
|
||||||
bool
|
|
||||||
>
|
|
||||||
almost_equal (const A &a, const B &b)
|
|
||||||
{
|
|
||||||
using common_t = std::common_type_t<A,B>;
|
|
||||||
return almost_equal<common_t> (static_cast<common_t> (a),
|
|
||||||
static_cast<common_t> (b));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
template <typename A, typename B>
|
|
||||||
inline
|
|
||||||
typename std::enable_if_t<
|
|
||||||
std::is_integral_v<A> &&
|
|
||||||
std::is_integral_v<B> &&
|
|
||||||
std::is_signed<A>::value == std::is_signed<B>::value,
|
|
||||||
bool
|
|
||||||
>
|
|
||||||
almost_equal (const A &a, const B &b) {
|
|
||||||
using common_t = std::common_type_t<A,B>;
|
|
||||||
return static_cast<common_t> (a) == static_cast<common_t> (b);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
template <typename Ta, typename Tb>
|
|
||||||
constexpr inline
|
|
||||||
typename std::enable_if<
|
|
||||||
!std::is_arithmetic<Ta>::value ||
|
|
||||||
!std::is_arithmetic<Tb>::value,
|
|
||||||
bool
|
|
||||||
>::type
|
|
||||||
almost_equal (const Ta &a, const Tb &b)
|
|
||||||
{ return a == b; }
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Useful for explictly ignore equality warnings
|
// Useful for explictly ignore equality warnings
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
@ -115,7 +54,7 @@ namespace util {
|
|||||||
std::is_arithmetic<Tb>::value,
|
std::is_arithmetic<Tb>::value,
|
||||||
bool
|
bool
|
||||||
>
|
>
|
||||||
exactly_equal (const Ta &a, const Tb &b)
|
equal (const Ta &a, const Tb &b)
|
||||||
{
|
{
|
||||||
return a == b;
|
return a == b;
|
||||||
}
|
}
|
||||||
@ -128,13 +67,50 @@ namespace util {
|
|||||||
!std::is_arithmetic<Tb>::value,
|
!std::is_arithmetic<Tb>::value,
|
||||||
bool
|
bool
|
||||||
>
|
>
|
||||||
exactly_equal (const Ta &a, const Tb &b)
|
equal (const Ta &a, const Tb &b)
|
||||||
{
|
{
|
||||||
return a == b;
|
return a == b;
|
||||||
}
|
}
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Comparisons
|
||||||
|
inline bool
|
||||||
|
almost_equal (float a, float b)
|
||||||
|
{
|
||||||
|
return ieee_single::almost_equal (a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
inline bool
|
||||||
|
almost_equal (double a, double b)
|
||||||
|
{
|
||||||
|
return ieee_double::almost_equal (a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
template <typename ValueA, typename ValueB>
|
||||||
|
constexpr auto
|
||||||
|
almost_equal (const ValueA &a, const ValueB &b)
|
||||||
|
{
|
||||||
|
if constexpr (std::is_floating_point_v<ValueA> && std::is_floating_point_v<ValueB>) {
|
||||||
|
using common_t = std::common_type_t<ValueA,ValueB>;
|
||||||
|
return almost_equal (common_t {a}, common_t{b});
|
||||||
|
} else if constexpr (std::is_integral_v<ValueA> &&
|
||||||
|
std::is_integral_v<ValueB> &&
|
||||||
|
std::is_signed_v<ValueA> == std::is_signed_v<ValueB>)
|
||||||
|
{
|
||||||
|
using common_t = std::common_type_t<ValueA,ValueB>;
|
||||||
|
return static_cast<common_t> (a) == static_cast<common_t> (b);
|
||||||
|
} else {
|
||||||
|
return equal (a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr
|
constexpr
|
||||||
@ -146,12 +122,16 @@ namespace util {
|
|||||||
return t == 0;
|
return t == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::enable_if_t<
|
std::enable_if_t<
|
||||||
!std::is_integral<T>::value, bool
|
!std::is_integral<T>::value, bool
|
||||||
>
|
>
|
||||||
almost_zero (T a)
|
almost_zero (T a)
|
||||||
{ return almost_equal (a, T{0}); }
|
{
|
||||||
|
return almost_equal (a, T{0});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
@ -162,7 +142,7 @@ namespace util {
|
|||||||
>
|
>
|
||||||
exactly_zero (T t)
|
exactly_zero (T t)
|
||||||
{
|
{
|
||||||
return exactly_equal (t, T{0});
|
return equal (t, T{0});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -173,7 +153,7 @@ namespace util {
|
|||||||
>
|
>
|
||||||
exactly_zero (T t)
|
exactly_zero (T t)
|
||||||
{
|
{
|
||||||
return exactly_equal (t, T{0});
|
return equal (t, T{0});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -337,7 +317,7 @@ namespace util {
|
|||||||
is_integer (T t)
|
is_integer (T t)
|
||||||
{
|
{
|
||||||
T i = 0;
|
T i = 0;
|
||||||
return exactly_equal (std::modf (t, &i), T{0});
|
return equal (std::modf (t, &i), T{0});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ matrix<Rows,Cols,T>::is_affine (void) const
|
|||||||
if (!exactly_zero (values[Rows-1][i]))
|
if (!exactly_zero (values[Rows-1][i]))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return exactly_equal (values[Rows-1][Rows-1], T{1});
|
return equal (values[Rows-1][Rows-1], T{1});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ test_double (util::TAP::logger &tap)
|
|||||||
util::ieee_double val;
|
util::ieee_double val;
|
||||||
val.set_bits (tests[i].bits);
|
val.set_bits (tests[i].bits);
|
||||||
|
|
||||||
success = success && util::exactly_equal (val, tests[i].floating);
|
success = success && util::equal (val, tests[i].floating);
|
||||||
}
|
}
|
||||||
|
|
||||||
tap.expect (success, "double precision bitwise equality");
|
tap.expect (success, "double precision bitwise equality");
|
||||||
@ -74,7 +74,7 @@ test_single (util::TAP::logger &tap)
|
|||||||
util::ieee_single val;
|
util::ieee_single val;
|
||||||
val.set_bits (tests[i].bits);
|
val.set_bits (tests[i].bits);
|
||||||
|
|
||||||
success = success && util::exactly_equal (val, tests[i].floating);
|
success = success && util::equal (val, tests[i].floating);
|
||||||
}
|
}
|
||||||
|
|
||||||
tap.expect (success, "single precision bitwise equality");
|
tap.expect (success, "single precision bitwise equality");
|
||||||
|
@ -46,8 +46,8 @@ int main ()
|
|||||||
foo d_foo { 7, 42.0 };
|
foo d_foo { 7, 42.0 };
|
||||||
auto f_tuple = util::as_tuple (d_foo);
|
auto f_tuple = util::as_tuple (d_foo);
|
||||||
|
|
||||||
tap.expect (util::exactly_equal (d_foo.a, std::get<0> (f_tuple)) &&
|
tap.expect (util::equal (d_foo.a, std::get<0> (f_tuple)) &&
|
||||||
util::exactly_equal (d_foo.b, std::get<1> (f_tuple)),
|
util::equal (d_foo.b, std::get<1> (f_tuple)),
|
||||||
"dynamic member access after conversion to tuple");
|
"dynamic member access after conversion to tuple");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ main (int, char**)
|
|||||||
for (const auto &[i, v, a, c]: util::izip (v_int, a_float, c_char)) {
|
for (const auto &[i, v, a, c]: util::izip (v_int, a_float, c_char)) {
|
||||||
success = success &&
|
success = success &&
|
||||||
v_int[i] == v &&
|
v_int[i] == v &&
|
||||||
util::exactly_equal (a_float[i], a) &&
|
util::equal (a_float[i], a) &&
|
||||||
c_char[i] == c;
|
c_char[i] == c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ main (void)
|
|||||||
tap.expect (!ref["integer"].is_object (), "integer not is_object");
|
tap.expect (!ref["integer"].is_object (), "integer not is_object");
|
||||||
tap.expect (!ref["integer"].is_string (), "integer not is_string");
|
tap.expect (!ref["integer"].is_string (), "integer not is_string");
|
||||||
tap.expect (
|
tap.expect (
|
||||||
util::exactly_equal (
|
util::equal (
|
||||||
(unsigned)ref["integer"].as_number ().as_uint (),
|
(unsigned)ref["integer"].as_number ().as_uint (),
|
||||||
1u
|
1u
|
||||||
),
|
),
|
||||||
@ -101,7 +101,7 @@ main (void)
|
|||||||
tap.expect (!ref["double"].is_object (), "double not is_object");
|
tap.expect (!ref["double"].is_object (), "double not is_object");
|
||||||
tap.expect (!ref["double"].is_string (), "double not is_string");
|
tap.expect (!ref["double"].is_string (), "double not is_string");
|
||||||
tap.expect (
|
tap.expect (
|
||||||
util::exactly_equal (
|
util::equal (
|
||||||
ref["double"].as_number ().as<double> (),
|
ref["double"].as_number ().as<double> (),
|
||||||
3.14
|
3.14
|
||||||
),
|
),
|
||||||
|
@ -69,10 +69,10 @@ main (void)
|
|||||||
const point4f q = p.homog<4> ();
|
const point4f q = p.homog<4> ();
|
||||||
|
|
||||||
tap.expect (
|
tap.expect (
|
||||||
almost_equal (q.x, 3.f) &&
|
equal (q.x, 3.f) &&
|
||||||
almost_equal (q.y, 4.f) &&
|
equal (q.y, 4.f) &&
|
||||||
almost_equal (q.z, 0.f) &&
|
equal (q.z, 0.f) &&
|
||||||
almost_equal (q.w, 1.f),
|
equal (q.w, 1.f),
|
||||||
|
|
||||||
"homogenous redim"
|
"homogenous redim"
|
||||||
);
|
);
|
||||||
|
@ -29,11 +29,9 @@ main (int, char**)
|
|||||||
{ "", "trailing empty" }
|
{ "", "trailing empty" }
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const auto tok: util::tokeniser (csv.c_str (), ','))
|
util::view src { csv.c_str (), csv.size () };
|
||||||
std::cout << '"' << tok << "\"\n";
|
for (const auto &[tok, expected]: util::zip (util::tokeniser (src, ','), TESTS))
|
||||||
|
tap.expect (equal (tok, expected.value), "%s", expected.message);
|
||||||
for (const auto &[tok, expected]: util::zip (util::tokeniser (csv.c_str (), ','), TESTS))
|
|
||||||
tap.expect_eq (tok, expected.value, "%s", expected.message);
|
|
||||||
|
|
||||||
return tap.status ();
|
return tap.status ();
|
||||||
}
|
}
|
19
view.hpp
19
view.hpp
@ -589,7 +589,7 @@ namespace util {
|
|||||||
typename BeginB, typename EndB
|
typename BeginB, typename EndB
|
||||||
>
|
>
|
||||||
constexpr bool
|
constexpr bool
|
||||||
operator== (const view<BeginA,EndA> &a, const view<BeginB,EndB> &b)
|
equal (const view<BeginA,EndA> &a, const view<BeginB,EndB> &b)
|
||||||
{
|
{
|
||||||
return a.size () == b.size () &&
|
return a.size () == b.size () &&
|
||||||
std::equal (std::begin (a), std::end (a), std::begin (b));
|
std::equal (std::begin (a), std::end (a), std::begin (b));
|
||||||
@ -608,9 +608,9 @@ namespace util {
|
|||||||
>
|
>
|
||||||
>
|
>
|
||||||
constexpr bool
|
constexpr bool
|
||||||
operator== (const view<IteratorA,IteratorB> &a, const ValueT &b)
|
equal (const view<IteratorA,IteratorB> &a, const ValueT &b)
|
||||||
{
|
{
|
||||||
return a == make_view (b);
|
return equal (a, make_view (b));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -628,15 +628,24 @@ namespace util {
|
|||||||
>
|
>
|
||||||
>
|
>
|
||||||
constexpr bool
|
constexpr bool
|
||||||
operator== (const ValueT &a, const view<IteratorA,IteratorB> &b)
|
equal (const ValueT &a, const view<IteratorA,IteratorB> &b)
|
||||||
{
|
{
|
||||||
return b == a;
|
return equal (b, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
template <typename IteratorA, typename IteratorB>
|
template <typename IteratorA, typename IteratorB>
|
||||||
constexpr bool
|
constexpr bool
|
||||||
|
operator== (const view<IteratorA,IteratorB> &a, const view<IteratorA,IteratorB> &b)
|
||||||
|
{
|
||||||
|
return a.begin () == b.begin () && a.end () == b.end ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
template <typename IteratorA, typename IteratorB>
|
||||||
|
constexpr bool
|
||||||
operator!= (const view<IteratorA,IteratorB> &a, const view<IteratorA,IteratorB> &b)
|
operator!= (const view<IteratorA,IteratorB> &a, const view<IteratorA,IteratorB> &b)
|
||||||
{
|
{
|
||||||
return !(a == b);
|
return !(a == b);
|
||||||
|
Loading…
Reference in New Issue
Block a user