首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >避免代码重复的最佳方法是定义比较操作符`<,<=,>,>=,==,!=,但要考虑到NaNs?

避免代码重复的最佳方法是定义比较操作符`<,<=,>,>=,==,!=,但要考虑到NaNs?
EN

Stack Overflow用户
提问于 2015-08-16 20:39:59
回答 2查看 200关注 0票数 8

I数学,x <= y等价于!(x > y)。在大多数情况下,浮点算法是这样的,但并不总是如此。当xy是NaN时,x <= y而不是!(x > y),因为将NaN与任何事物进行比较总是返回false。但是,x <= y <=> !(x > y)在大多数情况下都是真实的。

现在,假设我正在编写一个包含浮点值的类,并且我想为这个类定义比较运算符。对于确定性,假设我正在编写一个高精度浮点数,它在内部使用一个或多个double值来存储高精度数字。从数学上讲,该类的x < y定义已经定义了所有其他运算符(如果我与比较运算符的通常语义一致的话)。但是NaN破坏了这个数学的精确性。所以,也许我不得不把这些运算符中的许多分别写出来,只是为了考虑到NaNs。但还有更好的方法吗?我的问题是:如何尽可能避免代码重复,同时仍然尊重NaN__的行为?

相关:0/libs/utility/operators.htm.boost/operators如何解决这个问题?

注:我标记这个问题c++,因为这是我所理解的。请用那种语言写例子。

EN

回答 2

Stack Overflow用户

发布于 2015-08-16 23:25:47

就我个人而言,我将使用类似于this answer的技术,它定义了基于operator<()的比较函数,产生了严格的弱阶。对于具有空值的类型(这意味着要进行比较),总是会产生false,操作将定义为operator<(),对所有非空值提供严格的弱顺序,并进行is_null()测试。

例如,代码可以如下所示:

代码语言:javascript
复制
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);
    }
}

它的用途如下:

代码语言:javascript
复制
#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(); }

同一主题的变化可以是一个比较函数的实现,该比较函数被比较函数参数化,并负责适当地向比较函数提供参数。例如:

代码语言:javascript
复制
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<()创建的顺序不同,但它可能适合于将对象用作有序容器中的键。

票数 1
EN

Stack Overflow用户

发布于 2015-08-16 21:44:36

定义operator<时,需要处理NaN案例。出于排序和比较的目的,如果您将NaN视为小于任何非NaN,则可以这样做:

代码语言:javascript
复制
bool operator<(double l, double r) {
    if (isnan(l)) {
        if (isnan(r)) return false; // NaN == NaN
        return true;        // NaN < rational
    }
    return l < r;       // if r is NaN will return false, which is how we've defined it
}

其他操作符是用operator<定义的,不需要手动编写代码。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32039711

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档