依赖任何数字类型(unsigned,int,...)的隐式提升来加倍是否安全?

时间:2016-02-04 11:55:14

标签: c++ double unsigned-integer

我有一个图表的模板类,它采用权重类型的参数(可以是unsigned,int或double)。另外,为了比较双打,我使用以下类型的内联函数:

inline bool EpsLess(double x, double y, double epsilon = 1.e-10)
{
    return x < y - epsilon;
}
inline bool EpsEqual(double x, double y, double epsilon = 1.e-10)
{
    return !EpsLess(x,y) && !EpsLess(y,x);
}

以下类骨架中的比较器是否安全?

template <typename Weight>
class Graph
{
    struct Edge
    {
        std::string from;
        std::string to;
        Weight      weight;
    };

    struct LargestWeight
    {
        bool operator() (const Edge& e1, const Edge& e2) const
        {
            if (EpsEqual(e1.weight == e2.weight))
                if (e1.from == e2.from)
                    return e1.to < e2.to;
                else
                    return e1.from < e2.from;
            return EpsLess(e2.weight, e1.weight);
        }
    };

    // .. other stuff
};

当Weight类型为unsigned或int时,是否会遇到无法预料的后果?或者有更好的方法来实现双重比较吗?

2 个答案:

答案 0 :(得分:3)

这正是模板的用途。

我建议您在仅使用EpsLess<运算符的模板类中实现==()。类似的东西:

template<typename Type> Compare {

public:

    template<typename Ignore>
    inline bool EpsLess(Type x, Type y, Ignore epsilon = Ignore())
    {
        return x < y;
    }
};

然后将它专门化为双倍:

template<> Compare<double> {

public:
    inline bool EpsLess(double x, double y, double epsilon = 1.e-10)
    {
        return x < y - epsilon;
    }
};

您可以这样调用它:

if (Compare<Weight>::EpsEqual(e1.weight, e2.weight))

这将避免对非双重案例进行大量无用工作,并将其转移到普通的<运算符。

然后,您的家庭作业将根据新EpsEqual()重新实现EpsLess()作为模板函数本身。

答案 1 :(得分:0)

不,在所有情况下都不能信任整数转换为双倍。

在不损失精度的情况下,无法始终将整数转换为double。相反,如果Weight是一个可以容纳大值的整数类型,例如,你可能会遇到问题。一个size_t

所有32位整数都可以毫无问题地转换(即精度损失)。