4

我正在尝试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 编译的-O3.

4

1 回答 1

7

我期待编译器可以生成一组正弦结果并将它们放入而不需要实际计算泰勒级数。相反,生成的代码执行正弦函数,就好像它是任何其他非 constexpr 函数一样。

对于constexpr要在编译时评估的函数,必须应用以下内容:

  • 它的所有输入参数都必须是常量表达式。
  • 其结果必须在常量表达式中使用。

的 for 循环中的赋值test不是常量表达式。因此,sine无法在编译时进行评估。

您真正想要的是使用sine(). 使用 astd::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>{});
}

现场演示

于 2015-12-11T16:46:21.417 回答