依靠任何数字类型(无符号、整数等)的隐式提升来加倍是否安全

Is it safe to rely on implicit promotion from any numeric type (unsigned, int, ...) to double?

本文关键字:安全 是否 类型 数字 任何 无符号 整数 依靠      更新时间:2023-10-16

我有一个用于图形的模板类,它采用权重类型的参数(可以是无符号的、整数的或双精度的)。此外,为了比较双精度,我使用以下类型的内联函数:

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
};

当权重类型为无符号或 int 时,我会遇到不可预见的后果吗?还是有更好的方法来实现双重比较?

这正是模板的用途。

我建议您在仅使用 <== 运算符的模板类中实现 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))

这将避免一堆无用的工作,用于非双重情况,并被移交给一个普通的<操作员。

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

不,您不能在所有情况下都信任整数的双重转换。

从整数到双精度的转换并不总是在不损失精度的情况下完成。因此,如果权重是可以保存大值的整数类型,例如size_t

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