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