是否有必要在模板化函数中转换文字常量?

时间:2018-03-30 09:15:39

标签: c++ templates

我正在编写一个必须以单精度和双精度编译的代码。原始版本只有双精度,但我现在尝试使用模板启用单精度。

我的问题是:是否有必要将1.7.8转换为具有static_cast<TF>(1.)的指定类型,或者编译器会处理它吗?我发现铸件不是很漂亮,而是喜欢远离它。 (我有更长的其他函数,包含更多的文字常量)。

template<typename TF>
inline TF phih_stable(const TF zeta)
{
    // Hogstrom, 1988
    return 1. + 7.8*zeta;
}

2 个答案:

答案 0 :(得分:3)

转换和隐式转换是两件事。对于此示例,您可以将模板函数视为两个重载函数,但其​​中包含相同的代码。在接口级别(参数,返回值),编译器将生成隐式转换。

现在,您必须问自己的问题是:那些隐含的转换是否符合我的要求?如果他们这样做,只需保持原样。如果他们不这样做,您可以尝试添加显式转换(可能使用像TF(1.)这样的函数式转换),或者您可以将此函数专门用于doublefloat

另一个选项,不太通用但可能在这里工作,是你切换代码,即你编写单精度float的代码,然后让编译器应用其隐式转换。由于转化通常只会转到更大的类型,因此它应该适用于doublefloat,而不会产生float的任何开销。

答案 1 :(得分:1)

当你这样做时:

return 1. + 7.8*zeta;

文字1.7.8double,因此当zetafloat时,它首先会转换为double ,然后整个计算将以双精度完成,结果将被转换回float,这相当于:

return (float)(1. + 7.8 * (double)zeta);

否则说,这相当于调用phih_stable(double)并将结果存储在float中,因此您的模板对float无用。

如果您希望以单精度进行计算,则需要强制转换 1

return TF(1.) + TF(7.8) * zeta;

使用1.f7.8f怎么样?由于浮点精度,问题是(double)7.8f != 7.8。差异在1e-7左右,7.8f的实际存储值(假设32位float)是:

7.80000019073486328125

7.8的实际存储值(假设为64位double)为:

7.79999999999999982236431605997

所以你必须问自己是否接受这种精确度的损失。

您可以比较以下两个实现:

template <class T>
constexpr T phih_stable_cast(T t) {
    return T(1l) + T(7.8l) * t;
}

template <class T>
constexpr T phih_stable_float(T t) {
    return 1.f + 7.8f * t;
}

以下断言:

static_assert(phih_stable_cast(3.4f) == 1. + 7.8f * 3.4f, "");
static_assert(phih_stable_cast(3.4) == 1. + 7.8 * 3.4, "");
static_assert(phih_stable_cast(3.4l) == 1. + 7.8l * 3.4l, "");
static_assert(phih_stable_float(3.4f) == 1.f + 7.8f * 3.4f, "");
static_assert(phih_stable_float(3.4) == 1. + 7.8 * 3.4, "");
static_assert(phih_stable_float(3.4l) == 1.l + 7.8l * 3.4l, "");

由于在进行计算时精度损失,最后两个断言失败。

1 在使用long double long double的函数时,您甚至应该从return TF(1.l) + TF(7.8l) * zeta;向下转换为不失精度。 < / p>