我正在尝试sine
使用泰勒系列扩展构建一个简单的函数,可以在编译时使用C++ 14进行评估constexpr
.我的代码正在编译,但编译器不会生成常量.
sine
定义如下:
templateconstexpr T sine(T x) { T result = x; for (int i = 1; i < P; ++i) result += power (-1, i) * power (x, 1 + 2 * i) / factorial (1 + 2 * i); return result; }
我可以提供代码power
,factorial
如果需要的话.它们是微不足道的constexpr
.
我sine
在这样的循环中调用:
templatevoid test(double *out) { for (int i = 0; i < N; ++i) { out[i] = sine<20, double>(i * M_PI / N); } }
我期待编译器可以生成一组结果sine
并将其放入,out
而不需要实际计算泰勒系列.相反,生成的代码sine
就像执行任何其他非constexpr
函数一样执行.
我的编译器是从Xcode 7.2编译而来的-O3
.
我期待编译器可以为正弦生成一组结果并将它们放入,而不需要实际计算泰勒系列.相反,生成的代码执行正弦,就像它是任何其他非constexpr函数一样.
要constexpr
在编译时评估函数,必须满足以下条件:
它的所有输入参数都必须是常量表达式.
其结果必须用于常量表达式.
test
'for循环中的赋值不是常量表达式.因此,sine
无法在编译时进行评估.
你真正想要的是使用静态初始化数组的元素sine()
.使用一个std::array
和一些辅助机械可以这样做,如下所示:
#define r 0.01745329251 constexpr double factorial(int n) { double res = 1.0; for(int i(2); i <= n; ++i) res *= i; return res; } templateconstexpr T power(T &&base, int const n) { if(!n) return 0.0; T res = base; for(int i(1); i < n; ++i) res *= base; return res; } template constexpr T sine(T &&x) { T res = x * r; for (int i(3), sgn(-1); i <= N; i += 2, sgn = -sgn) { res += power(x * r, i) / factorial(i); } return res; } template constexpr std::array sine_array_impl(std::index_sequence ) { return {{sine(T{Is})...}}; } template constexpr std::array sine_array() { return sine_array_impl (std::make_index_sequence {}); }
现场演示