Reputation: 2313
I am working on an implementation of the sin() function based on the taylor series using templates. My code so far goes as follows:
template<unsigned I>
struct factorial{
enum{
value = I * factorial<I -1>::value
};
};
template<>
struct factorial<0>
{
enum{ value = 1};
};
template<unsigned pow>
inline double power(double const& value){
return value * power<pow-1>(value);
}
template<>
inline double power<1>(double const& value){
return value;
}
template <unsigned term>
inline double taylor_sine_term(double const& x) {
return (power<term>(-1) / factorial<(2*term)+1>::value) * power<(2*term)+1>(x);
}
The issue I am having is creating the function to use the taylor_sine_term
function to expand the series for N number of terms.The function would be functionally equivalent to the following.
template<unsigned terms>
inline double taylor_sine(double const& x){
return taylor_sine_term<1>(x)+taylor_sine_term<2>(x) + ... + taylor_sine_term<terms>(x);
}
Basically I need to figure out a way to generate a sequence of integer constants that can be used as the term number template parameter in the taylor_sine_term
function for N number of terms and sum them all together. The result will expand into the full taylor series for N number of terms. The problem is I don't know where to start.
Any help is appreciated, Thanks.
Upvotes: 0
Views: 340
Reputation: 303157
Same way you wrote the other ones: a recursive case and a base case:
template<unsigned terms>
inline double taylor_sine(double const& x) {
return taylor_sine_term<terms>(x) + // current term
taylor_sine<terms-1>(x); // rest of terms
}
template <>
inline double taylor_sine<0>(const double& x) {
return taylor_sine_term<0>(x);
}
Alternatively, you could use the index sequence trick to get all of them:
template <unsigned terms>
inline double taylor_sine(double const& x) {
return taylor_sine(x, std::make_index_sequence<terms+1>{});
}
template <unsigned terms, size_t... Is>
inline double taylor_sine(const double& x, std::index_sequence<Is...> ) {
double res = 0.0;
for (double t : {taylor_sine_term<Is>(x)...}) {
res += t;
}
return res;
/* or in C++17
return (taylor_sine_term<Is>(x) + ...);
*/
}
Note that you should change your base case on power
to be power<0>
.
Upvotes: 1
Reputation: 5321
It sounds like you want a recursively defined template
template<unsigned terms>
inline double taylor_sine(double const& x){
return taylor_sine<terms-1>(x)+taylor_sine_term<terms>(x);
}
Then you would want to specialize for either 0 or 1 to terminate. But I think you can't specialize the function template, so you would need to bury that all in a functor template, which you can specialize.
Upvotes: 0