如何在模板中定义浮点常量。在运行时避免使用强制转换

时间:2015-02-07 17:11:47

标签: c++ c++11 numerical-methods numerical

假设我有一个简单的函数可以执行以下操作:

template<typename T>
T get_half(T a){
    return 0.5*a;
}

通常会在T为double或float的情况下评估此函数。 该标准规定0.5将是double(浮点数为0.5f)。 如何编写上面的代码,以便0.5将始终为T类型,以便在评估产品或返回时没有强制转换? 我想要的是0.5在编译时是T类型的常量。这个问题的关键是我想在运行时避免转换。

例如,如果我写:

template<typename T>
T get_half(T a){
    return T(0.5)*a;
}

我能完全确定在编译时评估T(0.5)吗? 如果没有,那么实现这一目标的正确方法是什么?如果需要,我可以使用c ++ 11。

提前谢谢。

在c ++ 11中,我有一个numeric_traits类,如下所示(在头文件中)

template<typename Scalar>
struct numeric_traits{
    static constexpr Scalar one_half = 0.5;
    //Many other useful constants ....
};

所以在我的代码中我会用它作为:

template<typename T>
T get_half(T a){
    return numeric_traits<T>::one_half*a;
}

这就是我想要的,即0.5在编译时以我需要的精度解析,并且在运行时不会发生强制转换。但缺点是:

  • 每次我需要一个新的常量
  • 时,我需要修改numeric_traits
  • sintax可能过于烦人了? (当然,这不是一个大问题)
  • 可能有类似的东西:常量(0.5)在运行时解析为T类型。

再次感谢您。

1 个答案:

答案 0 :(得分:2)

没有任何方法可以强制常量永远不会在运行时计算,因为有些机器根本没有一条指令可以加载一个类型的所有可能值。例如,机器可能只有一个16位加载常量指令,其中0x12345678需要在运行时计算为0x1234 << 16 | 0x5678。或者,可以从内存中加载这样的常量,但这可能比计算它的成本更高。

您需要相信您的编译器。在可行的系统上,任何具有任何优化量的编译器都将翻译T(0.5),其转换方式与0.5f相同,假设Tfloat。并且0.5f将以最合理的方式为您的平台计算。这可能涉及将其作为常量加载,或者可能涉及计算它。或者谁知道,如果结果相同,您的编译器可能会将T(0.5)*a更改为a/2

在您的问题中,您举一个添加numeric_traits助手类的示例。这个,IMO,有点矫枉过正。在constexpr产生影响的极不可能的情况下,你可以写

template <typename T>
T get_half(T a) {
    constexpr T half = 0.5;
    return half * a;
}

然而,在我看来,这仍然弊大于利:您的get_half现在不再可以用于非文字类型。 需要类型以支持常量表达式中double的转换。假设您有一个任意精度的rational类型,在没有constexpr的情况下编写。现在,您的get_half无法使用,因为初始化constexpr T half = 0.5;无效,即使0.5 * a可能已编译。

即使你的numeric_traits助手类也是如此;它只是因为我把它移到了函数体中而没有效。