泰勒级数展开为constexpr [英] Taylor series expansion as constexpr

查看:109
本文介绍了泰勒级数展开为constexpr的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用taylor系列扩展构建一个简单的sine函数,可以在编译时使用C ++ 14 constexpr对其进行评估.我的代码正在编译,但是编译器不会生成常量.

I'm trying to build a simple sine function using taylor series expansion that can be evaluated at compile time using C++14 constexpr. My code is compiling, but the compiler doesn't generate a constant.

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;
}

如果需要,我可以提供powerfactorial的代码.它们很简单,而且constexpr.

I can provide code for power and factorial if needed. They are trivial and also constexpr.

我正在这样的循环中调用sine:

I'm calling sine from within a loop like this:

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中,而无需实际计算taylor系列.而是将生成的代码执行sine,就像执行其他任何非constexpr函数一样.

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.

我的编译器是Xcode 7.2中使用-O3进行编译的叮当声.

My compiler is clang from Xcode 7.2 compiling with -O3.

推荐答案

我期望编译器可以为 正弦并把它们放进去,而无需实际计算 泰勒系列.而是生成的代码执行正弦,就好像它是 任何其他非constexpr函数.

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函数,必须遵循以下条件:

For a constexpr function to be evaluated at compile time the following must apply:

  • 其所有输入参数必须为常量表达式.
  • 其结果必须在常量表达式中使用.

test的for循环中的分配不是常量表达式.因此,sine无法在编译时求值.

The assignment in the test's for loop is not a constant expression. Consequently, sine cannot be evaluated at compile time.

您真正想要的是使用sine()静态初始化数组的元素.使用std::array和一些帮助程序可以做到这一点,如下所示:

What you really want, is to statically initialize the elements of an array using sine(). Using a std::array and some helper machinery this is possible to do it as shown below:

#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>{});
}

实时演示

这篇关于泰勒级数展开为constexpr的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆