Man*_*726 2 c++ floating-point templates template-meta-programming c++11
我正在通过模板元编程来编写浮点运算的编译时实现.我的实现具有以下特征:
类型如下:
template<bool S , std::int16_t E , std::uint32_t M>
struct number
{
static constexpr const bool sign = S;
static constexpr const std::int16_t exponent = E;
static constexpr const std::uint32_t mantissa = M;
};
Run Code Online (Sandbox Code Playgroud)
这些操作运行良好,但现在我需要一种方法在编译时提取这些值并获取相应的double值.由于编译时算术的目标是加速直接在可执行文件上注入解决方案的计算,我需要一种在编译时有效初始化double常量的方法.不允许
涉及如此简单的解决方案std::pow( 2.0 , E ).
到目前为止,我知道双精度IEE754浮点数具有10位有符号指数和53位宽无符号整数尾数.我尝试的解决方案是通过联合使用类型惩罚:
template<bool S , std::int16_t E , std::uint32_t M>
struct to_runtime<tml::floating::number<S,E,M>>
{
static constexpr const long unsigned int mantissa = M << (53 - 32);
static constexpr const int exponent = E + (53 - 32);
struct double_parts
{
unsigned int sign : 1;
int exponent : 10;
long unsigned int mantissa : 53;
};
union double_rep
{
double d;
double_parts parts;
};
static constexpr const double_parts parts = { .sign = ((bool)S) ? 0 : 1 , .exponent = exponent , .mantissa = mantissa };
static constexpr const double_rep rep = { .parts = parts };
static constexpr double execute()
{
return rep.d;
}
};
Run Code Online (Sandbox Code Playgroud)
但是这个解决方案不可移植,调用未定义的行为(因为在做类型双关语时我们读取了未写入的union的成员),并且在实现转换时我也遇到了一些问题(此解决方案没有返回正确的数字).
double在给定我的数据(符号,指数,尾数)的情况下,还有其他方法可以在编译时初始化吗?
你可以实现一个constexpr pow2(std::int16_t)类似于:
constexpr double pow2(std::int16_t e)
{
return e == 0 ? 1. :
e > 0 ? 2. * pow2(std::int16_t(e - 1)) :
0.5 * pow2(std::int16_t(e + 1));
}
Run Code Online (Sandbox Code Playgroud)
要么
constexpr double pow2(std::int16_t e)
{
return e == 0 ? 1. :
((e & 1) ? (e > 0 ? 2. : 0.5) : 1.)
* pow2(std::int16_t(e / 2))
* pow2(std::int16_t(e / 2));
}
Run Code Online (Sandbox Code Playgroud)
然后
template<bool S , std::int16_t E , std::uint32_t M>
struct number
{
static constexpr const double value = (sign ? -1. : 1.) * M * pow2(E);
};
Run Code Online (Sandbox Code Playgroud)