是否可以创建一个保存1 * 10 ^ x值的双精度数,其中x基于整数模板参数。像这样:
template < int exp >
struct DoubleValue
{
static constexpr double value = ????;
}
double d = DoubleValue<20>::value; // = 1e20
double d = DoubleValue<-20>::value; // = 1e-20
由于可以用垃圾创建它,因此似乎应该可以实现。
我希望在编译时评估该值(据我所知,std :: pow无法正常工作)。 另外,如果可能的话,我希望能够避免实际的迭代计算((可能没有根据)担心精度问题)。我还希望能够使用较大的值作为指数,例如200,这样就不可能将其存储为标准整数类型。
答案 0 :(得分:6)
假设您的编译器支持C ++ 14或更高版本(这应该在2019年是一个有效的假设),使用constexpr
函数非常简单:
constexpr double myPow(double x, int exp)
{
double pow = 1.0;
for (int i = 0; i < exp; ++i)
pow *= x;
for (int i = 0; i > exp; --i)
pow /= x;
return pow;
}
template < int exp >
struct DoubleValue
{
static constexpr double value = myPow(10.0, exp);
};
请参见here以验证其是否有效,并且即使不进行优化也可以在编译时生成该值。
根据您的用例,您甚至可能不需要DoubleValue
结构,但可以直接使用myPow()
。
正如@Bob__在评论中指出的那样,关于数值精度的算法可能比这里介绍的算法更好。但是由于C ++ 14 many basic language features可以在constexpr
函数的主体中使用。因此,只要您不需要任何外部库,您就可以自由实现适合您需要的任何算法。
答案 1 :(得分:1)
如果您希望在编译时不使用std::pow
,可以这样做:
#include <iostream>
template <int e>
struct DoubleValue {
static constexpr double value = 10.0 * DoubleValue<e - 1>::value;
};
template <>
struct DoubleValue<0> {
static constexpr double value = 1.0;
};
int main() {
std::cout << DoubleValue<20>::value << '\n'; //1e+20
}
答案 2 :(得分:1)
由于您需要在编译时就可以使用该值,因此解决该问题的唯一方法就是我想到的是递归模板。但是,事实上,您需要所述模板根据传递的值的签名来做不同的事情,这使事情变得复杂。首先想到的是编写这样的递归模板:
template <int exp>
struct DoubleValue
{
static constexpr double value = (exp < 0
? DoubleValue<exp+1>::value / 10
: 10 * DoubleValue<exp-1>::value);
};
// Default case
template <>
struct DoubleValue<0>
{
static constexpr double value = 1;
};
但是,由于以下事实,这样的解决方案将不起作用:三元表达式的两个分支都需要解析,并且这将始终导致无限递归,因为其中一个分支不会t趋于0。然后,FINA浮现在脑海:
// Base case.
template <int exp, class Enable = void>
struct DoubleValue
{
};
// Case when exp is positive
template <int exp>
struct DoubleValue<exp, typename std::enable_if<(exp > 0)>::type>
{
static constexpr double value = 10 * DoubleValue<exp-1>::value;
};
// Case when exp is negative
template <int exp>
struct DoubleValue<exp, typename std::enable_if<(exp < 0)>::type>
{
static constexpr double value = DoubleValue<exp+1>::value / 10;
};
// Default case.
template <>
struct DoubleValue<0>
{
static constexpr double value = 1;
};