泰勒级数展开为 constexpr
Taylor series expansion as constexpr
我正在尝试使用泰勒级数展开构建一个简单的 sine
函数,该函数可以在编译时使用 C++14 constexpr
进行计算。我的代码正在编译,但编译器没有生成常量。
sine
定义如下:
template <int P, typename T = double> constexpr T sine(T x) {
T result = x;
for (int i = 1; i < P; ++i)
result += power<T>(-1, i) * power<T>(x, 1 + 2 * i) / factorial<T>(1 + 2 * i);
return result;
}
如果需要,我可以提供 power
和 factorial
的代码。它们是微不足道的,也是 constexpr
.
我在这样的循环中调用 sine
:
template <int N> void 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 的 clang,使用 -O3
.
编译
I was expecting that the compiler can generate a set of results for
sine and put them into out without actually needing to compute the
taylor series. Instead the generated code executes sine as if it was
any other non-constexpr function.
对于要在编译时计算的 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;
}
template<typename T>
constexpr 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 <typename T, int N = 5>
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 <class T, std::size_t N, std::size_t... Is>
constexpr std::array<T, N> sine_array_impl(std::index_sequence<Is...>) {
return {{sine(T{Is})...}};
}
template <class T, std::size_t N>
constexpr std::array<T, N> sine_array() {
return sine_array_impl<T, N>(std::make_index_sequence<N>{});
}
我正在尝试使用泰勒级数展开构建一个简单的 sine
函数,该函数可以在编译时使用 C++14 constexpr
进行计算。我的代码正在编译,但编译器没有生成常量。
sine
定义如下:
template <int P, typename T = double> constexpr T sine(T x) {
T result = x;
for (int i = 1; i < P; ++i)
result += power<T>(-1, i) * power<T>(x, 1 + 2 * i) / factorial<T>(1 + 2 * i);
return result;
}
如果需要,我可以提供 power
和 factorial
的代码。它们是微不足道的,也是 constexpr
.
我在这样的循环中调用 sine
:
template <int N> void 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 的 clang,使用 -O3
.
I was expecting that the compiler can generate a set of results for sine and put them into out without actually needing to compute the taylor series. Instead the generated code executes sine as if it was any other non-constexpr function.
对于要在编译时计算的 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;
}
template<typename T>
constexpr 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 <typename T, int N = 5>
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 <class T, std::size_t N, std::size_t... Is>
constexpr std::array<T, N> sine_array_impl(std::index_sequence<Is...>) {
return {{sine(T{Is})...}};
}
template <class T, std::size_t N>
constexpr std::array<T, N> sine_array() {
return sine_array_impl<T, N>(std::make_index_sequence<N>{});
}