本文介绍了避免代码重复定义比较运算符“&lt;,<=,&gt;,> =,==,!=`,但考虑NaNs的最佳方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 I数学, x 等价于!(x> y)。在大多数情况下,这是真实的浮点运算,但不总是。当 x 或 y 是NaN, x NaN ,因为不等价于!(x> y) false 。但仍然, x I mathematics, x <= y is equivalent to !(x > y). This is true for floating-point arithmetic, in most cases, but not always. When x or y is NaN, x <= y is not equivalent to !(x > y), because comparing a NaN to anything always returns false. But still, x <= y <=> !(x > y) is true most of the time.现在,假设我正在写一个包含浮点值的类,我想为这个类定义比较运算符。为了确定性,假设我正在写一个高精度浮点数,它在内部使用一个或多个 double 值来存储高精度数。数学上, x 已经定义了所有其他运算符(如果我与比较运算符的通常语义一致)。但 NaN 打破这个数学nicety。所以也许我被迫分开编写这些操作符,只是考虑到NaNs。但有没有更好的方法?我的问题是:如何尽可能避免代码重复,仍然要尊重 NaN ? Now, suppose I am writing a class that contains floating-point values, and I want to define comparison operators for this class. For definiteness, suppose I am writing a high-precision floating-point number, which uses one or more double values internally to store the high-precision number. Mathematically, the definition of x < y for this class already defines all the other operators (if I am being consistent with the usual semantics of the comparison operators). But NaNs break this mathematical nicety. So maybe I am forced to write many of these operators separately, just to take into account NaNs. But is there a better way? My question is: How can I avoid code duplication as much as possible and still respect the behavior of NaN?相关: http://www.boost.org/doc /libs/1_59_0/libs/utility/operators.htm 。如何升级/运营商解决这个问题?Related: http://www.boost.org/doc/libs/1_59_0/libs/utility/operators.htm. How does boost/operators resolve this issue?注意:我标记这个问题 c ++ ,因为这是我的理解。 Note: I tagged this question c++ because that's what I understand. Please write examples in that language.推荐答案我个人会使用类似此回答定义了基于运算符<()的比较函数,产生严格的弱顺序。对于具有空值的类型,意味着比较总是产生 false ,操作将以 operator 在所有非空值和 is_null()测试提供严格的弱顺序。Personally I would use a similar technique as in this answer which defines comparison function based on operator<() yielding a strict weak order. For types with a null value which is meant to have comparisons always yield false the operations would be defined in terms of operator<() providing a strict weak order on all non-null value and an is_null() test.例如,代码可能如下所示:For example, the code could look like 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 would be use like 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 the same theme could be an implementation in terms of one compare function which is parameterized by the comparison function and which is responsible to appropriately feed the comparison function with parameters. For 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); }}; 我可以想象有多个这些操作生成的命名空间来支持常见情况的合适选择。另一选项可以是与浮点不同的排序,并且例如,考虑空值最小或最大值。由于一些人使用NaN拳击,甚至可能合理地提供关于不同NaN值的命令并且在合适的位置处安排NaN值。例如,使用底层位表示提供了浮点值的总顺序,其可能适合于在有序容器中将对象用作键,尽管顺序可能不同于由 operator 。 这篇关于避免代码重复定义比较运算符“&lt;,<=,&gt;,> =,==,!=`,但考虑NaNs的最佳方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
10-16 07:28