c++ - Best way to avoid code duplication defining comparison operators `<, <=, >, >=, ==, !=`, but taking into account NaNs? -


i mathematics, x <= y equivalent !(x > y). true floating-point arithmetic, in cases, not always. when x or y nan, x <= y not equivalent !(x > y), because comparing nan returns false. still, x <= y <=> !(x > y) true of time.

now, suppose writing class contains floating-point values, , want define comparison operators class. definiteness, suppose writing high-precision floating-point number, uses 1 or more double values internally store high-precision number. mathematically, definition of x < y class defines other operators (if being consistent usual semantics of comparison operators). nans break mathematical nicety. maybe forced write many of these operators separately, take account nans. there better way? question is: how can avoid code duplication as possible , still respect behavior of nan?

related: http://www.boost.org/doc/libs/1_59_0/libs/utility/operators.htm. how boost/operators resolve issue?

note: tagged question c++ because that's understand. please write examples in language.

personally use similar technique in this answer defines comparison function based on operator<() yielding strict weak order. types null value meant have comparisons yield false operations defined in terms of operator<() providing strict weak order on non-null value , is_null() test.

for example, code this:

namespace nullable_relational {     struct tag {};      template <typename t>     bool non_null(t const& lhs, t const& rhs) {         return !is_null(lhs) && !is_null(rhs);     }      template <typename t>     bool operator== (t const& lhs, t const& rhs) {         return non_null(lhs, rhs) && !(rhs < lhs) && !(lhs < rhs);     }     template <typename t>     bool operator!= (t const& lhs, t const& rhs) {         return non_null(lhs, rhs) || !(lhs == rhs);     }      template <typename t>     bool operator> (t const& lhs, t const& rhs) {         return non_null(lhs, rhs) && rhs < lhs;     }     template <typename t>     bool operator<= (t const& lhs, t const& rhs) {         return non_null(lhs, rhs) && !(rhs < lhs);     }     template <typename t>     bool operator>= (t const& lhs, t const& rhs) {         return non_null(lhs, rhs) && !(lhs < rhs);     } } 

it use this:

#include <cmath> class foo     : private nullable_relational::tag {     double value; public:     foo(double value): value(value) {}     bool is_null() const { return std::isnan(this->value); }     bool operator< (foo const& other) const { return this->value < other.value; } }; bool is_null(foo const& value) { return value.is_null(); } 

a variation of same theme implementation in terms of 1 compare function parameterized comparison function , responsible appropriately feed comparison function parameters. example:

namespace compare_relational {     struct tag {};      template <typename t>     bool operator== (t const& lhs, t const& rhs) {         return compare(lhs, rhs, [](auto&& lhs, auto&& rhs){ return lhs == rhs; });     }     template <typename t>     bool operator!= (t const& lhs, t const& rhs) {         return compare(lhs, rhs, [](auto&& lhs, auto&& rhs){ return lhs != rhs; });     }      template <typename t>     bool operator< (t const& lhs, t const& rhs) {         return compare(lhs, rhs, [](auto&& lhs, auto&& rhs){ return lhs < rhs; });     }     template <typename t>     bool operator> (t const& lhs, t const& rhs) {         return compare(lhs, rhs, [](auto&& lhs, auto&& rhs){ return lhs > rhs; });     }     template <typename t>     bool operator<= (t const& lhs, t const& rhs) {         return compare(lhs, rhs, [](auto&& lhs, auto&& rhs){ return lhs <= rhs; });     }     template <typename t>     bool operator>= (t const& lhs, t const& rhs) {         return compare(lhs, rhs, [](auto&& lhs, auto&& rhs){ return lhs >= rhs; });     } }  class foo     : private compare_relational::tag {     double value; public:     foo(double value): value(value) {}      template <typename compare>     friend bool compare(foo const& f0, foo const& f1, compare&& predicate) {         return predicate(f0.value, f1.value);     } }; 

i imagine having multiple of these operation-generating namespaces support suitable choice common situations. option different ordering floating points and, e.g., consider null value smallest or largest value. since people use nan-boxing may reasonable provide order on different nan values , arrange nan values @ suitable places. example, using underlying bit representation provide total order of floating point values may suitable using objects key in ordered container although order might different order created operator<().


Comments

Popular posts from this blog

dns - How To Use Custom Nameserver On Free Cloudflare? -

python - Pygame screen.blit not working -

c# - Web API response xml language -