Расширение ряда Тейлора как 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 функция.

Мой компилятор — Clang из Xcode 7.2, компилируемый с -O3,

5

Решение

Я ожидал, что компилятор может генерировать набор результатов для
синус и положить их наружу, на самом деле не нужно вычислять
серия Тейлор. Вместо этого сгенерированный код выполняет синус, как если бы он был
любая другая не-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;
}

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

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]