使用整数模板参数创建编译时双精度
Use integer template argument to create compiletime double
是否可以创建一个保存值为 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::p ow 不起作用)。此外,如果可能的话,我希望能够避免实际的迭代计算((可能是毫无根据的)对精度问题的恐惧)。我还希望能够使用较大的值作为指数,例如 200,这使得无法将值存储在标准整数类型中。
假设您的编译器支持 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);
};
请参阅此处以验证它是否有效,并且即使没有优化,该值也会在编译时生成。
根据您的用例,您甚至可能不需要 DoubleValue
结构,但可以直接使用 myPow()
。
更新
正如@Bob__在评论中指出的那样,关于数值精度的算法可能比这里介绍的算法更好。但自C++14以来,许多基本的语言功能都可以在constexpr
函数的主体中使用。因此,只要您不需要任何外部库,您就可以自由实现适合您需求的任何算法。
如果你想要它在编译时没有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
}
C++小提琴
由于您需要在编译时可用的值,因此几乎解决它的唯一方法,我想到的是递归模板。但是,事实上,您需要根据传递值的符号来执行所述模板的不同操作,这使事情变得复杂。首先想到的是编写这样一个递归模板:
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;
};
但是,这样的解决方案不起作用,因为三元表达式的两个分支都需要解析,并且总是会导致无限递归,因为其中一个分支不会倾向于 0。然后,SFINAE浮现在脑海中:
// 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;
};
现场演示。
相关文章:
- 此代码编译良好,但文件未创建?请指出错误
- 使用带有 ref 参数的成员函数创建线程时出现编译错误
- 在VS Code中编译C / C ++时如何禁用自动创建EXE文件?
- 从编译时已知的日历日期创建"std::chrono::time_point"
- 编译时生成应在构造函数中创建的非 constexpr 对象数组
- 在编译时从 c++ 文件创建枚举
- 在编译时而不是运行时创建一个由两个字节组成的值
- 我可以在不创建项目的情况下在Visual Studio 2019中编译和运行HelloWorld.cpp吗?
- 如何在C++中创建自己的编译密钥
- 从"<Base>std::unique_ptr"创建"ClassType<std::unique_ptr>"时出现编译错误<Derived>
- 使用成员函数创建std::函数不会编译
- 有没有办法在 C++17 中创建编译时类型映射以进行类型检查?
- C++ - 我可以创建编译时变量对象吗?
- 如何为多个C++类型创建编译时检查
- 为什么和如何C++允许使用动态值创建编译时数组
- 使用整数模板参数创建编译时双精度
- 如何使用模板使用fibonacci编号创建编译时的模板/数组/矢量
- 使用 SFINAE 但不创建编译错误
- 使用可变参数模板创建编译时布尔表达式
- Visual Studio 2010创建编译代码的应用程序