Taylor series expansion as constexpr

I am trying to create a simple sine function using the taylor series extension, which can be evaluated at compile time using C ++ 14 constexpr . My code compiles, but the compiler does not generate a constant.

sine defined as follows:

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

I can provide code for power and factorial if necessary. They are trivial as well as constexpr .

I call sine from the loop:

 template <int N> void test(double *out) { for (int i = 0; i < N; ++i) { out[i] = sine<20, double>(i * M_PI / N); } } 

I expected that the compiler could generate a result set for sine and put them in out , without requiring to compute the Taylor series. Instead, the generated code executes sine , as if it were any other function not constexpr .

My compiler works with the Xcode 7.2 compiler using -O3 .

+5
source share
1 answer

I expected that the compiler could generate a set of results for the sine and output them without having to calculate Taylor. Instead, the generated code executes a sine, as if it were any other function other than constexpr.

For the constexpr function, which must be evaluated at compile time, the following should apply:

  • All its input arguments must be constant expressions.
  • Its result should be used in constant expression.

Assignment in a test for loop is not a constant expression. Therefore, sine cannot be evaluated at compile time.

What you really need is to statically initialize the elements of the array with sine() . Using std::array and some helper mechanisms, this can be done 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>{}); } 

Live demo

+6
source

Source: https://habr.com/ru/post/1237901/


All Articles